Seemed easy, is really hard, How do you program bullets?

Started by
14 comments, last by Satharis 9 years ago

I'm having a difficult time getting my game's bullets to work. I think I understand conceptually but my coding solutions may be lacking. Does anyone have experience with bullets in video games? Maybe an example?

Advertisement
What kind of bullets? Bullets that move a certain distance per frame? Bullets that instantly hit whatever you point at? Bullets affected by gravity and other external forces? Bullets that travel straight no matter what?

What kind of bullets? Bullets that move a certain distance per frame? Bullets that instantly hit whatever you point at? Bullets affected by gravity and other external forces? Bullets that travel straight no matter what?

A bullet for a 2D shooter. The projectile isn't effected by gravity and moves at somewhat faster than the average speed of the character.

OK. The typical process for something like that is (pseudocode):


bullet = bulletPool.NewBullet(); // or you could say "new Bullet" if you want a quick-and-dirty implementation.

bullet.orientation = firingObject.Orientation;

bullet.velocity = firingObject.Forward * desiredProjectileSpeed + firingObject.Velocity;
// adding firingObject.Velocity is optional - some games do this, some don't.
If you don't have a Forward vector for objects, but you do have an angle, you can get the forward vector like so:


object.Forward.X = cos(orientationAngleInRadians);
object.Forward.Y = sin(orientationAngleInRadians);
Simple bullet update is something like this:


position += velocity * deltaTime;

// Check for collisions with other objects (use circle-circle test only for example simplicity)
// Normally you would want to have some kind of broad-phase collision checking as well, but this will work fine for a thousand objects or so.
foreach (object2 in allObjects)
{
    // don't collide with self or the firing object
    if (object2 == bullet || object2 == firingObject)
        continue;

    var offset = object2.position - bullet.position;

    if (offset.lengthSquared <= bullet.radiusSquared + object2.radiusSquared)
    {
        Cleanup(bullet);

        ApplyDamageTo(object2);
    }
}

And then for detecting collision usually a raycast (swept point) or capsule (swept sphere) is used for representing the space that the bullet travels in one game frame.

OK. The typical process for something like that is (pseudocode):



bullet = bulletPool.NewBullet(); // or you could say "new Bullet" if you want a quick-and-dirty implementation.

bullet.orientation = firingObject.Orientation;

bullet.velocity = firingObject.Forward * desiredProjectileSpeed + firingObject.Velocity;
// adding firingObject.Velocity is optional - some games do this, some don't.
If you don't have a Forward vector for objects, but you do have an angle, you can get the forward vector like so:


object.Forward.X = cos(orientationAngleInRadians);
object.Forward.Y = sin(orientationAngleInRadians);
Simple bullet update is something like this:


position += velocity * deltaTime;

// Check for collisions with other objects (use circle-circle test only for example simplicity)
// Normally you would want to have some kind of broad-phase collision checking as well, but this will work fine for a thousand objects or so.
foreach (object2 in allObjects)
{
    // don't collide with self or the firing object
    if (object2 == bullet || object2 == firingObject)
        continue;

    var offset = object2.position - bullet.position;

    if (offset.lengthSquared <= bullet.radiusSquared + object2.radiusSquared)
    {
        Cleanup(bullet);

        ApplyDamageTo(object2);
    }
}

Should I really be allocating and deallocating memory like that?

Should I really be allocating and deallocating memory like that?


That's what the bulletPool.NewBullet() is for:

http://en.wikipedia.org/wiki/Object_pool_pattern

And then for detecting collision usually a raycast (swept point) or capsule (swept sphere) is used for representing the space that the bullet travels in one game frame.


Randy is correct - for very fast travelling objects, the simple circle-circle test that I've got in my example can allow very fast projectiles to "jump" through other objects. To prevent that, you should check the entire path that the bullet travels each frame to see if it hits anything.

Use a line segment check if your bullet's size is not important for purposes of collision. Use a capsule if it is.


Should I really be allocating and deallocating memory like that?

Most systems like this, like particle systems and other rapidly created/destroyed objects, live in a memory pool.

An appropriate size pool of objects is allocated and initialized, and then marked as not being active. When you need one it is marked as active, when you are done with it the item is marked as inactive.

The details of an appropriate size depends on your needs. I've seen high-performance particle systems that have space for several hundred thousand particles.

Are you using any physics engine? Maybe you could consider using one, I know that box2D has special behaviors to deal with bullets.


The only thing I can add to the discussion is that you need destroy the bullets even in case they don't collide with any other object (for instance, the player start shooting into the sky and there is no ceiling in your game). If you don't do this you will have performance issues sooner or later for handling hundreds of bullets that are traveling "to the infinity and beyond" =)

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

This topic is closed to new replies.

Advertisement