moving my snake

I’m trying to program a snake game just to practise my Xojo skills. So far I’ve managed to draw the snake onto a canvas. through the paint event, but now I’m not sure of how to actually move the snake inits supposed direction. Any ideas?
here’s the paint event:

g.ClearRect(0, 0, g.Width, g.Height)
g.ForeColor = RGB(0, 0, 0)
g.DrawRect(0, 0, me.Width, me.Height)

//maintaining size of snake in ratio to the window
dim windowWidth As double
dim SnakeUnit As integer
windowWidth = Floor(self.Width / 50)
snakeUnit = windowWidth

reDim snake(0)

//direction of snake
snakeDirection = "right"

//draw snake
for i as integer = ubound(snake) Downto -1
  g.ForeColor =  &c555555
  g.FillRect(0, 0, snakeUnit, snakeUnit)
  
  'select snakeDirection
  'case "right"
next

snake is an array, snakeDirection is a property. I’m trying to make the head move first and then its ‘body’ follows the head’s past coordinates, which is why the select case isn’t completed yet. But before that, I can’t find a way to move my snake’s head in the first place. Please help.

If the snake head is at position 3,4
Then where it goes next will be those co-ordinates, where one of the numbers has changed by 1

If going right, then the 3 will become 4
If going up, then the 4 will become 3

You need an Xvector and YVector integer.
One of them will be 0 , and one of them will be -1 or +1

Each ‘turn’ You add the value of the XVector to the x co-ord, and the Yvector to the Y co-ord, which will maintain a direction until you change the values of the XVector and YVector variables.

To make the snake move, this new value is inserted at position 0 of an array of co-ordinates.

Say the snake is 3 blocks in length, and the snake is at

3,4
3,5
4,5

To move it up, set the YVector to be -1 and XVector to be 0
Add those values to the values array(0) element, getting you 3,3

Insert 3,3 at position 0

Now you have
3,3
3,4
3,5
4,5

But since the snake is only 3 parts long, discard the 4th array element

And draw the snake using elements 0,1, and 2

You add a new element at pos(0) and you remove the last element. This is my Xojo snake:

and some settings to consider:

1 Like

Wow, looks great! There must be quite sophisticated coding since you can adjust the appearance and difficulty. I’ve only just started learning Xojo for a few months so I thought I could try code a game to practice. May I look at your code to get some insight and ideas @Alexander van der Linden ?

Sure. I’ll get back to you asap. Can’t get code now.

Ok. There is no ‘sophisticated’ code. It’s just my code, and remember there are more and different ways to reach your goals. This is just a small part of the code. When the snake dies I take a picture of the current canvas and store that with the user’s score in a SQLite db, so you can look back on previous games.

Of course I use a Canvas for the snake’s grid. I initialize it with:

[code]g.ForeColor = Prefs.GridColor

Dim StepSize As Integer = Prefs.BlockSize + Prefs.DividerSize

'precalculated width of the playing field
For I As Integer = 1 To MainWindow.Width Step StepSize
For J As Integer = 1 To MainWindow.Height Step StepSize
g.FillRect(I,J,Prefs.BlockSize,Prefs.BlockSize)
Next
Next [/code]

Prefs is a class in which I store all the user’s presets.

Next I calculate if the grid nicely fits into the Window

[code]'Adjust Window size (and Canvas)
If MainWindow.Width <> Prefs.BlockCount * StepSize Then
MainWindow.Width = (Prefs.BlockCount * Stepsize) + 1
MainWindow.Height = (Prefs.BlockCount * StepSize) + 1
End If

'define upper boundaries for trapping bouncing the walls
XMax = (MainWindow.Width / StepSize)+1
'MsgBox(Str(XMax))
'same for Ymax (square)
YMax = XMax[/code]

Next I initialise a Timer. The interval is set with the users speed setting
Then I draw the snake. It is a class with several methods and properties. The snake’s elements are drawn with a color blend:

for K as Integer = 0 to Ubound(TheSnake.Elements,1)-1 g.ForeColor= CalcGradient(0,k,Ubound(TheSnake.Elements),TheSnake.Headcolor,TheSnake.Tailcolor) g.FillRect((TheSnake.Elements(k,0)*StepSize)+1,(TheSnake.Elements(k,1)*StepSize)+1,Prefs.BlockSize,Prefs.BlockSize) next
The ‘CalcGradient’ method is a mod of the Colorblend function you can find (google Xojo colorblend).

In the timer event I trap the cursor keys (I could have done this with Select Case). As the snake can’t reverse you have to force the ‘wrong’ key into the right direction:

[code]If Keyboard.AsyncKeyDown(123) Then
If TheSnake.OldDirection <> “R” Then
TheSnake.Direction = “L”
End If
End If
If Keyboard.AsyncKeyDown(124) Then
If TheSnake.OldDirection <> “L” Then
TheSnake.Direction = “R”
End If
End If
If Keyboard.AsyncKeyDown(125) Then
If TheSnake.OldDirection <> “D” Then
TheSnake.Direction = “U”
End If
End If
If Keyboard.AsyncKeyDown(126) Then
If TheSnake.OldDirection <> “U” Then
TheSnake.Direction = “D”

End If
End If

