1
\$\begingroup\$

I have a code where I randomly generate enemy spawn position, but I want to exclude some areas since it's colliding with some sprites it shouldn't collide with.

This is the code where I generate the random points from where the enemy is coming from (from top,down, left and right):

int z = ran.nextInt(4);
int r1 = ran.nextInt(GameControl.CAMARA_WIDTH+1);
int r2 = ran.nextInt(GameControl.CAMARA_WIDTH+ 1);
int r3 = ran.nextInt(GameControl.CAMARA_HEIGHT+ 1);
int r4 = ran.nextInt(ControlJuego.CAMARA_HEIGHT+ 1);

I set the position of the enemy with the random variable:

if (var == 1) {
   newEnemy.getSpriteEnemy().setPosition(0, r1);
} else if (var == 2) {
   newEnemy.getSpriteEnemy().setPosition(GameControl.CAMARA_WIDTH, r2);
} else if (var == 3) {
   newEnemy.getSpriteEnemy().setPosition(r3, 0);
} else if (var == 4) {
   newEnemy.getSpriteEnemy().setPosition(r4, GameControl.CAMARA_HEIGHT);
 }

Later I move the enemies to the center of the screen.

An image for better vistualizatio of the problem:

Game

I don't want my enemies to ever spawn behind any of the corner sprites or to collide with any of the corner sprites before entering the screen. How can I solve this problem? How can I exclude this areas?

Thanks in advance for the help.

\$\endgroup\$
6
  • \$\begingroup\$ either you know how to create a function that you can use to shape the distribution. or you test for collision and discard + retry. (russian roulette) \$\endgroup\$
    – v.oddou
    Commented Nov 20, 2015 at 0:48
  • \$\begingroup\$ Principe: while(pos1.Intersects(pos2)) generateRandomPos(pos1); \$\endgroup\$ Commented Nov 20, 2015 at 0:51
  • \$\begingroup\$ @v.oddou I was thinking of discarding enemies that collisioned outside the screen, but I would be loosing some enemies so i would have a lower frequency of enemies on screen than I would want. But I think I could still implement the method for extra safety. \$\endgroup\$
    – OrangeHat
    Commented Nov 20, 2015 at 1:23
  • \$\begingroup\$ you don't have a lower frequency if you loop "while not success" for each spawn. the frequency control should be at a higher level. (in the function calling "rand enemy spawn") \$\endgroup\$
    – v.oddou
    Commented Nov 20, 2015 at 2:57
  • \$\begingroup\$ @v.oddou How can I detect collisions out of the screen/before entering the screen though? \$\endgroup\$
    – OrangeHat
    Commented Nov 22, 2015 at 2:48

2 Answers 2

3
\$\begingroup\$

If your corner sprites are as simple as you show here, you can avoid collisions by changing how you generate the random positions.

E.g. for the top, you currently generate a random int between 0 and width (well, ignoring that you seem to have transposed width and height in some spots). So suppose you have yellowWidth, the width of the yellow object at the top border, and greenWidth, the width of the green object similarly.

So the space between yellow and green is width - (yellowWidth + greenWidth). If you generate your top value with ran.nextInt((GameControl.CAMARA_WIDTH + 1) - (yellowWidth + greenWidth)); and add yellowWidth, it should fall between the two.

Given that your enemies aren't points but areas, you'll need to add a buffer to the sizes of yellowWidth and greenWidth. E.g. if you have enemyWidth, the final calculation would be something like:

int r1 = yellowWidth + enemyWidth/2 + ran.nextInt((GameControl.CAMARA_WIDTH + 1) - (yellowWidth + greenWidth + enemyWidth));

Just do the same with the other sides, switching to height and other-colored sprites as needed.

\$\endgroup\$
4
  • \$\begingroup\$ I tried your method (only changing the value of random values) and it didn't work. I still have enemies coming from the corners. \$\endgroup\$
    – OrangeHat
    Commented Nov 20, 2015 at 2:53
  • \$\begingroup\$ Might be because you've got height and width flipped for some spawn positions. r1 and r2 should use CAMERA_HEIGHT, r3 and r4 should use _WIDTH, assuming setPosition is (x, y). \$\endgroup\$ Commented Nov 20, 2015 at 7:05
  • \$\begingroup\$ Still not working. \$\endgroup\$
    – OrangeHat
    Commented Nov 21, 2015 at 22:58
  • \$\begingroup\$ Sorry it's not working, but comments aren't the right place to try and remote debug something. If you want more help you can create a chat room and invite me, I'll see what I can do. \$\endgroup\$ Commented Nov 22, 2015 at 5:52
1
\$\begingroup\$

Chris is right about the first method (distribution shaping).

Now the second (roulette): that's the method I implemented in my game.
full source here: http://sourceforge.net/projects/extremecarnage

bool HostilesManager::SpawnHostile(SPAWN_POSITION_en spawnPos, int isprite)
{
    // create a new car
    CarsManager::CarAcsor newcar = ChiefManager::GetCarsManager()->Push(spriteFiles[isprite]);
    hostiles.push_front(newcar);
    // *hostiles.front().pcar and *newcar are aliases
    const int bordw = ChiefManager::GetTerrainManager()->GetBorderWidth();
    const Vector2i terrSize = ChiefManager::GetTerrainManager()->GetSize();

    // spawn ennemys on the far right position only
    if (spawnPos == SP_LEVEL_RIGHT)
    {
        // random vertically, but 500 pixel from the left-end
        newcar->SetPosition(terrSize.x + 500,
                            bordw +
                            rnd.Get(terrSize.y - bordw * 2));
    }
    else // MIDDLE
    {
        Rect rc(newcar->rect);

        // same tech than the terrain generator
        int security = 0;
        bool intersect = true;
        const int max_repeats = terrSize.x / rc.w + terrSize.y / rc.h;   // fast heuristic
        while (intersect && security < max_repeats) // util it fits
        {
            // random generation here
            rc.pos.x = bordw + 50 + rnd.Get(terrSize.x - rc.w - (bordw << 1));
            rc.pos.y = bordw + rnd.Get(terrSize.y - rc.h - (bordw << 1));
            // verify intersection with decors objects:
            intersect = ChiefManager::GetCollisionsAndProbing()->IntersectRect(rc);
            ++security;
        }
        if (security == max_repeats)    // that didnt work
        {
            hostiles.pop_front();
            return false;
        }
        newcar->SetPosition(rc.pos.x,
                            rc.pos.y);
    }
    // set the target
    hostiles.front().target.x = 0;
    hostiles.front().target.y = 64 + rnd.Get(terrSize.y - 128);
    // random start direction :
    newcar->angle = rnd.Get(359);

    newcar->GiveWeapon(game_vars::g_minigun_id);
    newcar->SetIAClass(iaClassID_simple, ChiefManager::GetIAManager());
    BOOST_ASSERT(newcar->GetIAClassID() == iaClassID_simple);

    if (isprite > 0)    // that's for stronger ennemies
    {
        newcar->health = 200;
        newcar->SetIAClass(iaClassID_strong, ChiefManager::GetIAManager());
        BOOST_ASSERT(newcar->GetIAClassID() == iaClassID_strong);

        newcar->GiveWeapon(game_vars::g_heavymg_id);   // and more dangerous
    }

    return true;
}

ok so you get more than you need but the crucial part is the russian roulette loop that retries when a collision happens. as you can see, it ensures termination by using an arbitrary maximum limit on iterations.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .