How to start a snake game?
Blitz3D Forums/Blitz3D Beginners Area/How to start a snake game?
| ||
I've been thinking of this for quite some time (3 hours), and I can't seem to understand how it work. I've managed to come up with an algorithm that only allows logical movements(you can only turn left or right from your current direction). Here're what I need help with: 1) how to keep generating blocks inside the game loop that allows the snake to swallow? 2) how to add the block to the end of the snake, and make it follow it when it moves? These are my current problem. I believe this would be pretty useful, as it seems pretty similiar to creating 2d or 3d trails. :) Please help, and thanks in advance! |
| ||
1) what do you mean with swallow ? 2) Basically, you can think at your snake like a collection of type elements. Start for example with three elements, which represents an head, the body, and the tail. Each element should have a direction field, and when the snake walks, each element should take the new direction from the next one, while the first one (the head), changes its direction with the player control. ;snake structure example type t_snake field direction ;an integer indicating the direction field x ;x pos field y ;y pos end type In other words, suppose the snake goes up. At this moment, the head, the body and the tail have the same direction. Now you turn left; the head direction changes, so in the next loop: - the tail will move towards its direction, and takes the body's position and direction - the body will move toward its direction, and takes the head's position and direction - the head will move toward its direction, and takes the new direction from the player And so on. When you want to make the snake longer, just add a new element to the list, and manage its movement as well. This is a very rough example, but should put you in the right path; plus, if you try this on paper, drawing some simple square with an arrow which indicates the direction, you will get what I mean.. Sergio. |
| ||
A default game frameworks is a sutchGraphics 800,600,32,2 SetBuffer BackBuffer() While Not KeyHit(1) Flip Wend End inside you could generate a "meal" by using X=Rnd(10,600) and Y=Rnd(10,400) and then drawing a rect X,Y,10,10 If SERVED = 0 Z=Rnd(GraphicsWidth()-10) C=Rnd(GraphicsHeight()-10) SERVED = 1 EndIf Rect Z,C,10,10 thats how you generate meals. Now On to player movement. first you determine how the snake moves....ther are 4 directions so we assign 4 keys to set 4 directions If KeyHit(208) DIR=1 ElseIf KeyHit(200) DIR=2 ElseIf KeyHit(205) DIR=3 ElseIf KeyHit(203) DIR=4 EndIf If DIR=1 X=X+0 Y=Y+5 Rect X,Y,10,10 ElseIf DIR=2 X=X+0 Y=Y-5 Rect X,Y,10,10 ElseIf DIR=3 X=X+5 Y=Y+0 Rect X,Y,10,10 ElseIf DIR=4 X=X-5 Y=Y+0 Rect X,Y,10,10 EndIf now we set up collisions & score If RectsOverlap(X,Y,10,10,Z,C,10,10) SERVED=0 SCORE = SCORE + 10 EndIf Text 20,20,SCORE My Samples entire code : Graphics 800,600,32,2 SetBuffer BackBuffer() LENG = 10 DIR = 1 While Not KeyHit(1) Cls If SERVED = 0 Z=Rnd(GraphicsWidth()-10) C=Rnd(GraphicsHeight()-10) SERVED = 1 EndIf Rect Z,C,10,10 If KeyHit(208) DIR=1 ElseIf KeyHit(200) DIR=2 ElseIf KeyHit(205) DIR=3 ElseIf KeyHit(203) DIR=4 EndIf If DIR=1 X=X+0 Y=Y+5 Rect X,Y,10,10 ElseIf DIR=2 X=X+0 Y=Y-5 Rect X,Y,10,10 ElseIf DIR=3 X=X+5 Y=Y+0 Rect X,Y,10,10 ElseIf DIR=4 X=X-5 Y=Y+0 Rect X,Y,10,10 EndIf If RectsOverlap(X,Y,10,10,Z,C,10,10) SERVED=0 SCORE = SCORE + 10 EndIf Text 20,20,SCORE Flip Wend End |
| ||
thanks for the reply, but I still have some problem implementing it. Right now, I need help on cloning more and more "body blocks" as the game progresses. I only know the copyimage command. Is there a way I can use an array instead, to keep track of my blocks? or do I have to do something like this: type tSnake field direction field xpos field ypos field imgName end type ? Please help. Thanks :) |
| ||
First when i started writing my sample i tough types was teh way togo but tehn i tough wait he's a beginner why make things harder....... just try my last piece of code. the only thing i didn't implement was making the snake longer. ther are hints tough, have fun! |
| ||
@darklordz, yes could be harder, but in the long term would be also a good occasion to learn types. If you have different images for the snake, for example one for the head, one for the body, and one for the tail, just store it in an array of images, and then set the index in each snake element, when you create it: dim arr_img(3) ;array of images arr_img(1) = loadimage("snake_head.png") arr_img(2) = loadimage("snake_body.png") arr_img(3) = loadimage("snake_tail.png") you can also use three constants to make a more readable code: const s_head = 1 const s_body = 2 const s_tail = 3 for n = 1 to 3 snake.t_snake = new t_snake snake\img = n next when you need to make the snake longer, you have to change the tail into a body, and add a new tail. So you have to go to the last element in your snake collection: snake.t_snake = last snake and change the image to a body one snake\img = s_body then add a new tail snake.t_snake = new t_snake ;this should be the tail, because will be added at the end snake\img = s_tail Hope this helps, Sergio. |
| ||
Thanks for all the advices!! Here's what I have came up with, based on darklordz's suggestion. I'll try implementing yours in a moment, sergio. I'll let you know how it goes.Graphics 640,480,16,2 Global snakespeed = 5 Global foodx = Rnd(640) Global foody = Rnd(480) Global score = 0 Type snakeinfo Field xpos Field ypos Field direction ;1=up,2=right,3=down,4=right End Type snake.snakeinfo = New snakeinfo snake\xpos = 320 snake\ypos = 240 snake\direction = 1 block = CreateImage(10,10) SetBuffer ImageBuffer(block) Rect 0,0,10,10,1 food = CopyImage(block) SetBuffer BackBuffer() While Not KeyHit(1) Cls Text 0,0,score Select snake\direction Case 1 snake\ypos = snake\ypos - snakespeed Case 2 snake\xpos = snake\xpos + snakespeed Case 3 snake\ypos = snake\ypos + snakespeed Case 4 snake\xpos = snake\xpos - snakespeed End Select DrawImage block, snake\xpos, snake\ypos DrawImage food, foodx, foody If ImagesCollide(block,snake\xpos,snake\ypos,0,food,foodx,foody,0) Then score = score + 10 foodx = Rnd(640) foody = Rnd(480) EndIf If KeyHit(200) Then If snake\direction = 2 Or snake\direction = 4 Then snake\direction = 1 EndIf If KeyHit(203) Then If snake\direction = 1 Or snake\direction = 3 Then snake\direction = 4 EndIf If KeyHit(205) Then If snake\direction = 1 Or snake\direction = 3 Then snake\direction = 2 EndIf If KeyHit(208) Then If snake\direction = 2 Or snake\direction = 4 Then snake\direction = 3 EndIf Flip Wend |
| ||
Type tSnake Field xpos Field ypos Field snaketype End Type Const head = 1 Const body = 2 Const tail = 3 Snake.tSnake = New tSnake Snake\xpos = 10 Snake\ypos = 10 Snake\snaketype = head Snake.tSnake = New tSnake Snake\xpos = 10 Snake\ypos = 11 Snake\snaketype = body Snake.tSnake = New tSnake Snake\xpos = 10 Snake\ypos = 12 Snake\snaketype = tail Dim body(3) body(1) = LoadImage "Head.bmp" body(2) = LoadImage "Body.bmp" body(3) = LoadImage "Tail.bmp" Graphics 640, 480, 0, 2 SetBuffer BackBuffer() While Not KeyHit(1) ;input section ;blah, blah, blah newXpos = ?? newYpos = ?? ;logic section lastXpos = newXpos lastYpos = newYpos For Snake.tSnake = Each tSnake tempXpos = Snake\xpos tempYpos = Snake\ypos Snake\xpos = lastXpos Snake\ypos = lastYpos lastXpos = tempXpos lastYpos = tempYpos Next If FoodEaten = TRUE Snake.tSnake = Last tSnake Snake\snaketype = body Snake.tSnake = New tSnake Snake\xpos = lastXpos Snake\ypos = lastYpos Snake\snaketype = tail EndIf ;drawing section CLS For Snake.tSnake = each tSnake DrawImage body(Snake\snaketype), Snake\xpos * 32, Snake\ypos * 32 Next Flip Wend EndI just realized that my code will always draw the images the same way regardless of the direction of the next body part. I'm sure you can figure out how to make that work though. |
| ||
Help again... All of a sudden, I just can't seem to think about it logically anymore. I can't quite understand your code there, wolron. Here's what I have:Graphics 640,480,16,2 Type tSnake Field xPos Field yPos Field SnakeType Field Direction End Type Const head = 1 Const body = 2 Const tail = 3 Const up = 1 Const rgt = 2 Const dwn = 3 Const lft = 4 Snake.tSnake = New tSnake Snake\xPos = 320 Snake\yPos = 240 Snake\SnakeType = Head Snake\Direction = up Snake.tSnake = New tSnake Snake\xPos = 320 Snake\yPos = 241 Snake\SnakeType = Body Snake\Direction = up Snake.tSnake = New tSnake Snake\xPos = 320 Snake\yPos = 242 Snake\SnakeType = Tail Snake\Direction = up Dim SnakeBody(3) Block = CreateImage(24,24) SetBuffer ImageBuffer(Block) Oval 0,0,24,24 For count = 1 To 3 SnakeBody(count) = CopyImage(Block) Next SetBuffer BackBuffer() While Not KeyHit(1) Cls If KeyHit(200) Then If snake\direction = lft Or snake\direction = rgt Then snake\direction = up EndIf If KeyHit(203) Then If snake\direction = up Or snake\direction = dwn Then snake\direction = lft EndIf If KeyHit(205) Then If snake\direction = up Or snake\direction = dwn Then snake\direction = rgt EndIf If KeyHit(208) Then If snake\direction = lft Or snake\direction = rgt Then snake\direction = dwn EndIf For Snake.tSnake = Each tSnake If snake\direction Next Flip Wend As you can see, once inside the game loop, my codes are totally messed up. I'm really having a hard time with types. Here're some questions: 1) snake.tSnake = New tSnake 4 times? As you can see from my previous codes, I only change the direction of the "head", and the rest of the body parts are suppose to follow. But how do I access the "Head" record, and set it's x and y values? 2) None yet. I'm so frustrated, I can't put it in words. Perhaps I'll remember em later. Well, help again, I suppose. And thanks to all of you for your patience and help! |
| ||
I've got it working at last, after blindly tweaking and modifying wolron's code. I really have no idea how and what made it work, but I'm going to find out first thing tomorrow morning. Here's the code:Graphics 640,480,16,2 Type tSnake Field xPos Field yPos Field SnakeType End Type Global foodx = Rnd(640) Global foody = Rnd(480) Const head = 1 Const body = 2 Const tail = 3 Const up = 1 Const rgt = 2 Const dwn = 3 Const lft = 4 Global direction = up Snake.tSnake = New tSnake Snake\xPos = 320 Snake\yPos = 160 Snake\SnakeType = Head direction = up Snake.tSnake = New tSnake Snake\xPos = 320 Snake\yPos = 264 Snake\SnakeType = Body direction = up Snake.tSnake = New tSnake Snake\xPos = 320 Snake\yPos = 288 Snake\SnakeType = Tail direction = up Dim SnakeBody(3) Block = CreateImage(16,16) SetBuffer ImageBuffer(Block) Oval 0,0,16,16 For count = 1 To 3 SnakeBody(count) = CopyImage(Block) Next food = CopyImage(block) SetBuffer BackBuffer() While Not KeyHit(1) Cls DrawImage food,foodx, foody If KeyDown(200) Then direction = up If KeyDown(203) Then direction = lft If KeyDown(205) Then direction = rgt If KeyDown(208) Then direction = dwn If direction = up Then snake.tSnake = First tsnake newXpos = snake\xPos newYpos = snake\yPos - 3 EndIf If direction = dwn Then snake.tSnake = First tsnake newXpos = snake\xPos newYpos = snake\yPos +3 EndIf If direction = lft Then snake.tSnake = First tsnake newXpos = snake\xPos -3 newYpos = snake\yPos EndIf If direction = rgt Then snake.tSnake = First tsnake newXpos = snake\xPos +3 newYpos = snake\yPos EndIf lastXpos = newXpos lastYpos = newYpos For Snake.tSnake = Each tSnake tempXpos = Snake\xpos tempYpos = Snake\ypos Snake\xpos = lastXpos Snake\ypos = lastYpos lastXpos = tempXpos lastYpos = tempYpos Next If ImagesCollide(snakebody(1),newxpos, newypos,0,food,foodx,foody,0) Then foodx = Rnd(620) foody = Rnd(460) Snake.tSnake = Last tSnake Snake\snaketype = body Snake.tSnake = New tSnake Snake\xpos = lastXpos Snake\ypos = lastYpos Snake\snaketype = tail EndIf For Snake.tSnake = Each tSnake DrawImage snakebody(Snake\snaketype), Snake\xpos +16, Snake\ypos +16 Next Flip Wend If you test this out, you'll realise the following glitches: 1) I want the parts of the snake to follow one another, not overlap each other slightly. 2) I want the snake to move within a grid, say 24x24 or 32x32. But the snake in the code moves/turns accordingly to my controls 3) there're some problems when the snake collides with the food. Not very accurate. Anyway, thanks guys! I'll still be working on this one, until I've fully understand every command in it. And I hope that you'll all continue to support and help me. :) cheers |
| ||
2) I want the snake to move within a grid, say 24x24 or 32x32. But the snake in the code moves/turns accordingly to my controls The code I wrote does make it follow a grid. You changed the drawing code from: DrawImage body(Snake\snaketype), Snake\xpos * 32, Snake\ypos * 32to DrawImage snakebody(Snake\snaketype), Snake\xpos +16, Snake\ypos +16Notice that I was mulitplying the x & y values by 32. This was to make the snake align to a 20x15 grid of 32x32 squares. The snake moves in exact increments (gridsquare1 to gridsquare2 to ...). In your code you are making the snake move by 3 PIXELS each time. Change them to 1's (so that your snake moves 1 GRIDSQUARE at a time) and change your snake drawing line to match mine. You will most likely have to add a timer to slow the snake down, otherwise it will travel at the refresh rate of your monitor (60 Hz or more). If you prefer it not to move in this fashion (incrementally from gridsquare to gridsquare) but more like how PacMan moves (smoothly from intersection to intersection) then you would have to change a lot. You have to do things like storing the last direction pressed by the player but not actually changing direction until you reach the next gridsquare. This can be done, but it's best to try doing it the way I showed above first. |
| ||
thanks for the info wolron. I's just so desperate to get it working last night, I tried changing everything. I'll try to correct it. Just one thing I do not understand, why 10,10 10,11 10,12 for head body and tail? shouldn't they be 32(ooer, 16) pixels apart? Just need to understand that bit. Thanks! |
| ||
Those were just some random numbers I threw in there to start at. It's not 10 pixels, it's 10 gridsquares, which at 32 pixels per square would be 320 pixels, or center of the screen. So "11" is 32 pixels below "10" and "12" is 32 pixels below "11". Get it? You certainly could change it to 16 pixels per gridsquare if you wanted to, or even 8. You decide what you want. 32 pixels is a bit big isn't it? |
| ||
I'm new to Blitz, but I remember making something like this on AMOS Basic in the olden days! A snake game is a good project. Just a though though... when the snake changes direction, won't you need 'corner pieces' for the body to make it look as if it's turning? I haven't seen your images, but if they're the way I imagine them you'll need a body segment that doesn't always lie horizontal or vertical. Am I over-complicating this now? Sorry! |
| ||
hi again everyone. I'm halting the snake game project at the momment to complete my pong game. I thought that it would be silly to just create a game halfway and leave it. Therefore, I'll be adding some finishing touches to it. I've customized my pong game to feature levels of difficulties as well as support skins/themes. Although I don't really expect it to be commercial, I's hoping that it'd look and feel like a commercial game. Cheers everyone! I'd start working on the snake game again once I'm done with the pong thingy! Thank you all for your help |