import processing.core.PImage; import processing.core.PVector; /** * Dynamic version of SceneImage intended to move and update in the applet. */ public class DynamicSceneImage extends SceneImage { /** * How we'll keep track what the image should be doing. */ public enum State { IDLE, FOLLOWING } public PVector desiredPosition; public State state; /* pixels per second*/ public float movementSpeed; public PVector velocity; public PVector acceleration; public float maxForce; public float maxSpeed; public boolean useForceMovement; public DynamicSceneImage() { super(); desiredPosition = new PVector(); velocity = new PVector(); acceleration = new PVector(); state = State.IDLE; movementSpeed = 1f; maxForce = 0.18f; maxSpeed = 240f; useForceMovement = false; } public DynamicSceneImage(PImage image) { this(); this.image = image; } public DynamicSceneImage(DynamicSceneImage other) { super(other); copy(other); } /** * Copy the components of another element but use a different image. */ public DynamicSceneImage(DynamicSceneImage other, PImage image) { this(other); this.image = image; updateScale(); } /** * Deep copy of another object. */ public void copy(DynamicSceneImage other) { super.copy(other); desiredPosition = other.desiredPosition.get(); state = other.state; movementSpeed = other.movementSpeed; velocity = other.velocity.get(); acceleration = other.acceleration.get(); maxForce = other.maxForce; maxSpeed = other.maxSpeed; useForceMovement = other.useForceMovement; } public void idleBehavior(int time) { } public void followingBehavior(int time) { } /** * Update and state management. * @param time Should be delta time since last update in ms. */ public void update(int time) { if (state == State.IDLE) { idleBehavior(time); } else if (state == State.FOLLOWING) { followingBehavior(time); } move(time); } /** * Movement based on desired position or any force previously applied. * @param deltaTime Time since last movement in ms. */ public void move(int deltaTime) { // use force-based movement if (useForceMovement) { // scale the accelreation based on time acceleration.mult(1000f); // update velocity velocity.add(PVector.mult(acceleration, (deltaTime / 1000f))); // limit speed velocity.limit(maxSpeed); position.add(PVector.mult(velocity, (deltaTime / 1000f))); // reset acceleration to 0 each update acceleration.mult(0f); } else { // otherwise use the position-based movement PVector direction = PVector.sub(desiredPosition, position); float possibleDistance = deltaTime * 0.001f * movementSpeed; PVector newPosition = new PVector(); if (direction.mag() > possibleDistance) { direction.normalize(); newPosition = PVector.mult(direction, possibleDistance); } else { newPosition = PVector.mult(direction, 0.5f); } position.add(newPosition); } } /** * Apply force to this for force-based movement. * @param force The force to apply. */ public void applyForce(PVector force) { acceleration.add(force); } }