Page 1 of 2

Snake game with irrlicht

Posted: Tue Jan 22, 2008 5:25 am
by pibeytor
well this what i've done so far..

it's supposed that when you press down one key( W,A,D or S) the esphere has to move to that direction without holding the key..

my code just move one tap at the time...

and another question...

how can i do in order to make other spheres appear at a random place and follow the " head of the snake "

Code: Select all


#include <irrlicht.h>
#include <iostream>

using namespace irr;

#pragma comment(lib, "Irrlicht.lib")


scene::ISceneNode* node = 0;
IrrlichtDevice* device = 0;
bool teclas[256]={false};

class MyEventReceiver : public IEventReceiver{

public:	
	virtual bool OnEvent(const SEvent& event)	{ 
 

	if (node != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT&& !event.KeyInput.PressedDown){		
		switch(event.KeyInput.Key)
		{
		case KEY_KEY_A:		
		case KEY_KEY_D:			
			{				
				core::vector3df v = node->getPosition();
				v.X += event.KeyInput.Key == KEY_KEY_A ? 2.0f : -2.0f;
				node->setPosition(v);	
								
			}			
			return true;


		case KEY_KEY_W:
		case KEY_KEY_S:			
			{				
				core::vector3df v = node->getPosition();
				v.Y += event.KeyInput.Key == KEY_KEY_W ? 2.0f : -2.0f;
				node->setPosition(v);

			}			
			return true;		
		}
	} 
return false;  
}  
};

 
int main()
{	MyEventReceiver receiver;

	// create device

	IrrlichtDevice* device = createDevice(irr::video::EDT_DIRECT3D9,irr::core::dimension2d<irr::s32>(640,480),32,false,false,false,&receiver);
	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();


	node = smgr->addSphereSceneNode();
	node->setPosition(core::vector3df(0,0,0));
	node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
	node->setMaterialFlag(video::EMF_LIGHTING, false);


	
	scene::ICameraSceneNode * cam = smgr->addCameraSceneNode(0,core::vector3df(0,0,200));

	int lastFPS = -1;

	while(device->run())
	{
		driver->beginScene(true, true, video::SColor(0,0,100,200));
	
		smgr->drawAll(); // draw the 3d scene
		device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

		driver->endScene();

		int fps = driver->getFPS();

		if (lastFPS != fps)
		{
			core::stringw tmp(L"Movement Example - Irrlicht Engine [");
			tmp += driver->getName();
			tmp += L"] fps: "; 
			tmp += fps;

			device->setWindowCaption(tmp.c_str());
			lastFPS = fps;
		}
		//node->setPosition(node->getPosition() + core::vector3df(0.01f,0,0) );
	}

	device->drop();
	
	return 0;
}



Posted: Tue Jan 22, 2008 5:26 am
by vitek
You have to?

Posted: Tue Jan 22, 2008 5:35 am
by pibeytor
yes.. it's for my school project...

we have to use lists or whatever they are called..

so i need something to start.. but i need help..

Posted: Tue Jan 22, 2008 6:19 am
by Andreas
I guess a good start would be to show us what you've got so far. Did you copy&paste the tutorials? Did you take a look at the irrlicht API? Or did you maybe program a little game (with irrlicht?) before?

If not, these are the places to start:
http://irrlicht.sourceforge.net/tut001.html
http://irrlicht.sourceforge.net/docu/
http://irrlicht.sourceforge.net/docu/cl ... 1list.html

I'm sure there are enough people here willing to help, but i guess no one is interested in doing your homework for you. :wink:

Posted: Tue Jan 22, 2008 6:24 am
by greenya
pibeytor wrote:so i need something to start.. but i need help..
http://en.wikipedia.org/wiki/Snake_%28video_game%29

Posted: Tue Jan 22, 2008 11:59 am
by rogerborg
Indeed. STFW would be my initial response, particularly as we already advised you to be explicit with your questions.

I suggest that you post your full, unabridged, unedited project requirements, plus whatever you've produced on your own so far. If you show that you've put in some work of your own and gone as far as you can yourself, then maybe someone will feel inclined to help you out.

Posted: Wed Jan 23, 2008 7:19 am
by pibeytor
i've added my code in the first post..
i hope someone can help me out...

Re: Snake game with irrlicht

Posted: Wed Jan 23, 2008 7:47 am
by greenya
I do not write the code instead of you.
But i will try to explain in details how you can snake-it :)
pibeytor wrote: it's supposed that when you press down one key( W,A,D or S) the esphere has to move to that direction without holding the key..
my code just move one tap at the time...
You should have a variable storing current direction.
For example:

Code: Select all

int snakeDirection = 0; // 0=left, 1=top, 2=right, 3=bottom;
Then each time when you need to move your snake, you check this value and adjust its coordinates properly.
For example:

Code: Select all

