Jump to content
  • Advertisement
Sign in to follow this  
LOKIOdinson

Snake using SDL

This topic is 601 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi there i am a beginner in SDL and just wanted to make a snake clone 

i have made it to full extent(not totally polished but the game runs)

and i have encountered a problem 

my code moves the snake in all direction except the right in the first instance

if you can point me on how to edit this(i know i should use linked list and this is not the optimum way to write code)


#include<stdio.h>
#include<SDL.h>
#include<sstream>
#include<ctime>
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
const int screenWidth = 640;
const int screenHeight = 480;

bool init();
void close();

class food
{
private:
	int x=100, y=100, a, b;
	SDL_Rect foodBlock;
public:
	void render();
	void input(SDL_Event e);
	void changeLocation();
	SDL_Rect giveLocation();
}food1;

SDL_Rect food::giveLocation()
{	
	return foodBlock;
}

void food::changeLocation()
{
	x = rand() % screenWidth;
	y = rand() % screenHeight;
}
void food::render()
{
	foodBlock = { x,y,10,10 };
	SDL_SetRenderDrawColor(renderer, 255, 100,200, 255);
	SDL_RenderFillRect(renderer, &foodBlock);
	SDL_RenderDrawRect(renderer, &foodBlock);
}

class player
{
public:
	player();
	void input(SDL_Event e);
	void move(int d);
	void render();
	int getD();
	int getCount();
	void collision(int a);
private:
	int velX,velY,x,y,d=0;
	SDL_Rect snake[300] = {0,0,10,10};
	int direct=5;
	int old=5;
	int shit;
	int count=20;
	void reset();
//snake[0]will always be the head
}player1;


void player::collision(int a)
{
	int aXMin, aXMax, bXMin, bXMax,aYMin,aYMax,bYMin,bYMax, f=0;
	aXMin = snake[0].x;
	aXMax = snake[0].x + snake[0].w;
	aYMin = snake[0].y;
	aYMax = snake[0].y + snake[0].h;
	
	if (a == 1)
	{
		SDL_Rect b = food1.giveLocation();
		bXMin = b.x;
		bXMax = b.x + b.w;
		bYMin = b.y;
		bYMax = b.y + b.h;
		if (aYMax <= bYMin)
		{
			f = 1;
		}
		if (aYMin >= bYMax)
		{
			f = 1;
		}
		if (aXMax <= bXMin)
		{
			f = 1;
		}
		if (aXMin >= bXMax)
		{
			f = 1;
		}
		if (f != 1)
		{
			food1.changeLocation();
			player1.count++;
		}
	}
	else if (a == 2)
	{
		for (int i = 1; i < count;i++)
		{
			f = 0;
			//printf("%d\n",i);
			bXMin = snake[i].x;
			bXMax = snake[i].x + snake[i].w;
			bYMin = snake[i].y;
			bYMax = snake[i].y + snake[i].h;
			if (aYMax <= bYMin)
			{
				f = 1;
			}
			if (aYMin >= bYMax)
			{
				f = 1;
			}
			if (aXMax <= bXMin)
			{
				f = 1;
			}
			if (aXMin >= bXMax)
			{
				f = 1;
			}
			if (f != 1)
			{
				SDL_Delay(200);
				player1.reset();
				printf("inside");
			}
		}
		
	}

}
void player::reset()
{
	srand(time(NULL));
	x = rand()%screenWidth;
	y = rand()%screenHeight;
	velX = 10;
	velY = 10;
	d = 0;
	direct = 5;
	old = 5;
	count = 20;
	
}

int player::getCount()
{
	return count;
}

int player::getD()
{
	return d;
}
player::player()
{
	x = 400;
	y = 100;
	velX = 10;
	velY = 10;
	d = 0;
}
void player::move(int d)
{
	if(d==1)
	x += velX;
	else if(d==2)
	y += velY;
}

