Snake Game SDL

Feb 22, 2012 at 2:48am
Hello,

I am just starting out trying to make games in C++. I have some experience with the language but I have never made games or used SDL too much. As a start I took a motion tutorial from http://lazyfoo.net/SDL_tutorials/ and made it into a two player game where random red dots appear and the players race to collect 10. It has collision detection and such which I figure out how to do. After doing this I'm trying to expand it into snakes now not just dots. However I am having problems get the snakes to move correctly. I was able to hack it together somewhat but when changing direction from say right to up the whole snake flips at once instead of moving a section at a time. I think I am missing something conceptually about this. I could do it on a matrix but I dont want to restrict motion to a square matrix

snake.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
Snake::Snake()
{
	pieces.push_back(Dot());
	headX = pieces.at(0).getX();
	headY = pieces.at(0).getY();
	length = 1;
};

void Snake::show()
{
	int curX;
	int curY;
	for( int i =0; i < length; i++)
	{
		curX = pieces.at(i).getX();
		curY = pieces.at(i).getY();
		apply_surface( curX, curY, dot, screen );
	}
	
};

void Snake::handle_input()
{
	pieces.at(0).handle_input(0);
	for( int i =1; i < length; i++)
	{
		int xVel = pieces.at(i-1).getXVelocity();
		int yVel = pieces.at(i-1).getYVelocity();
		if(yVel < 0 && xVel ==0)
			pieces.at(i-1).setDirection(0);
		if(yVel > 0 && xVel ==0)
			pieces.at(i-1).setDirection(1);
		if(yVel == 0 && xVel < 0)
			pieces.at(i-1).setDirection(2);
		if(yVel == 0 && xVel >0)
			pieces.at(i-1).setDirection(3);
	}
};

void Snake::move()
{
	pieces.at(0).move();
	int previous_x;
	int previous_y;
	int previous_xVel;
	int previous_yVel;
	for( int i=1; i < length; i++)
	{
		previous_x = pieces.at(i-1).getX();
		previous_y = pieces.at(i-1).getY();
		previous_xVel = pieces.at(i-1).getXVelocity();
		previous_yVel = pieces.at(i-1).getYVelocity();
		if(previous_xVel != 0 || previous_yVel != 0)
		{
		pieces.at(i).setX(previous_x-(2*previous_xVel));
		pieces.at(i).setY(previous_y-(2*previous_yVel));
		}
		else
		{
			if(pieces.at(i-1).getDirection() == 0)
			{
				pieces.at(i).setX(previous_x);
				pieces.at(i).setY(previous_y+(DOT_HEIGHT));
			}
			else if(pieces.at(i-1).getDirection() ==1)
			{
				pieces.at(i).setX(previous_x);
				pieces.at(i).setY(previous_y-(DOT_HEIGHT));
			}
			else if(pieces.at(i-1).getDirection() ==2)
			{
				pieces.at(i).setX(previous_x+DOT_WIDTH);
				pieces.at(i).setY(previous_y);
			}
			else if(pieces.at(i-1).getDirection() ==3)
			{
				pieces.at(i).setX(previous_x-DOT_WIDTH);
				pieces.at(i).setY(previous_y);
			}
			else
			{
			pieces.at(i).setX(previous_x-(DOT_WIDTH));
			pieces.at(i).setY(previous_y-(DOT_HEIGHT));
			}
		}
		pieces.at(i).setXVelocity(previous_xVel);
		pieces.at(i).setYVelocity(previous_yVel);
	}
};

Dot Snake::getHead()
{
	return pieces.at(0);
};

void Snake::addToSnake()
{
	int x = pieces.at(length-1).getX();
	int y = pieces.at(length-1).getY();
	int xv = pieces.at(length-1).getXVelocity();
	int yv = pieces.at(length-1).getYVelocity();
	pieces.push_back(Dot(x-DOT_WIDTH,y,xv,yv));
	length++;
};


dot.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
Dot::Dot()
{
	//Initialize the offsets
	x = 0;
	y = 0;
	//Initialize the velocity
	xVel = 0;
	yVel = 0;
	radius = DOT_WIDTH/2;
}

Dot::Dot(int xStart, int yStart)
{
	//Initialize the offsets
	x = xStart;
	y = yStart;
	//Initialize the velocity
	xVel = 0;
	yVel = 0;
	radius = DOT_WIDTH/2;
}

