Question Graphics flickering and drawing on top of each other.

Dhatsah

Member
Joined
Nov 18, 2012
Messages
5
Programming Experience
Beginner
Hi there, You will see I am new to the forums so please be kind :)


I have a form, on which I draw an animated star field which is updated on a tick from a timer control, I have overlaid on the star field another graphic which represents the interior of a space ship. I am trying to make a game(I think that is why all teenagers start programming really)


I have managed to get them to both draw but my problem is that even though I call the UI draw sub after I have drawn all the stars in the star field, the stars still get drawn on top of the UI, I am not really sure what it is that I am doing wrong. Any advice would be greatly appreciated, also I am not sure which code you would want me show so please let me know, I would provide a screen shot but the problem is that every time I take one the stars are again hidden, they're only there for a split second, but it is quite noticeable.


Thanks in advance.
 
Thank you for your reply. I am not 100% sure what you mean, so I have posted the main form code and the code that is used to draw the images. I hope that I am right.

VB.NET:
Imports System.Threading

Public Class MainGameView


    Private Sub MainGameView_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        StartThreads()
        Turn()
        GameTick.Start()
    End Sub




    Public Function getG() ' function used to get the G for creating the graphics. 
        Return Me.CreateGraphics()
    End Function




    Private Sub GameTick_Tick(sender As Object, e As EventArgs) Handles GameTick.Tick


        UpdateStars() ' has to be in the main thread. 


    End Sub
End Class

and

VB.NET:
Imports System.ThreadingModule uiGraphics


    Dim black As Brush = Brushes.Black
    Dim rand As New Random()
    Dim UI As Bitmap




    'Public iSpeed As Integer = 1
    '                                                                   0       1   2   3       4       5
    Private stars(maxStars, 5) As Integer 'Tracks positon of stars      {state, x,  y,  size,   speed,  direction}






    Public Sub UpdateStars() 'ByRef g As Graphics
        If Warping = True Then
            WarpEffect()
        ElseIf iSpeed <> 0 Then
            DrawStars()


            'GenStar()
            T2.Join()
            T2 = New Thread(AddressOf GenStar)
            T2.Start()


            'MoveStars()
            T2.Join()
            T2 = New Thread(AddressOf MoveStars)
            T2.Start()


            drawUI()
            'GameView.T2.Join()
            'GameView.T2 = New Thread(AddressOf DrawStars)
            'GameView.T2.Start()
        ElseIf iSpeed = 0 Then
            DrawStars()
        End If
    End Sub


    Public Sub Turn()
        'T1.Join()
        'T1 = New Thread(AddressOf ResetView)
        'T1.Start()


        ResetView()
    End Sub


    Public Sub Warp()
        'Call starfield reset
    End Sub


    Private Sub ResetView() 'Used when switching between sectors/turning
        T2.Join()
        T2 = New Thread(AddressOf VirtualUpdateStars)
        T2.Start()


        T2.Join()
    End Sub




    Private Sub VirtualUpdateStars()
        Dim angle As Double
        For count = 0 To maxStars - 1 Step 1 '"Discards" all stars
            stars(count, 0) = 0
        Next


        For ticker = 0 To 1000
            GenStar()
            For count = 0 To maxStars - 1 Step 1
                If stars(count, 0) = 1 Then
                    angle = stars(count, 5) * Math.PI / 180
                    stars(count, 1) = stars(count, 1) + (Math.Cos(angle) * stars(count, 4) * 3 * (iSpeed + 1))
                    stars(count, 2) = stars(count, 2) + (Math.Sin(angle) * stars(count, 4) * 3 * (iSpeed + 1))
                End If


                If stars(count, 1) > 1024 Or stars(count, 1) < 0 Or stars(count, 2) > 780 Or stars(count, 2) < 0 Then
                    stars(count, 0) = 0
                End If
            Next
        Next
    End Sub


    Private Sub GenStar() 'Call via T2


        Dim count As Short = 0


        While (stars(count, 0) = 1 And count < maxStars - 1) 'First empty slot in array
            count += 1
        End While


        stars(count, 1) = xMid
        stars(count, 2) = yMid
        stars(count, 3) = rand.Next(4) + 1 'Size coefficient
        stars(count, 4) = rand.Next(3) + 1 'Speed coefficient
        stars(count, 5) = rand.Next(360) 'Angle in degrees, used instead of radians such that array could remain as integers
        stars(count, 0) = 1 'star exists


        'count = 0


    End Sub


    Private Sub MoveStars() 'Call via T2
        Dim angle As Double
        For count = 0 To maxStars - 1 Step 1
            If stars(count, 0) = 1 Then
                angle = stars(count, 5) * Math.PI / 180
                stars(count, 1) = stars(count, 1) + (Math.Cos(angle) * stars(count, 4) * (iSpeed + 1) * iSpeed)
                stars(count, 2) = stars(count, 2) + (Math.Sin(angle) * stars(count, 4) * (iSpeed + 1) * iSpeed)
            End If


            If stars(count, 1) > 1024 Or stars(count, 1) < 0 Or stars(count, 2) > 780 Or stars(count, 2) < 0 Then
                stars(count, 0) = 0
            End If
        Next




    End Sub


    Private Sub DrawStars() 'Call via T2
        Dim dist As Short
        Dim size As Short
        Dim radius As Short
        Dim white As Brush = Brushes.White
        Dim g As Graphics = MainGameView.getG


        'g.FillRectangle(black, 0, 0, MainGameView.Width, MainGameView.Height)
        For count = 0 To maxStars - 1 Step 1
            If stars(count, 0) = 1 Then
                dist = Math.Sqrt((stars(count, 1) - xMid) ^ 2 + (stars(count, 2) - yMid) ^ 2)
                size = stars(count, 3) * dist / 50
                radius = size / 2


                g.FillEllipse(white, stars(count, 1) - radius, stars(count, 2) - radius, size, size)


            End If


        Next
        drawUI()
    End Sub


    Private Sub WarpEffect()
        Dim black As Brush = Brushes.Black
        Dim p As Pen


        MainGameView.getG().FillRectangle(black, 0, 0, MainGameView.Width, MainGameView.Height)


        'Gen(Star)
        T2.Join()
        T2 = New Thread(AddressOf GenStar)
        T2.Start()


        'Move(stars)
        T2.Join()
        T2 = New Thread(AddressOf MoveStars)
        T2.Start()


        For count = 0 To maxStars - 1 Step 1
            If stars(count, 0) = 1 Then
                p = New Pen(Color.FromArgb(rand.Next(254), rand.Next(254), rand.Next(254), rand.Next(254)), rand.Next(5) + 5)
                MainGameView.getG().DrawLine(p, xMid, yMid, stars(count, 1), stars(count, 2))
            End If
        Next
    End Sub




    Public Sub makeUI()
        Dim g As Graphics
        g = MainGameView.CreateGraphics()
        UI = My.Resources.cockpit
        UI.MakeTransparent(Color.Fuchsia)
        g.DrawImage(UI, 0, 0)
    End Sub


    Public Sub drawUI()
        makeUI()


    End Sub