void player::render()
{
	int i = 0;
	int count = getCount();
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
	if (direct == 5)
	{
		for (i; i < count; i++)
		{
			SDL_Rect dest = { x + i * 10,y,10,10 };
			snake[i] = dest;
			SDL_RenderDrawRect(renderer, &snake[i]);
			SDL_RenderFillRect(renderer, &snake[i]);
		}
	}
	else if (direct == 0)
	{
		//snake[count] = {NULL,NULL,NULL,NULL};
		SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
		SDL_RenderClear(renderer);
		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

		for (i = count; i > 0; i--)
		{
			snake[i] = snake[i - 1];
		}
		snake[0].y = snake[0].y + velY;//-velY
		for (i; i < count; i++)
		{
			SDL_RenderDrawRect(renderer, &snake[i]);
			SDL_RenderFillRect(renderer, &snake[i]);
			//SDL_Delay(50);
		}
	}


	else if (direct == 1)
	{
		//snake[count] = {NULL,NULL,NULL,NULL};
		SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
		SDL_RenderClear(renderer);
		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
		
		for (i = count; i > 0; i--)
		{
			snake[i] = snake[i-1];
		}
		snake[0].y = snake[0].y + velY;
		for (i; i < count; i++)
		{
			SDL_RenderDrawRect(renderer, &snake[i]);
			SDL_RenderFillRect(renderer, &snake[i]);
			//SDL_Delay(50);
		}
	}

	else if (direct == 2)
	{
		SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
		SDL_RenderClear(renderer);
		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

		for (i = count; i > 0; i--)
		{
			snake[i] = snake[i - 1];
		}
		snake[0].x = snake[0].x + velX;//-velX
		for (i; i< count; i++)
		{
			SDL_RenderDrawRect(renderer, &snake[i]);
			SDL_RenderFillRect(renderer, &snake[i]);
			//SDL_Delay(50);
		}
	}
	else if (direct == 3)
	{
		SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
		SDL_RenderClear(renderer);
		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

		for (i = count; i > 0; i--)
		{
			snake[i] = snake[i - 1];
		}
		snake[0].x = snake[0].x + velX;
		for (i; i< count; i++)
		{
			SDL_RenderDrawRect(renderer, &snake[i]);
			SDL_RenderFillRect(renderer, &snake[i]);
			//SDL_Delay(50);
		}
	}
	if (snake[0].x<-5 || snake[0].x>screenWidth)
	{
		SDL_Delay(100);
		player1.reset();
		
	}
	else if (snake[0].y<-5 || snake[0].y>screenHeight)
	{
		SDL_Delay(100);
		player1.reset();
		
	}
	
	player1.collision(2);
}

void player::input(SDL_Event e)
{
	if (e.type == SDL_KEYDOWN && e.key.repeat == 0)
	{
		switch (e.key.keysym.sym)
		{
		case SDLK_DOWN:
			
			if (old != 0)
			{
				old = 1;
				direct = 1;
				velY = abs(velY);
			}
			break;
		case SDLK_UP:
		
			if (old != 1)
			{
				direct = 0;
				old = 0;
				velY = -abs(velY);
			}
			break;
		case SDLK_RIGHT:
			
			if (old != 2)
			{
				old = 3;
				direct = 3;
				velX = abs(velX);
			}
			break;
		case SDLK_LEFT:
			
			
			if (old != 3)
			{
				direct = 2;
				old = 2;
				velX = -abs(velX);
			}
			break;
		case SDLK_1:
			count++;
			break;
		case SDLK_2:
			count--;
			break;
		case SDLK_r:
			player1.reset();
			player1.render();
			break;
		
		}
	}
}

bool init()
{
	bool success = true;
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("error");
		success = false;
	}
	else
	{
		window = SDL_CreateWindow("SNAKE", 100, 100, screenWidth, screenHeight, SDL_WINDOW_SHOWN);
		if (window == NULL)
		{
			printf("error");
			success = false;
		}
		else
		{
			renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
			if (renderer == NULL)
			{
				printf("Error");
				success = false;
			}
		}
	}
	return success;
}
void close()
{
	SDL_DestroyWindow(window);
	SDL_DestroyRenderer(renderer);
	window = NULL;
	renderer = NULL;
}

int main(int argc, char* args[])
{
	if (!init())
	{
		printf("error");
	}
	else
	{
		SDL_Event e;
		bool quit = false;
		while (!quit)
		{
			SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
			SDL_RenderClear(renderer);
			if (SDL_PollEvent(&e) != 0)
			{
				if (e.type == SDL_QUIT || e.key.keysym.sym==SDLK_ESCAPE)
					quit = true;
				else if (e.type == SDL_KEYDOWN)
					player1.input(e);
				else if (e.key.keysym.sym == SDLK_f)
					food1.changeLocation();
			}
			int d = player1.getD();
			player1.move(d);
			player1.render();
			player1.collision(2);
			player1.collision(1);
			//player1.collision(2);//for food int a =1 and for snake int a =2
			food1.render();
			SDL_Delay(25);
			SDL_RenderPresent(renderer);
		}
	}
	return 0;
	close();
}
 
