Sign in to follow this  

Problems with classes interacting

This topic is 4227 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, im currently writing a space invaders clone using allegro, I can fire and everything however im having trouble getting collisions to work, I currently have a enemy ship member function called isHit which makes the checks... well heres my code... I really need help with this.
#include <allegro.h>
#include <vector>   // To use the vector class
#include <algorithm>    // To use for_each
#include <functional>   // To use mem_fun_ref

#include "siheader.h"
using namespace std;

void init();
void deinit();

int main() {
    
	init();
    vector<Ship> ships;
    vector<bullet> bullets;
   // Create a new ship and add it to the end of the vector
   for (int x=50; x<750; x=x+35) {
       for (int y=20; y<200; y=y+35) {
           ships.push_back( Ship(x, y) );
       }
   } 
   //playervariables
   int player_x=400;
   int player_y=500;
   BITMAP *playerImage;
   playerImage = load_bitmap( "test.bmp", NULL);
   
   BITMAP *backGround;
   backGround = load_bitmap( "back.bmp", NULL); 
   
   


	while (!key[KEY_ESC]) {
		acquire_screen();
		draw_sprite(screen, backGround, 0,0);
		if (key[KEY_RIGHT]) {
           player_x=player_x+4;
        }
		if (key[KEY_LEFT]){
           if (player_x > 0){
              player_x=player_x-4;
           }
        }
		if (key[KEY_SPACE]) {
           bullets.push_back( bullet(player_x, player_y) );
        }
        for (int i = 0; i < ships.size(); i++) {
            ships[i].update();
        }
        for (int i = 0; i < bullets.size(); i++) {
            bullets[i].update();
            bullets[i].isDestroyed();
        }
        for (int i = 0; i < bullets.size(); i++) {
            for (int i = 0; i < ships.size(); i++) {
                ships[i].isHit(bullets[i].returnX);
            }
        }
		//for_each(ships.begin(), ships.end(), mem_fun_ref(&Ship::update));
		//for_each(bullets.begin(), bullets.end(), mem_fun_ref(&bullet::update));
           //bullets.erase(remove_if(bullets.begin(), bullets.end(), mem_fun_ref(&bullet::isDestroyed)), bullets.end());
		rotate_sprite(screen, playerImage, player_x+100, player_y-100, itofix(player_x));
		
		draw_sprite(screen, playerImage, player_x, player_y);
	

        textout_ex(screen, font, "BLAH", 10, 590,makecol(255, 255, 255), -1);
		release_screen();
	}

	deinit();
	return 0;
}
END_OF_MAIN()

void init() {
	int depth, res;
	allegro_init();
	depth = desktop_color_depth();
	if (depth == 0) depth = 32;
	set_color_depth(depth);
	res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);
	if (res != 0) {
		allegro_message(allegro_error);
		exit(-1);
	}

	install_timer();
	install_keyboard();
	install_mouse();
	/* add other initializations here */
}

void deinit() {
	clear_keybuf();
	/* add other deinitializations here */
}

and heres the siheader include...
class Ship {
private:       // We don't want external code to access the coordinates directly
   int x, y;
public:        // We do want external code to be able to call these functions
   // This creates a Ship object with the appropriate coordinates
   Ship(int xpos,int ypos) : 
      x(xpos),  // Sets the ship's x to xpos
      y(ypos)   // Sets the ship's y to ypos

   {
      // No code is currently required here. 
      // Things may change as your class grows.
   }
   void update() { 
     circlefill( screen, x, y, 15, makecol(255,255,255));
     if (mouse_b & 1) {
        y=y+1;
     } 
   } 
   void isHit(bulletX){
        if (bulletX = x){
           exit(-1);
        }
   }  
};

class bullet {
private:       // We don't want external code to access the coordinates directly
   int x, y;
public:        // We do want external code to be able to call these functions
   // This creates a Ship object with the appropriate coordinates
   bullet(int xpos,int ypos) : 
      x(xpos),
      y(ypos) 
   {
      // No code is currently required here. 
      // Things may change as your class grows.
   }
   bool isDestroyed() {
       if (y<-10) {
          return true;
       }
       return false;
   }
   void update() { 
     circlefill( screen, x, y, 15, makecol(255,255,255));
     y=y-5;  
     //if (y<400) {
      //x=0;
      //y=0;
     //}
   }
   int returnX() {
       return x;
   }
};

