asteroids game, wrap around screen edges problem
scorpx333

Hi to all, i am making an asteroid clone game and i am stuck at wrap around screen edges function, without it everything is fine, when i hit the asteroid it breaks into 3 smaller asteroids, and so on. but they off screen. so in order to wrap them around the screen i had made this function in asteroid class (function is at the end of code part called AsteroidVsScreen())

1#include "asteroid.h" 2#include <allegro5\allegro.h> 3#include <allegro5\allegro_image.h> 4#include <allegro5\allegro_font.h> 5#include <allegro5\allegro_ttf.h> 6#include <allegro5\allegro_primitives.h> 7#include <allegro5\allegro_native_dialog.h> 8#include <math.h> 9 10 11 12asteroid::asteroid() 13{ 14dead = false; 15asteroidSize = 3; 16 Width=900; 17 Height=600; 18 19 20 21xspeed= rand() % 5 - 3; 22yspeed= rand() % 5 - 3; 23 24xposition = rand() % (Width - 100); 25yposition = rand() % (Height - 100); 26if (xposition > Width/2 - 200 && xposition < Width/2 + 200 && yposition > Height/2 -200 && yposition < Height + 200) 27{ 28xposition = 1; 29yposition = 1; 30} 31 32Ast_angl=0; 33 34} 35 36 37 38 39asteroid::asteroid(int size, int x, int y) 40{ 41asteroidSize = size; 42 43 44if (xposition > Width/2 - 200 && xposition < Width/2 + 200 && yposition > Height/2 -200 && yposition < Height + 200) 45{ 46xposition = 33; 47yposition = 33; 48} 49 50dead = false; 51 52xspeed= rand() % 5 - 3; 53yspeed= rand() % 5 - 3; 54if (xspeed == 0 && yspeed == 0) 55{ 56xspeed= (rand() % 8 - 5)/2; 57yspeed= (rand() % 8 - 5)/2; 58} 59xposition = x; 60yposition = y; 61 62 63Ast_angl=0; 64} 65 66 67 68void asteroid::refreshAsteroid(ALLEGRO_BITMAP *Asteroid,ALLEGRO_FONT *font24) 69{ 70 71 72if (dead==true) return; 73 74 75 76Ast_angl+=0.03; 77 xposition = xposition + xspeed; 78 yposition = yposition + yspeed; 79 80 //al_draw_textf(font24, al_map_rgb(255,0,0), 200,200,0, " %i",Ast_angl); 81 82 83if (asteroidSize == 3) 84{ 85 al_draw_scaled_rotated_bitmap(Asteroid,50,50,xposition,yposition,1,1,Ast_angl,0); 86 //al_draw_rectangle(xposition-25,yposition-25,xposition+25,yposition+25,al_map_rgb(255,0,0),3); 87} 88if (asteroidSize == 2) 89{ 90 al_draw_scaled_rotated_bitmap(Asteroid,50,50,xposition,yposition,0.5,0.5,Ast_angl,0); 91 //al_draw_rectangle(xposition-12,yposition-12,xposition+12,yposition+12,al_map_rgb(255,0,0),3); 92} 93if (asteroidSize == 1) 94{ 95 al_draw_scaled_rotated_bitmap(Asteroid,50,50,xposition,yposition,0.25,0.25,Ast_angl,0); 96 //al_draw_rectangle(xposition-6,yposition-6,xposition+6,yposition+6,al_map_rgb(255,0,0),3); 97 98} 99if (asteroidSize == 0) 100{ 101dead = true; 102return; 103} 104} 105 106void asteroid::AsteroidVsScreen()// al my game problems are here!!!!!!!!! 107{ 108 109 if (dead == true) return; 110 111if(xposition > Width) 112{ 113xposition=0; 114} 115 116else if(xposition < 0) 117{ 118xposition = Width; 119} 120 121if(yposition > Height) 122{ 123yposition =0; 124} 125 126else if(yposition < 0) 127{ 128yposition = Height; 129} 130 131 132 133} 134 135 136int asteroid::getAsteroidXPosition() 137{ 138return xposition; 139} 140int asteroid::getAsteroidYPosition() 141{ 142return yposition; 143} 144 145 146int asteroid::getAsteroidSize() 147{ 148return asteroidSize; 149} 150 151 152void asteroid::setAsteroidDead() 153{ 154dead = true; 155} 156 157asteroid::~asteroid() 158{ 159}

and now for the part in main where i call this function