Dot::Dot(int xStart, int yStart, int xvel, int yvel)
{
	//Initialize the offsets
	x = xStart;
	y = yStart;
	//Initialize the velocity
	xVel = xvel;
	yVel = yvel;
	radius = DOT_WIDTH/2;
} 
void Dot::handle_input(int player)
{
	if(player == 0)
	{
		//If a key was pressed
		if( event.type == SDL_KEYDOWN )
		{
			//Adjust the velocity
			switch( event.key.keysym.sym )
			{
			case SDLK_UP: yVel -= DOT_HEIGHT / 2; break;
			case SDLK_DOWN: yVel += DOT_HEIGHT / 2; break;
			case SDLK_LEFT: xVel -= DOT_WIDTH / 2; break;
			case SDLK_RIGHT: xVel += DOT_WIDTH / 2; break;
			}
		}
		//If a key was released
		else if( event.type == SDL_KEYUP )
		{
			//Adjust the velocity
			switch( event.key.keysym.sym )
			{
			case SDLK_UP: yVel += DOT_HEIGHT / 2; break;
			case SDLK_DOWN: yVel -= DOT_HEIGHT / 2; break;
			case SDLK_LEFT: xVel += DOT_WIDTH / 2; break;
			case SDLK_RIGHT: xVel -= DOT_WIDTH / 2; break;
			}
		}
	}
	
	//other color stuff ommitted
}

void Dot::move()
{
	//Move the dot left or right
	x+=xVel;

	//If the dot went too far to the left or right
	if(x + DOT_WIDTH > SCREEN_WIDTH)
		x = 0;
	if(x < 0)
		x = SCREEN_WIDTH-DOT_WIDTH;

	//Move the dot up or down
	y += yVel;

	//If the dot went too far up or down
	if(y + DOT_HEIGHT > SCREEN_HEIGHT)
		y = 0;
	if(y < 0)
		y = SCREEN_HEIGHT-DOT_HEIGHT;	
}
void Dot::move(int x_velocity, int y_velocity)
{
	//Move the dot left or right
	xVel = x_velocity;
	x+=x_velocity;

	//If the dot went too far to the left or right
	if(x + DOT_WIDTH > SCREEN_WIDTH)
		x = 0;
	if(x < 0)
		x = SCREEN_WIDTH-DOT_WIDTH;

	//Move the dot up or down
	yVel = y_velocity;
	y += y_velocity;

	//If the dot went too far up or down
	if(y + DOT_HEIGHT > SCREEN_HEIGHT)
		y = 0;
	if(y < 0)
		y = SCREEN_HEIGHT-DOT_HEIGHT;	
}

void Dot::show(int color)
{
	//Show the dot
	if(color == 0)
	apply_surface( x, y, dot, screen );
	else
		apply_surface( x, y, blueDot, screen );
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
int main( int argc, char* args[] )
{
        //declarations are ommited
	//While the user hasn't quit
	while( quit == false )
	{
		if(gameState == 0)
		{			
			//Start the frame timer
			fps.start();

			//While there's events to handle
			while( SDL_PollEvent( &event ) )
			{
				//Handle events for the dot
				snake1.handle_input();
				dotTwo.handle_input(1);

				//If the user has Xed out the window
				if( event.type == SDL_QUIT )
				{
					//Quit the program
					quit = true;
				}
			}

			//collison
			vector<smallDot> temp = pointDots;
			for(unsigned int i = 0; i < temp.size();i++)
			{			
				if(temp.at(i).checkCollision(snake1.getHead()))
				{
					temp.erase(temp.begin()+i);
					snake1.addToSnake();
					player1score += DOT_VALUE;
				}
			}
			pointDots = temp;
			temp.clear();
			temp = pointDots;
			for(unsigned int i = 0; i < temp.size();i++)
			{			
				if(temp.at(i).checkCollision(dotTwo))
				{
					temp.erase(temp.begin()+i);
					player2score += DOT_VALUE;
				}
			}
			pointDots = temp;
			temp.clear();

			//status

			//Move the dot
			snake1.move();
			dotTwo.move();

			//Add point dot
			dotsTimer.update();
			if(dotsTimer.check())
			{
				pointDots.push_back(smallDot());
			}

			//Fill the screen white
			SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );
			displayScores(player1score,player2score);
			//Show the dot on the screen
			for (unsigned int i = 0; i < pointDots.size(); i++)
			{
				//if (pointDots.at(i) == NULL)
				//  continue; // skip NULL objects
				pointDots.at(i).show();
			}
			snake1.show();
			dotTwo.show(1);

			//Update the screen
			if( SDL_Flip( screen ) == -1 )
				return 1;
			if( gameOver(player1score,player2score))
				gameState = 1;
			//Cap the frame rate
			
		}
		else if (gameState == 1)
		{
			//stuff for winner omitted for length
			SDL_Flip(screen);
		}
	}

	//Clean up
	clean_up();
	return 0;
}


I had to omit stuff for length but the full code and everything if you would like to look at it all is at https://github.com/bdumont36/Snake/tree/master/SDL_Game_Test/Snake%20Game along with all the other file and the visual studio solution

Any help or advice will be greatly appreciated
Feb 22, 2012 at 5:25am
closed account (o1vk4iN6)
Rather than having speed for the snake, depending on what direction the user is pressing take the "tail" of the snake (the last tile) and place it accordingly in whatever direction from the head of the snake.
Last edited on Feb 22, 2012 at 5:27am
Topic archived. No new replies allowed.