Is there a better way to do this? Or any way to get it working?

Share this post


Link to post
Share on other sites
Say, in the isHist function:

void isHit(bulletX){
if (bulletX = x){
exit(-1);
}
}

Why = and not == ??
I don't know what the idea behind the function, but if you use = instead of ==
you will always get true and the exit(-1) will be executed.

Share this post


Link to post
Share on other sites
Thanks for the reply, see I had gone a long period of not using C++ and using another language where just one = is valid, but I changed it and im still getting these errors...


Compiler: Default compiler
Building Makefile: "C:\Documents and Settings\Dawn's\Desktop\Brian\Programming\C++\space invaders\Makefile.win"
Executing make...
make.exe -f "C:\Documents and Settings\Dawn's\Desktop\Brian\Programming\C++\space invaders\Makefile.win" all
g++.exe -D__DEBUG__ -c main.cpp -o main.o -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include" -g3

In file included from main.cpp:6:
siheader.h:20: error: variable or field `isHit' declared void
siheader.h:20: error: expected `;' before '(' token
siheader.h:25: error: expected `;' before '}' token

main.cpp: In function `int _mangled_main()':
main.cpp:58: error: 'class Ship' has no member named 'isHit'

make.exe: *** [main.o] Error 1

Execution terminated

Share this post


Link to post
Share on other sites
I dont have allegro installed so I cant debug it, but the line

ships[i].isHit(bullets[i].returnX);

should be

ships[i].isHit(bullets[i].returnX());

and the function

void isHit(bulletX){
...

shoud be

void isHit(int bulletX){
...

Share this post


Link to post
Share on other sites
Ok now I have a new problem, in order to remove a vector element I need to cycle through them with iterators, I can iterate just fine to draw the bullets, and when I incorporated deleting after they got past a certain Y value I find that the program crashes when the last bullet is about to be deleted... this is hard to explane but heres the code thats causing the trouble (probably, as there are no error messages).



for (bulletIter = bullets.begin(); bulletIter != bullets.end(); ++bulletIter) {
bulletIter->update();
if (bulletIter->isDestroyed()) {
bullets.erase(bulletIter);
}
}



and heres the member function isDestroyed...


bool isDestroyed() {
if (y<110) {
return true;
}
return false;
}

Share this post


Link to post
Share on other sites
Erasing an iterator invalidates that iterator, which means you cannot use it again.

However, std::vector::erase returns a brand new iterator which is valid and is pointing to the element next to the one you just erased.



for (bulletIter = bullets.begin(); bulletIter != bullets.end(); ++bulletIter) {
bulletIter->update();
if (bulletIter->isDestroyed()) {
bulletIter = bullets.erase(bulletIter);
}
}


Share this post


Link to post
Share on other sites
You can make sure you dont erase anything from an already empty vector

if(bullets.size())
for (bulletIter = bullets.begin(); bulletIter != bullets.end(); ++bulletIter) {
bulletIter->update();
if (bulletIter->isDestroyed()) {
bullets.erase(bulletIter);
}
}


If you try to erase from an empty vector the program seems to crash

edit:
rip-off's method might be slicker though

Share this post


Link to post
Share on other sites
Quote:
Original post by pulpfist
You can make sure you dont erase anything from an already empty vector

if(bullets.size())
for (bulletIter = bullets.begin(); bulletIter != bullets.end(); ++bulletIter) {
bulletIter->update();
if (bulletIter->isDestroyed()) {
bullets.erase(bulletIter);
}
}


If you try to erase from an empty vector the program seems to crash


The original code will not "erase from an empty vector", as the condition "bulletIter != bullets.end()" would make it break the loop before the first iteration.

Share this post


Link to post
Share on other sites
Quote:

However, std::vector::erase returns a brand new iterator which is valid and is pointing to the element next to the one you just erased.

With the for loop at hand, wouldnt the iterator make two steps each cycle?

One when the iterator is assigned the the return value of erase and another when the loop update it with ++

Share this post


Link to post
Share on other sites
Don't do the looping yourself. Instead, make use of the "erase-remove idiom", combining two 'algorithms' from the standard library. I was going to give code showing how, but you already seem to have some commented out in your original sample. Was it not working for you? What seems to be the problem with it?

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Don't do the looping yourself. Instead, make use of the "erase-remove idiom", combining two 'algorithms' from the standard library. I was going to give code showing how, but you already seem to have some commented out in your original sample. Was it not working for you? What seems to be the problem with it?



Yes it was working, but the way im used to programming is that I run through all the iterations of one object type or class is that I delcare my forloop then do everything within that, im not sure, it just seems odd and unorganized to me to do it that way... unless of course there is a way to do that... but I guess ill just put that back in the code and use that way till later so for now I can work on collisions...

And ive hit another problem... basically just for testing purposes im only checking detection on the X axis, and the coordinates have to be exact... but this bit of code is causing problems...


for (bulletIter = bullets.begin(); bulletIter != bullets.end(); ++bulletIter) {
for (shipIter = ships.begin(); shipIter != ships.end(); ++shipIter) {
if (shipIter->isHit(bulletIter->returnX())) {
bullets.erase(bulletIter);
ships.erase(shipIter);
}
}
}




This doesnt cause errors, it causes the program to crash, but if I comment out this line bullets.erase(bulletIter); it works just fine... the same thing happens if I destroy the last ship that was created, and its the same problem I had above, just wondering if I have to use this to remove it... bullets.erase(remove_if(bullets.begin(), bullets.end(), mem_fun_ref(&bullet::isDestroyed)), bullets.end());

Also when working with iterators was I correct to declare one for ships and bullets? Is there a better way to do this?

[Edited by - evilsanta on May 22, 2006 3:04:49 PM]

Share this post


Link to post
Share on other sites
If you're going to do the looping yourself, it should be something like:


for (iter_bullet=bullets.begin();iter_bullet!=bullets.end();)
{
if (iter_bullet->ShouldBeRemoved()) iter_bullet=bullets.erase(iter_bullet);
else ++iter_bullet;
}




And no offence, but DesignerX corrected your mispelling from "==" to "=", and 9 minutes later you return with a list of compiler errors. Don't you think you should at least spend some time debugging yourself instead of instatenously posting "OMG I have errors fix please"?

[Edited by - mikeman on May 22, 2006 4:25:11 PM]

Share this post


Link to post
Share on other sites
Apologies, sometimes I can just get so frustrated that I give up and ask for people to "give me da codz" but I couldnt get your loop code to work so I just went with the built in one and changed my code around a bit... and it works fine now so thanks everyone, but just wondering if there is anything ineficient about my code as it just doesnt feel right to me, do I have to declare one iterator for every vector? and I think my class member functions may be a bit much...

Im just wondering if my code is repetative at all, if you dont want to look over my code and tell me noob mistakes dont worry about it... I just dont want to learn the wrong way to do something as I had a major incident with that the first language I learned...


#include <allegro.h>
#include <vector> // To use the vector class
#include <algorithm> // To use for_each
#include <functional> // To use mem_fun_ref

#include "siheader.h"
using namespace std;

void init();
void deinit();

int main() {

init();
vector<Ship> ships;
vector<bullet> bullets;
// Create a new ship and add it to the end of the vector
for (int x=50; x<750; x=x+35) {
for (int y=20; y<200; y=y+35) {
ships.push_back( Ship(x, y) );
}
}
vector<Ship>::iterator shipIter;
vector<bullet>::iterator bulletIter;
//playervariables
int player_x=400;
int player_y=500;
BITMAP *playerImage;
playerImage = load_bitmap( "test.bmp", NULL);

BITMAP *backGround;
backGround = load_bitmap( "back.bmp", NULL);




while (!key[KEY_ESC]) {
acquire_screen();
draw_sprite(screen, backGround, 0,0);
if (key[KEY_RIGHT]) {
player_x=player_x+4;
}
if (key[KEY_LEFT]){
if (player_x > 0){
player_x=player_x-4;
}
}
if (key[KEY_SPACE]) {
bullets.push_back( bullet(player_x, player_y) );
}
for (shipIter = ships.begin(); shipIter != ships.end();shipIter++) {
shipIter->update();
}
for (int i = 0; i < bullets.size(); i++) {
bullets[i].update();
}
for (bulletIter = bullets.begin(); bulletIter != bullets.end(); ++bulletIter) {
for (shipIter = ships.begin(); shipIter != ships.end(); ++shipIter) {
if (shipIter->isHit(bulletIter->returnX(),bulletIter->returnY())) {
bulletIter->setDestroyed();
shipIter->setDestroyed();
}
}
}
bullets.erase(remove_if(bullets.begin(), bullets.end(), mem_fun_ref(&bullet::isDestroyed)), bullets.end());
ships.erase(remove_if(ships.begin(), ships.end(), mem_fun_ref(&Ship::isDestroyed)), ships.end());
rotate_sprite(screen, playerImage, player_x+100, player_y-100, itofix(player_x));

draw_sprite(screen, playerImage, player_x, player_y);



release_screen();
}

deinit();
return 0;
}
END_OF_MAIN()

void init() {
int depth, res;
allegro_init();
depth = desktop_color_depth();
if (depth == 0) depth = 32;
set_color_depth(depth);
res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0);
if (res != 0) {
allegro_message(allegro_error);
exit(-1);
}

install_timer();
install_keyboard();
install_mouse();
/* add other initializations here */
}

void deinit() {
clear_keybuf();
/* add other deinitializations here */
}



and the header...


class Ship {
private: // We don't want external code to access the coordinates directly
int x, y;
bool destroy;
public: // We do want external code to be able to call these functions
// This creates a Ship object with the appropriate coordinates
Ship(int xpos,int ypos) :
x(xpos), // Sets the ship's x to xpos
y(ypos) // Sets the ship's y to ypos

{
// No code is currently required here.
// Things may change as your class grows.
}
void update() {
circlefill( screen, x, y, 15, makecol(255,255,255));
if (mouse_b & 1) {
y=y+1;
}
}
bool isHit(int bulletX, int bulletY) {
if (bulletX < x + 25){
if (bulletX > x - 25) {
if (bulletY == y+10) {
return true;
}
}
}
return false;
}
int returnX() {
return x;
}
int returnY() {
return y;
}
void setDestroyed() {
destroy = true;
}
bool isDestroyed() {
if (destroy == true) {
return true;
}
return false;
}
};

class bullet {
private: // We don't want external code to access the coordinates directly
int x, y;
bool destroy;
public: // We do want external code to be able to call these functions
// This creates a Ship object with the appropriate coordinates
bullet(int xpos,int ypos) :
x(xpos),
y(ypos)
{
// No code is currently required here.
// Things may change as your class grows.
}

void update() {
circlefill( screen, x, y, 15, makecol(255,255,255));
y=y-5;
if (y<40) {
destroy = true;
}
}
int returnX() {
return x;
}
int returnY() {
return y;
}
void setDestroyed() {
destroy = true;
}
bool isDestroyed() {
if (destroy == true) {
return true;
}
return false;
}
};



As I said, something just feels wierd with my code...

Share this post


Link to post
Share on other sites
Quote:

...but I couldnt get your loop code to work...


Sorry, I mispelled the name of the iterator two times(one as "iter" and one as "bullet_iter"). But that errors would be easy to correct. Please don't tell me you went ahead and copy/pasted my code as is, with the "ShouldBeRemoved()" dummy and everything!

Share this post


Link to post
Share on other sites
Quote:
Original post by mikeman
Quote:

...but I couldnt get your loop code to work...


Sorry, I mispelled the name of the iterator two times(one as "iter" and one as "bullet_iter"). But that errors would be easy to correct. Please don't tell me you went ahead and copy/pasted my code as is, with the "ShouldBeRemoved()" dummy and everything!


Of course not. I put the code in changed the variables, and yes I did notice your mispelling but I changed it, I didnt get any errors but the program crashed on runtime.

Share this post


Link to post
Share on other sites

This topic is 4227 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this