Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Snake Collision

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Snake Collision
elamre
Member #13,750
November 2011

Hello all,
Im trying to develop a simple 2 player snake game. Everything so far so good. Im only having troubles with my collision system. Maybe somebody can help me with this?
Im using Allegro 4.9.9.2 because 5 doesnt seem to like my Dev-C++ very much.
This is my collision function:

bool Snake::collision()
    {
         for(int i=0; i<100;i++){
             if((x+1)==xPrevious[i] && y==yPrevious[i-1]){
                  return false;
                  }
             }
         
     }

and my files
http://www.2shared.com/file/fHg8Hli4/Try_2.html
The collision code is in snake.cpp.
with real kind regards, Elmar.

 Sliding text? 

gnolam
Member #2,030
March 2002
avatar

  1. When asking for help, always say what the problem actually is. Is it not compiling? Is it crashing? Is it producing undesired results? If so, what are the desired results? Help people help you by telling them what to look for.

  2. When posting code, put it in <code></code> tags. Use the edit button to add them.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

elamre
Member #13,750
November 2011

Ok sorry! :)
and yeah the code tags, i was trying to use them but i used [code][/code].

It is perfectly fine running. Not crashing nor problems with compiling.
However once ingame, i cant move any direction using this code:

    void Snake::moveRight()
    {    
         if(!collision()){  
         if(x>610)
                         x=10;
         toPrevious();
         x+=10;
         }
         else
                           textout_ex( screen, font, "Me gusta Collision Y", 320, 240, makecol(0, 0, 255), makecol(0, 0, 0));  
    }

So it detects a collision even though there is none!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre said:

bool Snake::collision()
    {
         for(int i=0; i<100;i++){
             if((x+1)==xPrevious[i] && y==yPrevious[i-1]){
                  return false;
                  }
             }
         
     }

Think about what you are doing - you are checking if x plus one is the same as any of the last 100 x values and the current y is the same as the yPrevious value one before the current (i) yPrevious value. Does that make sense?

Try storing your snake values in a std::list :

#SelectExpand
1struct segment { 2 int x; 3 int y; 4} 5 6class snake { 7private : 8 list<segment> body; 9 segment head; 10 11public : 12 void UpdateSnake() { 13 if (!body.empty() && !body.grow()) { 14 body.erase(body.begin()); 15 } 16 body.push_back(head); 17 head.x += xdir; 18 head.y += ydir; 19 dead = CheckCollision(); 20 } 21 bool CheckCollision() { 22 for (list<segment>::iterator it = body.begin() ; it != body.end() ; ++it) { 23 if ((it->x == head.x) && (it->y == head.y)) {return true;} 24 } 25 return false; 26 } 27 28};

elamre
Member #13,750
November 2011

Well to me it makes a lot of sense to be honest. if it wants to go up, it will check first if the above position is equal to one of the previous positions.
And with your code, Thankx. But i have no clue how to use this, i have added it to my snake, but the list doesnt have a type, and when making it int it doesnt work. (Im unknown with lists). Also where to call for update snake? where does head.x and head.y reffer to? and the body.empty and body.grow are listfunctions i assume?
And then the iterator, The iterator is unknown. And it is unable to process It.

thanks for your help until now :). But im still a bit stuck with this problem.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre said:

Well to me it makes a lot of sense to be honest. if it wants to go up, it will check first if the above position is equal to one of the previous positions.

But you're still only checking if it moves up, and you don't know if it has. And, you're not checking the right index for the previous Y value (You should use i, not i - 1).

Quote:

And with your code, Thankx. But i have no clue how to use this, i have added it to my snake, but the list doesnt have a type, and when making it int it doesnt work. (Im unknown with lists). Also where to call for update snake? where does head.x and head.y reffer to? and the body.empty and body.grow are listfunctions i assume?
And then the iterator, The iterator is unknown. And it is unable to process It.

That's okay, I'll walk you through it.

A list is a C++ container template defined in the system header list and contained in the std namespace. This means to use it you will need to :

#include <list> // include the header that defines list
using std::list;// tell the compiler we will be using list to refer to std::list

To use a template, you need to tell it what type it will be using.

list<segment> body;// declares a list of segment objects named body

To iterate over a list, you need to use a list<TYPE>::iterator. iterators are just an efficient way to move back and forth over the objects contained in the list (or more generally, container).

#SelectExpand
1 2// list iteration method one 3list<segment>::iterator it = body.begin();// The list::begin() method returns an iterator pointing to the beginning of the list. It may return the same value as list::end(). 4while (it != body.end()) { 5 segment& s = *it;// iterators point to the elements stored in the list 6 printf("s.x = %i , s.y = %i\n" , s.x , s.y); 7 ++it;// move the iterator to point to the next element 8} 9 10// list iteration method two 11for (list<segment>::iterator it = body.begin() ; it != body.end() ; ++it) { 12 segment& s = *it;// using a reference allows us to modify the object stored in the list if we want to 13 printf("s.x = %i , s.y = %i\n" , s.x , s.y); 14}

