NPC help

Hi. I ran into a bit of a problem… I’m trying to get my NPC to walk towards the character when the character hits the outside GhostControl. I have the collision and everything, it’s just the walking part… I need it to stop when it comes within 5 units (meters, I guess?). With my code it works… Once. The rest of the time it only rotates (which I set it to do in the same if statement…). Also, controlling the speed would also be nice… The NPC goes zooming around… So, if anyone can help, it would be appreciated! Thanks.



Code:

[java]package test;





import AutoCam.AutoRotateCamera_slim;



import com.jme3.animation.AnimChannel;

import com.jme3.animation.AnimControl;

import com.jme3.animation.AnimEventListener;

import com.jme3.animation.LoopMode;

import com.jme3.bullet.BulletAppState;

import com.jme3.app.SimpleApplication;

import com.jme3.bounding.BoundingBox;

import com.jme3.bullet.PhysicsSpace;

import com.jme3.bullet.collision.PhysicsCollisionEvent;

import com.jme3.bullet.collision.PhysicsCollisionListener;

import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

import com.jme3.bullet.collision.shapes.SphereCollisionShape;

import com.jme3.bullet.control.CharacterControl;

import com.jme3.bullet.control.GhostControl;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.bullet.util.CollisionShapeFactory;

import com.jme3.effect.EmitterSphereShape;

import com.jme3.effect.ParticleEmitter;

import com.jme3.effect.ParticleMesh.Type;

import com.jme3.font.BitmapText;

import com.jme3.input.ChaseCamera;

import com.jme3.input.KeyInput;

import com.jme3.input.MouseInput;

import com.jme3.input.controls.ActionListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.input.controls.MouseButtonTrigger;

import com.jme3.light.DirectionalLight;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector2f;

import com.jme3.math.Vector3f;

import com.jme3.post.FilterPostProcessor;

import com.jme3.post.filters.BloomFilter;

import com.jme3.post.filters.DepthOfFieldFilter;

import com.jme3.renderer.Camera;

import com.jme3.renderer.queue.RenderQueue.ShadowMode;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.scene.shape.Sphere;

import com.jme3.scene.shape.Sphere.TextureMode;

import com.jme3.terrain.geomipmap.TerrainLodControl;

import com.jme3.terrain.geomipmap.TerrainQuad;

import com.jme3.terrain.heightmap.AbstractHeightMap;

import com.jme3.terrain.heightmap.ImageBasedHeightMap;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.WrapMode;

import com.jme3.util.SkyFactory;

import java.util.ArrayList;

import java.util.List;



import jme3test.bullet.BombControl;

import jme3tools.converters.ImageToAwt;



