A Question on lookAt()

Hi. When ever I try to use the lookAt(Vector3f pos, Vector3f up) method of my spatial, it doesn’t look at the position that I want it to. Am I missing something, or am I incorrectly using the method? Will I end up having to do my own math?

Just so everyone knows, I’ve got two Character Controls, one with a GhostControl on it with a SphereCollisionShape on that, and I’m trying to get it that when when CharacterControl hits that sphere the other looks at it, and walks in the direction.

Code:

[java]model1.lookAt(character.getPhysicsLocation(), new Vector3f(0,0,0));[/java]

(I’ve also used the model getLocalTranslation() and getWorldTranslation()… None seem to work.)

Another question, what is the up vector?



Thanks! Hopefully I provided enough information.



-NomNom



EDIT: I have gotten the collision with the GhostControl, I just can’t get the lookAt() down.

kinda guessing here:

is getPhysicsLocation() returning a local translation of character and are model1 and character in the same parent node(ie. they have the same World Transformation) ?

if they’re in different parent nodes you may want to account for each parent node’s transformation, maybe character.getParent() node has a different transformation(rot/pos/scale) than model1.getParent() node, and I’m assuming character.getPhysicsLocation returns a local translation… even if it’s a world translation it will only work if your model1’s world transform is non-transformed

Why is your up vector zero?



Did you read the docs for lookAt?

[java]/**

  • <code>lookAt</code> is a convienence method for auto-setting the local
  • rotation based on a position and an up vector. It computes the rotation
  • to transform the z-axis to point onto ‘position’ and the y-axis to ‘up’.
  • Unlike {@link Quaternion#lookAt} this method takes a world position to
  • look at not a relative direction.

    *
  • @param position
  •        where to look at in terms of world coordinates<br />
    
  • @param upVector
  •        a vector indicating the (local) up direction. (typically {0,<br />
    
  •        1, 0} in jME.)<br />
    

*/[/java]

1 Like

Thanks for your replies. It was very helpful. I figured out that my problem is that the CharacterControl is keeping it back -.- It works with regular nodes, but not with a node that has a control to it. I guess I’ll just have to work out the math? Has anyone else done that (been able to do lookAt() except with the setViewDirection/setWalkDirection)? Thanks for the help!





-NomNom

(though I admit, I don’t understand what you said xD )

maybe you want:

[java]com.jme3.math.Quaternion.lookAt(Vector3f direction, Vector3f up)[/java]

that is, if you want a lookAt with direction instead of position

used with:

[java]Spatial.setLocalRotation(Quaternion quaternion)[/java]

or Node.*

The character control has the viewDirection vector to determine its view direction. Have you tried setting that? I think the view direction will override the spatial direction in the update method of the character controller.



Matt

Here is my five-cents worth …



I would not use a Vector3f object where all the X, Y and Z values are ZERO. I bet that would totally confuse any method that is trying to compute an UP direction For most purposes, up is positive Y, (I think). So it may help to try your up vector as Vector3f.UNIT_Y … or something else that is not zero/zero/zero.

@cyuczieekc thank you! I’m sure this will work. I probably should’ve looked there… Let’s hope I can get that to work with the node (I don’t think the CharacterControl allows rotation…)



@mattm yeah, I think you’re right about the overriding… I have tried it, and it doesn’t want to work with me :frowning: (I tried the getPhysicsLocation, getLocalTranslation, and getWorldTranslation)



@alfinete I’m sure with inflation it’s more than 5 cents :wink: Yeah, I tried that and the others… I just happened to leave the (0,0,0) in my code there because I switched it back to test something… (I tried it out though, and with other things the (0,0,0) works just as well as (0,1,0)… I tried it on a regular node instead of a node with a physics control on it and it worked).



Thank you all for your help :slight_smile: . Let’s just hope I can use the rotation method since setViewDirection doesn’t seem to work -.-





-NomNom

In the update method of the character control it sets the direction of the spatial using the lookat method with the viewDirection and unity vector as arguments. Are you sure setting the view direction of the character controller doesnt work? If i had to guess i would say that the controlle you are doing your spatial transforms in comes before your character controller so effectively dont apply. When you have a character controller direction should be set via viewdirection and location via physicslocation.

I’ve tried tons of different locations… The character always looks off into the distance… Here’s the code:

[java]package test;





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.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.FastMath;

import com.jme3.math.Quaternion;

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.CartoonEdgeFilter;

import com.jme3.post.filters.DepthOfFieldFilter;

import com.jme3.post.filters.PosterizationFilter;

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.HillHeightMap;

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 main.NPC;



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, 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;

    ChaseCamera 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;

    Geometry red;



    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();

    setupFilter();

    setupNPC();

    }

    private void setupNPC(){

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

    SphereCollisionShape enemySphere = new SphereCollisionShape(20f);

    character1 = new CharacterControl(capsule, 0.01f);

    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("CharShoot", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));

    inputManager.addListener(this, "CharLeft");

    inputManager.addListener(this, "CharRight");

    inputManager.addListener(this, "CharUp");

    inputManager.addListener(this, "CharDown");

    inputManager.addListener(this, "CharSpace");

    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);



    arm = new Node("Node");

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

    armrbc = new RigidBodyControl(armccs, 0);

    armrbc.attachDebugShape(assetManager);

    rootNode.attachChild(arm);

    getPhysicsSpace().add(armrbc);

    }



    private void setupChaseCamera() {

    flyCam.setEnabled(false);

    chaseCam = new ChaseCamera(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);



    Vector3f rd = red.getWorldTranslation();

    character.setViewDirection(rd);

    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("CharShoot") && !value) {

    bulletControl();

    }

    }



    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()){

    System.out.println("GOGOGOGOGOGO!!!");

    }

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

    if(event.getObjectA().getCollisionShape() == character.getCollisionShape()){

    System.out.println("GOGOGOGOGOGO!!!");



    }

    }

    }



    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]



    Does it look at the red box for you? Thanks.





    -NomNom

i am a total noob, but after examining your code while bored here at work, i have found what i think might be a small snag…



under setupNPC() you have defined

[java]red.setLocalTranslation(character.getPhysicsLocation());[/java]

placing a red box at the same location as the player



then in simpleUpdate() you have

[java]red.lookAt(character.getPhysicsLocation(),new Vector3f(0,1,0));[/java]

having red box rotate to lookAt the very same location it occupies



but this is where i am guessing the issue really lies:

in simpleUpdate() you have

[java]

Vector3f rd = red.getWorldTranslation();

character.setViewDirection(rd);

[/java]

effectively telling the player control to rotate locally to face itself.

(if red is at character and character is looking at red)



i think you meant to have the model1 node characterControl “character1” to actually look at the red box which is at the (player) model node’s location, and have the red box rotate to face model1.



if so:

[java]

character.setWalkDirection(walkDirection);

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

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

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

Vector3f rd = red.getWorldTranslation();

character1.setViewDirection(rd);

[/java]



…should clear that up if i am guessing your desired scenario correctly, but i have not tested as i am at work and cannot run anything openGL here :cry:



ps. i am not sure what you are doing with Vector3f npcvd aside from incrementing X and Z so i left that alone.



hope that helped some.

Also, the view direction is a direction, not a location. You cant set view direction to look at a location.

If you want to do a look at using the spatial lookat logic you will need to disable the use of teh view direction in the character controller:



setUseViewDirection(false).



Otherwise, you will need to make sure the view direction is set in the direction you want. You could do this by setting the spatial to look at what you want and then taking the vector of the second rotation axis to give you the direction (view direction).



x.lookAt(LocationVector)



character.setViewDirection(x.getLocalRotation().getRotationAxis(2));



Note that there are 2 look ats. The one on the spatial looks at a location. The one on the Quaternion sets the quat to look in a specific direction.

I’m so sorry for the long reply. The forum didn’t send me an email… lol…



mattm: I actually realized this today before I read your post. I wish I had known that you replied, because I would be much further on with my project -.- anyways, thanks! For some reason I thought that setViewDirection() was the same thing as lookAt()… I have no idea why I thought that, especially after I read through my code a couple of times and the use of it with the player wasn’t making sense with my idea of it… I wish the CharacterControl had a lookAt()…



Decoy: Thanks for checking over things. Yeah… I completely forgot about that translation bit… but “red” was just so I could see if lookAt() worked (which it did). I guess I should’ve explained my problem a bit better… Now I just have to go back over the Beginner Math and try to get some rotations working





-NomNom

@mattm I went over things again and it worked! Thanks! Now I’m just having a bit of trouble stopping my character, but that’s at a different post…