# Custom Controls

A `com.jme3.scene.control.Control` is a customizable jME3 interface that allows you to cleanly steer the behaviour of game entities: Traps, alarms, doors, animal NPCs, self-steering vehicles, artificially intelligent behaviour in NPCs, anything that moves. Several instances of Controls together implement the behaviours of a type of Spatial. To control global game behaviour see Application States – you can also use both together.

To control the behaviour of types of entities:

1. Create one control for each type of behavior. When you add several controls to one spatial, they will be executed in the order they were added.
   For example, an NPC can be controlled by a PhysicsControl and an AIControl.
2. Define the custom control and implement its behaviour in the Control's update() method:
   - You can pass arguments into your custom control.
   - In the control class, the object `spatial` gives you access to the spatial that the control is attached to.
   - Modify the `spatial`'s transformation (move, scale, rotate), play animations, check for enemies around it and react, etc.
3. Add an instance of the control to a spatial, and the Spatial's game state is updated automatically from now on.

       spatial.addControl(myControl);

To implement game logic for a type of spatial, you will either extend AbstractControl, or implement the Control interface, as explained in this article.

## Usage Examples

For example, you could write a CharacterAnimControl that animates a character accordingly while it is being moved by a CharacterControl. Or you can write an AIControl that remote-controls NPC behaviour in fight situatons. Or you could write a DestructionControl that automatically replaces a structure with an appropriate piece of debris after collision with a projectile… The possibilities are endless. Existing examples in the code base include:

- allows manipulation of skeletal animation, including blending and multiple channels.
- allows you to sync the camera position with the position of a given spatial.
- displays a flat picture orthogonally, e.g. a speech bubble or informational dialog.
- subclasses (such as CharacterControl, RigidBodyControl, VehicleControl) allow you to add physical properties to any spatial. PhysicsControls tie into capabilities provided by the BulletAppState.

## The Control Interface

The interface can be found under `com.jme3.scene.control.Control`. It has the following method signatures:

- `cloneForSpatial(Spatial)`: Clones the Control and attaches it to a clone of the given Spatial. The AssetManager uses this method if the same spatial is loaded twice. You can specify which fields you want your object to reuse (e.g. collisionshapes) in this case.
- `setEnabled(boolean)`: Enable or disable the control. If disabled, update() does nothing. Goes with accessor `isEnabled();`.
- There are also some internal methods that you do not call from user code: `setSpatial(Spatial s)`, `update(float tpf);`, `render(RenderManager rm, ViewPort vp)`.

If you want to create a Control that also extends an existing class, then create a custom extension of the Control Interface. Usage example: 1. Create a custom control interface

    public interface MyControl extends Control {
        public void setSomething(int x); // add your custom methods
    }

2. Create custom classes implementing your control interface

    public class ControlledThing extends MyThing implements MyControl {

        protected Spatial spatial;

        protected boolean enabled = true;

        public ControlledThing() { } // empty serialization constructor

        public ControlledThing(int x) { // custom constructor
            super(x);
        }

        @Override
        public void update(float tpf) {
            if (enabled && spatial != null) {
                // ...
                // Write custom code to control the spatial here!
            }
        }

        @Override
        public void render(RenderManager rm, ViewPort vp) {
            // optional for advanced users, e.g. to display a debug shape
        }

        @Override
        public Control cloneForSpatial(Spatial spatial) {
            ControlledThing control = new ControlledThing(y);
            // set custom properties
            spatial.setControl(control);
            return control;
        }

        @Override
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
            // ...
        }

        @Override
        public boolean isEnabled() {
            return enabled;
        }

        @Override
        public void setSomething(int z) {
            // You can add custom methods ...
        }

        @Override
        public void write(JmeExporter ex) throws IOException {
            super.write(ex);
            OutputCapsule oc = ex.getCapsule(this);
            oc.write(enabled, "enabled", true);
            oc.write(spatial, "spatial", null);
            // write custom variables ....
        }
        @Override
        public void read(JmeImporter im) throws IOException {
            super.read(im);
            InputCapsule ic = im.getCapsule(this);
            enabled = ic.readBoolean("enabled", true);
            spatial = (Spatial) ic.readSavable("spatial", null);
            // read custom variables ....
        }
    }

## AbstractControl

This class can be found under `com.jme3.scene.control.AbstractControl`.

- This is a default abstract class that implements the Control interface.
- It gives you access to a boolean `enabled`, and a Spatial `spatial`.
- Extend AbstractControl to create a custom Control.

Usage: Your custom subclass implements the three methods `controlUpdate()`, `controlRender()`, `setSpatial()`, and `cloneForSpatial()` as shown here:

    public class MyControl extends AbstractControl implements Savable, Cloneable {

      private Thing thing; // some custom field of yours

      public MyControl(){} // empty serialization constructor

      public MyControl(thing) { // some custom constructor
        this.thing = thing;
        // Note: you can not access spatial here
      }

      @Override
      public void setSpatial(Spatial spatial) {
        super.setSpatial(spatial);
        // optional init method
        // you can get and set user data in the spatial here
      }

      @Override
      protected void controlUpdate(float tpf){
        if(spatial != null && thing != null) {
          // Implement your custom control here ...
          // Change scene graph, access and modify userdata in the spatial, etc
        }
      }

      @Override
      protected void controlRender(RenderManager rm, ViewPort vp){
         // optional rendering manipulation (for advanced users)
      }

      @Override
      public Control cloneForSpatial(Spatial spatial){
        final MyControl control = new MyControl(...);
        control.setSpatial(spatial);
        return control;
      }

      @Override
      public void read(JmeImporter im) throws IOException {
          super.read(im);
          // im.getCapsule(this).read(...);
      }

      @Override
      public void write(JmeExporter ex) throws IOException {
          super.write(ex);
          // ex.getCapsule(this).write(...);
      }

    }

## Best Practices

Tip: Use the getControl() accessor to get Control objects from Spatials. No need to pass around lots of object references. Here an example from the
code:

    public class CharacterAnimControl implements Control {
      ...
      public void setSpatial(Spatial spatial) {
        ...
        animControl      = spatial.getControl(AnimControl.class);
        characterControl = spatial.getControl(CharacterControl.class);
        ...
      }
    }

Tip: You can create custom Control interfaces so a set of different Controls provide the same methods and can be accessed with the interface class type.

    public interface ManualControl extends Control {
        public void steerX(float value);
        public void steerY(float value);
        public void moveX(float value);
        public void moveY(float value);
        public void moveZ(float value);
       ...
    }

Then you create custom sub-Controls and implement the methods accordingly to the context:

    public class ManualVehicleControl   extends ManualControl {...}

and

    public class ManualCharacterControl extends ManualControl {...}

Then add the appropriate controls to spatials:

    characterSpatial.addControl(new ManualCharacterControl());
    ...
    vehicleSpatial.addControl(new ManualVehicleControl());
    ...

Tip: Use the getControl() method on a Spatial to get a specific Control object, and activate its behaviour!

    ManualControl c = mySpatial.getControl(ManualControl.class);
    c.steerX(steerX);

view online version