End Module

The thread is initialized in another module I assume you do not need that. Thanks you again :D
 
First things first, you should basically never be calling CreateGraphics yourself. You should be doing all your drawing on the Paint event of the control you want to draw on, either in the control's own OnPaint method, which requires creating your own custom control, or in the Paint event handler in the form. If you want this to work then the first thing to do is to reconstruct your code that way. Basically:

1. Declare one or more variables to store the data that represents the drawing.
2. On the Paint event, use the Graphics object provided to draw based on the data in the aforementioned variable(s).
3. To change the drawing, update the variable(s) and force a repaint.
4. To force a repaint, call the Refresh method of the control or its Invalidate and Update methods.

Here are a couple of examples of my own:

Very Simple Drawing Program
Manipulating GDI+ Drawings
 
Thank you for your reply.

Does this mean that I would need to draw both images into 1 picture box? Or does the form itself have a Paint Event?

Also why is it bad to call CreateGraphics ourself? I only ask so that I can better understand.

Thanks again.
 
Does this mean that I would need to draw both images into 1 picture box? Or does the form itself have a Paint Event?
Every control has it's own Paint event. A form is a control.
Also why is it bad to call CreateGraphics ourself? I only ask so that I can better understand.
Controls get repainted to the screen on each Paint event. Anything you draw on a control disappears each time it gets repainted. That's why you need to do your drawing on the Paint event: so that it gets redrawn each time the control is repainted.
 
Ok. So does this mean that I have to put my draw code in the paintevent as opposed to in a seperate module, or do you mean I have to call my module from the paintevent?

Sorry if I am being a bit dense.
 
You can call any methods you'd like from the Paint event handler method. Pass the provided Graphics object (or the whole PaintEventArgs object) if you need to draw in your other methods.
 
Back
Top