Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Question about snake game
#1
I have a question about the snake game. The snake's body is divided into small pieces and they follow the head. How can I make the pieces that make up the body follow the head of the snake when I move it?
Reply
#2
Here's a port of an n6 example game. Hopefully you can find some clues by looking at the code Smile  I don't remember why I implemented the game like this, and probably there are smarter ways.

Code:
' Port of n6 example game.

SNAKE_MAX_LENGTH = 30*40
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
snake = dim(SNAKE_MAX_LENGTH, 2)
level = dim(40, 30)

set window "Smape", 320, 240, false, 2
set redraw off

do
    snakeLength = 1
    snakeHead = 0
    snakeDirection = 0
    speed = 10
    speedCounter = speed
    snake[snakeHead][0] = 20
    snake[snakeHead][1] = 15
    for y = 0 to 29  for x = 0 to 39  level[x][y] = 0
    gameOver = false
    nextPlupTime = clock()
    do
        if clock() >= nextPlupTime
            if rnd(3) = 0  level[rnd(40)][rnd(30)] = 2
            else  level[rnd(40)][rnd(30)] = 1
            nextPlupTime = clock() + 2000 + rnd(2000)
        endif

        if keydown(38) and snakeDirection <> DOWN  snakeDirection = UP
        if keydown(40) and snakeDirection <> UP  snakeDirection = DOWN
        if keydown(37) and snakeDirection <> RIGHT  snakeDirection = LEFT
        if keydown(39) and snakeDirection <> LEFT  snakeDirection = RIGHT
   
        speedCounter = speedCounter - 1
        if speedCounter = 0
            prev = snakeHead
            if snakeDirection > 0  snakeHead = (snakeHead + 1)%SNAKE_MAX_LENGTH
            speedCounter = speed
            if snakeDirection = UP
                snake[snakeHead][0] = snake[prev][0]
                snake[snakeHead][1] = snake[prev][1] - 1
            elseif snakeDirection = DOWN
                snake[snakeHead][0] = snake[prev][0]
                snake[snakeHead][1] = snake[prev][1] + 1
            elseif snakeDirection = LEFT
                snake[snakeHead][0] = snake[prev][0] - 1
                snake[snakeHead][1] = snake[prev][1]
            elseif snakeDirection = RIGHT
                snake[snakeHead][0] = snake[prev][0] + 1
                snake[snakeHead][1] = snake[prev][1]
            endif
            x = snake[snakeHead][0]
            y = snake[snakeHead][1]
            if x < 0 or x >= 40 or y < 0 or y >= 30
                gameOver = true
            else
                if level[x][y] > 0
                    snakeLength = snakeLength + 1
                    if level[x][y] = 2  speed = max(speed - 1, 0)
                    level[x][y] = 0
                endif
            endif
        endif

        set color 0, 0, 0
        cls

        for y = 0 to 29
            for x = 0 to 39
                if level[x][y] = 1
                    set color 0, 255, 0
                    draw rect x*8, y*8, 8, 8 , true
                elseif level[x][y] = 2
                    set color 255, 0, 0
                    draw rect x*8, y*8, 8, 8, true
                endif
            next
        next

        set color 255, 255, 255
        set caret 0, 0
        x = snake[snakeHead][0]
        y = snake[snakeHead][1]
        for i = snakeHead to snakeHead - snakeLength + 1
            j = i
            if j < 0 then j = j + SNAKE_MAX_LENGTH
            draw rect snake[j][0]*8, snake[j][1]*8, 8, 8, true
            if i <> snakeHead
                if snake[j][0] = x and snake[j][1] = y then gameOver = true
            endif
        next

        wait 10
        redraw
    until gameOver
loop


Attached Files
.n7   smape.n7 (Size: 3.14 KB / Downloads: 3)
Reply
#3
Love the "classics"...

Could not help myself... Added a few minor upgrades: Little bit of colour; Score/Hiscore; Quit level and restart (ESC); Quit game (Q).  Note: No external hiscore.

Scoring has been modified. "Green" food is the normal 10 points. "Red" food is worth 100 points. Note: The speed of the snake will still increase... Moo Ha Ha Ha...


.n7   snake2.n7 (Size: 4.31 KB / Downloads: 4)

Challenge: Sound and messages?

J
Logic is the beginning of wisdom.
Reply
#4
(07-20-2024, 10:46 AM)johnno56 Wrote: Love the "classics"...

Could not help myself... Added a few minor upgrades: Little bit of colour; Score/Hiscore; Quit level and restart (ESC); Quit game (Q).  Note: No external hiscore.

Scoring has been modified. "Green" food is the normal 10 points. "Red" food is worth 100 points. Note: The speed of the snake will still increase... Moo Ha Ha Ha...



Challenge: Sound and messages?

J

Would be interesting to modify the visuals so that the snake uses tiles with rounded corners where it turns etc. But I'm too busy with that game jam thing (right now I'm sitting on a bench at the mall though, not jamming at all, wife and youngest daughter running around in clothes stores ...).
Reply
#5
(07-20-2024, 09:23 AM)Marcus Wrote: Here's a port of an n6 example game. Hopefully you can find some clues by looking at the code Smile  I don't remember why I implemented the game like this, and probably there are smarter ways.

Code:
' Port of n6 example game.

SNAKE_MAX_LENGTH = 30*40
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
snake = dim(SNAKE_MAX_LENGTH, 2)
level = dim(40, 30)

set window "Smape", 320, 240, false, 2
set redraw off

do
    snakeLength = 1
    snakeHead = 0
    snakeDirection = 0
    speed = 10
    speedCounter = speed
    snake[snakeHead][0] = 20
    snake[snakeHead][1] = 15
    for y = 0 to 29  for x = 0 to 39  level[x][y] = 0
    gameOver = false
    nextPlupTime = clock()
    do
        if clock() >= nextPlupTime
            if rnd(3) = 0  level[rnd(40)][rnd(30)] = 2
            else  level[rnd(40)][rnd(30)] = 1
            nextPlupTime = clock() + 2000 + rnd(2000)
        endif

        if keydown(38) and snakeDirection <> DOWN  snakeDirection = UP
        if keydown(40) and snakeDirection <> UP  snakeDirection = DOWN
        if keydown(37) and snakeDirection <> RIGHT  snakeDirection = LEFT
        if keydown(39) and snakeDirection <> LEFT  snakeDirection = RIGHT
   
        speedCounter = speedCounter - 1
        if speedCounter = 0
            prev = snakeHead
            if snakeDirection > 0  snakeHead = (snakeHead + 1)%SNAKE_MAX_LENGTH
            speedCounter = speed
            if snakeDirection = UP
                snake[snakeHead][0] = snake[prev][0]
                snake[snakeHead][1] = snake[prev][1] - 1
            elseif snakeDirection = DOWN
                snake[snakeHead][0] = snake[prev][0]
                snake[snakeHead][1] = snake[prev][1] + 1
            elseif snakeDirection = LEFT
                snake[snakeHead][0] = snake[prev][0] - 1
                snake[snakeHead][1] = snake[prev][1]
            elseif snakeDirection = RIGHT
                snake[snakeHead][0] = snake[prev][0] + 1
                snake[snakeHead][1] = snake[prev][1]
            endif
            x = snake[snakeHead][0]
            y = snake[snakeHead][1]
            if x < 0 or x >= 40 or y < 0 or y >= 30
                gameOver = true
            else
                if level[x][y] > 0
                    snakeLength = snakeLength + 1
                    if level[x][y] = 2  speed = max(speed - 1, 0)
                    level[x][y] = 0
                endif
            endif
        endif

        set color 0, 0, 0
        cls

        for y = 0 to 29
            for x = 0 to 39
                if level[x][y] = 1
                    set color 0, 255, 0
                    draw rect x*8, y*8, 8, 8 , true
                elseif level[x][y] = 2
                    set color 255, 0, 0
                    draw rect x*8, y*8, 8, 8, true
                endif
            next
        next

        set color 255, 255, 255
        set caret 0, 0
        x = snake[snakeHead][0]
        y = snake[snakeHead][1]
        for i = snakeHead to snakeHead - snakeLength + 1
            j = i
            if j < 0 then j = j + SNAKE_MAX_LENGTH
            draw rect snake[j][0]*8, snake[j][1]*8, 8, 8, true
            if i <> snakeHead
                if snake[j][0] = x and snake[j][1] = y then gameOver = true
            endif
        next

        wait 10
        redraw
    until gameOver