I am sorry for writing a crappy code
just nudge me in the right direction and don't flame me please!
thanks in advance!
Edited by LOKIOdinson

Share this post


Link to post
Share on other sites
Advertisement

Please use the code tags when posting code here, it makes it a lot easier to read.

In the editor, it's the symbol that looks like this:

<>

 

Because of that I haven't read thoroughly through all your code, but some comments:

You seem to be using a lot of magic numbers. collision(int a), for example. I would suggest using better names for variables so it's easier to see at a glance what things are, and you might also want to consider using enums instead of just passing various numbers around.

Additionally, I would probably just use a std::vector instead of any form of linked list, but that's just me.

Share this post


Link to post
Share on other sites

Refactor. Here's your nudge.

PERFECT NUDGE 
THANKS A LOT!!!!!!!!!


Please use the code tags when posting code here, it makes it a lot easier to read.

In the editor, it's the symbol that looks like this:

<>

 

Because of that I haven't read thoroughly through all your code, but some comments:

You seem to be using a lot of magic numbers. collision(int a), for example. I would suggest using better names for variables so it's easier to see at a glance what things are, and you might also want to consider using enums instead of just passing various numbers around.

Additionally, I would probably just use a std::vector instead of any form of linked list, but that's just me.

I know my naming schemes are horrible i am trying to improve them 

i sorta right them in the flow and dont think about that while writing its a seriously bad habit and will try to improve them !

thanks for the valuable and great advice 

will write it in an improved way

might just post here after improving 

and thanks a lot! :)

Share this post


Link to post
Share on other sites

Generally, yes.

 

Just to add to this, it's best to make class variables private unless they need to be public for some reason.

Getters and setters are the way these variables are handled, usually.

For a private variable int X of class myClass, here is a sample getter and setter:

int myClass::getX()
{
    return X;
}

void myClass::setX(int newVal)
{
    X = newVal;
}

The functions getX() and setX() are public. This reduces the chance of accidentally changing values when they shouldn't be touched. 

Share this post


Link to post
Share on other sites

Generally, yes.

 
Just to add to this, it's best to make class variables private unless they need to be public for some reason.
Getters and setters are the way these variables are handled, usually.
For a private variable int X of class myClass, here is a sample getter and setter:
int myClass::getX()
{
    return X;
}

void myClass::setX(int newVal)
{
    X = newVal;
}
The functions getX() and setX() are public. This reduces the chance of accidentally changing values when they shouldn't be touched.


This being said, writing getters and setters like this is often a code smell. The purpose of encapsulation is to enforce design contracts. If you have a private member variable that's hidden behind get and set functions that do nothing but get and set that variable, you have effectively made that variable public in a complicated way - there isn't any kind of design contract being enforced by the get/set functions, so you should either rethink making the variable private or rethink the design that led to you needing both the get and the set. On classes that aren't just aggregations of data, preferably the latter first. Edited by Oberon_Command

Share this post


Link to post
Share on other sites

This being said, writing getters and setters like this is often a code smell. The purpose of encapsulation is to enforce design contracts. If you have a private member variable that's hidden behind get and set functions that do nothing but get and set that variable, you have effectively made that variable public in a complicated way - there isn't any kind of design contract being enforced by the get/set functions, so you should either rethink making the variable private or rethink the design that led to you needing both the get and the set. On classes that aren't just aggregations of data, preferably the latter first.


This is something that has always confused me and is the biggest stumbling block for my adoption of OOP. It's been said that, for example, the player class has no need to call the physics or rendering engines, and yet, both of those require player data, like position. So, player->render() is bad OOP, but so it renderer->render(player). In order for the latter to work, the data from the player class would need to be retrieved by the render member function via getters.

Share this post


Link to post
Share on other sites

It's pretty simple really - the idea of encapsulation is to enforce a contract, where the interface between objects is only what is necessary for them to perform their task, and everything else is handled internally.

 

If rendering needs a player position, it can ask for it via a getter on the Player. That's fine. But there's no need to add a setter as well because the renderer shouldn't be changing a player's position. Reporting its own position is part of the Player's interface. Letting other people set it is not. Provide only what is needed, no more.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!