Simulate Arrow Flight

Projectiles are a common game component and Box2D can help simulate projectile motion fairly well. But even Box2D has it’s limitations. The typical flight trajectory of an arrow is a good example. When you create a body with an arrow shape and shoot it off in the Box2D world, you won’t get the expected behavior of the nose facing the direction of motion. Try the simulation below with ‘No Drag’ selected so see what I mean.

This is because in the physical world there are lots of factors that impact the flight of an arrow, such as air humidity, wind, the shape of the arrow, the weight of the arrow, friction against the arrow tip, shaft, and fletching, etc that are not simulated in Box2D. But there’s a way to help Box2D achieve the desired behavior. Select ‘Drag’ to see the end result.


Drag
No Drag

Lets start by looking at the ArrowClass which is used to create new arrow objects. Some of the class attributes should be familiar from previous examples.

There are two timer attributes: ‘lifetime’ and ‘max_existence_time’. The attribute ‘lifetime’ specifies how long the arrow should exist once it is no longer active, e.g. it is stuck on a surface. The second timer attribute, ‘max_existence_time’ is used to limit the time that the arrow can exist in the world. For instance, if the arrow is shot off an edge where there is no ground it will keep falling indefinitely. This is a way to make sure that it is removed from the world within a reasonable timeframe and doesn’t eat up precious CPU and memory resources.

The attribute ‘drag’ is used in the example as ¬†flag to simulate air drag or not. This should be removed from any game code.

The init function creates the arrow physics body at the provided position and fires it off at the given angle and force. There is user data provided, the most important is a reference to the arrow javascript object in the attribute ‘ent’ which is used to reference the object on a contact event.

The shape of the arrow is a skinny elongated kite made up of four vertices. You can use some other shape if that feels more natural. In this example, the groupIndex value is set to -1 for all arrow objects so they cannot collide with each other.

The update function is where the magic happens to get the desired flight behavior. The flying angle is calculated using basic trigonometry with the input values from the linear velocity of the physics body.

This is also the place where the timer attributes are decremented.

A contact listener is setup that calls the onTouch function. Here you can figure out what the arrow hit and determine what to do. In this example, if the arrow hits a static body, e.g. a wall, the ground, the ceiling or a platform, the physics body is set to be inactive. This will make it ‘stick’ in the static body.

If the arrow hits a dynamic body, e.g. a brick, it is immediately destroyed. In a game, you would use this to apply damage to an enemy or possibly award points to the player.

This example has shown you how to use Box2D to simulate the flight of an arrow. Not realistic enough? Want to try an make it even better? Check out this detailed explanation for some tips and give it a go. Let me hear how it goes.

Download source: arrow.js (367 downloads)