First Thanks to the people in the forum who gave me tips and helped me
Translation software always produces wrong translations
I need more information to understand
As I get deeper into JME,More and more problems were encountered
I can’t solve a camera problem these days
Look video
This video shows the offset and rotation of the shooting state camera
The question now video
The second video shows my problem, ChaseCamera doesn’t have the same perspective as the first video
package net.jmecn;
import com.jme3.scene.debug.Arrow;
import com.jme3.input.ChaseCamera;
import com.jme3.anim.AnimComposer;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.collision.shapes.HullCollisionShape;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.KeyInput;
import com.jme3.input.CameraInput;
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.AmbientLight;
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.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.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.jme3.scene.control.CameraControl.ControlDirection;
import com.jme3.scene.CameraNode;
import com.jme3.ui.Picture;
/**
* 按键发射小球轰击砖墙。
*
* @author yanmaoyuan
*
*/
public class HelloPhysics extends SimpleApplication implements ActionListener {
/**
* 开火,发射小球。鼠标左键触发。
*/
public final static String FIRE = "fire";
public final static String FORWARD = "forward";
public final static String BACKWARD = "backward";
public final static String LEFT = "left";
public final static String RIGHT = "right";
public final static String V = "v";
public final static String JUMP = "jump";
public int v1= 0;
//方向控制器
private CharacterControl player;
private Vector3f walkDirection = new Vector3f();
private Vector3f walkDirectioni = new Vector3f();
private boolean left = false, right = false, up = false, down = false, v=false;
/**
* 显示或隐藏BulletAppState的debug形状。按空格键触发。
*/
public final static String DEBUG = "debug";
// 临时变量,用于保存摄像机的方向。避免在simpleUpdate中重复创建对象。
private Vector3f camDir = new Vector3f();
private Vector3f camLeft = new Vector3f();
/** 砖块的尺寸 */
private static final float brickLength = 0.48f;
private static final float brickWidth = 0.24f;
private static final float brickHeight = 0.12f;
private AnimComposer control;
private BulletAppState bulletAppState;
private Node character;
private ChaseCamera chaseCam;
private CameraInput cameraInput;
@Override
public void simpleInitApp() {
createArrow(new Vector3f(5, 0, 0), ColorRGBA.Green);
createArrow(new Vector3f(0, 5, 0), ColorRGBA.Red);
createArrow(new Vector3f(0, 0, 5), ColorRGBA.Blue);
// cam.setLocation(new Vector3f(0, 4f, 6f));
// cam.lookAt(new Vector3f(2, 2, 0), Vector3f.UNIT_Y);
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
bulletAppState.setDebugEnabled(true);
// 初始化按键
initKeys();
// 初始化光照
initLight();
// 初始化场景
initScene();
// 添加图片
addPicture();
}
/**
* 创建一个箭头
*
* @param vec3 箭头向量
* @param color 箭头颜色
*/
private void createArrow(Vector3f vec3, ColorRGBA color) {
// 创建材质,设定箭头的颜色
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", color);
// 创建几何物体,应用箭头网格。
Geometry geom = new Geometry("arrow", new Arrow(vec3));
geom.setMaterial(mat);
// 添加到场景中
rootNode.attachChild(geom);
}
@Override
public void onAction(String name, boolean isPressed, float tpf) {
// if (isPressed) {
// if (FIRE.equals(name)) {
// shootBall();
// } else if (DEBUG.equals(name)) {
// boolean debugEnabled = bulletAppState.isDebugEnabled();
// bulletAppState.setDebugEnabled(!debugEnabled);
// }
// }
if (DEBUG.equals(name) && isPressed) {
boolean debugEnabled = bulletAppState.isDebugEnabled();
bulletAppState.setDebugEnabled(!debugEnabled);
} else if (LEFT.equals(name)) {
left = isPressed;
} else if (RIGHT.equals(name)) {
right = isPressed;
} else if (FORWARD.equals(name)) {
up = isPressed;
} else if (BACKWARD.equals(name)) {
down = isPressed;
}else if(V.equals(name)) {
if(!isPressed){
switch(v1){
case 0 :
chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, -2.5f).add(camLeft)); v1++;
break; //可选
case 1 :
chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, 0f)); v1=0;
break; //可选
//你可以有任意数量的case语句
default : //可选
//语句
}
// if(v1==0){
// chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, -2.5f).add(camLeft));
// v1++;
// }
//
// if(v1>1){
// System.err.println(v1+"按下0");
// chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, 0f));
// v1=0;
// }
}
v = isPressed;
}else if (JUMP.equals(name) && isPressed) {
if(player.onGround()==true){
player.jump();
player.warp(walkDirection);
}
System.err.println(player.onGround());
// player.warp(walkDirection);
}
}
/**
* 初始化按键输入
*/
private void initKeys() {
inputManager.addMapping(FIRE, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping(DEBUG, new KeyTrigger(KeyInput.KEY_F1));
inputManager.addMapping(LEFT, new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping(RIGHT, new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping(FORWARD, new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping(BACKWARD, new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping(JUMP, new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addMapping(V, new KeyTrigger(KeyInput.KEY_V));
inputManager.addListener(this, FIRE, DEBUG,LEFT,RIGHT,FORWARD,BACKWARD,JUMP,V);
}
/**
* 初始化光照
*/
private void initLight() {
// 环境光
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.3f, 0.3f, 0.3f, 1f));
// 阳光
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-1, -2, -3).normalizeLocal());
rootNode.addLight(ambient);
rootNode.addLight(sun);
}
/**
* 初始化场景
*/
private void initScene() {
model();
makeFloor();
// makeWall();
}
/**
* 制作地板
*/
private void makeFloor() {
// 网格
float radius = 100f;// 胶囊半径0.3米
float height = 0.1f;// 胶囊身高1.8米
float stepHeight = 100f;// 角色步高0.5米
Box floor = new Box(radius, height, stepHeight);
floor.scaleTextureCoordinates(new Vector2f(3, 6));
// 材质
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex = assetManager.loadTexture("Interface/pic.png");
tex.setWrap(WrapMode.Repeat);
mat.setTexture("ColorMap", tex);
// 几何体
Geometry geom = new Geometry("floor", floor);
geom.setMaterial(mat);
geom.setLocalTranslation(0, -1.8f, 0);// 将地板下移一定距离,让表面和xoz平面重合。
// 刚体
RigidBodyControl rigidBody = new RigidBodyControl(0);
geom.addControl(rigidBody);
rigidBody.setCollisionShape(new BoxCollisionShape(new Vector3f(radius, height, stepHeight)));
rigidBody.setFriction(10f);
rootNode.attachChild(geom);
bulletAppState.getPhysicsSpace().add(rigidBody);
}
/**
* 建造一堵墙
*/
private void makeWall() {
// 利用for循环生成一堵由众多砖块组成的墙体。
float startpt = brickLength / 4;
float height = 0;
for (int j = 0; j < 15; j++) {
for (int i = 0; i < 6; i++) {
Vector3f vt = new Vector3f(i * brickLength * 2 + startpt, brickHeight + height, 0);
makeBrick(vt);
}
startpt = -startpt;
height += 2 * brickHeight;
}
}
private void model() {
float radius = 0.5f;// 胶囊半径0.3米
float height = 3.3f;// 胶囊身高1.8米
float stepHeight = 0.5f;// 角色步高0.5米
//模型
character = new Node("Character");
Node model = (Node)assetManager.loadModel("Textures/jisi/Test/hecheng.j3o");
model.move(0, -(height/2+radius), 0);
//model.scale(1.8f);
character.attachChild(model);// 挂到角色根节点下
rootNode.attachChild(character);
control = model.getControl(AnimComposer.class);
control.setCurrentAction("walk");
control.setGlobalSpeed(2f);
// Geometry submesh = (Geometry) model.getChild("ç½æ ¼.003_4");
// HullCollisionShape hullCollisionShape = new HullCollisionShape(submesh.getMesh());
// //刚体
// RigidBodyControl rigidBody = new RigidBodyControl(hullCollisionShape,0f);
// rigidBody.setCollisionShape(new BoxCollisionShape(new Vector3f(10f, 0.1f, 5f)));
// bulletAppState.getPhysicsSpace().add(rigidBody);
// 使用胶囊体作为玩家的碰撞形状
CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(radius, height, 1);
// 使用CharacterControl来控制玩家物体
player = new CharacterControl(capsuleShape, stepHeight);
player.setJumpSpeed(10f);// 起跳速度
player.setFallSpeed(20f);// 坠落速度
player.setGravity(9.8f * 3);// 重力加速度
// player.setPhysicsLocation(new Vector3f(-999, 90, -99));// 直接改变这个角色的位置。
character.addControl(player);
bulletAppState.getPhysicsSpace().add(player);
// Disable the default flyby cam
// Disable the default flyby cam
// cam.setLocation(new Vector3f(10f, 0.1f, 5f));
// Enable a chase cam for this target (typically the player).
chaseCam = new ChaseCamera(cam, character, inputManager);
// inputManager.deleteMapping("ChaseCamZoomIn");
// inputManager.deleteMapping("ChaseCamZoomOut");
// //to disable rotation
// inputManager.deleteMapping(CameraInput.CHASECAM_TOGGLEROTATE);
// //to disable zoom out
inputManager.deleteMapping(CameraInput.CHASECAM_ZOOMOUT);
//to disable zoom in
inputManager.deleteMapping(CameraInput.CHASECAM_ZOOMIN);
flyCam.setEnabled(false);
chaseCam.setLookAtOffset(new Vector3f(0, 1.5f, 0));
//
// chaseCam.setSmoothMotion(true);//启用此追逐相机的平滑运动
// chaseCam.setTrailingEnabled(true);//启用相机尾随:相机在移动时平滑地进入目标轨迹。
chaseCam.setDragToRotate(false); //把鼠标锁定在窗口里
// chaseCam.setMinDistance(15f);
// chaseCam.setMaxDistance(15f);
// chaseCam.setMinVerticalRotation(0.01f);//设置摄像机围绕目标的最小垂直旋转角度,默认为 0; (说人话就是鼠标向下的最小角度)
// chaseCam.setMaxVerticalRotation(1f);//设置摄像机围绕目标的最大垂直旋转角度
// chaseCam.setZoomOutTrigger(new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
// chaseCam.setZoomInTrigger(new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
//System.err.println(chaseCam.getZoomSensitivity());
//chaseCam.setZoomSensitivity(10f);
// flyCam.setEnabled(true);
// flyCam.setDragToRotate(true);
// // Disable the default flyby cam
// flyCam.setEnabled(true);
// //create the camera Node
// CameraNode camNode = new CameraNode("CamNode", cam);
// //This mode means that camera copies the movements of the target:
// camNode.setControlDir(ControlDirection.SpatialToCamera);
// //Attach the camNode to the target:
// character.attachChild(camNode);
// //Move camNode, e.g. behind and above the target:
// camNode.setLocalTranslation(walkDirection);
// //Rotate the camNode to look at the target:
// camNode.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y);
}
/**
主循环
**/
@Override
public void simpleUpdate(float tpf) {
inputManager.setCursorVisible(false);
camDir.set(cam.getDirection()).multLocal(0.1f);
camLeft.set(cam.getLeft()).multLocal(0.1f);
camDir.y = 0;
camLeft.y = 0;
walkDirection.set(0, 0, 0);
// 计算运动方向
boolean changed = false;
if (left) {
walkDirectioni.addLocal(camLeft);
walkDirection.addLocal(camLeft);
changed = true;
}
if (right) {
walkDirectioni.addLocal(camLeft.negate());
walkDirection.addLocal(camLeft.negate());
changed = true;
}
if (up) {
walkDirectioni.addLocal(camDir);
walkDirection.addLocal(camDir);
changed = true;
}
if (down) {
walkDirectioni.addLocal(camDir.negate());
walkDirection.addLocal(camDir.negate());
changed = true;
}
if (v) {
// player.setViewDirection(walkDirectioni);
if(v){
}else{
}
// System.err.println();
changed = true;
}
if (changed) {
walkDirectioni.y = 0.0f;// 将行走速度的方向限制在水平面上。
walkDirectioni.normalizeLocal();// 单位化
walkDirectioni.multLocal(3f);// 改变速率
walkDirection.y = 0;// 将行走速度的方向限制在水平面上。
walkDirection.normalizeLocal();// 单位化
walkDirection.multLocal(0.3f);// 改变速率
}
if (walkDirection.length() != 0f) {
player.setViewDirection(walkDirection);
}
player.setWalkDirection(walkDirection);
// player.setAngularDamping(5f);
// player.setViewDirection(walkDirectioni);
// cam.setLocation(player.getPhysicsLocation());
}
/**
* 在指定位置放置一个物理砖块
*
* @param loc
* 砖块的位置
*/
private void makeBrick(Vector3f loc) {
// 网格
Box box = new Box(brickLength, brickHeight, brickWidth);
box.scaleTextureCoordinates(new Vector2f(1f, .5f));
// 材质
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex = assetManager.loadTexture("Interface/pic.png");
mat.setTexture("ColorMap", tex);
// 几何体
Geometry geom = new Geometry("brick", box);
geom.setMaterial(mat);
geom.setLocalTranslation(loc);// 把砖块放在指定位置
// 刚体
RigidBodyControl rigidBody = new RigidBodyControl(2f);
geom.addControl(rigidBody);
rigidBody.setCollisionShape(new BoxCollisionShape(new Vector3f(brickLength, brickHeight, brickWidth)));
rootNode.attachChild(geom);
bulletAppState.getPhysicsSpace().add(rigidBody);
}
/**
* 从摄像机所在位置发射一个小球,初速度方向与摄像机方向一致。
*/
private void shootBall() {
// 网格
Sphere sphere = new Sphere(32, 32, 0.4f, true, false);
sphere.setTextureMode(TextureMode.Projected);
// 材质
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
Texture tex = assetManager.loadTexture("Interface/pic.png");
mat.setTexture("ColorMap", tex);
// 几何体
Geometry geom = new Geometry("cannon ball", sphere);
geom.setMaterial(mat);
// 刚体
RigidBodyControl rigidBody = new RigidBodyControl(1f);
geom.addControl(rigidBody);
rigidBody.setCollisionShape(new SphereCollisionShape(0.5f));
rigidBody.setPhysicsLocation(cam.getLocation());// 位置
rigidBody.setLinearVelocity(cam.getDirection().mult(50));// 初速度
rootNode.attachChild(geom);
bulletAppState.getPhysicsSpace().add(rigidBody);
}
/**
* 加载“图片”
*
* @return
*/
private void addPicture() {
Picture pic = new Picture("picture");
// 设置图片
pic.setImage(assetManager, "Interface/pic_a.png", true);
// 设置图片全屏显示
pic.setWidth(cam.getWidth());
pic.setHeight(cam.getHeight());
// 将图片后移一个单位,避免遮住状态界面。
pic.setLocalTranslation(0, 0, -1);
guiNode.attachChild(pic);
}
public static void main(String[] args) {
HelloPhysics app = new HelloPhysics();
app.start();
}
}
chaseCam.setLookAtOffset(camDir.add(0f, 1.5f, -2.5f).add(camLeft))
I use this method to control camera offset
What misunderstandings might I have had about this approach
Is there any method or literature that can tell me how to achieve the visual Angle in the first video
If you are confused by my question, please tell me which sentence it is
I’ve learned a lot during this time thank you