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

AH that was my problem, totally forgot about that. Also i tried to make them all 0, but that wouldnt work either. But i forgot that it FIRST substracts from the value, and only after that checks. Hence my problem.
And about the tail, i know that i didnt have it implented yet, i wanted to make the movement work first :).
So now the tail!

Ok the tail works great, my only problem is the collision checking,

i use

while(snake.Dead() == false){
the functions to run the game are here
}
return 0;

where

bool Snake::Dead(){
return dead
}

However i die instantly! :(

EDIT:
Nvm, i figured it out. Played a bit with the code, came to an understanding that the snakes head is a structure as well. And made a startup timer.
So now the engine is done. Thank you really much! Youve helped me develop a simple snake game, and gave me a base understanding of how iterator work.

Still, even though this is done, why didnt my old code work? (other then the fact i used +1 on the wrong location)

Kind regards, ELmar

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Well, for one thing, you didn't keep track of how many segments were currently in the body, you checked against all 100 positions in the array regardless of current size. I never saw any more of your older code, so I couldn't say why it didn't work.

elamre
Member #13,750
November 2011

The rest is in my first post.
I know, i only checked it for 100 segments, but i could've changed that (for example by making a bigger array and copying all the positions in that). Or i could've made it with a vector.

EDIT
Also i have a question about the structure declared in the class. So i want to make it multiplayer for example. Then ill have to check if the player 2 head x and y coordinates dont touch that of player 1. THat is no problem. But then ill need another for statement witht the iterator, and have no clue how to do this.
This is what i had in mind:

#SelectExpand
1if(player1.getX() == player2.getX){ 2 if(player1.getY() == player2.getY()) 3 Collision = true; 4 } 5 6int Snake::getX() 7{ 8 return head.x; 9} 10//This was the easy part 11//But for the tail to check??? 12 for (list<player2.segment>::iterator it = player2.body.begin() ; it != player2.body.end() ; ++it) 13{ 14segment& s = *it; 15 if ((it->x == player1.x) && (it->y == player1.y)) { 16 Collision = true;} 17 }

I know the variables are private, but wouldnt it help if i made them public? that way i can easier check for a collision between tail and the head of another snake.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

bool CheckForSnakeCollision(const Snake& s1 , const Snake& s2) {
   // check head one against body two
   // check head two against body one
}

You don't need to make anything public or use a friend declaration either, but you could :

class Snake {
// ...
   friend CheckForSnakeCollision(const Snake& s1 , const Snake& s2);
};

Or you can use getter variables that return const references :

class Snake {
// ...
   const list<segment>& Body() {return body;}
   const segment& Head() {return head;}
};

elamre
Member #13,750
November 2011

hmm, the friend one i dont get really. so it grants a class the same permissions as another class? But why would i want that in this case?
The getter,
Yeah that basicly, and then use the collision check i stated in the previous post?
and the first option, this one is not really clear to me. Ill try to play around with it.

Also, isnt this very inefficient? checking for 2 lists if there are any collisions?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre said:

hmm, the friend one i dont get really. so it grants a class the same permissions as another class? But why would i want that in this case?

You can either friend a function prototype which gives it access to private members of the class, or you can friend another class, doing the same thing.

Quote:

The getter,
Yeah that basicly, and then use the collision check i stated in the previous post?
and the first option, this one is not really clear to me. Ill try to play around with it.

Use Snake::Body() and Snake::Head() on opposing snakes, and iterate over each body segment, checking it against the head of the other snake.

Quote:

Also, isnt this very inefficient? checking for 2 lists if there are any collisions?

Imagine your snakes are 1000 segments long, and you only check each time a snake moves, that is only (60/ticks_per_move)*1000 checks every second. If you moved on every frame, that would be 60000*2 checks, or 120000. Computers are capable of millions of calculations per second, so don't worry about things like that yet. Only look into them if they are actually causing you problems. If you're really worried, then use a vector instead of a list. That gives you direct access instead of indirect access, but it also makes adding and removing segments take longer (which is still probably the least of your worries). In short, don't worry about it.

elamre
Member #13,750
November 2011

Haha, ok so the calculations should be just fine :).
Also for the checking part, i dont really see how i can read the values of the structure. Ive added the following functions (as you suggested).

const list<segment>& Body()  
{return body;}
const segment& Head() 
{return head;}

Now to retrieve the values of the following code:

bool CheckForSnakeCollision(const Snake& s1 , const Snake& s2) {
   for (s1.list<segment>::iterator it = s1.body.begin() ; it != s1.body.end() ; ++it) {
      if ((it->x == s2.get_x) && (it->y == s2.get_y)) {
                 return true;}
      }
   return false;
}
//where get_y and get_x:
int Snake::get_x()
{
   return head.x
}
//same goes for get_y, but then returning head.y

But obviously this wont work. I cant seem to find a way to call the first part of the for loop (The iterator part) from another object. Should this be done by getters as well???

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I forgot you need to make the getters 'const' :

