Snake movement, Body & tail follow head.

Blitz3D Forums/Blitz3D Beginners Area/Snake movement, Body & tail follow head.

Aussie(Posted 2012) [#1]
Hey there everyone,
I decided to have a go at making a simple 3d snake style game & have run into trouble with the body & tail part of the snake following the head.
The way I was thinking of doing it was to use types to store the info of the position & rotation of the head when a key is pressed so when the body & tail = the position of the marker then the body & tail rotate to match the rotation of the head at that position, then delete the marker after the body parts & the tail have passed the position.
What’s happening is both the body & tail are rotating as soon as the key is pressed. I’m not 100% sure why but I think it is to do with the body & tail reading the rotation of the head instead of reading it from the marker.
Could some one take a look & see what’s going on.
Also would this be the right way about doing this?
Cheers.



Mikorians(Posted 2012) [#2]
Weak suggestion... You might try setting the body parts as children of their respective parent entities, thus their motion would be relative to the position of the root entity.


Aussie(Posted 2012) [#3]
Thanks for the suggestion Mikorians but later on i want to be able to add more body segments to the snake to make it longer, trying to have a go at getting a 3d snake game up & going.
Once i can get it up & running i want to try & implement it into a movement around a sphere i was playing around with a while ago.


Midimaster(Posted 2012) [#4]
I know the problem from our train project. One segment should follow the segment ahead.

The solution is not as simple... You have to think about "onthe fly railway creation".

Each segment has a head point and a tail point. Only the head point of the first one can be manipulated by the player. The following segments always keep the connection to the tail point of the segment ahead.

So you have to calculate the tail point after a movement and then change the head point of its follower to this. Now you have to calculate his tail point and so on....

As I see, you already have a snake segment type TYPE SNAKE. The segments have to be part of the type. What about adding a field ENTITY as a part of the typ for the entities, instead of using Sbody(1..3)?

And your idea of using waypoints is excellent. But there for you have to set a new Waypoint Array as a field into your type. The idea: The first segment sets a new marker which becomes part of its type. It collect some waypoint and sends the oldest values to the following segment. So each segment inherits its position and direction from the waypoint list of the segment ahead each update step.

Graphics3D 800,600,0,2

SetBuffer BackBuffer()


Global H_Snake.Snake


Light= CreateLight()
	RotateEntity light,90,0,0
camera = CreateCamera()
	PositionEntity camera,0,50,0
	RotateEntity camera,90,0,0
plane = CreatePlane()
	EntityColor plane,0,0,255
	

Create_player()
	
While Not KeyDown (1)


	Update_player()
	UpdateWorld
	RenderWorld

	Flip
Wend

End


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Type Snake 
	Field xpos# 
	Field zpos# 

;some more Fields:	
	Field Entity
	Field WayX#[11],WayZ#[11],WayR#[11]
End Type

Function Create_player()
	
	;the first entity is GLOBAL, because we will need it again individual:
	H_Snake.Snake = New Snake
		H_Snake\Entity = CreateCube()
		EntityColor H_Snake\Entity,0,255,0
		

	; the others have only a few proerties fixed now:
		For i%=0 To 10
			Snake.Snake = New Snake
			Snake\Entity = CreateCube()
		Next

End Function


Function Update_player()
	Local locX#,locZ#, locRot#

		;speed of the snake 0.25
		MoveEntity H_Snake\Entity, 0 , 0 , 0.25
		If KeyDown(203) Then
			TurnEntity H_Snake\Entity,0,2,0
	
		ElseIf KeyDown(205) Then
			TurnEntity H_Snake\Entity,0,-2,0
		EndIf
	
	For Snake.Snake = Each Snake
		;this is important: A FILO-stack 
		;new waypoint will "sink down" during 10 Updates
		For i%=10 To 1 Step -1
			Snake\WayZ[i]=Snake\WayZ[i-1]
			Snake\WayX[i]=Snake\WayX[i-1]
			Snake\WayR[i]=Snake\WayR[i-1]
		Next

		; following segments will get there values from the segment before:
		If Snake<>H_Snake	
			PositionEntity Snake\Entity,locX,0,locZ
			RotateEntity Snake\Entity,0,locRot,0
		EndIf

		;new position will become new waypoint on top:
		Snake\WayZ[0]=EntityZ(Snake\Entity,True)
		Snake\WayX[0]=EntityX(Snake\Entity,True)
		Snake\WayR[0]=EntityYaw(Snake\Entity,True)

		; keep oldest waypoint of this segment for the next segments
		locZ=Snake\WayZ[10]
		locX=Snake\WayX[10]
		locRot=Snake\WayR[10]
					
	Next
	
End Function



The system is that every segment has a stack with 10 waypoints. The newest is on WayX[0], the oldest on WayX[10]. Alle waypoints are "below" the segment, only the oldest waypoint is even "behind" it. So it is ideal for to set position of the next segment.

In this sample the speed of the snake is 0.25 and the size of a segment is 2. So after 10 waypoints the oldest is 10x0.25 = 2.5 behind the current position.

If you need a slower speed (f.e.0.1) you have to store more waypoints to reach the tail of your segment with the last one:

Type Snake 
...
Field WayX[21]
....
Function Update_player()

	Local locX#,locZ#, locRot#

		MoveEntity H_Snake\Entity,0,0,0.1

....
	For Snake.Snake = Each Snake
		For i%=20 To 1 Step -1
			Snake\WayZ[i]=Snake\WayZ[i-1]
....
		locZ=Snake\WayZ[20]
		locX=Snake\WayX[20]
		locRot=Snake\WayR[20]
					
	Next
....


Last edited 2012


Mikorians(Posted 2012) [#5]
Half awake... Groan... Ah. I loved snakebyte.
We used to use an array of previous positions organized thus.
oox=ox:ooy=oy:ox=x:oy=y:x=x+dx:y=y+dy
or
for t=0 to 4:x(t)=x(t+1):y(t)=y(t+1):next
I guess in the case of the train you'd need dummy points, so increase the array accordingly...? I know there's more to it... Listen to midimaster...

Last edited 2012


Aussie(Posted 2012) [#6]
Thanks heaps Midimaster.
Just a couple of questions.
What is a FILO stack?
What is the difference between Snake\WayZ[0] & Snake\WayZ(0) the [] () part?

Going to have a play at adding more parts now. :)

I have added a tail part.

Function Create_player()
	
	;the first entity is GLOBAL, because we will need it again individual:
	H_Snake.Snake = New Snake
		H_Snake\Entity = CreateCube()
		EntityColor H_Snake\Entity,0,255,0
		

	; the others have only a few proerties fixed now:
		For i%=0 To 7
			Snake.Snake = New Snake
			Snake\Entity = CreateCube()
		Next
		For i%=8 To 8
			Snake.Snake = New Snake
			Snake\Entity = CreateCube()
			EntityColor Snake\Entity,255,0,0
		Next

End Function


Next I want to add more body parts.
The way I am thinking about this is to create a variable for the segments. Something like
Segments = ??
Tail = ??
                For i%=0 To Segments
			Snake.Snake = New Snake
			Snake\Entity = CreateCube()
		Next
		For i%= Tail To Tail
			Snake.Snake = New Snake
			Snake\Entity = CreateCube()
			EntityColor Snake\Entity,255,0,0
		Next

& then have to do something similar for the waypoints.


Aussie(Posted 2012) [#7]
Ok I have added more body parts & am now a bit stuck in regards how to go about replacing the last part of the snake (the tail) & changing it to a body part when a new tail part is created
Here is what I have.


Going to add pickups & collisions now. :)


gradualcheetah(Posted 2012) [#8]
here you go.


i tried to kinda comment what i did in there. basically all i did was add the field "bodytype" to the type Snake. when you hit spacebar it checks for the bodytype "3" (2=body,3=tail) and once it finds "3"(the tail) it deletes it, makes it into a bodytype of 2 and makes it a circle. then i just went where you made the new tail on space hit and made it so that when you add a tail the tail mesh gets the bodytype of 3.

hope i was of at least some help!

Last edited 2012


Midimaster(Posted 2012) [#9]
Sorry I did a typo... It has to be "FIFO"


FIFO

a FIFO ("First In First Out") stack is a stack where things, that came in new, get served first like in a queue.

The values enter the array at position 0 and then "sink" down to position 10. This is the moment, when they get out.



ARRAY () VERSUS []

The "normal" Array...
Dim a%(9)
Print a(3)

...does not work inside types. You have to use a special "BlitzArray" with different brackets:

Typ TPlayer
     Field a%[9]
End Type
P.TPlayer =New TPlayer
Print P\a[3]







CRITICS ON YOUR CODE

At first your code works well, so there is no need to change what I now write. But some considerations:

You added some new fields:
Type Snake 
	Field xpos# 
	Field zpos#
	Field Speed#
	Field Turnspeed# 

This implements, that each segment has the chance to have a individual speed and turnspeed. But in reality only the whole snake has one common speed. So the parameter Speed# and TurnSpeed# should be GLOBAL:

Global Speed#, TurnSpeed#
Type Snake 
	Field xpos# 
	Field zpos#


Or do you plan to have more than one snake on the screen?


Aussie(Posted 2012) [#10]
Thanks heaps guys, got it all working nicely for now.

Thanks Midimaster for the info & there will only be the one snake.

Just got a question to do with the FIFO array & a bug to sort out.

I have set the a waycount at 20

x%=20
…..
…..
…..
For Snake.Snake = Each Snake
	;this is important: A FIFO-stack 
	;new waypoint will "sink down" during 10 Updates
		
		
	Snake\Waycount% = x%
		For i% = Snake\Waycount% To 1 Step -1
			Snake\WayZ[i]=Snake\WayZ[i-1]
			Snake\WayX[i]=Snake\WayX[i-1]
			Snake\WayR[i]=Snake\WayR[i-1]
		Next

		; following segments will get there values from the segment before:
		If Snake<>H_Snake	
			PositionEntity Snake\Entity,locX,0,locZ
			RotateEntity Snake\Entity,0,locRot,0
		EndIf

		;new position will become new waypoint on top:
		Snake\WayZ[0]=EntityZ(Snake\Entity,True)
		Snake\WayX[0]=EntityX(Snake\Entity,True)
		Snake\WayR[0]=EntityYaw(Snake\Entity,True)

		; keep oldest waypoint of this segment for the next segments
		locZ=Snake\WayZ[Snake\Waycount%]
		locX=Snake\WayX[Snake\Waycount%]
		locRot=Snake\WayR[Snake\Waycount%]
					
	Next
	
 


My question is, is this creating 20 waypoints behind the head of the snake so the body segments know the position & rotation or is it creating 20 waypoints for each body segment of the snake? I am struggling to get my head around this part & why if I have say, 60 body segments they keep following the head.

The bug I have is when I collect a pickup both a tail part & body segment quickly flash up at 0,0,0 then appear in the body of the snake.

Going to keep playing around with it & once I have it all working nicely I will start adding some bells & whistles. :)



Last edited 2012


Midimaster(Posted 2012) [#11]
experiment 1:
use 10 or 30 waypoints instead of 20 and you will see how they are working :-)

Each segment has a list of 20 waypoints and the last is given to the following segment. So if you use less or more, you will see segments to closed together or empty room between the segments .

So you can add as many segments as you like. You will never get problems with the waypoints.

experiment 2:
it needs one update until the newest segment is added to the snake. Meanwhile you see it at position 0,0,0. Solution: In the moment when you create a new segment, position the entity (f.e. the cube) behind your camera. When the next FLIP comes it will be "unvisible", but when the next update comes it will be positioned correct.

Last edited 2012

Last edited 2012


psychicbottle(Posted 2012) [#12]
I like where you are going with this, you should add a high score system into it. It,s fun already!


Aussie(Posted 2012) [#13]
Thanks Midimaster, I think I understand how the FIFO works. Would I be correct in saying that the head takes 20 steps in a direction & each step is stored in the FIFO once the 20 steps have been completed it then passes the first one created to the next segment in the snake & so on?

Thanks psychicbottle, that’s one of the next things I will be doing. Going to start on my own models & images over the next few days.


Midimaster(Posted 2012) [#14]
yes


psychicbottle(Posted 2012) [#15]
Aussie, start a work log, i know this is a small project but i think we would all like to see you come along on it.


Aussie(Posted 2012) [#16]
Good idea psychicbottle.
As of where I am with the code now, I will start the work log. Will see this one through to the end.


psychicbottle(Posted 2012) [#17]
Glad to hear it, i will keep up to date on your progress!