/**

*

  • @author normenhansen

    */

    public class TESTWalkingCharacterWORK extends SimpleApplication implements ActionListener, PhysicsCollisionListener, AnimEventListener {



    private BulletAppState bulletAppState;

    //character

    CharacterControl character;

    Node model, arm;

    //temp vectors

    Vector3f walkDirection = new Vector3f();

    Vector3f npcvd;

    //terrain

    TerrainQuad terrain;

    RigidBodyControl terrainPhysicsNode;

    GhostControl armrbc;

    //Materials

    Material matRock;

    Material matWire;

    Material matBullet;

    //animation

    AnimChannel animationChannel;

    AnimChannel shootingChannel;

    AnimControl animationControl;

    float airTime = 0;

    //camera

    boolean left = false, right = false, up = false, down = false;

    ChaseCam chaseCam;

    //bullet

    Sphere bullet;

    SphereCollisionShape bulletCollisionShape;

    //explosion

    ParticleEmitter effect;

    //brick wall

    Box brick;

    float bLength = 0.8f;

    float bWidth = 0.4f;

    float bHeight = 0.4f;

    FilterPostProcessor fpp;

    GhostControl enemySphereBox;

    CharacterControl character1;

    Node model1, square, model2;

    boolean inSide = false, inDoor=false, tooClose=false;

    Geometry red;

    Vector3f r = new Vector3f(0,0,0);



    public static void main(String[] args) {

    TESTWalkingCharacterWORK app = new TESTWalkingCharacterWORK();

    app.start();

    }



    @Override

    public void simpleInitApp() {



    bulletAppState = new BulletAppState();

    bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);

    stateManager.attach(bulletAppState);

    npcvd = new Vector3f(0,0,0);

    setupKeys();

    prepareBullet();

    prepareEffect();

    createLight();

    createSky();

    createTerrain();

    createWall();

    createCharacter();

    setupChaseCamera();

    setupAnimationController();

    createArm();

    setupFilter();

    setupNPC();

    setupGUI();

    }

    private void setupGUI(){

    this.setDisplayStatView(false);

    BitmapText helloText = new BitmapText(guiFont, false);

    helloText.setSize(guiFont.getCharSet().getRenderedSize());

    helloText.setText(“Hello World”);

    helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);

    guiNode.attachChild(helloText);

    System.out.println(guiNode.getChildren().toString());

    }

    private void setupNPC(){

    CapsuleCollisionShape capsule = new CapsuleCollisionShape(1.5f, 2f);

    SphereCollisionShape enemySphere = new SphereCollisionShape(20f);

    character1 = new CharacterControl(capsule, 0.01f);

    character1.setUseViewDirection(false);

    enemySphereBox = new GhostControl(enemySphere);

    model1 = (Node) assetManager.loadModel(“Models/Oto/Oto.mesh.xml”);

    model1.setName(“model1”);

    model1.setLocalScale(0.5f);



    model1.addControl(enemySphereBox);

    model1.addControl(character1);

    character1.setPhysicsLocation(new Vector3f(-160, 10, -10));

    enemySphereBox.setPhysicsLocation(new Vector3f(character1.getPhysicsLocation().x+5,character1.getPhysicsLocation().y,character1.getPhysicsLocation().z+5));

    rootNode.attachChild(model1);



    getPhysicsSpace().add(enemySphereBox);

    getPhysicsSpace().add(character1);

    getPhysicsSpace().enableDebug(assetManager);





    model2 = (Node) assetManager.loadModel(“Models/Oto/Oto.mesh.xml”);

    model2.setName(“model2”);

    model2.setLocalTranslation(new Vector3f(-170, 10, -13));

    model2.setLocalScale(0.5f);

    rootNode.attachChild(model2);



    Box box2 = new Box( 1,1,1);

    red = new Geometry(“Box”, box2);

    Material mat2 = new Material(assetManager, “Common/MatDefs/Misc/SolidColor.j3md”);

    mat2.setColor(“Color”, ColorRGBA.Red);

    red.setMaterial(mat2);

    red.setLocalTranslation(character.getPhysicsLocation());

    rootNode.attachChild(red);

    }

    private void setupFilter() {

    FilterPostProcessor fpp = new FilterPostProcessor(assetManager);

    BloomFilter bloom = new BloomFilter(BloomFilter.GlowMode.Objects);

    DepthOfFieldFilter doff = new DepthOfFieldFilter();

    doff.setFocusDistance(5);

    doff.setFocusRange(100);



    //fog = new FogFilter();

    fpp.addFilter(bloom);

    fpp.addFilter(doff);

    //fog.setFogDistance(300);

    //fog.setFogDensity(1.3f);

    // fpp.addFilter(fog);

    viewPort.addProcessor(fpp);

    }



    private PhysicsSpace getPhysicsSpace() {

    return bulletAppState.getPhysicsSpace();

    }



    private void setupKeys() {

    inputManager.addMapping(“wireframe”, new KeyTrigger(KeyInput.KEY_T));

    inputManager.addListener(this, “wireframe”);

    inputManager.addMapping(“CharLeft”, new KeyTrigger(KeyInput.KEY_A));

    inputManager.addMapping(“CharRight”, new KeyTrigger(KeyInput.KEY_D));

    inputManager.addMapping(“CharUp”, new KeyTrigger(KeyInput.KEY_W));

    inputManager.addMapping(“CharDown”, new KeyTrigger(KeyInput.KEY_S));

    inputManager.addMapping(“CharSpace”, new KeyTrigger(KeyInput.KEY_RETURN));

    inputManager.addMapping(“OpenDoor”, new KeyTrigger(KeyInput.KEY_O));

    inputManager.addMapping(“CharShoot”, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));

    inputManager.addListener(this, “CharLeft”);

    inputManager.addListener(this, “CharRight”);

    inputManager.addListener(this, “CharUp”);

    inputManager.addListener(this, “CharDown”);

    inputManager.addListener(this, “CharSpace”);

    inputManager.addListener(this, “OpenDoor”);

    inputManager.addListener(this, “CharShoot”);

    }



    private void createWall() {

    float xOff = -144;

    float zOff = -40;

    float startpt = bLength / 4 - xOff;

    float height = 6.1f;

    brick = new Box(Vector3f.ZERO, bLength, bHeight, bWidth);

    brick.scaleTextureCoordinates(new Vector2f(1f, .5f));

    for (int j = 0; j < 15; j++) {

    for (int i = 0; i < 4; i++) {

    Vector3f vt = new Vector3f(i * bLength * 2 + startpt, bHeight + height, zOff);

    addBrick(vt);

    }

    startpt = -startpt;

    height += 1.01f * bHeight;

    }

    }



    private void addBrick(Vector3f ori) {

    Geometry reBoxg = new Geometry(“brick”, brick);

    reBoxg.setMaterial(matRock);

    reBoxg.setLocalTranslation(ori);

    reBoxg.addControl(new RigidBodyControl(1.5f));

    reBoxg.setShadowMode(ShadowMode.CastAndReceive);

    this.rootNode.attachChild(reBoxg);

    this.getPhysicsSpace().add(reBoxg);

    }



    private void prepareBullet() {

    bullet = new Sphere(32, 32, 0.4f, true, false);

    bullet.setTextureMode(TextureMode.Projected);

    bulletCollisionShape = new SphereCollisionShape(0.4f);

    matBullet = new Material(getAssetManager(), “Common/MatDefs/Misc/SolidColor.j3md”);

    matBullet.setColor(“Color”, ColorRGBA.Green);

    matBullet.setColor(“m_GlowColor”, ColorRGBA.Green);

    getPhysicsSpace().addCollisionListener(this);

    }



    private void prepareEffect() {

    int COUNT_FACTOR = 1;

    float COUNT_FACTOR_F = 1f;

    effect = new ParticleEmitter(“Flame”, Type.Triangle, 32 * COUNT_FACTOR);

    effect.setSelectRandomImage(true);

    effect.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (float) (1f / COUNT_FACTOR_F)));

    effect.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));

    effect.setStartSize(1.3f);

    effect.setEndSize(2f);

    effect.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));

    effect.setParticlesPerSec(0);

    effect.setGravity(-5f);

    effect.setLowLife(.4f);

    effect.setHighLife(.5f);

    effect.setInitialVelocity(new Vector3f(0, 7, 0));

    effect.setVelocityVariation(1f);

    effect.setImagesX(2);

    effect.setImagesY(2);

    Material mat = new Material(assetManager, “Common/MatDefs/Misc/Particle.j3md”);

    mat.setTexture(“Texture”, assetManager.loadTexture(“Effects/Explosion/flame.png”));

    effect.setMaterial(mat);

    effect.setLocalScale(100);

    rootNode.attachChild(effect);

    }



    private void createLight() {

    Vector3f direction = new Vector3f(-0.1f, -0.7f, -1);

    DirectionalLight dl = new DirectionalLight();

    dl.setDirection(direction);

    dl.setColor(new ColorRGBA(1f, 1f, 1f, 1.0f));

    rootNode.addLight(dl);

    }



    private void createSky() {

    rootNode.attachChild(SkyFactory.createSky(assetManager, “Textures/Sky/Bright/BrightSky.dds”, false));

    }



    private void createTerrain() {

    matRock = new Material(assetManager, “Common/MatDefs/Terrain/TerrainLighting.j3md”);

    matRock.setBoolean(“useTriPlanarMapping”, false);

    matRock.setBoolean(“WardIso”, true);

    matRock.setTexture(“AlphaMap”, assetManager.loadTexture(“Textures/Terrain/splat/alphamap.png”));

    Texture heightMapImage = assetManager.loadTexture(“Textures/Terrain/splat/mountains512.png”);

    Texture grass = assetManager.loadTexture(“Textures/Terrain/splat/grass.jpg”);

    grass.setWrap(WrapMode.Repeat);

    matRock.setTexture(“DiffuseMap”, grass);

    matRock.setFloat(“DiffuseMap_0_scale”, 64);

    Texture dirt = assetManager.loadTexture(“Textures/Terrain/splat/dirt.jpg”);

    dirt.setWrap(WrapMode.Repeat);

    matRock.setTexture(“DiffuseMap_1”, dirt);

    matRock.setFloat(“DiffuseMap_1_scale”, 16);

    Texture rock = assetManager.loadTexture(“Textures/Terrain/splat/road.jpg”);

    rock.setWrap(WrapMode.Repeat);

    matRock.setTexture(“DiffuseMap_2”, rock);

    matRock.setFloat(“DiffuseMap_2_scale”, 128);

    Texture normalMap0 = assetManager.loadTexture(“Textures/Terrain/splat/grass_normal.png”);

    normalMap0.setWrap(WrapMode.Repeat);

    Texture normalMap1 = assetManager.loadTexture(“Textures/Terrain/splat/dirt_normal.png”);

    normalMap1.setWrap(WrapMode.Repeat);

    Texture normalMap2 = assetManager.loadTexture(“Textures/Terrain/splat/road_normal.png”);

    normalMap2.setWrap(WrapMode.Repeat);

    matRock.setTexture(“NormalMap”, normalMap0);

    matRock.setTexture(“NormalMap_1”, normalMap2);

    matRock.setTexture(“NormalMap_2”, normalMap2);

    matWire = new Material(assetManager, “Common/MatDefs/Misc/WireColor.j3md”);

    matWire.setColor(“Color”, ColorRGBA.Green);



    AbstractHeightMap heightmap = null;

    try {

    heightmap = new ImageBasedHeightMap(ImageToAwt.convert(heightMapImage.getImage(), false, true, 0), 0.25f);

    heightmap.load();



    } catch (Exception e) {

    e.printStackTrace();

    }



    float[] mapData = this.Smooth(heightmap.getHeightMap(), 512, 8);





    terrain = new TerrainQuad(“terrain”, 65, 513, mapData);

    List<Camera> cameras = new ArrayList<Camera>();

    cameras.add(getCamera());

    TerrainLodControl control = new TerrainLodControl(terrain, cameras);

    terrain.addControl(control);

    terrain.setMaterial(matRock);

    terrain.setModelBound(new BoundingBox());

    terrain.updateModelBound();

    terrain.setLocalScale(new Vector3f(2, 2, 2));



    terrainPhysicsNode = new RigidBodyControl(CollisionShapeFactory.createMeshShape(terrain), 0);

    terrain.addControl(terrainPhysicsNode);

    rootNode.attachChild(terrain);

    getPhysicsSpace().add(terrainPhysicsNode);

    }



    private void createCharacter() {

    CapsuleCollisionShape capsule = new CapsuleCollisionShape(1.5f, 2f);

    character = new CharacterControl(capsule, 0.01f);

    model = (Node) assetManager.loadModel(“Models/Oto/Oto.mesh.xml”);

    model.setName(“model”);

    model.setLocalScale(0.5f);

    model.addControl(character);

    character.setPhysicsLocation(new Vector3f(-140, 10, -10));

    rootNode.attachChild(model);

    getPhysicsSpace().add(character);







    }

    private void createArm(){

    /CapsuleCollisionShape armccs = new CapsuleCollisionShape(0.5f, 0.5f);

    armrbc = new GhostControl(armccs);

    armrbc.setPhysicsLocation(animationControl.getSkeleton().getBone(“arm.right”).getModelSpacePosition().add(new Vector3f(50,50,100)));

    armrbc.setPhysicsRotation(animationControl.getSkeleton().getBone(“arm.right”).getLocalRotation());





    armrbc.attachDebugShape(assetManager);

    model.addControl(armrbc);

    getPhysicsSpace().add(armrbc);
    /

    }

    private void setupChaseCamera() {

    flyCam.setEnabled(false);

    chaseCam = new ChaseCam(cam, model, inputManager);

    }

    private static final int Increment = 2;

    public static float[] Smooth(float[] HeightMap, int MapWidth, int Passes)

    {

    int Alternator = 0;

    for (int p = 0; p < Passes; p++)

    {

    for (int i = MapWidth + 1 + Alternator; i < HeightMap.length - MapWidth - 1 - Alternator; i += Increment)

    {

    // Each middle value equals the average point between the points around it

    HeightMap = ((HeightMap + HeightMap +

    HeightMap + HeightMap +

    HeightMap + HeightMap +

    HeightMap +

    HeightMap) / 8f);

    }

    if (Alternator == 0)

    Alternator = 1;

    else

    Alternator = 0;

    }

    return HeightMap;

    }

    private void setupAnimationController() {

    animationControl = model.getControl(AnimControl.class);

    animationControl.addListener(this);

    animationChannel = animationControl.createChannel();

    shootingChannel = animationControl.createChannel();

    shootingChannel.addBone(animationControl.getSkeleton().getBone(“uparm.right”));

    shootingChannel.addBone(animationControl.getSkeleton().getBone(“arm.right”));

    shootingChannel.addBone(animationControl.getSkeleton().getBone(“hand.right”));

    }



    @Override

    public void simpleUpdate(float tpf) {

    Vector3f camDir = cam.getDirection().clone().multLocal(0.2f);

    Vector3f camLeft = cam.getLeft().clone().multLocal(0.2f);

    camDir.y = 0;

    camLeft.y = 0;

    walkDirection.set(0, 0, 0);

    if (left) {

    walkDirection.addLocal(camLeft);

    }

    if (right) {

    walkDirection.addLocal(camLeft.negate());

    }

    if (up) {

    walkDirection.addLocal(camDir);

    }

    if (down) {

    walkDirection.addLocal(camDir.negate());

    }

    if (!character.onGround()) {

    airTime = airTime + tpf;

    } else {

    airTime = 0;

    }

    if (walkDirection.length() == 0) {

    if (!“stand”.equals(animationChannel.getAnimationName())) {

    animationChannel.setAnim(“stand”, 1f);

    }

    } else {

    character.setViewDirection(walkDirection);

    if (airTime > .3f) {

    if (!“stand”.equals(animationChannel.getAnimationName())) {

    animationChannel.setAnim(“stand”);

    }

    } else if (!“Walk”.equals(animationChannel.getAnimationName())) {

    animationChannel.setAnim(“Walk”, 0.7f);

    }

    }

    character.setWalkDirection(walkDirection);

    red.lookAt(character.getPhysicsLocation(),new Vector3f(0,1,0));

    npcvd.setX(npcvd.getX()+1);

    npcvd.setZ(npcvd.getZ()+1);







    //System.out.println(armrbc.getPhysicsLocation().toString());

    //System.out.println(animationControl.getSkeleton().getBone(“arm.right”).getModelSpacePosition().add(new Vector3f(50,50,100)).toString());

    //rootNode.getChild(“model1”).getLocalRotation().lookAt(rootNode.getChild(“model”).getWorldTranslation(), Vector3f.UNIT_Y);

    //model.lookAt(model1.getWorldTranslation(), Vector3f.ZERO);

    }



    public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals(“CharLeft”)) {

    if (value) {

    left = true;

    } else {

    left = false;

    }

    } else if (binding.equals(“CharRight”)) {

    if (value) {

    right = true;

    } else {

    right = false;

    }

    } else if (binding.equals(“CharUp”)) {

    if (value) {

    up = true;

    } else {

    up = false;

    }

    } else if (binding.equals(“CharDown”)) {

    if (value) {

    down = true;

    } else {

    down = false;

    }

    } else if (binding.equals(“CharSpace”)) {

    character.jump();

    } else if (binding.equals(“OpenDoor”)) {









    } else if (binding.equals(“CharShoot”) && !value) {

    if(value){

    bulletControl();

    }//else{

    //chaseCam.setEnabled(true);

    //}

    }

    }



    private void bulletControl() {

    shootingChannel.setAnim(“Dodge”, 0.1f);

    shootingChannel.setLoopMode(LoopMode.DontLoop);

    //Geometry bulletg = new Geometry(“bullet”, bullet);

    //bulletg.setMaterial(matBullet);

    //bulletg.setShadowMode(ShadowMode.CastAndReceive);

    //bulletg.setLocalTranslation(character.getPhysicsLocation().add(cam.getDirection().mult(2)));

    //RigidBodyControl bulletControl = new BombControl(bulletCollisionShape, 1);

    //bulletControl.setCcdMotionThreshold(0.1f);

    //bulletControl.setLinearVelocity(cam.getDirection().mult(80));

    // bulletg.addControl(bulletControl);

    //rootNode.attachChild(bulletg);

    //getPhysicsSpace().add(bulletControl);

    }



    public void collision(PhysicsCollisionEvent event) {

    if (event.getObjectA() instanceof BombControl) {

    final Spatial node = event.getNodeA();

    effect.killAllParticles();

    effect.setLocalTranslation(node.getLocalTranslation());

    effect.emitAllParticles();

    } else if (event.getObjectB() instanceof BombControl) {

    final Spatial node = event.getNodeB();

    effect.killAllParticles();

    effect.setLocalTranslation(node.getLocalTranslation());

    effect.emitAllParticles();

    }

    if(event.getObjectA() instanceof GhostControl){

    if(event.getObjectB().getCollisionShape() == character.getCollisionShape()&&((character1.getPhysicsLocation().x-character.getPhysicsLocation().x)+(character1.getPhysicsLocation().y-character.getPhysicsLocation().y)+(character1.getPhysicsLocation().z-character.getPhysicsLocation().z)<= 15)){

    System.out.println(“GOGOGOGOGOGO!!!”);

    //r.add(new Vector3f(3,0,3));

    model1.lookAt(character.getPhysicsLocation(), new Vector3f(0,0,0));

    character1.setWalkDirection(model1.getLocalRotation().getRotationColumn(2));

    character1.setWalkDirection(character1.getWalkDirection().addLocal(character1.getViewDirection().setY(0).normalize().multLocal(0.2f)));

    }

    }else if(event.getObjectB() instanceof GhostControl){

    if(event.getObjectA().getCollisionShape() == character.getCollisionShape()&&((character1.getPhysicsLocation().x-character.getPhysicsLocation().x)+(character1.getPhysicsLocation().y-character.getPhysicsLocation().y)+(character1.getPhysicsLocation().z-character.getPhysicsLocation().z)<= 15)){

    System.out.println(“GOGOGOGOGOGO!!!”);

    //r.add(new Vector3f(3,0,3));

    model1.lookAt(character.getPhysicsLocation(), new Vector3f(0,0,0));

    character1.setWalkDirection(model1.getLocalRotation().getRotationColumn(2));

    character1.setWalkDirection(character1.getWalkDirection().addLocal(character1.getViewDirection().setY(0).normalize().multLocal(0.2f)));

    }

    }else{

    character1.setWalkDirection(Vector3f.ZERO);



    }

    }



    public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {

    if (channel == shootingChannel) {

    channel.setAnim(“stand”);

    }

    }



    public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {

    }

    }[/java]



    I’m sure I’ve overlooked something…





    -NomNom

Just a quick reply as using phone. Remember that, as a physics object, your character will use the walk direction value on the physics tick, not the update. You can, of course, set the value in the update, but mske sure it is the value you want when the physics tick happens.