Search code examples
c#.nettransparencygdi+drawstring

Layering graphics with transparency


Just making a little game and want to layer my pause menu over top.

A timer is responsible for the game loop. When it's paused, it calls a separate function that draws the pause menu. Right now I am drawing a small centred rectangle. The rectangle however isn't transparent, even though I clear it to be transparent.

Is there any way I can do that?

Here's the code for my game loop that updates the states and draws based on them. As you can see, when the game is paused, it calls a separate method.

    private void tmrGameLoop_Tick(object sender, EventArgs e)
    {

        if (Paused)
        {
            Pause();
            return;
        }

        using (Graphics gr = CreateGraphics())
        {
            using (BufferedGraphicsContext bgc = new BufferedGraphicsContext())
            {
                using (BufferedGraphics bg = bgc.Allocate(gr, DisplayRectangle))
                {
                    bg.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                    bg.Graphics.Clear(Color.Transparent);
                    // draw the stuff
                    bg.Render();
                }
            }
        }
    }

This is Pause(). It draws over top as expected, but because it's a separate graphics object, it draws over and isn't transparent as I expected it to be.

    private void Pause()
    {
        using (Graphics gr = CreateGraphics())
        {
            using (BufferedGraphicsContext bgc = new BufferedGraphicsContext())
            {
                using (BufferedGraphics bg = bgc.Allocate(gr, m_menu))
                {
                    bg.Graphics.Clear(Color.Transparent);
                    // draw pause menu
                    bg.Render();
                }
            }
        }
    }

Is there any way to do this so that it is transparent?


Solution

  • You seem to believe that Graphics.Clear(Color.Transparent) would create a transparent canvas.

    Well, this only true if you apply it to a Bitmap. For controls it lets the BackColor of the Parent shine through and for Forms, which don't have a Parent it makes the Form look black.

    It also resets the Graphics object, which may also not be what you want..

    Here is how to draw a semi-transparent overlay over a Form:

    using (SolidBrush br = new SolidBrush(Color.FromArgb(192, Color.Silver)))
        g.FillRectangle(br, ClientRectangle);
    
    StringFormat fmt = new StringFormat()
        { Alignment = StringAlignment.Center,
          LineAlignment = StringAlignment.Center };
    
    using (SolidBrush br = new SolidBrush(Color.FromArgb(128, Color.Tomato)))
    using (Font f = new Font("Consolas", 40f))
        g.DrawString("PAUSED",f, br, ClientRectangle, fmt);
    

    Result:

    enter image description here

    Use your numbers for the alpha values of the overlay and (maybe) the text!

    Usually the Graphics object to use should be the e.Graphics from the Form's Paint event.

    But since you seem to do all your drawing from a Timer.Tick you might get away with creating it using CreateGraphics, which is usually not recommended, as the result is non-persistent..