loop
I'll see if I can understand the code where the body follows the head, thank you. Smile
Reply
#6
(07-20-2024, 06:50 PM)aliensoldier Wrote:
(07-20-2024, 09:23 AM)Marcus Wrote: Here's a port of an n6 example game. Hopefully you can find some clues by looking at the code Smile  I don't remember why I implemented the game like this, and probably there are smarter ways.

Code:
' Port of n6 example game.

SNAKE_MAX_LENGTH = 30*40
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4
snake = dim(SNAKE_MAX_LENGTH, 2)
level = dim(40, 30)

set window "Smape", 320, 240, false, 2
set redraw off

do
    snakeLength = 1
    snakeHead = 0
    snakeDirection = 0
    speed = 10
    speedCounter = speed
    snake[snakeHead][0] = 20
    snake[snakeHead][1] = 15
    for y = 0 to 29  for x = 0 to 39  level[x][y] = 0
    gameOver = false
    nextPlupTime = clock()
    do
        if clock() >= nextPlupTime
            if rnd(3) = 0  level[rnd(40)][rnd(30)] = 2
            else  level[rnd(40)][rnd(30)] = 1
            nextPlupTime = clock() + 2000 + rnd(2000)
        endif

        if keydown(38) and snakeDirection <> DOWN  snakeDirection = UP
        if keydown(40) and snakeDirection <> UP  snakeDirection = DOWN
        if keydown(37) and snakeDirection <> RIGHT  snakeDirection = LEFT
        if keydown(39) and snakeDirection <> LEFT  snakeDirection = RIGHT
   
        speedCounter = speedCounter - 1
        if speedCounter = 0
            prev = snakeHead
            if snakeDirection > 0  snakeHead = (snakeHead + 1)%SNAKE_MAX_LENGTH
            speedCounter = speed
            if snakeDirection = UP
                snake[snakeHead][0] = snake[prev][0]
                snake[snakeHead][1] = snake[prev][1] - 1
            elseif snakeDirection = DOWN
                snake[snakeHead][0] = snake[prev][0]
                snake[snakeHead][1] = snake[prev][1] + 1
            elseif snakeDirection = LEFT
                snake[snakeHead][0] = snake[prev][0] - 1
                snake[snakeHead][1] = snake[prev][1]
            elseif snakeDirection = RIGHT
                snake[snakeHead][0] = snake[prev][0] + 1
                snake[snakeHead][1] = snake[prev][1]
            endif
            x = snake[snakeHead][0]
            y = snake[snakeHead][1]
            if x < 0 or x >= 40 or y < 0 or y >= 30
                gameOver = true
            else
                if level[x][y] > 0
                    snakeLength = snakeLength + 1
                    if level[x][y] = 2  speed = max(speed - 1, 0)
                    level[x][y] = 0
                endif
            endif
        endif

        set color 0, 0, 0
        cls

        for y = 0 to 29
            for x = 0 to 39
                if level[x][y] = 1
                    set color 0, 255, 0
                    draw rect x*8, y*8, 8, 8 , true
                elseif level[x][y] = 2
                    set color 255, 0, 0
                    draw rect x*8, y*8, 8, 8, true
                endif
            next
        next

        set color 255, 255, 255
        set caret 0, 0
        x = snake[snakeHead][0]
        y = snake[snakeHead][1]
        for i = snakeHead to snakeHead - snakeLength + 1
            j = i
            if j < 0 then j = j + SNAKE_MAX_LENGTH
            draw rect snake[j][0]*8, snake[j][1]*8, 8, 8, true
            if i <> snakeHead
                if snake[j][0] = x and snake[j][1] = y then gameOver = true
            endif
        next

        wait 10
        redraw
    until gameOver
loop
I'll see if I can understand the code where the body follows the head, thank you. Smile


I barely looked at the code. But I believe the snake "moves" through the 'snake' array. Every element in the array contains a position (x and y value). The snake's head is a moving index in the array. Every time the snake moves one step, the head index increases and a new position is added to the array. That way, the tail is always present as earlier indexes in the array. So if the length of the snake is 4, the positions drawn are those at snake[snakeHead], snake[snakeHead - 1] .. snake[snakeHead - 3].

