A rocket engine is crucial for most space-based games and many 2D games as well. In this recipe, we'll cover the minimum that is required to create a thruster that can be used in many different contexts. The following figure shows a thruster with ParticleEmitter
:
For this recipe, we need to make sure that we see the debug shapes of physics. To do this, we need to call the bulletAppState.setDebugEnabled(true);
statement.
We will begin by setting up some things that are not strictly needed for the rocket engine but will aid the testing. Perform the following steps to build a rocket engine:
Node
class called ground
.RigidBodyControl
with PlaneCollisionShape
. The plane should face upwards like floors normally do, as follows:RigidBodyControl floorControl = new RigidBodyControl(new PlaneCollisionShape(new Plane(new Vector3f(0, 1, 0), 0)), 0); ground.addControl(floorControl); floorControl.setPhysicsLocation(new Vector3f(0f, -10, 0f));
rootNode
of the application and physicsSpace
of bulletAppState
.AnalogListener
interface in our application.inputManager
along with a mapping object called boost that is bound to the Space bar:inputManager.addListener(this, "boost"); inputManager.addMapping("boost", new KeyTrigger(KeyInput.KEY_SPACE));
SimpleApplication
.Node
class called spaceShip
that will be our spaceship's representation.RigidBodyControl
instance with BoxCollisionShape
and add it to the spaceShip
node as follows:RigidBodyControl control = new RigidBodyControl(new BoxCollisionShape(new Vector3f(1, 1, 1)), 1); spaceShip.addControl(control);
Node
, which will be our thruster. Give it the name Thruster
to be able to identify it more easily later, as follows:Node thruster = new Node("Thruster");
localTranslation
of this so that it will end up at the bottom of the spaceship, as shown in the following line of code:thruster.setLocalTranslation(0, -1, 0);
spaceShip
node.spaceShip
node to both the rootNode
and physicsSpace
of bulletAppState
.ThrusterControl
, extending AbstractControl
.Spatial
field called thruster
, that will store the thruster
node.setSpatial
method and set it by calling getChild("Thruster")
on the supplied spatial.fireBooster()
.Vector3f
field called direction
as follows:Vector3f direction = spatial.getWorldTranslation().subtract(thruster.getWorldTranslation());
RigidBodyControl
class in the spatial and call applyImpulse
with the direction vector. We use the inverted direction as the relative position that the impulse should originate from. This can be implemented as follows:spatial.getControl(RigidBodyControl.class).applyImpulse(direction, direction.negate());
fireBooster
method. We do this in the onAnalog
method that was added when we implemented the AnalogListener
interface:if(name.equals("boost") && value > 0){ spaceShip.getControl(ThrusterControl.class).fireBooster(); }
The graphics in this recipe are very minimalistic and mostly rely on the debug mode of BulletAppState
to draw them. The physics shapes don't normally have a visual representation since they're not part of the scene graph. Using the debug mode can be very useful during early prototypes.
The RigidBodyControl
instance of the spaceship makes sure it's affected by gravity and other forces.
The sole purpose of a thruster is to be able to easily retrieve the position that is relative to the spaceship from where the boosting force needs to be applied. This is why we place it at the bottom of the spaceship. The benefit of using the Control
pattern to control a Thruster
is that we can apply it to other geometries easily (and even use it in SceneComposer
).
The fireBooster
method of ThrusterControl
takes the position of spaceShip
and subtracts the position of the thruster node to get the direction of the force to apply. The relative position of the force is the direct opposite of this direction.
18.117.187.113