Snake movement (smooth, not a grid)

Hi!

I’m trying to make some sort of a snake game, but I’m having trouble with the movement. I refuse to go the “make the snake move along a grid, placing each part of the snake to the cell the previous part occupied the last update” route as I think it looks stupid, so I started making a smooth moving snake but still with 90 degree turns.

This is working OKish already after the very first try by having each part move independently of each other. Every time the player turns the head, it saves the coordinates and the new direction where the turn happened and each part checks these coordinates of the previous part and does the same change once it hits the said coordinates, again saving the coordinates for the next part to check them etc. Once the part has made the turn, I then fix it’s position relative to the part before it to make it line up perfectly as there are some rounding errors etc.

But there are some problems still plus you can just feel that the snake isn’t connected but it’s rather just several blocks moving next to each other (and when it bugs out the snake snaps in two).

I have two different options here… either I keep going like this and try to perfect the snake movement so that it a) looks good and b) has no chance of crapping out or I take it one step further and make a freeform moving snake with the head rotating in small degree changes and the body flowing freely (yet the way you’d expect it to do) behind it.

The latter is what I’d like to do, but as I’m not too good at maths I’m having trouble figuring out how to calculate the positions of the body parts.

I came across this which seems interesting to try but I couldn’t figure out how to fully translate that into Javanese to see how it works. Again, sucking at maths doesn’t help as I can’t figure out the corresponding Java tools to use (namely the Vector2.Transform and Matrix.CreateRotationZ in that code (can I use affine transform here somehow?). I’m doing this on libgdx if there are some tools in their built in vector classes and whatnot that I should use.

Any input and help would be appreciated to get me going :slight_smile:

I just wrote down a little helper-class, you could use.
Just use Math.sin / Math.cos for x / y coordinates. Math.toRadians is only used to convert degrees (360 = one turn) to radians (2 * pi = one turn).


public class RotatingMoveable {
	private float x;
	private float y;
	
	public RotatingMoveable(float x, float y) {
		this.x = x;
		this.y = y;
	}
	
	public float getX() {
		return x;
	}
	
	public float getY() {
		return y;
	}
	
	// direction is degrees (0-360, but you can choose -57829547 too ;) )
	public void move(float speed, float direction) {
		x += (float)(Math.sin(Math.toRadians(direction)))*speed;
		y += (float)(Math.cos(Math.toRadians(direction)))*speed;
	}
	
	public void set(float x, float y) {
		this.x = x;
		this.y = y;
	}
}

Thanks for the reply, that looks like what I’d use to move the head but then how to figure out the correct position for the body parts following the head? I’d need to somehow calculate the correct position for each part based on the location and the rotation of the part before it :-\

Can’t you still use a grid but interpolate in between for movement?

Hm. I’ll have to give that a try for the 90 degree turns based movement, should be better than what I have now, thanks for the idea.

I did some more googling and as a result, this is my current move method (for trying to do a “free roaming” snake)… it doesn’t quite work but seeing what it does makes me think I’m on the right track at least… if nothing else this will hopefully teach me some maths too…


	public void move(float delta) {
	
		SnakePart snakeHead = parts.get(0);
		int snakeLength = parts.size() - 1;
		
		snakeHead.setPosX((float)(snakeHead.getPosX() - Math.sin(Math.toRadians(snakeHead.getRotDegree())) * snakeHead.getSpeed() * delta));
		snakeHead.setPosY((float)(snakeHead.getPosY() + Math.cos(Math.toRadians(snakeHead.getRotDegree())) * snakeHead.getSpeed() * delta));
		
		for (int i = 1; i <= snakeLength; i++) {
		
			SnakePart partBefore = parts.get(i-1);
			SnakePart thisPart = parts.get(i);
			
			float xChange = partBefore.getPosX() - thisPart.getPosX();
			float yChange = partBefore.getPosY() - thisPart.getPosY();
			
			float angle = (float)Math.atan2(yChange, xChange);
			
			thisPart.setPosX(partBefore.getPosX() - (float)Math.cos(angle) * parts.size() - 1);
			thisPart.setPosY(partBefore.getPosY() - (float)Math.sin(angle) * parts.size() - 1);
						
		}
		
	}

I think I got it!

I had misunderstood one of the examples I just googled, this is the final one which seems to work so far… hopefully it will be of use to someone fighting with the same problem in the future :slight_smile:


	public void move(float delta) {
	
		SnakePart snakeHead = parts.get(0);
		int snakeLength = parts.size() - 1;
		
		snakeHead.setPosX((float)(snakeHead.getPosX() + Math.sin(Math.toRadians(snakeHead.getRotDegree())) * snakeHead.getSpeed() * delta));
		snakeHead.setPosY((float)(snakeHead.getPosY() + Math.cos(Math.toRadians(snakeHead.getRotDegree())) * snakeHead.getSpeed() * delta));
		
		for (int i = 1; i <= snakeLength; i++) {
		
			SnakePart partBefore = parts.get(i-1);
			SnakePart thisPart = parts.get(i);
			
			float xChange = partBefore.getPosX() - thisPart.getPosX();
			float yChange = partBefore.getPosY() - thisPart.getPosY();
			
			float angle = (float)Math.atan2(yChange, xChange);
			
			thisPart.setPosX(partBefore.getPosX() - (float)Math.cos(angle) * 10);
			thisPart.setPosY(partBefore.getPosY() - (float)Math.sin(angle) * 10);
						
		}
		
	}