I’m trying to make my npcs avoid to collide against other npc’s already attacking the player.
I’m using the Unaligned Obstacle Avoidance algorithm.
I already changed almost every parameter but even in the best result I got the npc has a strange behavior like you can see in the following video:
Here is the code I’m using:
Entity Manager:
package net.medievalsoul.entity;
import com.jme3.ai.agents.Agent;
import com.jme3.ai.agents.util.GameEntity;
import com.jme3.ai.agents.util.control.MonkeyBrainsAppState;
import com.jme3.app.state.AbstractAppState;
import com.jme3.math.Vector3f;
import java.util.ArrayList;
import java.util.List;
import medievalsoul.GameManager;
import net.medievalsoul.avatar.Avatar;
public class EntityManager extends AbstractAppState
{
private final GameManager gm;
private static ArrayList<Entity> monsters;
private static ArrayList<Entity> players;
private Entity target;
private static boolean targetSelected;
private static List<GameEntity> aiEntityList;
private static MonkeyBrainsAppState brainsAppState;
public EntityManager(GameManager gm)
{
this.gm = gm;
gm.getAppStateManager().attach(this);
EntityManager.monsters = new ArrayList<Entity>();
EntityManager.players = new ArrayList<Entity>();
EntityManager.targetSelected = false;
EntityManager.aiEntityList = new ArrayList<GameEntity>();
EntityManager.brainsAppState = MonkeyBrainsAppState.getInstance();
//starting agents
brainsAppState.setApp(gm.getApplication());
gm.getAppStateManager().attach(brainsAppState);
//brainsAppState.start();
}
public static MonkeyBrainsAppState getMonkeyBrainsAppState()
{
return brainsAppState;
}
public static void addEntity(Entity entity, Agent agent)
{
if(entity instanceof Avatar)
players.add(entity);
else if(entity instanceof Monster)
{
monsters.add(entity);
aiEntityList.add(agent);
//adding agent to MonkeyBrainsAppState
brainsAppState.addAgent(agent);
}
}
public static List<GameEntity> getAiAgents()
{
return aiEntityList;
}
public static void setTargetSelected(boolean selected)
{
targetSelected = selected;
}
public static boolean getIsTargetSelected()
{
return targetSelected;
}
@Override
public void update(float tpf)
{
brainsAppState.update(tpf);
for(Entity entity : players)
{
target = entity;
}
for(Entity entity : monsters)
{
if(target != null && entity.getIsDead() == false)
{
Vector3f viewOrigin = entity.getNode().getLocalTranslation();
Vector3f viewDestination = target.getNode().getLocalTranslation();
Vector3f delta = viewDestination.subtract(viewOrigin);
delta.y = 0.0f;
entity.getPhysicBody().setViewDirection(delta.normalizeLocal());
}
if(entity.getInAction() == true)
{
entity.setTarget(target);
entity.action();
target.getPhysicBody().setWalkDirection(Vector3f.ZERO);
}
}
}
}
And this is where I’m implementing the algorithm:
Monster:
public Monster(GameManager gm, String modelName, Vector3f initialPosition)
{
this.gm = gm;
this.target = null;
this.walk = false;
this.walking = false;
this.idle = true;
this.idling = false;
this.attackRight = false;
this.attackLeft = false;
this.alreadyDead = false;
this.origin = new Vector3f(0,0,0);
this.destination = new Vector3f(0,0,0);
this.spatial = new MonsterSpatial(this.gm);
this.spatial.getNode().setLocalTranslation(initialPosition);
this.monsterPhy = new MonsterPhysics(this.gm);
this.spatial.create(modelName);
this.visModel = this.spatial.getVisModel();
this.spatial.getNode().setUserData("Monster", this);
this.animationController = new EntityAnimationController();
this.extend = ((BoundingBox) this.spatial.getNode().getWorldBound()).getExtent(new Vector3f());
this.monsterPhy.setPhysicsBody(extend);
this.spatial.getNode().addControl(this.monsterPhy.getPhysicBody());
this.spatial.getNode().addControl(this);
this.gm.getBulletAppState().getPhysicsSpace().addAll(this.spatial.getNode());
this.defaultDamage = 2;
this.defaultRange = 20.0f;
this.speed = 60.0f;
skills = new HashMap<String,EntitySkill>();
status = new HashMap<String,EntityStatus>();
EntityStatus str = new EntityStatus("Str", 1.0f);
status.put("Str", str);
EntityStatus dex = new EntityStatus("Dex", 15.0f);
status.put("Dex", dex);
EntityStatus inte = new EntityStatus("Int", 15.0f);
status.put("Int", inte);
EntitySkill skill = new EntitySkill("Swordsmanship", 10.0f);
skills.put("Swordsmanship", skill);
this.initiative = FastMath.nextRandomInt(1, 20);
this.health = status.get("Str").getValue();
createStatusBar();
this.attackSuccessList = new HashMap<String, Boolean>();
this.inAction = false;
this.isDead = false;
this.inventory = new ArrayList<Object>();
this.bodySlots = new HashMap<String,Object>();
Weapon sword = new Weapon("sword032",EffectNames.Frost.getName());
ItemManager.addItem(sword);
equipItem(BoneNames.RightHand.name(), sword);
//initialization of Agents with their names and spatials
agent = new Agent("Monster agent", this.spatial.getNode());
//there isn't any method in framework like createAgentSpatial()
//user is supposed to build his own spatials for game
//setting moveSpeed, rotationSpeed, mass..
agent.setMoveSpeed(12.0f);
agent.setRotationSpeed(30.0f);
//used for steering behaviors in com.jme3.ai.agents.behaviors.npc.steering
agent.setMass(50);
agent.setMaxForce(10);
agent.setRadius(Math.max(extend.x, extend.z) * 2.0f + 5.0f);
}
public void setBehavior(List<GameEntity> aiAgents)
{
//creating main behavior
//agent can have only one behavior but that behavior can contain other behaviors
SimpleMainBehavior mainBehavior = new SimpleMainBehavior(agent);
CompoundSteeringBehavior steer = new BalancedCompoundSteeringBehavior(agent);
seekSteer = new SeekBehavior(agent);
obstacleAvoidanceBehavior = new UnalignedCollisionAvoidanceBehavior(agent, EntityManager.getAiAgents(),3.0f,5.0f);
//obstacleAvoidanceBehavior.setupStrengthControl(new Plane(new Vector3f(0,1,0),0));
obstacleAvoidanceBehavior.setupStrengthControl(10.75f);
steer.addSteerBehavior(obstacleAvoidanceBehavior);
steer.addSteerBehavior(seekSteer);
mainBehavior.addBehavior(steer);
agent.setMainBehavior(mainBehavior);
}
public Agent getAiAgent()
{
return agent;
}
public void move()
{
seekSteer.setTarget(target.getAiAgent());
List<GameEntity> targets = EntityManager.getAiAgents();
//targets.remove(agent);
obstacleAvoidanceBehavior.setObstacles(targets);
getPhysicBody().setViewDirection(agent.getVelocity());
getPhysicBody().setWalkDirection(new Vector3f(agent.getVelocity().x,0.0f,agent.getVelocity().z));
if(!walking)
{
walk = true;
walking = true;
idle = false;
idling = false;
attackRight = false;
attackLeft = false;
}
}
What I’m doing wrong?
Thanks in advance!