1 2list<asteroid>::iterator iter; 3list<bullet>::iterator bulliter; 4 5iter = AsteroidList.begin(); 6 7while(iter != AsteroidList.end()) 8{ 9 10 asteroid& s = *iter; 11 //s.AsteroidVsScreen();// the problematic function (gives 0 0 ) 12 13 14 15 if (s.getAsteroidSize() == 3) { TempAsteroidSize = 25; } 16 if (s.getAsteroidSize() == 2) { TempAsteroidSize = 12; } 17 if (s.getAsteroidSize() == 1) { TempAsteroidSize = 6; } 18 19 20 bulliter = BulletList.begin(); 21while(bulliter != BulletList.end()) 22{ 23 bullet& bull = *bulliter; 24 25 26 if (bull.getBulletXPosition() > s.getAsteroidXPosition()-TempAsteroidSize && 27 bull.getBulletXPosition() < s.getAsteroidXPosition() + TempAsteroidSize && 28 bull.getBulletYPosition() > s.getAsteroidYPosition() -TempAsteroidSize&& 29 bull.getBulletYPosition() < s.getAsteroidYPosition() + TempAsteroidSize) 30 { 31 tempSize = s.getAsteroidSize() - 1; 32 tempx = s.getAsteroidXPosition(); 33 tempy = s.getAsteroidYPosition(); 34 35 s.~asteroid(); 36 37 38 39 iter = AsteroidList.erase(iter);//if colision asteroid is errased 40 bulliter = BulletList.erase(bulliter); 41 collision=true;// withaut this the iter++ will make an error 42 if (tempSize > 0){ 43 44AsteroidList.push_back(*new asteroid(tempSize, tempx+(n+1)*10, tempy+(n+1)*10)); 45AsteroidList.push_back(*new asteroid(tempSize, tempx, tempy)); 46AsteroidList.push_back(*new asteroid(tempSize, tempx-(n+1)*10, tempy-(n+1)*10)); 47 48 } 49 50 } 51 else{bulliter++;} 52 53} 54if (!collision){iter++;} 55if (collision){collision=false; score+=1;} // the iter error solved 56 57}// while asteroids

then the part of the code that refreshes asteroids on the screen

```iter = AsteroidList.begin();
while(iter != AsteroidList.end())
{

// Retrieve the asteroid that the iterator points at
asteroid& s = *iter;
s.refreshAsteroid(Asteroid,font24);

iter ++;

}
```

Any suggestions would be great

Edgar Reynaldo

Your first problem is mixing drawing with logic. You should not both alter position and draw in the same function. Split your functions apart and keep any logic separate from any drawing.

Ideally, your loop should look like this :

```while (!game.Quit()) {
game.CheckInputs();
game.Update(time_passed);
game.Display();
}
```

You have input logic, update logic, and drawing all separated out.

Update logic checks for collisions, and marks asteroids and bullets as dead, and updates their positions, as well as the position of the player. Drawing just draws, based on the state of the game. Input logic affects turn rate and acceleration, or angle and velocity of the player, or anything else controlled by the user.

Your update function should probably look something like this (pseudocode) :

1void Game::Update(double dt) { 2 3 for each asteroid a {a.Update(dt);} 4 for each bullet b {b.Update(dt);} 5 player.Update(dt); 6 7 for each asteroid a { 8 for each bullet b { 9 if (overlaps(b.circle , a.circle)) { 10 a.destroy();// This doesn't always delete the asteroid, 11 // but takes care of creating new sub asteroids if necessary 12 b.destroy(); 13 } 14 } 15 if (overlaps(player.circle , a.circle)) { 16 player.GotHit(); 17 } 18 } 19 20}

scorpx333

Thank you Edgar Reynaldo, but maybe you know how could i complete this game with such code structure: logic and drawing together? or this is impossible? I need only to solve the combination of: asteroids being on the screen and breaking into smaller asteroid, problem. So i'll have an alpha version of this game working
(i'll rewrite all the code with right functions positions afterwards for beta + other)

Thomas Fjellstrom

It's not impossible, but it can make things harder. It's certainly messier.

Edgar Reynaldo
scorpx333 said:

Thank you Edgar Reynaldo, but maybe you know how could i complete this game with such code structure: logic and drawing together?

I'll just let you know, you're doing it The Hard WayTM. If you separate everything out, it will be much easier to code. I even gave you an example of what your Update function would look like. I don't want to set a bad example by helping you do it the wrong way.

scorpx333

Ok, but wait a sec, look at code again if i put line 76-78 from asteroid class function asteroid::refreshAsteroid()
into asteroid function asteroid::AsteroidVsScreen()
it will separate drawing from logic because in main I call AsteroidVsScreen()(that will make logic) in line 11 in one loop.

And I call s.refreshAsteroid(Asteroid,font24) (that makes drawing) in other loop

but still it doesn't work. Or i don't understand the separation thing?

Edgar Reynaldo
scorpx333 said:

Ok, but wait a sec, look at code again if i put line 76-78 from asteroid class function asteroid::refreshAsteroid()
into asteroid function asteroid::AsteroidVsScreen()
it will separate drawing from logic because in main I call AsteroidVsScreen()(that will make logic) in line 11 in one loop.

Yes, that would help. If you do that, you should change the name of the function to reflect that it updates the state of the asteroid, and doesn't just fix the screen position.

Quote:

but still it doesn't work.

Be specific - what do you expect it to do, and what is happening instead?

scorpx333

I expect that asteroid::refreshAsteroid() function would work normally on new created 3 asteroids after the big one is destroyed,(it works on big one) but instead 3 asteroids get the needed size, but their positions (x and y ) becomes (0,0) and they don't move, if i don't use asteroid::refreshAsteroid() part:
if(xposition > Width)
112{
113xposition=0;
114}
115
116else if(xposition < 0)
117{
118xposition = Width;
119}
120
121if(yposition > Height)
122{
123yposition =0;
124}
125
126else if(yposition < 0)
127{
128yposition = Height;
129}
130

it works, but my asteroids need to be on screen if not destructed with a bullet or ship

Edgar Reynaldo
scorpx333 said:

if (tempSize > 0){
AsteroidList.push_back(*new asteroid(tempSize, tempx+(n+1)*10, tempy+(n+1)*10));
AsteroidList.push_back(*new asteroid(tempSize, tempx, tempy));
AsteroidList.push_back(*new asteroid(tempSize, tempx-(n+1)*10, tempy-(n+1)*10));
}

What is the value of n? Also, you are adding the data pointed to by a new asteroid. That means you leak the address (and memory) of the asteroid you just created. Don't use *new, just use the asteroid constructor.

scorpx333 said:

their positions (x and y ) becomes (0,0) and they don't move,

Then you are setting their position and velocity to zero somewhere else, because the constructor takes the position values you passed to it, and their velocity shouldn't be changing either.

Use your IDE's find function, and look at all the instances of the position and velocity variables, and figure out which lines are changing the values. Because AsteroidVsScreen doesn't change the velocity, and it only changes the position if they go off screen.

scorpx333

the n is 0, it doesn't do anything(forgot to rewrite that).

after experimenting a bit i found out that AsteroidVsScreen only adds speed 1 time to new smaller asteroids, constructor gets position but somehow AsteroidVsScreen gets that x and y isn't on screen and makes them 0 0 then adds x=0+speed and stops, but why it stops, why AsteroidVsScreen only goes for 1 time for the new asteroid.

Edgar Reynaldo

Well, I can't guess what is wrong anymore. I need to see all of your code together if you want me to figure out what is wrong. Post a zip file of all your source code and I will take a look at it.

scorpx333

Edgar Reynaldo, here is my zip file, if you could check it, that would be really helpful, and thank you for your time spent on my game problem

Edgar Reynaldo

There's no attachment...

scorpx333

sorry for that i am trying to find a way to post it, ok now it should be working, do you need full game file or this source?

Edgar Reynaldo

Edit your post and look in the bottom right of the screen for 'attachments for use with substandard browsers', or use Firefox or Chrome to upload your attachment.

Edit
Well, first off, you need to fix your formatting. Use consistent indentation with the same number of spaces per level everywhere, or use tabs exclusively.

I found the problem. It is in your constructor. Your default constructor sets values for Width and Height, but your Asteroid::Asteroid(int,int,int) constructor does not. This means they are probably 0, but are really uninitialized. That is why if (xposition > Width) {xposition = 0;} always sets the value to 0.

scorpx333

THANK YOU EDGAR Reynaldo!!!!!!!!
YOU WHERE RIGHT it works now, how could i be so blind and don't see this mistake
i've add height and width to constructor and everything works!!!!!!!!

Edgar Reynaldo

To prevent this problem in the future, google for 'initialization list', and then always write one in your constructors that initializes every member variable to a set value.