switch (snakeDirection)
{
case 0: // left
snakePosition.X--;
break;
case 1: // top
snakePosition.Y--;
...
When user presses the key (W,A,S or D) you do proper changing of snakeDirection value.
For example:

Code: Select all

...
case KEY_KEY_A: // left
{            
snakeDirection = 0;
return true;
}
...

pibeytor wrote: and another question...

how can i do in order to make other spheres appear at a random place and follow the " head of the snake "
Store all spheres in an array. For example if maximum length of your snake can be 20, than you can allocate array with 20 elements inside. Each element -- is a pointer on the scene::ISceneNode.
initialization
Init first pointer (the head of the snake) with correct scene node (sphere). All other (19 elements) set to NULL -- this is the way how you will know that this element is empty.
growing
Then, when you need to grow snake -- you just filling first empty element in the array with a pointer to newly created sphere.
moving
Each time you need to move the snake, you moving its head (first element of the array) using snakeDirection only the head -- so you update snakePosition -- it is position of the head. Because you do not need to know all other positions since snake moves "as snake" :)
So in short:

Code: Select all

// move the snake spheres to its head
for (int i=19; i>=1; i--)
{
if (snakeArray[i] != NULL)
{
snakeArray[i]->setPosition( snakeArray[i-1]->getPosition() );
}
}
// move head of the snake
snakeArray[0]->setPosition(vector3df(snakeDirection.X,0,snakeDirection.Z));

Posted: Wed Jan 23, 2008 8:38 am
by hybrid
Please note that this move code is frame rate dependant. You''ll have to move into the desired direction by speed/timeDelta (where timeDelta is calculated with the ITimer).

Posted: Wed Jan 23, 2008 9:26 am
by JP
Better to not update the first post like that as it just causes a bit of confusion, just add on your new questions to the end of the thread ;)

Posted: Wed Jan 23, 2008 9:19 pm
by pibeytor
thnx greenya

but i still dont understand how change the direction.
i dont know were tu place the code.. inside my event receiver or inside the main..

or i have to make another function named snakedirection? and call it from there?

Posted: Wed Jan 23, 2008 11:00 pm
by randomMesh
pibeytor wrote:...or i have to make another function named snakedirection? and call it from there?
Maybe this helps.

There is one thing you have to figure out for yourself:
If new snake parts are added, they are placed on the top of all others, wich means you only can see one.

Just place it correctly upon creation and the Snake::move() method will work.

Good luck.

Code: Select all

#include <irrlicht.h>


class Snake
{
private:

	irr::IrrlichtDevice* device;
	
	irr::u8 snakeDirection; // 0 left / 1 up / 2 right / 3 down
	
	irr::f32 snakeSpeed;
	
	irr::f32 snakeRadius;
	
	irr::core::array<irr::scene::ISceneNode*> snakeParts;
	
public:
	Snake(irr::IrrlichtDevice* device) :
		device(device),
		snakeDirection(0),
		snakeSpeed(50.0f),
		snakeRadius(10.0f)
	{
		//make head
		addPart();
	}
	
	void move(const irr::f32 elapsed) const
	{
		irr::u32 parts = snakeParts.size();
		--parts;

		irr::u32 i;
		for (i = parts; i >= 1; i--)
			snakeParts[i]->setPosition(snakeParts[i-1]->getAbsolutePosition()); 

		// move head of the snake
		irr::core::vector3df headPos = snakeParts[0]->getAbsolutePosition();
		switch (snakeDirection)
		{
			case 0: headPos.X = headPos.X - snakeSpeed* elapsed; break;
			case 1: headPos.Z = headPos.Z + snakeSpeed* elapsed;break;
			case 2: headPos.X = headPos.X + snakeSpeed* elapsed;break;
			case 3: headPos.Z = headPos.Z - snakeSpeed* elapsed;break;
		}
		snakeParts[0]->setPosition(headPos);
	}

	void addPart()
	{	
		irr::scene::ISceneNode* newPart = device->getSceneManager()->addSphereSceneNode(snakeRadius); 
		newPart->setMaterialFlag(irr::video::EMF_LIGHTING, false);

		this->snakeParts.push_back(newPart);
	}

	void setSnakeDirection(irr::u8 direction)
	{
		this->snakeDirection = direction;
	}
	
	const irr::u8 getSnakeDirection() const { return this->snakeDirection; }
};




class EventHandler : public irr::IEventReceiver
{
private:
	Snake& snake;

public:
	EventHandler(Snake& snake) :
		snake(snake)
	{
	}

	bool OnEvent(const irr::SEvent& event)
	{

		if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
		{
			switch (event.KeyInput.Key)
			{
				case irr::KEY_LEFT:
					if (snake.getSnakeDirection() != 2)
						snake.setSnakeDirection(0);
					return true;
				case irr::KEY_UP:
					if (snake.getSnakeDirection() != 3)
						snake.setSnakeDirection(1);
					return true;
				case irr::KEY_RIGHT:
					if (snake.getSnakeDirection() != 0)
						snake.setSnakeDirection(2);
					return true;
				case irr::KEY_DOWN:
					if (snake.getSnakeDirection() != 1)
						snake.setSnakeDirection(3);
					return true;

				case irr::KEY_SPACE:
					snake.addPart();
					return true;
				
				default: return false;
			}
        }

		return false;
	}

};

