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\$
  • \$\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 Nov 20 '15 at 0:48
  • \$\begingroup\$ Principe: while(pos1.Intersects(pos2)) generateRandomPos(pos1); \$\endgroup\$ – Ahmet Zambak Nov 20 '15 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 Nov 20 '15 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 Nov 20 '15 at 2:57
  • \$\begingroup\$ @v.oddou How can I detect collisions out of the screen/before entering the screen though? \$\endgroup\$ – OrangeHat Nov 22 '15 at 2:48
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\$
  • \$\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 Nov 20 '15 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\$ – Chris Mills-Price Nov 20 '15 at 7:05
  • \$\begingroup\$ Still not working. \$\endgroup\$ – OrangeHat Nov 21 '15 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\$ – Chris Mills-Price Nov 22 '15 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\$

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.