#SelectExpand
1class Snake { 2 const list<segment>& Body() const {return body;} 3 const segment& Head() const {return head;} 4}; 5 6bool SnakeVsSnake(const Snake& s1 , const Snake& s2) { 7 const list<segment>& s1body = s1.Body(); 8 const list<segment>& s2body = s2.Body(); 9 const segment& s1head = s1.Head(); 10 const segment& s2head = s2.Head(); 11 for (list<segment>::const_iterator it = s1body.begin() ; it != s1body.end() ; ++it) { 12 if ((it->x == s2head.x) && (it->y == s2head.y)) { 13 return true;// head two hit body one 14 } 15 } 16 for (list<segment>::const_iterator it = s2body.begin() ; it != s2body.end() ; ++it) { 17 if ((it->x == s1head.x) && (it->y == s1head.y)) { 18 return true;// head one hit body two 19 } 20 } 21 return false; 22}

And you'll still need to check each snake head vs its own body as well.

elamre
Member #13,750
November 2011

Nice!
I have only but 2 questions, its about the functions and the use of objects.
Say ive made the following function:

void showCollision(const Snake& p1, const Snake& p2, const Snake& p3, const Snake& p4, Setup S1)
{
     if(SnakeVsSnake(p1,p2)==1){
        S1.DrawText("Player 2 hit player 1");
        p2.stopMoving();
        }
     else if(SnakeVsSnake(p1,p2)==2){
        S1.DrawText("Player 1 hit player 2");
        p1.stopMoving();
        }
}

Now this works fine! for 1 thing, i cant use p2/p1.stopMoving. This is because we are using a pointer here were we dont need that(right?) and thats also why it IS working for the S1.DrawText(const *char).
However, i only know 1 way to fix this, namely:

void showCollision(const Snake& p1, Snake P1, const Snake& p2, Snake P2, const Snake& p3, Snake P3, const Snake& p4, Sake P4, Setup S1)
{
     if(SnakeVsSnake(p1,p2)==1){
        S1.DrawText("Player 2 hit player 1");
        P2.stopMoving();
        }
     else if(SnakeVsSnake(p1,p2)==2){
        S1.DrawText("Player 1 hit player 2");
        P1.stopMoving();
        }
}

However then we get a code with 9 arguments! where i think only 5 are needed(at max)is there a way to go from const& p1 to p1?
also the error it gives:

main.cpp passing `const Snake' as `this' argument of `bool Snake::stopMoving()' discards qualifiers 

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

If you need to modify a snake object (by using Snake::StopMoving()) then you should not be using a 'const Snake&', but a 'Snake&' only. That way you can still modify it. The warning came up because you are trying to call a non-const member function on a const Snake object.

To simplify code, you can use an array (this example uses a modified SnakeVsSnake called SnakeHitSnake that only checks if snake 1 hit snake 2 but not the other way around) :

void ShowCollision(....) {
   Snake& snakes[4] = {p1 , p2 , p3 , p4};// Or use a Snake* [4].
   const char* text[4] = {"p1" , "p2" , "p3" , "p4"};
   char* buf[1024];
   for (unsigned int i = 0 ; i < 4 ; ++i) {
      for (unsigned int j = i + 1 ; j < 4 ; ++j) {
         if (SnakeHitSnake(snakes[i] , snakes[j])) {
            snakes[i].StopMoving();
            sprintf(buf , "%s hit %s!" , text[i] , text[j]);
         }
      }
   }
}

elamre
Member #13,750
November 2011

Both of your methods arent working. Ive been looking around a bit, and cant find a proper way to do it.
I found a way that makes an array of new objects

     Snake* myObject[4];
     int i;
     Snake * objectPointer;
     for (i = 0; i < 50; i++)
     {
         objectPointer = new Snake;

     }

But then ill have to copy all the values of the reference object, for a dummy object. and i think this is wasting resources a bit much.
So my guess is that i need to get rid of the constant in order to make my reference object functions work. However i do not know how to easily do this.

Also a total different question, is there a function to draw a string in allegro? Ive been searching a lot lately, but all i can come up with are 2 functions which use const * char. And i cant seem to convert a string to a const char (Or i have to use functions which require runtime librarys, in which case i cant port it to for example linux anymore)

thx :)

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Define "aren't working".

Why are you trying to make 50 new snakes?

elamre said:

So my guess is that i need to get rid of the constant in order to make my reference object functions work. However i do not know how to easily do this.

Edgar said:

If you need to modify a snake object (by using Snake::StopMoving()) then you should not be using a 'const Snake&', but a 'Snake&' only. That way you can still modify it. The warning came up because you are trying to call a non-const member function on a const Snake object.

Just don't use the 'const' keyword - in the member function declaration, or in the function prototype.

elamre said:

Also a total different question, is there a function to draw a string in allegro? Ive been searching a lot lately, but all i can come up with are 2 functions which use const * char. And i cant seem to convert a string to a const char (Or i have to use functions which require runtime librarys, in which case i cant port it to for example linux anymore)

See the manual : http://www.allegro.cc/manual/5/
Specifically, the font addon : http://www.allegro.cc/manual/5/font.html

To get a const char* from a std::string, use the string::c_str() method :

string s = "Lalalala";
printf("%s\n" , s.c_str());

elamre
Member #13,750
November 2011

Yeah the 50 was a mistake :p. It was from an example i found.
Ill try and get of the const then :).
Also the s.c_str() is not working. Ive tried it before and googled it. But i cannot come up with a solution for that problem. And yes i did include <String> and even <CString> yet no succes! :(
And i know how to draw a char to the screen, but i want to be able to do it with strings :).

also not working = it cant convert const snake to snake*. Thats when using the following code:

Snake *snakes[4] = {p1,p2,p3,p4};

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

elamre said:

Also the s.c_str() is not working. Ive tried it before and googled it. But i cannot come up with a solution for that problem. And yes i did include <String> and even <CString> yet no succes! :(

#include <string>
using std::string;// so you can refer to it as 'string', instead of 'std::string'.

Quote:

also not working = it cant convert const snake to snake*. Thats when using the following code:

Snake *snakes[4] = {p1,p2,p3,p4};

I told you, if you need to modify a Snake object, don't use a const reference or pointer. Also, you would have to use &p1, etc... to take the address of the objects in your example code.

 1   2 


Go to: