package electrosphere.entity.state; import electrosphere.entity.types.creature.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.Actor; import electrosphere.renderer.anim.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); Actor entityActor = EntityUtils.getEntityActor(parent); // Model entityModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(parent)); Vector3f position = EntityUtils.getEntityPosition(parent); Vector3f movementVector = CreatureUtils.getMovementVector(parent); Vector3f newPosition; //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(entityActor != null){ if(!entityActor.isPlayingAnimation() || !entityActor.getCurrentAnimation().equals(Animation.ANIMATION_MOVEMENT_STARTUP)){ entityActor.playAnimation(Animation.ANIMATION_MOVEMENT_STARTUP); entityActor.incrementAnimationTime(0.01); } } //check if can transition state if(velocity >= maxNaturalVelocity){ velocity = maxNaturalVelocity; state = MovementTreeState.MOVE; } //move the entity newPosition = new Vector3f(position).add(new Vector3f(movementVector).mul(velocity)); if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.world, parent, newPosition)){ newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.world, parent, newPosition); } EntityUtils.getEntityPosition(parent).set(newPosition); EntityUtils.getEntityRotation(parent).rotationTo(new Vector3f(0,0,1), movementVector); break; case MOVE: //check if can restart animation //if yes, restart animation if(entityActor != null){ if(!entityActor.isPlayingAnimation() || !entityActor.getCurrentAnimation().equals(Animation.ANIMATION_MOVEMENT_MOVE)){ entityActor.playAnimation(Animation.ANIMATION_MOVEMENT_MOVE); entityActor.incrementAnimationTime(0.01); } } //check if can move forward (collision engine) //if can, move forward by entity movement stats newPosition = new Vector3f(position).add(new Vector3f(movementVector).mul(velocity)); if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.world, parent, newPosition)){ newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.world, parent, newPosition); } EntityUtils.getEntityPosition(parent).set(newPosition); EntityUtils.getEntityRotation(parent).rotationTo(new Vector3f(0,0,1), movementVector); break; case SLOWDOWN: //run slowdown code velocity = velocity - acceleration; CreatureUtils.setVelocity(parent, velocity); if(entityActor != null){ if(!entityActor.isPlayingAnimation() || !entityActor.getCurrentAnimation().equals(Animation.ANIMATION_MOVEMENT_STARTUP)){ entityActor.playAnimation(Animation.ANIMATION_MOVEMENT_STARTUP); entityActor.incrementAnimationTime(0.01); } } //check if can transition state if(velocity <= 0){ velocity = 0; state = MovementTreeState.IDLE; } //move the entity newPosition = new Vector3f(position).add(new Vector3f(movementVector).mul(velocity)); if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.world, parent, newPosition)){ newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.world, parent, newPosition); } EntityUtils.getEntityPosition(parent).set(newPosition); EntityUtils.getEntityRotation(parent).rotationTo(new Vector3f(0,0,1), movementVector); break; case IDLE: if(entityActor != null){ if(!entityActor.isPlayingAnimation() || !entityActor.getCurrentAnimation().equals(Animation.ANIMATION_IDLE_1)){ entityActor.playAnimation(Animation.ANIMATION_IDLE_1); entityActor.incrementAnimationTime(0.01); } } break; } } public void addNetworkMessage(EntityMessage networkMessage) { networkMessageQueue.add(networkMessage); } }