0
\$\begingroup\$

I'm currently making space invaders (in OpenGL/SDL) and I'm running into an issue with the movement of the aliens. I have a 2-d vector of aliens (5 rows of 11) and I'm translating each in the x direction by a constant factor times elapsed time. If the right or leftmost alien in the vector hits either side of the screen, I decrement the y position of every alien. For some reason, when it collides the side of the screen, it infinitely translates downward in the y direction.

I thought that this would not happen since I wasn't multiplying the y position by elapsed time, but I think that its probably happening due to the fact that the update() method is being called once per frame. Here is the code for the update function (inside of the enemies class which holds the 2-d array):

void update(float elapsed) {
        //Update positions

        float minX = -5.2;
        float maxX = 5.2;

        bool hitRight = false;
        bool hitLeft = false;

        //if the enemies haven't hit the right side
        if (((enemyVect[0][rightmost]->x) + ((enemyVect[0][rightmost]->width) / 2.0) <= maxX)) {
            for (int i = 0; i < enemyVect.size(); i++) {
                for (int j = 0; j < enemyVect[i].size(); j++) {
                    enemyVect[i][j]->x += elapsed * 0.4 * xDirect;

                }
            }

        }
        //if they've hit the right side
        else if(((enemyVect[0][rightmost]->x) + ((enemyVect[0][rightmost]->width) / 2.0) >= maxX)){
            xDirect = -1;
            hitRight = true;
            for (int i = 0; i < enemyVect.size(); i++) {
                for (int j = 0; j < enemyVect[i].size(); j++) {
                    if(hitRight)enemyVect[i][j]->y -= 0.6; //move each row of enemyVect down to the next level
                }
            }
            hitRight = false;
        }
//if the enemies haven't hit the left side
        if (((enemyVect[0][leftmost]->x) -((enemyVect[0][leftmost]->width) / 2.0) >= minX)) {
            for (int i = 0; i < enemyVect.size(); i++) {
                for (int j = 0; j < enemyVect[i].size(); j++) {
                    enemyVect[i][j]->x += elapsed * 0.4 * xDirect;
                }
            }

        }
//if they've hit the left side
            else if (((enemyVect[0][leftmost]->x) - (enemyVect[0][leftmost]->width / 2.0) <= minX)) {
                xDirect = 1;
                for (int i = 0; i < enemyVect.size(); i++) {
                    for (int j = 0; j < enemyVect[i].size(); j++) {
                        enemyVect[i][j]->y -= 0.6; //move each row of enemyVect down to the next level
                    }
                }
            }           
        }

    };

How should I go about making it so that the y position of each alien only gets decremented once right after the collision with either side of the screen?

\$\endgroup\$
1
\$\begingroup\$

After your rightmost enemy hits the right wall you've got to move the whole row back to the left before the end of your update function. As you have it now, the first if statement always fails after you hit a wall because the aliens are in the same place so the first else if runs moving your enemies down.

\$\endgroup\$
  • \$\begingroup\$ So then in the first else if I should start moving the aliens backwards right after the y position is decremented? Or how should I change the code? \$\endgroup\$ – loremIpsum1771 Mar 7 '16 at 6:10
  • 1
    \$\begingroup\$ That would work. You could even put it in the existing code. enemyVect[i][j]->y -= 0.6; enemyVect[i][j]->x -= 1.0; or whatever x value works for your code. Of course you'll have to do the same thing for the left wall as well. \$\endgroup\$ – Mike G Mar 7 '16 at 6:53
1
\$\begingroup\$
//if the enemies haven't hit the right side
//except you've said to do this, even if they *have* -------------------------v
if (((enemyVect[0][rightmost]->x) + ((enemyVect[0][rightmost]->width) / 2.0) <= maxX))
{
   ... //Move them all xDirect
}
//if they've hit the right side
//'=' case has already been handled this frame and has moved all
//of the enemies past the edge instead of doing this -----------------------------v
else if(((enemyVect[0][rightmost]->x) + ((enemyVect[0][rightmost]->width) / 2.0) >= maxX))
{
   ... //Move down; reverse
}