Edit: The % operator is used to keep the indexes within the array size. When the snake head index reaches the end of the array it starts over at 0. The length of the array is exactly enough for the snake to cover the entire screen Smile

You can probably write smarter code that just stores the turns that the snake does or something. But that would require more complicated code ... I think Big Grin
Reply
#7
I don't understand the code very well, so I have prepared a small example to use as a basis for testing.

In the example I have the player who is the head of the snake and I have the body which is the tail, the player moves with the keys and the body I have added to a list and I show three bodies at the moment. How do I make the body is in the player's position and moves with him like the tail of the snake.

Code:
'prueba de cola de serpiente

'variables-----------------------
visible player,list_body

set window "serpiente",640,480,false
set redraw off

'player-----------------------------
function Player()
    obj = []
    obj.radius = 14
    obj.x = 320 - obj.radius/2
    obj.y = 240 - obj.radius/2
    obj.speedX = 0
    obj.speedY = 0
    obj.Active = true
   
    obj.update = function()
        if this.Active = true
            this.move()
            this.Draw()
        endif
    endfunc
   
    obj.Draw = function()
        set color 255,204,0
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
   
    obj.move = function()
       if keydown(KEY_RIGHT,false)
        this.speedX = 2
        this.speedY = 0
       endif   
       if keydown(KEY_LEFT,false)
        this.speedX = -2
        this.speedY = 0   
       endif
       
        if keydown(KEY_UP,false)
            this.speedX = 0
            this.speedY = -2
        endif
        if keydown(KEY_DOWN,false)
            this.speedX = 0
            this.speedY = 2
        endif
       
        this.x = this.x + this.speedX
        this.y = this.y + this.speedY
    endfunc
   
    return obj
endfunc
'end player--------------------------

'body--------------------------------
function Body(x,y)
    obj = []
    obj.radius = 10
    obj.x = x - obj.radius/2
    obj.y = y - obj.radius/2
   
    obj.update = function()
        this.Draw()
    endfunc
   
    obj.Draw = function()
        set color 255,0,204
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
   
    return obj
endfunc
'end body----------------------------

'iniciar variables-------------------
player = Player()
list_body = []
list_body[sizeof(list_body)] = Body(320,64)
list_body[sizeof(list_body)] = Body(320-32,64)
list_body[sizeof(list_body)] = Body(320-64,64)

while not keydown(KEY_ESCAPE,true)
    set color 0,0,0
    cls
   
    'actualizar objetos del juego-----------
    player.update()
    if sizeof(list_body)
        for i = 0 to sizeof(list_body)-1
            list_body[i].update()
        next
    endif
    '---------------------------------------
       
    fwait 60
    redraw
wend
Reply
#8
(07-21-2024, 05:39 PM)aliensoldier Wrote: I don't understand the code very well, so I have prepared a small example to use as a basis for testing.

In the example I have the player who is the head of the snake and I have the body which is the tail, the player moves with the keys and the body I have added to a list and I show three bodies at the moment. How do I make the body is in the player's position and moves with him like the tail of the snake.

Code:
'prueba de cola de serpiente

'variables-----------------------
visible player,list_body

set window "serpiente",640,480,false
set redraw off

'player-----------------------------
function Player()
    obj = []
    obj.radius = 14
    obj.x = 320 - obj.radius/2
    obj.y = 240 - obj.radius/2
    obj.speedX = 0
    obj.speedY = 0
    obj.Active = true
   
    obj.update = function()
        if this.Active = true
            this.move()
            this.Draw()
        endif
    endfunc
   
    obj.Draw = function()
        set color 255,204,0
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
   
    obj.move = function()
       if keydown(KEY_RIGHT,false)
        this.speedX = 2
        this.speedY = 0
       endif   
       if keydown(KEY_LEFT,false)
        this.speedX = -2
        this.speedY = 0   
       endif
       
        if keydown(KEY_UP,false)
            this.speedX = 0
            this.speedY = -2
        endif
        if keydown(KEY_DOWN,false)
            this.speedX = 0
            this.speedY = 2
        endif
       
        this.x = this.x + this.speedX
        this.y = this.y + this.speedY
    endfunc
   
    return obj
endfunc
'end player--------------------------

