package electrosphere.entity.state; import electrosphere.entity.CreatureUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.main.Globals; import electrosphere.net.NetUtils; import electrosphere.net.message.EntityMessage; import electrosphere.renderer.Animation; import electrosphere.renderer.Model; import java.util.LinkedList; import java.util.concurrent.CopyOnWriteArrayList; import org.joml.Vector3f; /** * * @author amaterasu */ /* Behavior tree for movement in an entity */ public class MovementTree { public static enum MovementTreeState { STARTUP, MOVE, SLOWDOWN, IDLE, } MovementTreeState state; Entity parent; CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); public MovementTree(Entity e){ state = MovementTreeState.IDLE; parent = e; } public MovementTreeState getState(){ return state; } public void start(){ //TODO: check if can start moving state = MovementTreeState.STARTUP; } public void interrupt(){ state = MovementTreeState.IDLE; } public void slowdown(){ state = MovementTreeState.SLOWDOWN; } public void transitionState(){ switch(state){ case STARTUP: //transition if velocity >= acceleration state = MovementTreeState.MOVE; break; case MOVE: state = MovementTreeState.SLOWDOWN; break; case SLOWDOWN: state = MovementTreeState.IDLE; break; } } public void simulate(){ float velocity = CreatureUtils.getVelocity(parent); float acceleration = CreatureUtils.getAcceleration(parent); float maxNaturalVelocity = CreatureUtils.getMaxNaturalVelocity(parent); Model entityModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(parent)); Vector3f position = EntityUtils.getEntityPosition(parent); Vector3f movementVector = CreatureUtils.getMovementVector(parent); //parse attached network messages for(EntityMessage message : networkMessageQueue){ networkMessageQueue.remove(message); // System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); switch(message.getEntityMessageType()){ case MOVE: position.set(message.getX(), message.getY(), message.getZ()); if(Globals.mainConfig.runServer){ Globals.server.broadcastMessage(EntityMessage.constructMoveMessage(parent.getId(), message.getX(), message.getY(), message.getZ())); } break; } } //state machine switch(state){ case STARTUP: //run startup code velocity = velocity + acceleration; CreatureUtils.setVelocity(parent, velocity); if(entityModel != null){ if(entityModel.currentAnimation == null || !entityModel.currentAnimation.name.equals(Animation.ANIMATION_MOVEMENT_STARTUP)){ entityModel.playAnimation(Animation.ANIMATION_MOVEMENT_STARTUP); entityModel.currentAnimation.incrementTime(0.01); } } //check if can transition state if(velocity >= maxNaturalVelocity){ velocity = maxNaturalVelocity; state = MovementTreeState.MOVE; } //move the entity position.add(new Vector3f(movementVector).mul(velocity)); position.y = Globals.drawCellManager.getElevationAtRealPoint(position.x, position.z); EntityUtils.getEntityRotation(parent).rotationTo(new Vector3f(0,0,1), movementVector); break; case MOVE: //check if can restart animation //if yes, restart animation if(entityModel != null){ if(entityModel.currentAnimation == null || !entityModel.currentAnimation.name.equals(Animation.ANIMATION_MOVEMENT_MOVE)){ entityModel.playAnimation(Animation.ANIMATION_MOVEMENT_MOVE); entityModel.currentAnimation.incrementTime(0.01); } } //check if can move forward (collision engine) //if can, move forward by entity movement stats position.add(new Vector3f(movementVector).mul(velocity)); position.y = Globals.drawCellManager.getElevationAtRealPoint(position.x, position.z); EntityUtils.getEntityRotation(parent).rotationTo(new Vector3f(0,0,1), movementVector); break; case SLOWDOWN: //run slowdown code velocity = velocity - acceleration; CreatureUtils.setVelocity(parent, velocity); if(entityModel != null){ if(entityModel.currentAnimation == null || !entityModel.currentAnimation.name.equals(Animation.ANIMATION_MOVEMENT_STARTUP)){ entityModel.playAnimation(Animation.ANIMATION_MOVEMENT_STARTUP); entityModel.currentAnimation.incrementTime(0.01); } } //check if can transition state if(velocity <= 0){ velocity = 0; state = MovementTreeState.IDLE; } //move the entity position.add(new Vector3f(movementVector).mul(velocity)); position.y = Globals.drawCellManager.getElevationAtRealPoint(position.x, position.z); EntityUtils.getEntityRotation(parent).rotationTo(new Vector3f(0,0,1), movementVector); break; case IDLE: if(entityModel != null){ if(entityModel.currentAnimation == null || !entityModel.currentAnimation.name.equals(Animation.ANIMATION_IDLE_1)){ entityModel.playAnimation(Animation.ANIMATION_IDLE_1); entityModel.currentAnimation.incrementTime(0.01); } } break; } } public void addNetworkMessage(EntityMessage networkMessage) { networkMessageQueue.add(networkMessage); } }