Tutorial 3: Behaviours

In this tutorial we will be introducing a new class: HvrBehaviour. This class lets you add functionality and user interaction to your Argo application. In Tutorial 2: Core Components we discussed the render loop, and the importance of interactions with Hvr* components taking place on the rendering thread.

1. HvrBehaviour

An HvrBehaviour lets you hook in to the lifecycle of an HvrPlayer. An HvrBehaviour is attached to an HvrPlayer, and can be detached at any time. Many unique HvrBehaviour instances can be attached to an HvrPlayer.

Your HvrBehaviour requires three methods to be overridden:

  1. onInitialise - called when the HvrBehaviour is ready to run
  2. onUpdate - called once each frame before the HvrPlayer does any rendering
  3. onDestroy - called when the HvrPlayer is destroyed, or the HvrBehaviour is detached from it.

2. RunAwayBehaviour Example

Create the following HvrBehaviour, and add it to the code you created in Tutorial 1: Getting Started. The HvrBehaviour should be attached to the HvrPlayer inside the HvrPlayer.post Runnable, just after the HvrActor is added.

public class RunAwayBehaviour extends HvrBehaviour {
    
    private HvrActor actor;
  
    public ActorRunAwayBehaviour(HvrActor actor){
        this.actor = actor;
    }
  
    @Override
    public void onInitialise() {
        // Nothing to set up
    }
  
    @Override
    public void onDestroy(){
        // Nothing to destroy
    }
  
    @Override
    public void onUpdate(){
        // Retrieve the position of the actor
        Vector3fc actorPosition = actor.getTransform().getPosition();
        // Set the position of the actor to the previously retrieved position,
        // with a small change to the Z poisition
        actor.getTransform.setPosition(actorPosition.x, 
                                       actorPosition.y, 
                                       actorPosition.z - 0.02f);
    }
}

Example integration:

// This code is taken from Tutorial 1's example code
// ...
hvrPlayer.post(() -> {
    HvrActor actor = hvrPlayer.getRenderer().addActor(actorFile);
    actor.getTransform().setPosition(0.0f, 0.0f, -2.0f);
    hvrPlayer.getCamera().setView(0.0f, 1.0f, 0.0f);
  
    // Add our RunAwayBehaviour
    RunAwayBehaviour runAwayBehaviour = new RunAwayBehaviour(actor);
    hvrPlayer.addBehaviour(runAwayBehaviour);
});
// ...

Once you’ve added this to your application, run the application and you should see that the HvrActor will move away from the camera.

The RunAwayBehaviour is updating each time the HvrPlayer does it’s rendering, and subtracting 0.02 from the HvrActor’s Z position. As the camera is looking along the -Z axis, this means that the HvrActor is moving away from the camera each frame.

3. HvrInputBehaviour

HvrBehaviour is a great base tool, but most of the functionality you’ll want to add involves actual user interactions - touches, swipes and gestures. These input events are delivered to Views on the Android main/UI thread, but any changes you want to make to the HvrPlayer, HvrRenderer, or HvrActors should be done on the HvrPlayer’s rendering thread.

To solve this, Argo provides a class called HvrInputBehaviour, which is an extension of HvrBehaviour. HvrInputBehaviour hides the onUpdate method, and replaces it with the onInputEvent and onInputFinished methods.

  • onInputEvent is called once for each input event, before HvrInputBehaviour.onInputFinished is called.
  • onInputFinished is called once every frame, after all calls to onInputEvent have been completed. This will occur immediately before HvrPlayer performs any rendering.

####4. InputRunAwayBehaviour Example

Try replacing the RunAwayBehaviour created in the example earlier with the following RunAwayInputBehaviour, which is based on the HvrInputBehaviour class.

Example RunAwayInputBehaviour class:

public class RunAwayInputBehaviour extends HvrInputBehaviour {
    
    private HvrActor actor;
    private boolean isDown;
  
    public ActorRunAwayBehaviour(HvrActor actor){
        this.actor = actor;
    }
  
    @Override
    public void onInputEvent(HvrInputEvent event){
        if(event.getAction() == HvrInputEvent.ACTION_DOWN) {
            isDown = true;
        }
        if(event.getAction() == HvrInputEvent.ACTION_UP){
            isDown = false;
        }
    }
  
    @Override
    public void onInputFinished(){
        if(isDown){
            Vector3fc actorPosition = actor.getTransform().getPosition();
            actor.getTransform.setPosition(actorPosition.x, 
                                           actorPosition.y, 
                                           actorPosition.z - 0.02f);

        }    
    }
}

Example Integration:

// This code is taken from Tutorial 1's example code
// ...
hvrPlayer.post(() -> {
    HvrActor actor = hvrPlayer.getRenderer().addActor(actorFile);
    actor.getTransform().setPosition(0.0f, 0.0f, -2.0f);
    hvrPlayer.getCamera().setView(0.0f, 1.0f, 0.0f);
  
    // Add our RunAwayBehaviour
    RunAwayInputBehaviour runAwayBehaviour = new RunAwayInputBehaviour(actor);
    hvrPlayer.addBehaviour(runAwayBehaviour);
});
// ...

If you correctly attach an instance of RunAwayInputBehaviour to an HvrPlayer, you should see the same behaviour as in the RunAwayBehaviour example, but only when the user is touching the screen.

Next Steps