TheSnake.OldDirection = TheSnake.Direction
[/code]

To place the cookie you have to make sure that it isn’t placed on a current snake (element):

[code]Do
onSnake = False
'randomly generate new food position
foodXPos = App.Randomizer.InRange(0, BlockCount - 1)
foodYPos = App.Randomizer.InRange(0, BlockCount - 1)

'make sure the position of the food does not lie on the snake,
'we loop through every segment of the snake and compare it’s position with the position of the food
For i = 0 To Ubound(theSnake.Elements)
If (foodXPos = TheSnake.Elements(i,0)) And (foodYPos = TheSnake.Elements(i,1)) Then
'ok, so we hit the snake! this food position is not suitable
onSnake = True
Exit For
End If
Next

Loop Until (onSnake = False)[/code]

Good luck and happy coding!

Thanks! I am pretty sure my code is complete thanks to your reference, but there’s just one thing.

Sub Action()
  Dim s As Animal
  Dim qSize As integer
  
  reDim snake(3)
  
  qSize = Round(gameCanvas.Width / 50)
  xEnd = Round((gameCanvas.Width / qSize)* qSize)
  yEnd = Round((gameCanvas.Height / qSize)* qSize)
  
  For sn As Integer = snake.Ubound DownTo 0
    s = snake(sn)
    s.Direction = "R"
    
    If Keyboard.AsyncKeyDown(123) Then
      If s.oldDirection <> "R" Then
        s.Direction = "L"
      End If
    End If 
    If Keyboard.AsyncKeyDown(124) Then
      If s.OldDirection <> "L" Then
...........................

It shows this and then says there’s a bug on the ’ s.Direction = “R” 'line. I’m having trouble finding a way to actually move the snake. Any ideas?

if s.Direction = "R" Then
  s.SetDirection("R")
  s.oldDirection = s.Direction
elseif s.Direction = "L" Then 
  s.SetDirection("L")
  s.oldDirection = s.Direction
elseif s.Direction = "U" Then 
  s.SetDirection("U")
  s.oldDirection = s.Direction
elseif s.Direction = "D" Then 
  s.SetDirection("D")
  s.oldDirection = s.Direction
end if

the setDirection method is supposed to add a blockSize to the x coordinate of ‘s’ if it goes right for every timer period and vice versa, but then right after the app runs the bug shows up and the interface retreats.

What does it say the trouble is?

Guessing it is scope … is S visible to the code at this point?
if it is, is it nil? (in which case this code is happening before you have created S)

If .direction wasnt a string variable, it wouldnt run at all.

In every timertick you read the keys. Depending on the pressed key the snake moves in 3 possible directions.

In my snake implementation the Snake array only keeps track of X and Y coordinates of the grid. Not the real coordinates of the Canvas, that is done in a translation of the grid to Canvas coordinates.

So if the grid is eg. 10x10 squares and the snake moves to the right and the ‘up’ key is pressed a new element is pushed at snake(0) which holds the block coordinate that is immediately above the current element(0) and the last element is deleted. Then you call the drawing method that fills that particular block. So the snake moves up. Then you repeat it in the next timer tick.

So if the snake(0) = 5.5 then the new snake(0) holds now 5.4. If there is no key pressed in the timer tick you keep moving in that direction.

I was a bit busy a few days ago.Just got back to the code. I’m not able to move my snake. There were some errors that occurred and I tried removing the snake array and converted it into just an initialised snake object. Still having trouble moving the snake. I just can’t find the way to move the single snake body across the grid. I’m not sure how to utilise the x and y coordinates.Would really appreciate the help.

Send me your code in a PM and I will have a look at it.

I created a small demo project that shows you how to move the snake around the grid.
DemoSnake

Beware, I coded it real quick and dirty but it works. No wall trapping, no cookies just keyboard/snake interaction.

Thanks! I’ll be sure to experiment with the example. I haven’t fully understood yet of how to utilise the array class in Xojo so your example should help.

Hello,
Is it possible to share your snake example again ? (link dead)
Thanks a lot

Stephan

Yes, send me a pm and I mail you a copy

You can also find Xojo code for a simple Snake-Game when you scroll down this page: https://bit.ly/3iGi8fk
Direkt link to source code: https://bit.ly/2ZJ5aGc

This thread is old and probably what I am going to add will not help the OP but it may help people reading it in the future. I would like to point out that there are two ways (that I know) to program motion:

First option: One can set a timer to fire at regular intervals and change the position of the object a certain distance each time the timer fires (see the example code posted by Alexander). To control the speed of the object one can decrease the timer period or increase the distance of each jump.

Second option: Use the time elapsed from the previos position, the speed of the object and its direction (plus its acceleration, if there is one) to calculate the new position. Do that calculation repeteadly, inside a timer for example.

For a snake moving inside a grid at constant speed (which may vary in time, but not due to a continuous acceleration, but rather in discountinuos steps) the first option is perfectly fine. However, with this approach if the timer can’t fire when you expect it to fire the moving object will slow down.

The second option doesn’t require the timer to fire exactly when it was intended to move the object to the correct position, but it involves understanding and using (quite simple) motion equations. Also, if there is any acceleration involved in the motion (like gravity), the second option is easier to use, in my opinion.

Julen

1 Like

Thanks