int main()
{
	irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL);
	if (device == 0) return 1;

	irr::scene::ISceneManager* smgr = device->getSceneManager();
	irr::video::IVideoDriver* driver = device->getVideoDriver();
	
	Snake snake(device);

	EventHandler event(snake);
	device->setEventReceiver(&event);

	irr::scene::ICameraSceneNode* camera = smgr->addCameraSceneNode();
	camera->setPosition(irr::core::vector3df(0.0f, 200.0f, 0.0f));
	
	//Timer
	irr::ITimer* timer = device->getTimer();
	irr::u32 then = timer->getTime();
	irr::u32 now = 0;
	irr::f32 elapsed = 0.0f;

	while (device->run())
	{
		//compute time since last frame
		now = timer->getTime();
		elapsed = (now - then) / 1000.f;
		then = now;
		
		if (device->isWindowActive())
		{
			driver->beginScene(true, true, irr::video::SColor(255, 0, 0, 0));
			snake.move(elapsed);
			smgr->drawAll();
			driver->endScene();
		}
	}
	
	device->drop();
	return 0;
}


Posted: Wed Jan 23, 2008 11:48 pm
by pibeytor
Just place it correctly upon creation and the Snake::move() method will work.
are you telling me that if i combine both codes the snake will work?
i'm trying to do that..

Posted: Wed Jan 23, 2008 11:52 pm
by randomMesh
pibeytor wrote:
Just place it correctly upon creation and the Snake::move() method will work.
are you telling me that if i combine both codes the snake will work?
No. My code is a stand alone one.

Just wanted to give you an idea how to organize data in classes and move in a frame rate independent way.

As for the positioning of the new snake part i suggest you store the direction of the last part upon creation somehow and then set it to the opposite direction. There is a private variable snakeRadius, which will help.

Note that i changed the type of snakeSpeed from u32 to f32.
Btw.: The moving seems strange since it is a top-down view and a static camera.

Posted: Thu Jan 24, 2008 6:34 am
by pibeytor
So far, so good my snake can move with the directional keys. but i'm dont really know how to feed it and make it grow..

Code: Select all

#include <irrlicht.h>
#include <iostream>
#include <cstdlib>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")

scene::ISceneNode* snake = 0;
IrrlichtDevice* device = 0;
//bool teclas[256]={false};

int snakeDirection=rand()%5;
//float snakePosition=0;

class MyEventReceiver : public IEventReceiver
{
public:	
	virtual bool OnEvent(const SEvent& event)	
	{ 
 	if (snake != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT&& !event.KeyInput.PressedDown){		
				
		if(event.KeyInput.Key==KEY_UP){
				snakeDirection=0;//up
				return true;
		}
		
		if(event.KeyInput.Key==KEY_DOWN){
				snakeDirection=1;//down
				return true;
		}
		
		if(event.KeyInput.Key==KEY_LEFT){
				snakeDirection=2;//left;
				return true;
		}
		
		if(event.KeyInput.Key==KEY_RIGHT){
				snakeDirection=3;//right
				return true;
		}
			
	} 
return false;  
}  
};

 int main()
{	
	MyEventReceiver receiver;

	// create device

	IrrlichtDevice* device = createDevice(irr::video::EDT_DIRECT3D9,irr::core::dimension2d<irr::s32>(640,480),32,false,false,false,&receiver);
	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();

//snake head
	snake = smgr->addSphereSceneNode();
	snake->setPosition(core::vector3df(0,0,0));
	snake->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
	snake->setMaterialFlag(video::EMF_LIGHTING, false);

	scene::ICameraSceneNode * cam = smgr->addCameraSceneNode(0,core::vector3df(0,0,200));

	int lastFPS = -1;

	while(device->run())
	{
		driver->beginScene(true, true, video::SColor(0,0,100,200));
				
		smgr->drawAll(); // draw the 3d scene
		device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

		driver->endScene();

		int fps = driver->getFPS();

		if (lastFPS != fps)
		{
			core::stringw tmp(L"ULTIMATE SNAKE [");
			tmp += driver->getName();
			tmp += L"] fps: "; 
			tmp += fps;

			device->setWindowCaption(tmp.c_str());
			lastFPS = fps;
		}

		// snake movement
		switch (snakeDirection){ 

			case 0: // top 
				snake->setPosition(snake->getPosition() + core::vector3df(0,0.1f,0) ); 
				break; 
			case 1: // down
				snake->setPosition(snake->getPosition() - core::vector3df(0,0.1f,0) );
				break;
			case 2://left
				snake->setPosition(snake->getPosition() + core::vector3df(0.1f,0,0) );
				break;
			case 3://right
				snake->setPosition(snake->getPosition() - core::vector3df(0.1f,0,0) );
				break;
					
			return true;		
		}//end switch 
	}

	device->drop();
	
	return 0;
}