'body--------------------------------
function Body(x,y)
    obj = []
    obj.radius = 10
    obj.x = x - obj.radius/2
    obj.y = y - obj.radius/2
   
    obj.update = function()
        this.Draw()
    endfunc
   
    obj.Draw = function()
        set color 255,0,204
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
   
    return obj
endfunc
'end body----------------------------

'iniciar variables-------------------
player = Player()
list_body = []
list_body[sizeof(list_body)] = Body(320,64)
list_body[sizeof(list_body)] = Body(320-32,64)
list_body[sizeof(list_body)] = Body(320-64,64)

while not keydown(KEY_ESCAPE,true)
    set color 0,0,0
    cls
   
    'actualizar objetos del juego-----------
    player.update()
    if sizeof(list_body)
        for i = 0 to sizeof(list_body)-1
            list_body[i].update()
        next
    endif
    '---------------------------------------
       
    fwait 60
    redraw
wend

Sorry, I totally forgot about your question. I'll have a look at it right away!
Reply
#9
Code:
'prueba de cola de serpiente

' Marcus: You can remove this, just checking some things.
#dbg

'variables-----------------------
' Marcus: I think list_body should belong to player ================================================
'visible player,list_body
visible player
' ==================================================================================================

set window "serpiente",640,480,false
set redraw off

'player-----------------------------
function Player()
    obj = []
    obj.radius = 14
    obj.x = 320 - obj.radius/2
    obj.y = 240 - obj.radius/2
    obj.speedX = 0
    obj.speedY = 0
    obj.Active = true
    ' Marcus: Putting body list here and a list of recorded head positions =========================
    obj.bodyList = []
    obj.positions = []
    ' ==============================================================================================
   
    ' Marcus: Add one body part to player ==========================================================
    obj.AddBody = function()
        body = Body(0, 0)
        this.bodyList[sizeof(this.bodyList)] = body
        ' Not sure when AddBody might be called, so calling UpdateBody here too.
        this.UpdateBody()
    endfunc
    ' ==============================================================================================
 
    obj.update = function()
        if this.Active = true
            this.move()
            ' Marcus: Reposition body parts ========================================================
            this.UpdateBody()
            ' ======================================================================================
            this.Draw()
        endif
    endfunc
   
    ' Marcus: Set body parts' positions ============================================================
    obj.UpdateBody = function()
        if sizeof(this.bodyList)
            ' We position the body parts one after one, starting with the one closest to the head.
            ' dist is the calculated travel distance between the head and the current body part.
            ' Initiate it to the radius of the head.
            dist = this.radius
            for i = 0 to sizeof(this.bodyList) - 1
                b = this.bodyList[i]
                ' Add radius of body part to dist.
                dist = dist + b.radius
                ' Divide dist by the speed of the snake to convert the traveled distance to an
                ' index in the position list. Use 'min' to make sure it's not outside the list.
                index = min(int(dist/2), sizeof(this.positions) - 1)
                if index >= 0
                    ' Convert single number coordinates to x and y.
                    'b.y = int(this.positions[index]/width(primary))
                    'b.x = int(this.positions[index]%width(primary))
                    b.x = this.positions[index][0]
                    b.y = this.positions[index][1]
                else
                    ' No recorded positions, put at head position.
                    b.x = this.x
                    b.y = this.y
                endif
                ' Add radius of body part to dist.
                dist = dist + b.radius
            next
        endif
    endfunc
    ' ==============================================================================================
 
    obj.Draw = function()
        ' Marcus: Draw body parts ==================================================================
        if sizeof(this.bodyList)
            for i = 0 to sizeof(this.bodyList) - 1  this.bodyList[i].Draw()
        endif
        ' ==========================================================================================

        set color 255,204,0
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
 
    obj.move = function()
      if keydown(KEY_RIGHT,false)
        this.speedX = 2
        this.speedY = 0
      endif 
      if keydown(KEY_LEFT,false)
        this.speedX = -2
        this.speedY = 0 
      endif
     
        if keydown(KEY_UP,false)
            this.speedX = 0
            this.speedY = -2
        endif
        if keydown(KEY_DOWN,false)
            this.speedX = 0
            this.speedY = 2
        endif
       
        ' Marcus: Save previous position ===========================================================
        if this.speedX or this.speedY
            ' I store the position, x and y, as a single number.
            'insert this.positions, 0, this.y*width(primary) + this.x
            insert this.positions, 0, [this.x, this.y]
            ' Store only 5000 positions for now, might have to increase it depending on how long
            ' the snake can become.
            if sizeof(this.positions) > 5000  free key this.positions, 5000
        endif
        ' ==========================================================================================
     
        this.x = this.x + this.speedX
        this.y = this.y + this.speedY
    endfunc
 
    return obj
