I made a simple move with the ray but I kept having problems with the Y-axis can you briefly tell me how you made the Y-axis fit the ground without shaking
movedemo.jar
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package mygame;
import camera.TerrainChaseCamera;
import com.jme3.app.DebugKeysAppState;
import com.jme3.app.SimpleApplication;
import com.jme3.app.StatsAppState;
import com.jme3.audio.AudioListenerState;
import com.jme3.collision.CollisionResults;
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.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;
/**
*
* @author Icyboxs
*/
public class movedemo extends SimpleApplication implements ActionListener{
private TerrainChaseCamera chaseCam;
private CollisionResults results = new CollisionResults();
public Node model = new Node("model");
public Node camNode = new Node("cam");
public Node terrainNode = new Node("terrainNode");
public boolean left = false, right = false, up = false, down = false, v = false,isPresseds=false;
public final static String BUTTON_LEFT = " BUTTON_LEFT";
public final static String DEBUG = "DEBUG";
public final static String DEBUG1 = "DEBUG1";
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 Vector3f camDir = new Vector3f();
public Vector3f camLeft = new Vector3f();
private Ray ray=new Ray();
public movedemo(){
super(
new StatsAppState(),
new AudioListenerState(),
new DebugKeysAppState()
);
}
public static void main(String[] args) {
movedemo app = new movedemo();
app.start();
}
@Override
public void simpleInitApp() {
Box b = new Box(10, 10, 10);
Geometry geom = new Geometry("Box", b);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Blue);
geom.setMaterial(mat);
geom.move(0, 10, 0);
Box b2 = new Box(10, 10, 10);
Geometry geom2 = new Geometry("Box", b);
Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat2.setColor("Color", ColorRGBA.Green);
geom2.setMaterial(mat2);
rootNode.attachChild(geom2);
Box box = new Box(500, 2, 500);
Geometry geom1 = new Geometry("Box", box);
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setColor("Color", ColorRGBA.White);
geom1.setMaterial(mat1);
camNode.setLocalTranslation(0, 5, 0);
model.attachChild(geom);
model.attachChild(camNode);
System.err.println(terrainNode.getChildren());
terrainNode.attachChild(geom1);
rootNode.attachChild(terrainNode);
rootNode.attachChild(model);
initKeys();
TerrainCollisionCamera();
}
@Override
public void simpleUpdate(float tpf) {
//TODO: add update code
terrainNode.collideWith(RayCollision(), results);
CameraCollision(results);
RoleMove();
}
public void TerrainCollisionCamera() {
chaseCam = new TerrainChaseCamera(cam, model.getChild("cam"), inputManager,this);
chaseCam.setDebugFrustum(false);
// chaseCam.createCameraFrustum();// 开启DEBUG 相机
chaseCam.setCameraCollisionDetection(true, "terrainNode");//开启地形碰撞设置地形名称
chaseCam.setDragToRotate(false); //把鼠标锁定在窗口里
chaseCam.setCursorVisible(false);//设置光标不可见
chaseCam.setInvertVerticalAxis(true);//反转鼠标的垂直轴移动
chaseCam.setMinDistance(1f);
chaseCam.setMaxDistance(1000f);
chaseCam.setDefaultVerticalRotation(0);
chaseCam.setMinVerticalRotation(-1.57f);
}
private void initKeys() {
inputManager.addMapping(BUTTON_LEFT, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addMapping(DEBUG, new KeyTrigger(KeyInput.KEY_F1));
inputManager.addMapping(DEBUG1, new KeyTrigger(KeyInput.KEY_F2));
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, BUTTON_LEFT, DEBUG, DEBUG1, LEFT, RIGHT, FORWARD, BACKWARD, JUMP, V);
}
@Override
public void onAction(String name, boolean bln, float f) {
if (FORWARD.equals(name)){
if(bln){
System.err.println("按下W");
up=true;
}else if(!bln){
System.err.println("弹起W");
up=false;
}
}else if (BACKWARD.equals(name)){
if(bln){
System.err.println("按下S");
down=true;
}else if(!bln){
System.err.println("弹起S");
down=false;
}
}else if (LEFT.equals(name)){
if(bln){
System.err.println("按下A");
left = true;
}else if(!bln){
System.err.println("弹起A");
left = false;
}
}else if (RIGHT.equals(name)){
if(bln){
System.err.println("按下D");
right = true;
}else if(!bln){
System.err.println("弹起D");
right = false;
}
}else if (V.equals(name)){
if(bln){
System.err.println("按下V");
model.move(0,0,0);
}else if(!bln){
System.err.println("弹起V");
}
}
}
public void RoleMove() {
camDir.set(cam.getDirection()).multLocal(0.5f);
camLeft.set(cam.getLeft()).multLocal(0.5f);
System.err.println(camDir.y+","+camLeft.y);
if(up){
model.move(camDir);
}else if(down){
model.move(camDir.negate());
}else if(left){
model.move(camLeft);
}else if(right){
model.move(camLeft.negate());
}
}
public Ray RayCollision() {
ray.setOrigin(model.getChild("cam").getWorldTranslation());
ray.setDirection(model.getChild("cam").getLocalTranslation().normalize().negate());
ray.setLimit((float)100);
return ray;
}
private void CameraCollision(CollisionResults results) {
System.err.println(results.size());
/**
* 判断检测结果 Judgment ray result
*/
if (results.size() > 0) {
// 离射线原点最近的交点
Vector3f closest = results.getClosestCollision().getContactPoint();
// 离射线原点最远的交点
Vector3f farthest = results.getFarthestCollision().getContactPoint();
// 离射线原点最近的距离
float ClosestDist = results.getClosestCollision().getDistance();
float FarthestDist = results.getFarthestCollision().getDistance();
if(ClosestDist<10){
// camDir.y=(float) 1.0;
// camLeft.y=(float) 1.0;
}else if(ClosestDist>10){
// camDir.y=(float) -1.0;
// camLeft.y=(float) -1.0;
}
System.err.println("最近点(Nearest point),"+ClosestDist);
System.err.println("最远点(Farthest point),"+FarthestDist);
results.clear();
}else{
}
}
}
TerrainChaseCamera.jar
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package camera;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.AssetManager;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.CameraInput;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.input.ChaseCamera;
import com.jme3.input.InputManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.debug.WireFrustum;
import com.jme3.shadow.ShadowUtil;
import java.util.Objects;
import java.util.logging.Logger;
/**
*
* @author Icyboxs
*/
public class TerrainChaseCamera extends ChaseCamera {
private static Logger log =Logger.getLogger(TerrainChaseCamera.class.toString());
private float maxDistances=10f;
private Quaternion quaternion= new Quaternion();
private Vector3f afterVector= new Vector3f();
protected boolean DebugFrustum= false;
protected boolean CameraCollisionDetection= false;
private SimpleApplication simpleApp;
private CollisionResults results = new CollisionResults();
private String ChildName;
private boolean CursorVisible =true;
// 射线
private Ray ray=new Ray();
public TerrainChaseCamera(Camera cam, Spatial target, InputManager inputManager,SimpleApplication simpleApp) {
super(cam, target, inputManager);
this.simpleApp=simpleApp;
}
public TerrainChaseCamera(Camera cam, Spatial target, InputManager inputManager) {
super(cam, target, inputManager);
}
/**
* 使用射线检测,判断离摄像机最近的点。
*/
public Ray RayCollision() {
ray.setOrigin(targetLocation);
ray.setDirection(cam.getLocation().subtract(targetLocation).normalize());
// System.err.println(ray.getDirection());
return ray;
}
public Camera getcam(){
return cam;
}
/**
* Set whether the mouse cursor should be visible or not.
*
* @param visible whether the mouse cursor should be visible or not.
*/
public boolean getCursorVisible(){
return this.CursorVisible;
}
public boolean setCursorVisible(boolean CursorVisible){
return this.CursorVisible=CursorVisible;
}
/**
* 是否开启DEBUG相机
*
*
*/
public boolean getDebugFrustum(){
return this.DebugFrustum;
}
public boolean setDebugFrustum(boolean DebugFrustum){
if(DebugFrustum){
createCameraFrustum();
}
return this.DebugFrustum=DebugFrustum;
}
/**
* 相机地形碰撞状态
*
*
*/
public boolean getCameraCollisionDetection(){
return this.CameraCollisionDetection;
}
/**
* 开启相机地形碰撞 设置开启和碰撞地形名称
*/
public boolean setCameraCollisionDetection(boolean CameraCollisionDetection,String ChildName){
if(CameraCollisionDetection){
this.ChildName=ChildName;
return this.CameraCollisionDetection=CameraCollisionDetection;
}else{
this.ChildName=ChildName;
return this.CameraCollisionDetection=CameraCollisionDetection;
}
}
/**
* update the camera control, should only be used internally
*
* @param tpf time per frame (in seconds)
*/
@Override
public void update(float tpf) {
updateCamera(tpf);
updateCameraExtension(tpf);
}
/**
*追逐相机扩展功能
*@param tpf time per frame (in seconds)
**/
public void updateCameraExtension(float tpf) {
inputManager.setCursorVisible(CursorVisible);
if(DebugFrustum){
simpleApp.getRootNode().getChild("Viewing.Frustum").setLocalTranslation(cam.getLocation());
simpleApp.getRootNode().getChild("Viewing.Frustum").setLocalRotation(cam.getRotation());
}
if(CameraCollisionDetection){
//射线检测
if(ChildName == null){
}else{
simpleApp.getRootNode().getChild(ChildName).collideWith(RayCollision(), results);
CameraCollision(results);
}
}
}
public void createCameraFrustum() {
//this.DebugFrustum=true;
Vector3f[] points = new Vector3f[8];
for (int i = 0; i < 8; i++) {
points[i] = new Vector3f();
}
Camera frustumCam = cam.clone();
frustumCam.setLocation(new Vector3f(0, 0, 0));
frustumCam.lookAt(Vector3f.UNIT_Z, Vector3f.ZERO);
ShadowUtil.updateFrustumPoints2(frustumCam, points);
Mesh mesh = WireFrustum.makeFrustum(points);
Geometry frustumGeo = new Geometry("Viewing.Frustum", mesh);
Material mat = new Material( simpleApp.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("Color", ColorRGBA.Red);
frustumGeo.setMaterial(mat);
frustumGeo.setCullHint(Spatial.CullHint.Never);
frustumGeo.setShadowMode(RenderQueue.ShadowMode.Off);
simpleApp.getRootNode().attachChild(frustumGeo);
}
/**
* 控制相机碰撞地形缩放
*
* @param results
*/
private void CameraCollision(CollisionResults results) {
// System.err.println("碰撞结果:" + results.size());
// System.err.println("射线:" + ray);
/**
* 判断检测结果
*/
if (results.size() > 0) {
// 从近到远,打印出射线途径的所有交点。
// for (int i = 0; i < results.size(); i++) {
// CollisionResult result = results.getCollision(i);
//
// float dist = result.getDistance();
// Vector3f point = result.getContactPoint();
// Vector3f normal = result.getContactNormal();
// Geometry geom = result.getGeometry();
// System.err.printf("序号:%d, 距离:%.2f, 物体名称:%s, 交点:%s, 交点法线:%s\n", i, dist, geom.getName(), point, normal);
// }
// 离射线原点最近的交点
Vector3f closest = results.getClosestCollision().getContactPoint();
// 离射线原点最远的交点
Vector3f farthest = results.getFarthestCollision().getContactPoint();
// 离射线原点最近的距离
float ClosestDist = results.getClosestCollision().getDistance();
float FarthestDist = results.getFarthestCollision().getDistance();
if(ClosestDist<=maxDistances){
targetDistance=ClosestDist;
// float incrimentDistance = (-distance+dist1); // might need subtracted in opposite order
//
// zoomCamera(incrimentDistance);
}else{
}
//System.err.printf("最近点:%s, 最远点:%s\n", closest, farthest);
// System.err.printf("离射线原点最近的距离:%s\n", dist);
results.clear();
}else{
//setMinDistance(10f);
//setMaxDistance(10f);
// zoomCamera(10f);
// zoomCamera(10);getMaxDistance()
targetDistance=maxDistances;
// System.err.printf("getDistanceToTarget:%s\n", getDistanceToTarget());
}
// System.err.printf("maxDistances:%s\n", maxDistances);
// System.err.printf("minDistance:%s\n", minDistance);
// System.err.println(distance);
}
@Override
public void onAnalog(String name, float value, float tpf) {
if (name.equals(CameraInput.CHASECAM_MOVELEFT)) {
rotateCamera(-value);
} else if (name.equals(CameraInput.CHASECAM_MOVERIGHT)) {
rotateCamera(value);
} else if (name.equals(CameraInput.CHASECAM_UP)) {
vRotateCamera(value);
} else if (name.equals(CameraInput.CHASECAM_DOWN)) {
vRotateCamera(-value);
} else if (name.equals(CameraInput.CHASECAM_ZOOMIN)) {
zoomCamera(-value);
maxDistances += -value * zoomSensitivity;
if(maxDistances<minDistance){
maxDistances=minDistance;
}
if (zoomin == false) {
distanceLerpFactor = 0;
}
zoomin = true;
} else if (name.equals(CameraInput.CHASECAM_ZOOMOUT)) {
maxDistances += value * zoomSensitivity;
if(maxDistances>maxDistance){
maxDistances=maxDistance;
}
zoomCamera(+value);
if (zoomin == true) {
distanceLerpFactor = 0;
}
zoomin = false;
}
}
}
I commented out ray’s judgment on the Y-axis.
Please point out if there is any problem with the above code.
Let me know if you have any ideas.
private void CameraCollision(CollisionResults results) {
System.err.println(results.size());
/**
* 判断检测结果 Judgment ray result
*/
if (results.size() > 0) {
// 离射线原点最近的交点
Vector3f closest = results.getClosestCollision().getContactPoint();
// 离射线原点最远的交点
Vector3f farthest = results.getFarthestCollision().getContactPoint();
// 离射线原点最近的距离
float ClosestDist = results.getClosestCollision().getDistance();
float FarthestDist = results.getFarthestCollision().getDistance();
if(ClosestDist<10){
// camDir.y=(float) 1.0;
// camLeft.y=(float) 1.0;
}else if(ClosestDist>10){
// camDir.y=(float) -1.0;
// camLeft.y=(float) -1.0;
}
System.err.println("最近点(Nearest point),"+ClosestDist);
System.err.println("最远点(Farthest point),"+FarthestDist);
results.clear();
}else{
}
}
This control ray detects the distance between the blue box mounted camNode and the ground
My idea is very simple. If the ray that we’re looking down detects that the current position intersects the ray below a certain value, we increase the Y-axis value Otherwise vice versa.
But there are still a lot of problems in the actual operation,
It’s not as smooth as in your video