# Explaining Asteroids Movement code

I'm writing an Asteroids Atari clone, and I want to figure out how the AI for the asteroids is done.

I have came across that piece of code, but I can't get what it does 100%

if ((float)rand()/(float)RAND_MAX < 0.5) {
m_Pos.x = -app::getWindowWidth() / 2;
if ((float)rand()/(float)RAND_MAX < 0.5)
m_Pos.x = app::getWindowWidth() / 2;
m_Pos.y = (int) ((float)rand()/(float)RAND_MAX * app::getWindowWidth());
} else {
m_Pos.x = (int) ((float)rand()/(float)RAND_MAX * app::getWindowWidth());
m_Pos.y = -app::getWindowHeight() / 2;
if (rand() < 0.5)
m_Pos.y = app::getWindowHeight() / 2;
}

m_Vel.x = (float)rand()/(float)RAND_MAX * 2;
if ((float)rand()/(float)RAND_MAX < 0.5)
{
m_Vel.x = -m_Vel.x;
}

m_Vel.y =(float)rand()/(float)RAND_MAX * 2;

if ((float)rand()/(float)RAND_MAX < 0.5)
m_Vel.y = -m_Vel.y;
-
It looks like there's a copy-paste error in the code. is this the exact code? – Jimmy Aug 31 '12 at 19:51
Can you elaborate a bit about what you do and don't understand about the code? – postgoodism Aug 31 '12 at 19:51

This looks like code to spawn a new asteroid at the border of a screen. Here's the outline of the code:

// returns a random float between 0 and 1
float randFloat() { return rand() / (float)RAND_MAX; }

// set position to a random position on the border of the screen.
if (randFloat() < 0.5)  {
// SpawnOnLeftOrRightSide
if (randFloat() < 0.5)
SpawnOnLeft();
else
SpawnOnRight();
}
else {
// SpawnOnTopOrBottomSide
if (randFloat() < 0.5)
SpawnOnTop();
else
SpawnOnBottom();
}
// I fixed what I assume is a copy-paste error here. In the original code, 50% of the time velocity.Y will be unchanged.
velocity.X = randFloat() * 4 - 2; // velocity.X ranges from [-2 to 2)
velocity.Y = randFloat() * 4 - 2; // velocity.Y ranges from [-2 to 2)

The key point to the SpawnOn__ lines is that the coordinate system is 1-to-1 mapped to the X and Y pixels on the screen, but shifted so that (0,0) is at the center of the screen. This means that (in the case we chose to spawn on either the left or right edge of the screen, if m_Pos.X is -screenWidth/2, then the asteroid is on the left edge of the screen, and if m_Pos.X is screenWidth/2 then the asteroid is on the right edge. The Y-position is then chosen to be a random distance on that edge.

-
Center shifted so that (0,0) is in the center makes a lot more sense. I can't imagine that was fully functional code. 50% chance of y not being set and 50% chance of it going negative. Silly code. – Byte56 Aug 31 '12 at 20:10
why we need to check for if(randFloat) two nested times ? – Ahmed Saleh Aug 31 '12 at 20:56
The first time checks for up/down versus left/right edges. Once you know which set of those to go with, you need a second check to see if left or right (or up or down). – fnord Aug 31 '12 at 21:30
@fnord or you could just map 25% of the distribution to each direction; and save yourself the extra randFloat(). Save yourself another randFloat() by simply clamping random coordinates to the nearest edge. – dcousens Sep 1 '12 at 6:40

Well, it's interesting and really bad code. I would not emulate this if that's your intention.

All in all, this code is trying to randomly set the position of m_Pos and randomly setting it's velocity m_Vel. I assume this would be used for spawning asteroids or other enemies. The only relation it has to movement (as you mention in your title) is the velocities set. There's nothing here that updates position based on velocity or anything like that, so I wouldn't call it movement code.

I'll go through the code line by line.

float r = (float)rand()/(float)RAND_MAX;

Is not used in the code you provided. However, the equation (float)rand()/(float)RAND_MAX is used a lot, and you should know that this produces a float between 0 and 1. References rand() and RAND_MAX.

if ((float)rand()/(float)RAND_MAX < 0.5) {
m_Pos.x = -app::getWindowWidth() / 2;

We'll call this case A. If (float)rand()/(float)RAND_MAX is less than .5 set the x position to negative half the window width (off screen I guess?)

if ((float)rand()/(float)RAND_MAX < 0.5)
m_Pos.x = app::getWindowWidth() / 2;

Unless a second take on random is less than .5, then set the x position to the center of the screen.

m_Pos.y = (int) ((float)rand()/(float)RAND_MAX * app::getWindowWidth());

Set the y position to some random position using the window width. Odd.

else {
m_Pos.x = (int) ((float)rand()/(float)RAND_MAX * app::getWindowWidth());
m_Pos.y = -app::getWindowHeight() / 2;
if (rand() < 0.5)
m_Pos.y = app::getWindowHeight() / 2;
}

The else for case A. Set the x position randomly in the width of the window. Then set the y to half way off screen or half way on screen depending on (rand() < 0.5) (Which no longer divides by RAND_MAX like everywhere else, for an unknown reason. Meaning this is unlikely to result in a value less than .5.)

m_Vel.x = (float)rand()/(float)RAND_MAX * 2;

Set the x velocity randomly.

if ((float)rand()/(float)RAND_MAX < 0.5)
{
m_Vel.x = -m_Vel.x;
m_Vel.y =(float)rand()/(float)RAND_MAX * 2;
}

Again, if (float)rand()/(float)RAND_MAX is less than .5, here negate the x velocity you were using before and set the y velocity to some positive random value.

if ((float)rand()/(float)RAND_MAX < 0.5)
m_Vel.y = -m_Vel.y;

Finally, negate the y velocity if our random value is less than .5.

-