I suspect that adding only the outer-most if and else suggested below would "fix it", but I've also cleaned up and optimized a bit:

//Breakpoint 2
if (xDirect == 1) //optimize: only while moving right
{
  //if the enemies haven't hit the right side
  float rightX = (enemyVect[0][rightmost]->x) + ((enemyVect[0][rightmost]->width) / 2.0);
  if (rightX < maxX)
  {
    //optimize: calculate delta-x only once
    //don't move further than the distance to the edge
    float delta = fminf(maxX - rightX, (elapsed * 0.4 * xDirect));
    for (int i = 0; i < enemyVect.size(); i++)
      for (int j = 0; j < enemyVect[i].size(); j++)
         enemyVect[i][j]->x += delta;
  }
  //otherwise (if they've hit the right side)
  else // >=
  {
     ... //Move down; reverse
     //Breakpoint 1///////////////////
     xDirect = -1;
  }
}
else //only while moving left
{
  ...
}
\$\endgroup\$
  • \$\begingroup\$ Sorry for the late response, I've been extremely busy! I tried the code ( and I applied the same logic for the collision with the left side of the screen) but for some reason, I seem to be having the same problem as before. I think the MikeG was right in saying that I need to move the aliens back to the left during the collision, but the only way I can think to do that is to add another two loops nest in the if statement for if the right side has been hit. Is there a better way to implement this? \$\endgroup\$ – loremIpsum1771 Mar 10 '16 at 5:55
  • \$\begingroup\$ @loremIpsum1771, I agree that you are moving them past the edge so you'll either need to move them back, or just don't move them past the edge in the first place and I went with the latter. The structure of the flow-control should have shortcut out, but I don't have the project to step through. \$\endgroup\$ – Jon Mar 10 '16 at 16:07
  • 1
    \$\begingroup\$ @loremIpsum1771, I revised the code. Add only "breakpoint 1" and, once it fires, add "breakpoint 2" and verify the value of xDirect. It should be -1 and fall-through to the else. Add a third breakpoint where xDirect reverses the second time and inspect the conditions that are making it fire. \$\endgroup\$ – Jon Mar 10 '16 at 16:10
  • \$\begingroup\$ If you're curious, check my answer at the bottom. \$\endgroup\$ – loremIpsum1771 Mar 16 '16 at 18:57
1
\$\begingroup\$

The problem is you are not modifying the position of your aliens when they are hitting a side, consider the following pseudo code.

if (not hitting right)
  move right
else if (hitting right)
  move down
  change direction

Now the problem is that once the aliens hit the right side they are never not hitting it. That is to say the position of the right most alien (or left most) looks something like this.

(1, 0), (2, 0), (3, 0), (4, 0), (4, 1), (4, 2), ... (4, \infty)

There are a number of ways to resolve this issue, one is as follows.

if (not hitting right)
  move right
else if (hitting right)
 move down and left
 change direction

Now your aliens can break the condition that changes their y direction.

It might be easier to modify your code such that your if statements modify a vector that is applied to all aliens, this may look something as follows.

v = <-1, 0> // global, start right, move left

if (hit left)
  v = <1, 1>
else if (hit right)
  v = <-1, 1>

foreach(alien in aliens)
  alien.position += v

v.y = 0

Now you have reduced branching, code size, and complexity making your life easier.

\$\endgroup\$
  • \$\begingroup\$ If you're curious, check my answer at the bottom. \$\endgroup\$ – loremIpsum1771 Mar 16 '16 at 18:57
0
\$\begingroup\$

For anyone that's interested, this is the code that I got to work for moving the enemies:

//move the enemies
    for (int i = 0; i < entities.size(); i++) {
        entities[i]->x += elapsed * 4.3 * entities[i]->xDirection;
        if (entities[i]->x >= maxX || entities[i]->x <= minX) {

            for (int k = 0; k < entities.size(); k++) {
                entities[k]->xDirection *= -1;
            }
            for (int j = 0; j < entities.size(); j++) {
                entities[j]->y -= 0.02;
            }
        }
    }

I ended up putting the enemies in a vector of entities instead of using a 2d vector which made the code a little less verbose.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.