Hello community,
I’m a newbie in terms of the jMonkeyEngine and have some problems with my first tries.
In my FPS-game there is a simple map and some enemys (ninjas) are around.
While there is peace, the enemies “patrol” around in kind of a square.
That works fine.
Now I try to realize something like a “aggro radius”. When the player comes too close, the enemy will/should attack.
I’ve tried to use a GhostControl for that (in form of a big “CapsuleCollisionShape”) that is around the enemy and waits for a collision with the player. Then, the enemy will attack.
But - as I see in the debug mode - I’m not able to place this GhostControl so that it follows the enemy, even if I add the control to the “BulletAppState”. Because I have no real expierence with this engine I am not able to solve this problem myself
I would be very thankful if you guys can give me some hints
My Code:
Class: Main.java
[java]
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
public class Main extends SimpleApplication implements ActionListener
{
private Spatial sceneModel;
private BulletAppState bulletAppState;
private RigidBodyControl landscape;
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
private boolean keyLeft = false, keyRight = false, keyUp = false, keyDown = false;
private Vector3f camDir = new Vector3f();
private Vector3f camLeft = new Vector3f();
public static void main(String[] args)
{
Main app = new Main();
app.start();
}
public void simpleInitApp()
{
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.getPhysicsSpace().enableDebug(assetManager);
initCam();
initKeys();
initLight();
initScene();
initPlayer();
Ninja ninja = new Ninja(this, new Vector3f(30f, 3.5f, -50f));
bulletAppState.getPhysicsSpace().add(ninja);
Ninja ninjab = new Ninja(this, new Vector3f(30f, 3.5f, -50f));
bulletAppState.getPhysicsSpace().add(ninjab);
Ninja ninjac = new Ninja(this, new Vector3f(30f, 3.5f, -50f));
bulletAppState.getPhysicsSpace().add(ninjac);
Ninja ninjad = new Ninja(this, new Vector3f(30f, 3.5f, -50f));
bulletAppState.getPhysicsSpace().add(ninjad);
Ninja ninja2 = new Ninja(this, new Vector3f(120f, 3.5f, -130f));
bulletAppState.getPhysicsSpace().add(ninja2);
}
private void initCam()
{
flyCam.setMoveSpeed(100);
flyCam.setZoomSpeed(0.0f);
}
private void initLight()
{
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(1.3f));
rootNode.addLight(al);
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
rootNode.addLight(dl);
}
private void initKeys()
{
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(this, "Left");
inputManager.addListener(this, "Right");
inputManager.addListener(this, "Up");
inputManager.addListener(this, "Down");
inputManager.addListener(this, "Jump");
}
public void initScene()
{
viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
sceneModel = assetManager.loadModel("Scenes/Terrain.j3o");
sceneModel.setLocalScale(2f);
CollisionShape sceneShape = CollisionShapeFactory.createMeshShape((Node) sceneModel);
landscape = new RigidBodyControl(sceneShape, 0);
sceneModel.addControl(landscape);
rootNode.attachChild(sceneModel);
bulletAppState.getPhysicsSpace().add(landscape);
}
public void initPlayer()
{
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1f, 3f, 1);
player = new CharacterControl(capsuleShape, 0.05f);
player.setJumpSpeed(12);
player.setFallSpeed(30);
player.setGravity(30);
player.setPhysicsLocation(new Vector3f(0, 10, 0));
bulletAppState.getPhysicsSpace().add(player);
player.warp(new Vector3f(0.0f, 20.0f, 0.0f));
}
public void onAction(String binding, boolean isPressed, float tpf)
{
if (binding.equals("Left"))
{
keyLeft = isPressed;
} else if (binding.equals("Right"))
{
keyRight = isPressed;
} else if (binding.equals("Up"))
{
keyUp = isPressed;
} else if (binding.equals("Down"))
{
keyDown = isPressed;
} else if (binding.equals("Jump"))
{
if (isPressed)
{
player.jump();
}
}
}
@Override
public void simpleUpdate(float tpf)
{
camDir.set(cam.getDirection()).multLocal(0.6f);
camLeft.set(cam.getLeft()).multLocal(0.4f);
walkDirection.set(0, 0, 0);
if (keyLeft)
{
walkDirection.addLocal(camLeft);
}
if (keyRight)
{
walkDirection.addLocal(camLeft.negate());
}
if (keyUp)
{
walkDirection.addLocal(camDir);
}
if (keyDown)
{
walkDirection.addLocal(camDir.negate());
}
walkDirection.setY(0.0f);
if (player.onGround())
{
player.setWalkDirection(walkDirection.mult(0.5f));
}
cam.setLocation(player.getPhysicsLocation());
}
}
[/java]
Class: Ninja.java
[java]
package mygame;
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.LoopMode;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.math.Vector3f;
import java.util.Random;
public class Ninja extends NPC
{
private Main main;
private float patrolRadian = 20f;
private float walkSpeed = 3.5f;
private Vector3f centerPoint;
private Vector3f nextPatPoint;
private boolean isWaiting = true;
private float waitCount = 0;
private float waitDelay = 15;
private boolean isWalking = false;
private float walkTargetDistance = 0;
private float walkStartPointX, walkStartPointY, walkStartPointZ;
private GhostControl actionRadius; //Test
public Ninja(Main mainArg, Vector3f centerPointArg)
{
super(mainArg, "Models/Ninja/Ninja.mesh.xml", 1, 1f, 6f, 80);
main = mainArg;
setScale(new Vector3f(0.03f, 0.03f, 0.03f));
centerPoint = centerPointArg;
//Test***
actionRadius = new GhostControl(new CapsuleCollisionShape(10, 5));
addControl(actionRadius);
//***Test
setPhysicsLocation(centerPoint);
idle();
}
@Override
public void update(float tpf)
{
super.update(tpf);
if (isWaiting)
{
waitCount += tpf;
if (waitCount >= waitDelay)
{
waitCount = 0;
isWaiting = false;
patrol();
}
} else if (isWalking)
{
if (getWorldTranslation().subtract(new Vector3f(walkStartPointX, walkStartPointY, walkStartPointZ)).length() > walkTargetDistance)
{
isWalking = false;
isWaiting = true;
setWalkDirection(Vector3f.ZERO);
idle();
}
}
}
public void walk()
{
animate(0, "Walk", LoopMode.Cycle);
}
private void idle()
{
switch (new Random().nextInt(3))
{
case 0:
animate(0, "Idle1", LoopMode.Cycle);
break;
case 1:
animate(0, "Idle2", LoopMode.Cycle);
break;
case 2:
animate(0, "Idle3", LoopMode.Cycle);
break;
}
}
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName)
{
}
public void onAnimChange(AnimControl control, AnimChannel channel, String animName)
{
}
private void patrol()
{
Random random = new Random();
float fac1 = 1f;
float fac2 = 1f;
if (random.nextBoolean())
{
fac1 = -1f;
}
if (random.nextBoolean())
{
fac2 = -1f;
}
this.nextPatPoint = centerPoint.add(new Vector3f(random.nextFloat() * patrolRadian * fac1, 0.0f, random.nextFloat() * patrolRadian * fac2)).setY(0);
walkStartPointX = getWorldTranslation().getX();
walkStartPointY = getWorldTranslation().getY();
walkStartPointZ = getWorldTranslation().getZ();
walkTargetDistance = nextPatPoint.subtract(getWorldTranslation()).length();
isWalking = true;
walk();
setViewDirection((nextPatPoint).subtract(getWorldTranslation()).negate());
setWalkDirection((nextPatPoint).subtract(getWorldTranslation()).normalizeLocal().mult(walkSpeed));
}
}
[/java]
Class NPC.java
[java]
package mygame;
import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.GhostControl;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import java.util.ArrayList;
public abstract class NPC extends BetterCharacterControl implements AnimEventListener
{
private Main main;
private Spatial node;
private AnimControl animControl;
private ArrayList<AnimChannel> animChannels = new ArrayList<AnimChannel>();
public NPC(Main mainArg, String modelPathArg, int numberAnimChannels, float radiusArg, float heightArg, float weightArg)
{
super(radiusArg, heightArg, weightArg);
main = mainArg;
node = main.getAssetManager().loadModel(modelPathArg);
node.addControl(this);
animControl = node.getControl(AnimControl.class);
animControl.addListener(this);
for (int i = 0; i < numberAnimChannels; i++)
{
animChannels.add(animControl.createChannel());
}
main.getRootNode().attachChild(node);
}
@Override
public void setSpatial(Spatial e)
{
super.setSpatial(e);
if (e != null)
{
node = e;
}
}
protected void animate(int channelNumber, String move, LoopMode mode)
{
animChannels.get(0).reset(true);
animChannels.get(channelNumber).setAnim(move, 0.3f);
animChannels.get(channelNumber).setLoopMode(mode);
}
public void setPosition(Vector3f newPos)
{
node.setLocalTranslation(newPos);
}
public void setScale(Vector3f newScale)
{
node.setLocalScale(newScale);
}
public void setRotation(Quaternion newRotation)
{
node.setLocalRotation(newRotation);
}
public void move(Vector3f offset)
{
node.move(offset);
}
public Vector3f getWorldTranslation()
{
return node.getWorldTranslation();
}
public void lookAt(Vector3f lookPoint)
{
node.lookAt(lookPoint, new Vector3f(0, 1, 0));
}
public void addControl(Control controlArg)
{
node.addControl(controlArg);
}
}
[/java]
To run this, you will need to include the test-library (“jME3-testdata.jar”). Also, you will need a basic terrain/Scene (named “Terrain.j3o”).
The parts in the code marked with “Test”-comments are the “critical” parts.
I hope that here is somebody who wants to help me
Thanks!
stayawayknight
PS: I’m sorry for the (bad) language!