endfunc
'end player--------------------------

'body--------------------------------
function Body(x,y)
    obj = []
    obj.radius = 10
    obj.x = x - obj.radius/2
    obj.y = y - obj.radius/2
 
    obj.update = function()
        this.Draw()
    endfunc
 
    obj.Draw = function()
        set color 255,0,204
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
 
    return obj
endfunc
'end body----------------------------

'iniciar variables-------------------
player = Player()
list_body = []
list_body[sizeof(list_body)] = Body(320,64)
list_body[sizeof(list_body)] = Body(320-32,64)
list_body[sizeof(list_body)] = Body(320-64,64)

while not keydown(KEY_ESCAPE,true)
    set color 0,0,0
    cls
   
    if keydown(KEY_SPACE, true)  player.AddBody()
 
    'actualizar objetos del juego-----------
    player.update()
    if sizeof(list_body)
        for i = 0 to sizeof(list_body)-1
            list_body[i].update()
        next
    endif
    '---------------------------------------
   
    ' Marcus: Some debug output ====================================================================
    set color 255, 255, 255
    set caret 0, 0
    wln "PRESS SPACE BAR TO ADD BODY PARTS"
    wln
    wln "bodyparts: " + sizeof(player.bodyList)
    wln "recorded positions: " + sizeof(player.positions)
    ' ==============================================================================================
     
    fwait 60
    redraw
wend

I've marked my changes with "Marcus" Smile

This solution is probably not very good. The head's position is always recorded into a list, player.positions. Currently I store a maximum of 5000 positions, which covers a snake length of 10,000 pixels (because the speed of the snake is 2). Then I "simply" position the body parts, using the list of recorded positions, in player.UpdateBody.

Press space bar to add body parts.

Edit But as with the other snake code I posted, this is NOT a very smart solution. It should be enough to store the positions where the player turns, and then use the distance between the head and these points to calculate the positions of the body parts.
Reply
#10
(08-08-2024, 02:56 PM)Marcus Wrote:
Code:
'prueba de cola de serpiente

' Marcus: You can remove this, just checking some things.
#dbg

'variables-----------------------
' Marcus: I think list_body should belong to player ================================================
'visible player,list_body
visible player
' ==================================================================================================

set window "serpiente",640,480,false
set redraw off