For more information on the Standard Template Library containers (like list), take a look here :
http://www.sgi.com/tech/stl/index.html

And I actually made a typo. body.grow() doesn't exist - it is not a member of the list class. What I meant was that if the snake will grow on this update, then you should not erase the tail of the snake (which is stored at the beginning of the list). So, something more like this :

--growcounter;
bool grow = (growcounter == 0);
if (growcounter == 0) {growcounter = time_between_growth;}
if (!body.empty() && !grow) {
   body.erase(body.begin());
}

If you have any more questions or can't get it to work, post your errors here, and your questions too.

elamre
Member #13,750
November 2011

Im tying to implent the code(and having a hard time with it) But doesnt the segment structure have to be declared in the snake class aswell? or can i just declare it wherever i want?

Edit:
Nvm i found it out.
However the iteration methods arent totally clear to me, Where do i have to use them? i see that one is the collision check?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

The segment structure can be declared anywhere before a class or function that uses it. This means it can go in a separate header, or in the same header as the one for your snake class, before you declare it.

Be specific with your problems.

elamre
Member #13,750
November 2011

// list iteration method one
list<segment>::iterator it = body.begin();// The list::begin() method returns an iterator pointing to the beginning of the list. It may return the same value as list::end().
while (it != body.end()) {
   segment& s = *it;// iterators point to the elements stored in the list
   printf("s.x = %i , s.y = %i\n" , s.x , s.y);
   ++it;// move the iterator to point to the next element
}

// list iteration method two
for (list<segment>::iterator it = body.begin() ; it != body.end() ; ++it) {
   segment& s = *it;// using a reference allows us to modify the object stored in the list if we want to
   printf("s.x = %i , s.y = %i\n" , s.x , s.y);
}

Im getting what this code is doing (only the printf function, u suppose this is like cout?) But have no clue where to use it. And your last piece of code (with the growcounter) i suppose this is my grow() function?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

If you don't know what printf does, you need to get yourself a C/C++ reference guide to look at. This one might be okay :
http://www.cplusplus.com/
http://www.cplusplus.com/reference/clibrary/

You'll want to iterate over the list when you check each segment in the body list against the head segment to find out if the snake ran over itself and died.

Thomas Fjellstrom
Member #476
June 2000
avatar

I'd just like to say that 4.9.9.2 IS allegro 5, just a WIP/Alpha version.

And if you're having problems with the 5.0.x releases, don't hesitate to ask for help on the installation forum.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

elamre
Member #13,750
November 2011

@Thomas,
Yeah, i could probably find the problem with google. but if it aint broken, dont fix it! :) And this allegro is working perfectly fine for me, and has all the functions i need ;)

OT,
First of all, thanks for the help :).
second off all:
I have no clue how to declare the grow member

#SelectExpand
1struct segment { 2 int x; 3 int y; 4 int growcounter; 5 void grow(); 6 7 void segment::grow() 8 { 9 --growcounter; 10 bool grow = (growcounter == 0); 11 if (growcounter == 0) {growcounter = 5;} 12 if (!body.empty() && !grow) { 13 body.erase(body.begin()); 14 } 15};

But still it says that class std::list<........> 'has no member named 'grow';
Also ive added my project again, maybe somebody can see what im doing wrong there?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You don't need a separate grow function, and the growth variables should be in your snake class, not your segment class. To combine the examples I gave would give you :

void Snake::UpdateSnake() {
   --growcounter;
   bool grow = (growcounter == 0);
   if (growcounter == 0) {growcounter = time_between_growth;}
   if (!body.empty() && !grow) {
      body.erase(body.begin());
   }
   body.push_back(head);
   head.x += xdir;
   head.y += ydir;
   dead = CheckCollision(); 
}

growcounter and time_between_growth are both members of the snake class.

elamre
Member #13,750
November 2011

Ah oh ok, thx.
And the xdir and ydir are my snake x and y values rght?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

xdir and ydir are the x and y directions, or velocities, which I assume are 1, or however wide and tall a square or segment is. Only call Snake::Update when you want your snake to move (ie, not on every frame). Better yet, rename Update to Move, and make a new Update function :

void Snake::Update() {
   --update_counter;
   if (update_counter == 0) {
      Move();
      update_counter = time_til_next_update;
   }
}

elamre
Member #13,750
November 2011

I have no clue on how to do it anymore :s.

So what what you gave me:
An update function with variables update_counter and a set value time_til_next_update, I should declare this int's in my class i suppose.
This part of code i get, so my time till next update variable is basicly the speed if im correct?
Then the updateSnake, this one i dont get. It sets the tail values, right?
but i dont really get the grow (boolean) and the growCounter.
And how to use these functions. I think i should use the Update() function in my main, which will use the renamed Update_Snake (Move() ) function. But when do i have to use my move function then?

    void Snake::movePlayer()
    {
            clear_keybuf();
            
            if (key[KEY_UP]) moveUp();        
            else if (key[KEY_DOWN]) moveDown();    
            else if (key[KEY_RIGHT])moveRight();
            else if (key[KEY_LEFT])moveLeft();
            Draw();
}

Thanks for keeping so patient, and helping me so much! Much appreciated! :)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

