diff --git a/src/main/java/electrosphere/engine/LoadingThread.java b/src/main/java/electrosphere/engine/LoadingThread.java index 693a3937..5af3a3aa 100644 --- a/src/main/java/electrosphere/engine/LoadingThread.java +++ b/src/main/java/electrosphere/engine/LoadingThread.java @@ -16,6 +16,7 @@ import electrosphere.game.state.MacroSimulation; import electrosphere.game.server.terrain.manager.ServerTerrainManager; import electrosphere.game.server.world.ServerWorldData; import electrosphere.entity.types.attach.AttachUtils; +import electrosphere.game.server.ai.creature.MindlessAttacker; import electrosphere.game.state.MicroSimulation; import electrosphere.logger.LoggerInterface; import electrosphere.main.Globals; @@ -477,9 +478,16 @@ public class LoadingThread extends Thread { // EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); } + //spawn evil goblin Entity goblin = CreatureUtils.spawnBasicCreature("Goblin"); - EntityUtils.getPosition(goblin).set(5, 0, 3); + EntityUtils.getPosition(goblin).set(30, 0, 30); EntityUtils.getScale(goblin).set(0.005f); + //give evil goblin sword + Entity goblinSword = ItemUtils.spawnBasicItem("Katana"); + AttachUtils.attachEntityToEntityAtBone(goblin, goblinSword, "Bone.031"); + //attach ai to evil goblin + MindlessAttacker.attachToCreature(goblin); + Entity testHomie = CreatureUtils.spawnBasicCreature("Human"); EntityUtils.getScale(testHomie).set(0.005f); diff --git a/src/main/java/electrosphere/game/server/ai/AI.java b/src/main/java/electrosphere/game/server/ai/AI.java new file mode 100644 index 00000000..7c565824 --- /dev/null +++ b/src/main/java/electrosphere/game/server/ai/AI.java @@ -0,0 +1,11 @@ +package electrosphere.game.server.ai; + +/** + * + * @author amaterasu + */ +public abstract class AI { + + public abstract void simulate(); + +} diff --git a/src/main/java/electrosphere/game/server/ai/AIManager.java b/src/main/java/electrosphere/game/server/ai/AIManager.java new file mode 100644 index 00000000..39f3de56 --- /dev/null +++ b/src/main/java/electrosphere/game/server/ai/AIManager.java @@ -0,0 +1,36 @@ +package electrosphere.game.server.ai; + +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author amaterasu + */ +public class AIManager { + + List aiList = new LinkedList(); + + public AIManager(){ + + } + + public void simulate(){ + for(AI ai : aiList){ + ai.simulate(); + } + } + + public void registerAI(AI ai){ + if(!aiList.contains(ai)){ + aiList.add(ai); + } + } + + public void deregisterAI(AI ai){ + if(aiList.contains(ai)){ + aiList.remove(ai); + } + } + +} diff --git a/src/main/java/electrosphere/game/server/ai/creature/MindlessAttacker.java b/src/main/java/electrosphere/game/server/ai/creature/MindlessAttacker.java new file mode 100644 index 00000000..d605bdab --- /dev/null +++ b/src/main/java/electrosphere/game/server/ai/creature/MindlessAttacker.java @@ -0,0 +1,112 @@ +package electrosphere.game.server.ai.creature; + +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.AttackTree; +import electrosphere.entity.state.MovementTree; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.game.server.ai.AI; +import electrosphere.main.Globals; +import org.joml.Vector3f; + +/** + * + * @author amaterasu + */ +public class MindlessAttacker extends AI{ + + Entity character; + + Entity target; + + float aggroRange = 10.0f; + float attackRange = 1.0f; + + int attackCooldownMax = 250; + int attackCooldown = 0; + + public MindlessAttacker(Entity character){ + this.character = character; + } + + public static void attachToCreature(Entity creature){ + MindlessAttacker ai = new MindlessAttacker(creature); + Globals.aiManager.registerAI(ai); + } + + + + @Override + public void simulate(){ + if(target != null){ + if(inAttackRange()){ + attack(); + } else { + if(inAggroRange()){ + moveToTarget(); + } else { + target = null; + } + } + } else { + searchForTarget(); + } + } + + void attack(){ + if(attackCooldown == 0){ + attackCooldown = attackCooldownMax; + AttackTree attackTree = CreatureUtils.getAttackTree(character); + attackTree.start(EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND); + } else { + attackCooldown--; + } + } + + void moveToTarget(){ + Vector3f targetPosition = EntityUtils.getPosition(target); + Vector3f charactterPosition = EntityUtils.getPosition(character); + Vector3f moveVector = new Vector3f(targetPosition).sub(charactterPosition).normalize(); + CreatureUtils.setMovementVector(character, moveVector); + MovementTree characterMoveTree = CreatureUtils.getEntityMovementTree(character); + if(characterMoveTree.getState()==MovementTree.MovementTreeState.IDLE || characterMoveTree.getState()==MovementTree.MovementTreeState.SLOWDOWN){ + characterMoveTree.start(); + } + } + + boolean inAttackRange(){ + boolean rVal = false; + Vector3f position = EntityUtils.getPosition(character); + Vector3f targetPosition = EntityUtils.getPosition(target); + if(new Vector3f(position).distance(targetPosition) < attackRange){ + rVal = true; + } + return rVal; + } + + boolean inAggroRange(){ + boolean rVal = false; + Vector3f position = EntityUtils.getPosition(character); + Vector3f targetPosition = EntityUtils.getPosition(target); + if(new Vector3f(position).distance(targetPosition) < aggroRange){ + rVal = true; + } + return rVal; + } + + + void searchForTarget(){ + Vector3f position = EntityUtils.getPosition(character); + for(Entity current : Globals.entityManager.getLifeStateEntities()){ + if(current != character){ + Vector3f potentialTargetPosition = EntityUtils.getPosition(current); + if(position.distance(potentialTargetPosition) < aggroRange){ + target = current; + break; + } + } + } + } + +} diff --git a/src/main/java/electrosphere/game/state/MicroSimulation.java b/src/main/java/electrosphere/game/state/MicroSimulation.java index 99e2dc19..7d603957 100644 --- a/src/main/java/electrosphere/game/state/MicroSimulation.java +++ b/src/main/java/electrosphere/game/state/MicroSimulation.java @@ -28,6 +28,9 @@ public class MicroSimulation { } public void simulate(){ + //simulate ai + Globals.aiManager.simulate(); + //update actor animations for(Entity currentEntity : Globals.entityManager.getDrawable()){ //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); diff --git a/src/main/java/electrosphere/main/Globals.java b/src/main/java/electrosphere/main/Globals.java index bb6453cf..338feb08 100644 --- a/src/main/java/electrosphere/main/Globals.java +++ b/src/main/java/electrosphere/main/Globals.java @@ -18,6 +18,7 @@ import electrosphere.game.client.terrain.manager.ClientTerrainManager; import electrosphere.game.client.world.ClientWorldData; import electrosphere.game.collision.CommonWorldData; import electrosphere.engine.LoadingThread; +import electrosphere.game.server.ai.AIManager; import electrosphere.game.server.creature.type.model.CreatureTypeMap; import electrosphere.game.server.item.type.model.ItemTypeMap; import electrosphere.game.state.MacroSimulation; @@ -217,6 +218,9 @@ public class Globals { public static Entity playerCharacter; + //ai manager + public static AIManager aiManager; + public static boolean RENDER_FLAG_RENDER_SHADOW_MAP = false; @@ -251,6 +255,8 @@ public class Globals { widgetManager = new WidgetManager(); //hitbox manager hitboxManager = new HitboxManager(); + //ai manager + aiManager = new AIManager(); } public static void initDefaultGraphicalResources(){