'player-----------------------------
function Player()
    obj = []
    obj.radius = 14
    obj.x = 320 - obj.radius/2
    obj.y = 240 - obj.radius/2
    obj.speedX = 0
    obj.speedY = 0
    obj.Active = true
    ' Marcus: Putting body list here and a list of recorded head positions =========================
    obj.bodyList = []
    obj.positions = []
    ' ==============================================================================================
   
    ' Marcus: Add one body part to player ==========================================================
    obj.AddBody = function()
        body = Body(0, 0)
        this.bodyList[sizeof(this.bodyList)] = body
        ' Not sure when AddBody might be called, so calling UpdateBody here too.
        this.UpdateBody()
    endfunc
    ' ==============================================================================================
 
    obj.update = function()
        if this.Active = true
            this.move()
            ' Marcus: Reposition body parts ========================================================
            this.UpdateBody()
            ' ======================================================================================
            this.Draw()
        endif
    endfunc
   
    ' Marcus: Set body parts' positions ============================================================
    obj.UpdateBody = function()
        if sizeof(this.bodyList)
            ' We position the body parts one after one, starting with the one closest to the head.
            ' dist is the calculated travel distance between the head and the current body part.
            ' Initiate it to the radius of the head.
            dist = this.radius
            for i = 0 to sizeof(this.bodyList) - 1
                b = this.bodyList[i]
                ' Add radius of body part to dist.
                dist = dist + b.radius
                ' Divide dist by the speed of the snake to convert the traveled distance to an
                ' index in the position list. Use 'min' to make sure it's not outside the list.
                index = min(int(dist/2), sizeof(this.positions) - 1)
                if index >= 0
                    ' Convert single number coordinates to x and y.
                    'b.y = int(this.positions[index]/width(primary))
                    'b.x = int(this.positions[index]%width(primary))
                    b.x = this.positions[index][0]
                    b.y = this.positions[index][1]
                else
                    ' No recorded positions, put at head position.
                    b.x = this.x
                    b.y = this.y
                endif
                ' Add radius of body part to dist.
                dist = dist + b.radius
            next
        endif
    endfunc
    ' ==============================================================================================
 
    obj.Draw = function()
        ' Marcus: Draw body parts ==================================================================
        if sizeof(this.bodyList)
            for i = 0 to sizeof(this.bodyList) - 1  this.bodyList[i].Draw()
        endif
        ' ==========================================================================================

        set color 255,204,0
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
 
    obj.move = function()
      if keydown(KEY_RIGHT,false)
        this.speedX = 2
        this.speedY = 0
      endif 
      if keydown(KEY_LEFT,false)
        this.speedX = -2
        this.speedY = 0 
      endif
     
        if keydown(KEY_UP,false)
            this.speedX = 0
            this.speedY = -2
        endif
        if keydown(KEY_DOWN,false)
            this.speedX = 0
            this.speedY = 2
        endif
       
        ' Marcus: Save previous position ===========================================================
        if this.speedX or this.speedY
            ' I store the position, x and y, as a single number.
            'insert this.positions, 0, this.y*width(primary) + this.x
            insert this.positions, 0, [this.x, this.y]
            ' Store only 5000 positions for now, might have to increase it depending on how long
            ' the snake can become.
            if sizeof(this.positions) > 5000  free key this.positions, 5000
        endif
        ' ==========================================================================================
     
        this.x = this.x + this.speedX
        this.y = this.y + this.speedY
    endfunc
 
    return obj
endfunc
'end player--------------------------

'body--------------------------------
function Body(x,y)
    obj = []
    obj.radius = 10
    obj.x = x - obj.radius/2
    obj.y = y - obj.radius/2
 
    obj.update = function()
        this.Draw()
    endfunc
 
    obj.Draw = function()
        set color 255,0,204
        draw ellipse this.x,this.y,this.radius,this.radius,true
    endfunc
 
    return obj
endfunc
'end body----------------------------

'iniciar variables-------------------
player = Player()
list_body = []
list_body[sizeof(list_body)] = Body(320,64)
list_body[sizeof(list_body)] = Body(320-32,64)
list_body[sizeof(list_body)] = Body(320-64,64)

while not keydown(KEY_ESCAPE,true)
    set color 0,0,0
    cls
   
    if keydown(KEY_SPACE, true)  player.AddBody()
 
    'actualizar objetos del juego-----------
    player.update()
    if sizeof(list_body)
        for i = 0 to sizeof(list_body)-1
            list_body[i].update()
        next
    endif
    '---------------------------------------
   
    ' Marcus: Some debug output ====================================================================
    set color 255, 255, 255
    set caret 0, 0
    wln "PRESS SPACE BAR TO ADD BODY PARTS"
    wln
    wln "bodyparts: " + sizeof(player.bodyList)
    wln "recorded positions: " + sizeof(player.positions)
    ' ==============================================================================================
     
    fwait 60
    redraw
wend

I've marked my changes with "Marcus" Smile

This solution is probably not very good. The head's position is always recorded into a list, player.positions. Currently I store a maximum of 5000 positions, which covers a snake length of 10,000 pixels (because the speed of the snake is 2). Then I "simply" position the body parts, using the list of recorded positions, in player.UpdateBody.

Press space bar to add body parts.

Edit  But as with the other snake code I posted, this is NOT a very smart solution. It should be enough to store the positions where the player turns, and then use the distance between the head and these points to calculate the positions of the body parts.

Thanks Marcus, I'll see if I understand this better. Smile

Although I don't really want to program the snake game, what I wanted to do is have some planes follow another one. It's in those airplane games where there is a group of planes that move in circles and they all do it together.
Reply


Forum Jump:


Users browsing this thread: 5 Guest(s)