#SelectExpand
1void Snake::CheckInputs() { 2 if (key[KEY_RIGHT]) { 3 xdir = 1;// or however wide a square / segment is 4 ydir = 0; 5 } 6 if (key[KEY_LEFT]) { 7 xdir = -1;// or the reverse of above 8 ydir = 0; 9 } 10 if (key[KEY_UP]) { 11 xdir = 0; 12 ydir = -1; 13 } 14 if (key[KEY_DOWN]) { 15 xdir = 0; 16 ydir = 1; 17 } 18}

That way, the direction will be set until the next time someone presses a key. You don't have to move right away when they press a key. It's up to you though. If you want them to move whenever you press a key, just add in Move() to the if clauses there after setting the direction.

while (!quit) {
   while (ticks < 1) {rest(1);}
   snake.CheckInputs();
   snake.Update();
   snake.Display();
}

elamre
Member #13,750
November 2011

Owh btw, how can i do the drawing for the tail? just by reading out all the segments? (so in a for loop, like i did for the array tail)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre
Member #13,750
November 2011

Yeah, its the same idea :).
Now i reworked my whole code, no errors. runs. But i cant seem to be able to move the snakes head.
Ive used your exact pieces, using this for the drawing:
textout_ex( buffer, font, "@", head.x, head.y, makecol( 255, 0, 0), makecol( 0, 0, 0) );
and in the constructor(int x, int y):

 head.x=x;
 head.y=y;

So it draws the initial position of the head. But does not change when pressing a key! =/

int main(){
    Setup setup(640,480);
    Snake snake(200,100);
    while ( !key[KEY_ESC] ){
        snake.CheckInputs();
        snake.Update();
        snake.Draw();
        rest(50);
    }    
    return 0;  
}

my main (i know using rest is not very good, ill change that later on).

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre
Member #13,750
November 2011

#SelectExpand
1void Snake::Update() { 2 --update_counter; 3 if (update_counter == 0) { 4 Move(); 5 update_counter = 10; 6 } 7} 8 9void Snake::CheckInputs() { 10clear_keybuf(); 11 if (key[KEY_RIGHT]) { 12 xdir = 1;// or however wide a square / segment is 13 ydir = 0; 14 } 15 if (key[KEY_LEFT]) { 16 xdir = -1;// or the reverse of above 17 ydir = 0; 18 } 19 if (key[KEY_UP]) { 20 xdir = 0; 21 ydir = -1; 22 } 23 if (key[KEY_DOWN]) { 24 xdir = 0; 25 ydir = 1; 26 } 27}

It doesnt draw anything anymore now =/

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre said:

So it draws the initial position of the head. But does not change when pressing a key! =/

elamre said:

It doesnt draw anything anymore now =/

So is it drawing or isn't it?

Just post everything you have, in a zip file if necessary.

elamre
Member #13,750
November 2011

Here it is :).

I cant seem to attach the file :s.
And its not drawing no :(

http://www.2shared.com/file/rCTGYtr8/Try3.html

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

First problem - your Snake::Snake(int,int) constructor doesn't initialize all it's values. This means update_counter,xdir,ydir,growcounter may all be zero, but they aren't guaranteed to be. So when you hit these lines the counter variables subtract endlessly and are never equal to zero :

#SelectExpand
1void Snake::Update() {
2 --update_counter;
3 if (update_counter == 0) {
4 Move(); 5 update_counter = 10; 6 } 7} 8 9void Snake::Move() {
10 --growcounter;
11 bool grow = (growcounter == 0);
12 if (growcounter == 0) {
13 growcounter = 5; 14 } 15 if (!body.empty() && !grow) { 16 body.erase(body.begin()); 17 } 18 body.push_back(head); 19 head.x += xdir; 20 head.y += ydir; 21 //dead = CheckCollision(); 22}

You still need to add in drawing the body to Snake::Draw as well.

 1   2 


Go to: