如何让相机跟随2个物体?

时间:2013-11-26 09:49:15

标签: java object camera jmonkeyengine

我正在制作我的第一款3D游戏,这是一种街头霸王/铁拳游戏。我已经看到了一些相机模式的工作原理,即。 chasecam和camnode。我不知道的是如何使相机同时跟随两个玩家。我希望相机在玩家彼此靠近时放大,并在没有玩家时放大。

我很感激任何有关想法或可能的解决方案的帮助。

由于

1 个答案:

答案 0 :(得分:1)

如果您知道两条信息,您希望相机在哪里以及您希望它看起来在哪里,您可以非常轻松地手动设置相机位置。

相机应该看起来

这是最容易确定的事情,相机应该看着两个物体的中间位置。一旦您知道可以使用

设置相机的位置
Vector3f boxsCentre=box1.getWorldTranslation().add(box2.getWorldTranslation()).mult(0.5f);
cam.lookAt(boxsCentre, Vector3f.UNIT_Y);

相机应该在哪里

相机应该更加棘手。你知道它应该在线的某个地方,从两个物体的中心沿垂直于这两个物体之间的线的方向延伸。谢天谢地,十字架产品给了我们这个。我们希望相机始终与物体处于同一水平,因此通过直接向上的矢量穿过分离矢量,我们得到垂直线

Vector3f seperationVector=box2.getWorldTranslation().subtract(box1.getWorldTranslation());
Vector3f perpendicularFromTheAction= seperationVector.cross(Vector3f.UNIT_Y);

perpendicularFromTheAction.normalizeLocal();

所以,这给了我们一条线,但我们应该把相机放在哪里。我只是玩弄了这个,发现两次物体之间的距离很好看,所以

float distance=2*seperationVector.length();
Vector3f newCameraLocation=boxsCentre.add(perpendicularFromTheAction.mult(distance));

然后您可以设置摄像机位置

cam.setLocation(newCameraLocation);

全部放在一起

我已经将这个代码与两个正在循环移动的盒子一起使用来演示这个,因为你可以看到你得到你想要的效果

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.*;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;

public class FightTest extends SimpleApplication {

    Geometry box1;
    Geometry box2;
    public static void main(String[] args) {
        FightTest app = new FightTest();
        app.start();
    }

    @Override
    public void simpleInitApp() {

        //put in some reference boxes
        for(int i=-20;i<=20;i+=20){
            for(int j=-20;j<=20;j+=20){
                if (j!=0||i!=0){
                    Geometry referenceBox = createBox(ColorRGBA.Red);
                    referenceBox.setLocalTranslation(i, 0, j);
                    rootNode.attachChild(referenceBox);
                }

            }
        }

        //put in our two players
        box1 = createBox(ColorRGBA.Blue);
        box1.setLocalTranslation(5, 0, 0);

        box2 = createBox(ColorRGBA.Green);

        rootNode.attachChild(box1);
        rootNode.attachChild(box2);
    }

    private Geometry createBox(ColorRGBA color){

        Box b = new Box(Vector3f.ZERO, 1, 1, 1);
        Geometry box = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", color);
        box.setMaterial(mat);

        return box;
    }

    @Override
    public void simpleUpdate(float tpf) {
        adjustCam();
        movePlayers(tpf);
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }

    private void adjustCam(){
        //we want our camera to look at the centre of the boxes
        Vector3f boxsCentre=box1.getWorldTranslation().add(box2.getWorldTranslation()).mult(0.5f);

        cam.lookAt(boxsCentre, Vector3f.UNIT_Y);

        //we also want our camera to move closer/further away as the boxes seperate.
        //and move around so its always parallel to the action

        //parallel to the action means on the line given by the cross product of the
        //box seperation and the upwards vector

        Vector3f seperationVector=box2.getWorldTranslation().subtract(box1.getWorldTranslation());
        Vector3f perpendicularFromTheAction= seperationVector.cross(Vector3f.UNIT_Y);

        perpendicularFromTheAction.normalizeLocal();

        //we could (and you should) get complicated on exactly how far the camera should 
        //move backwards, but I'm just going to make the camera twice as far away as the 
        //objects are seperated 
        float distance=2*seperationVector.length();

        Vector3f newCameraLocation=boxsCentre.add(perpendicularFromTheAction.mult(distance));

        cam.setLocation(newCameraLocation);
    }

    float timeAccumulator=0; 
    private void movePlayers(float tpf){
        //basic movement, just for demo
        timeAccumulator+=tpf;

        if (timeAccumulator<2){
            box1.move(new Vector3f(5f*tpf,0,0));
            box2.move(new Vector3f(0,0,5f*tpf));
        }else if (timeAccumulator<4){
            box1.move(new Vector3f(-5f*tpf,0,0));
            box2.move(new Vector3f(0,0,-5f*tpf));
        }else{
             timeAccumulator=0;
        }

    }
}