Canvas.paint

I’m currently working on a classical ‘snake’ game like in the old Nokia cellphones. The project is nearly finished, now I’m in the stage of polishing things.

The body of the snake is stored into a array of string that holds the x and y canvas parameter. The movement of the snake is steered by reading the cursor keys and inserting a new element in the array and removing the last element. A 50 millisec timer reads the input and changes the array elements. The paint code is:

[code]
’ coordinates are stored as “x,y”
For i As Integer = 0 To Snakepositions.Ubound
paintPosX =Val( Mid(Snakepositions(i),0,InStr(0,Snakepositions(i),",")))
paintPosY =Val( Mid(Snakepositions(i),InStr(0,Snakepositions(i),",")+1))
If i = 0 Then
g.ForeColor=Preferences.SnakeHeadColor
Else

  g.ForeColor= CalcGradient(0,i,SnakePositions.Ubound,&c00800000,&cC6FFC600)
End If
'paint current element 
g.FillRect(paintPosX,paintPosY, SnakeUnit, SnakeUnit)

Next[/code]

This functions neat. The only remark that I have is that the movement of the snake is rather ‘bumpy’ which gives the impression of flashing. Every timer tick the new position is calculated and painted.
The length of ‘snakeunit’ = 16 pixel. Any suggestions on how I can make the movement less bumpy? I have reduced the size of SnakeUnit but then the movement is too slow. (The CalcGradient calculates the colorblend of the current element.)

Is your Canvas.DoubleBuffer property set to Yes?

Setting it to yes usually fixes most flashing issues experienced with Canvas drawing.

Also, you might want to store Integer values in your position array, instead of using string manipulation functions with each iteration in the loop.

Instr and Mid might slow down the algorithm a lot.

Hi Alwyn,

I profiled the code but it is really fast enough…

How do you know that? Profiling slows down your application and then it might be that some timer events are omitted.
There are only a few place where optimizing the code is necessary, one of it is the Paint event.
And are you using Refresh() in the timer’s Action event? In that case I would not re-calculate the stuff to be drawn if it has not changed.

Hi,

no, I don’t use Refresh()…

Hmmm, it is tricky to say what the problem might be with only the one snippet of code…

I’m wondering, just as a test, what happens when you change

g.ForeColor= CalcGradient(0,i,SnakePositions.Ubound,&c00800000,&cC6FFC600)

to a fixed color, e.g.:

g.ForeColor = &cff0000

Something else you could also try, on the Action event of the timer, disable the timer, call the Canvas.Refresh(), and then enable the timer again.

Then how is the Paint event raised from the timer’s Action event? Invalidate()?

Yep.

Can you post a video? I’m not sure what is ‘bumpy’ that you’re seeing. A 50millisec timer is about 20 frames per second. Could that be it?

OK, I will do that this evening. (Europe time)

And if Snakepositions.Ubound is a finite number then I would create an array of all the colors and cache it instead of recalculating them every loop

Is this OSX or WIN? I have done drawing 100x more complex than this under OSX quite smoothly

But also 20fps is well within the realm of human perception, perhaps only do a canvas.invalidate whenever you have calculated that there is in fact movement, as opposed to forcing it to redraw 20x a second if not needed

Another thing might be to draw on a PICTURE object instead of directly to the canvas, and the reduce your PAINT event to just a DRAWPICTURE statement. This way you control the buffering,

Also if this is for WIndows… turn GDI+ to ON

This Win. Forgot to mention. Thanks for the suggestions.

Here’s a screen capture View My Video

Remember: the capture is 5 fps but the game itself runs smoother. The bumpiness is caused by the block of 16 pixels appearing upfront. I thought maybe I can make the new block or snakepart appear more smoothly by some dissolve technique of some sort.

under the circumstances I don’t think that looks so bad … it is more likely the DISTANCE you are moving, that is causing the percieved bumpieness

Thanks. The capture is only 5 fps and inbetween the snake takes one or two moves which are not captured.

Game is looking good Alexander.

I recall playing a version of it written in QBasic, named Nibbles, back in the day when MS-DOS was still the OS of choice.

[quote=211477:@Alwyn Bester]Game is looking good Alexander.

I recall playing a version of it written in QBasic, named Nibbles, back in the day when MS-DOS was still the OS of choice.[/quote]

As a matter of fact I looked into the source of Nibbles, but they use the text screen (80*24) to display the game and create the snake with ASCII chars.

Yes, remember it being ASCII.

So do you have a virtual machine set up with MS-DOS then?

You can install QuickBasic in Windows. Feels strange to see that old UI…

O, ok, will have to try that some time.

I suppose that says a lot about backward compatibility when it comes to Microsoft products.