Sorry for activating this thread again.
When I click on areas 1 and 4 the model doesn’t tilt and rotate like an aeroplane as I would
But if the destination is at 2 or 3 and the model is tilted (turned like an aeroplane) the way I want it to be
But I don’t know what happened, maybe the code itself is wrong knowledge coincidentally happened
If there is a better way to do these please let me know thanks a lot!
/*
* 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 SelectUnit.Hominini;
import CameraAndMouse.RayMap;
import FindPath.FindPath;
import FindPath.Tools;
import static SelectUnit.Hominini.T100.i;
import SelectUnit.UnitControl;
import SelectUnit.UnitGlobalData;
import com.dongbat.walkable.FloatArray;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.collision.ContactListener;
import com.jme3.bullet.collision.PhysicsCollisionEvent;
import com.jme3.bullet.collision.PhysicsCollisionListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.GhostControl;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import mygame.Main;
import org.dyn4j.geometry.Vector2;
import physicsState.MinieBulletAppState;
import physicsState.dyn4j.BodyControl;
import scenario.NestedArrayList;
import scenario.scenarioState;
import static scenario.scenarioState.mapGrid3D;
/**
*
* @author icyboxs
*/
public class T100Control extends AbstractControl implements ContactListener, UnitControl,PhysicsCollisionListener {
//停止距离
private float STOPPING_DISTANCE = 2.5f;
public SimpleApplication simpleApp;
List<Vector3f> move = new ArrayList<Vector3f>();
int imove = 0;
private Vector3f moveTo = null;
private float moveSpeed = 0.5f; // 设置移动速度
Quaternion targetQua = new Quaternion();
private Vector3f previousGridPosition=new Vector3f();
private Vector3f spatialPreviousGridPosition = new Vector3f();
private float length;
private int Cellsize = (int) mapGrid3D.getCellsize();
private int CurrentState = 0;
private final int MoveState = 1;
private final int WaitState = 2;
private float AverageDistance=0;
private int FieldOfView=128;//视野范围
private ArrayList<Integer> VisionRange = new ArrayList<>();
/**
* @return the CurrentState
*/
public int getCurrentState() {
return CurrentState;
}
public T100Control(SimpleApplication app,Vector3f v3f,Spatial Role) {
this.simpleApp = app;
this.setSpatial(Role);
this.spatial.setLocalScale(3f, 3f, 3f);
this.spatial.setLocalTranslation(v3f);
this.spatial.setUserData("CombatantsUnitNode", i);
this.spatial.setUserData("Type", "CombatUnit");
this.spatial.setShadowMode(RenderQueue.ShadowMode.Cast);
this.spatial.setQueueBucket(RenderQueue.Bucket.Transparent);
Node GhostPhysicsNode = new Node();
GhostControl ghostControl = new GhostControl(new CapsuleCollisionShape(8f, 4f));
MinieBulletAppState.bulletAppState.getPhysicsSpace().add(ghostControl);
GhostPhysicsNode.addControl(ghostControl);
GhostPhysicsNode.move(0, 0.9f, 0);
((Node)this.spatial).attachChild(GhostPhysicsNode);
}
public void setPath(FloatArray floatArray) {
this.move.clear();
time = 0;
for (int i = 0; i < floatArray.size; i += 2) {
float x = (float) floatArray.get(i);
float y = 0.0f;
float z = (float) floatArray.get(i + 1);
Vector3f vector = new Vector3f(x, y, z);
this.move.add(vector);
}
}
public void setPath(FloatArray floatArray,float AverageDistance) {
this.AverageDistance=AverageDistance;
setPath(floatArray);
}
float FOWtime = 0;
@Override
protected void controlUpdate(float tpf) {
if (spatial != null) {
// if (imove < move.size() - 1) {
if (!move.isEmpty()) {
CurrentState = MoveState;
// var s=spatial.getUserData("CombatantsUnitNode");
// System.err.println(s);
// 获取当前空间位置
Vector3f currentWorldPosition = spatial.getLocalTranslation();
// 将世界位置转换为网格坐标
Vector3f currentGridPosition = new Vector3f((int) currentWorldPosition.x / Cellsize, 0, (int) currentWorldPosition.z / Cellsize);
// 判断位置是否改变
// this.FOWtime += tpf;
// if (this.FOWtime > 0.25) {
if (!currentGridPosition.equals(previousGridPosition)) {
// 位置已更改,执行相应的操作
// ...
getVisionRange().clear();
VisionRange = scenarioState.setFowImag((int) spatial.getLocalTranslation().x, (int) spatial.getLocalTranslation().z, scenarioState.raster,FieldOfView);
// simpleApp.enqueue(new Runnable() {
// @Override
// public void run() {
// getVisionRange().clear();
// //scenarioState.setFowImagAlphai((int)previousGridPosition.x*Cellsize, (int) previousGridPosition.z*Cellsize, scenarioState.raster);
// VisionRange = scenarioState.setFowImag((int) spatial.getLocalTranslation().x, (int) spatial.getLocalTranslation().z, scenarioState.raster,FieldOfView);
// }
// });
// System.out.println((int)spatial.getLocalTranslation().x+","+(int) spatial.getLocalTranslation().z+"----spatial");
// System.out.println(previousGridPosition.x*Cellsize+","+previousGridPosition.z*Cellsize+"----previousGridPosition");
// 更新前一网格坐标
previousGridPosition = currentGridPosition;
}
// this.FOWtime = 0;
// }
MoveWork(this.spatial, tpf);
} else {
CurrentState = WaitState;
}
}
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
@Override
public void setSpatial(Spatial spatial) {
super.setSpatial(spatial);
MinieBulletAppState.bulletAppState.getPhysicsSpace().addContactListener(this);
MinieBulletAppState.bulletAppState.getPhysicsSpace().addCollisionListener(this);
}
/**
* 让物体按照寻路给出的坐标进行移动
*
* @param spatial
* @param tpf
*/
float time = 0;
private float interp = 0.0f;
protected void MoveWork(Spatial spatial, float tpf) {
Vector3f currentPoint = spatial.getLocalTranslation();
Vector3f nextPoint = this.move.get(0);
// 计算节点朝下一个点移动的步进
//float t = Math.min(tpf, maxT);
Vector3f step = nextPoint.subtract(currentPoint).normalizeLocal().multLocal(tpf).multLocal(50f);
//Vector3f step = currentPoint.interpolateLocal(nextPoint, 1.5f*tpf);
step.setY(0);//设置高度
//旋转
Quaternion rotation = spatial.getLocalRotation();
// Vector3f directionToTarget=nextPoint.subtract(currentPoint).normalize();
// Vector3f up = Vector3f.UNIT_Z;
// Vector3f crossProduct = Dir.cross(up);
Vector3f directionToTarget=nextPoint.subtract(currentPoint).normalize();
// 当前单位的朝向方向(假设朝向方向是Z轴方向)
Vector3f forward = rotation.mult(Vector3f.UNIT_Z);
// 计算叉积来判断目标在朝向的左侧还是右侧
Vector3f crossProduct = forward.cross(directionToTarget);
System.out.println(crossProduct);
if (crossProduct.y < 0) {
System.out.println("目标在单位的右边。");
targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(1, 0, 1));
rotation.nlerp(targetQua, 10f*tpf);
} else if (crossProduct.y > 0) {
System.out.println("目标在单位的左边。");
targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(0, 0, -1));
// rotation.nlerp(targetQua, 10f*tpf);
rotation.slerp(targetQua, 1f*tpf);
}
// Vector3f Dir=nextPoint.subtract(currentPoint);
// Vector3f up = Vector3f.UNIT_Z;
// Vector3f crossProduct = Dir.cross(up);
// // 判断象限
// System.out.println(Dir);
// if (Dir.x > 0 && Dir.z > 0) {
// System.out.println("目标位于第一象限。");
// targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(1, 0, 0));
// rotation.nlerp(targetQua, 1f*tpf);
// } else if (Dir.x < 0 && Dir.z > 0) {
// targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(0, 0, 1));
// rotation.nlerp(targetQua, 1f*tpf);
// System.out.println("位于第二象限");
// } else if (Dir.x < 0 && Dir.z < 0) {
// targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(-1, 0, 0));
// rotation.nlerp(targetQua, 1f*tpf);
// System.out.println("位于第三象限");
// } else if (Dir.x > 0 && Dir.z < 0) {
// targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(0, 0, -1));
// rotation.nlerp(targetQua, 1f*tpf);
// System.out.println("位于第四象限");
// } else {
// System.out.println("目标 位于原点,或者太靠近原点而无法确定。");
// }
// targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(0, 1, 0));
// rotation.nlerp(targetQua, 1f*tpf);
//移动
spatial.move(step);
// 检查是否已经到达下一个点getLocalTranslation
float distanceToNextPoint = spatial.getWorldTranslation().distance(nextPoint);
//System.err.println(distanceToNextPoint);
if (distanceToNextPoint < STOPPING_DISTANCE+(UnitGlobalData.getInstance().getGroup().size()*0.25f)) {
// 如果已经到达下一个点,更新当前路径索引
//imove++;
this.move.remove(0);
}
// this.time += tpf;
//
// if (this.time > 0.5) {
// System.err.println(this.spatial.getLocalTranslation()+"1秒内");
//
// float distance = this.spatial.getWorldTranslation().distance(this.spatialPreviousGridPosition);
// System.err.println(distance + ",distance123");
// if (distance<3f && getCurrentState()==1) {
//
// System.err.println("停止移动");
// this.move.clear();
// } else {
//
// }
//
// this.spatialPreviousGridPosition.set(this.spatial.getWorldTranslation()) ;
// System.err.println(this.spatialPreviousGridPosition);
// this.time = 0;
// }
}
public void collision(T100Control controlA, T100Control controlB, Spatial objectAParent, Spatial objectBParent, Vector3f worldTranslationA, Vector3f worldTranslationB){
if(controlB.getCurrentState() == 2 || controlA.getCurrentState() == 2){
if (controlB.getCurrentState() == 2 && controlB == this) {
Vector3f local = worldTranslationB.subtract(worldTranslationA).normalizeLocal();
try {
FloatArray path = FindPath.getInstance().PathFinding(worldTranslationB.x, worldTranslationB.z, worldTranslationB.add(local.mult(20f)).x, worldTranslationB.add(local.mult(20f)).z, 2);
controlB.setPath(path);
} catch (Exception e) {
}
if (UnitGlobalData.getInstance().getGroup().contains((Node) objectBParent) && UnitGlobalData.getInstance().getGroup().contains((Node) objectAParent)) {
if (UnitGlobalData.getInstance().getGroup().contains((Node) objectBParent) && UnitGlobalData.getInstance().getGroup().contains((Node) objectAParent)) {
controlA.move.clear();
}
}
} else if (controlA.getCurrentState() == 2 && controlA == this) {
Vector3f local = worldTranslationA.subtract(worldTranslationB).normalizeLocal();
//((Spatial) pcoA.getUserObject()).getParent().setLocalTranslation(this.spatial.getWorldTranslation().add(local.setY(0)));
try {
FloatArray path = FindPath.getInstance().PathFinding(worldTranslationA.x, worldTranslationA.z, worldTranslationA.add(local.mult(20f)).x, worldTranslationA.add(local.mult(20f)).z, 2);
controlA.setPath(path);
} catch (Exception e) {
}
if (UnitGlobalData.getInstance().getGroup().contains((Node) objectBParent) && UnitGlobalData.getInstance().getGroup().contains((Node) objectAParent)) {
if (UnitGlobalData.getInstance().getGroup().contains((Node) objectBParent) && UnitGlobalData.getInstance().getGroup().contains((Node) objectAParent)) {
controlB.move.clear();
}
}
}
}
// if (controlA.getCurrentState() == 2 && controlA == this) {
// Vector3f localB = worldTranslationA.subtract(worldTranslationB).normalizeLocal();
// simpleApp.enqueue(new Runnable() {
// @Override
// public void run() {
// System.out.println(localB+",localB");
// objectAParent.move(localB.setY(0));
// }
// });
// } else if (controlB.getCurrentState() == 2 && controlB == this) {
// Vector3f localA = worldTranslationB.subtract(worldTranslationA).normalizeLocal();
//
// simpleApp.enqueue(new Runnable() {
// @Override
// public void run() {
// System.out.println(localA+",localA");
// objectBParent.move(localA.setY(0));
// }
// });
// }
if (controlB.getCurrentState() == 1 && controlB == this) {
Vector3f localB = worldTranslationA.subtract(worldTranslationB).normalizeLocal();
simpleApp.enqueue(new Runnable() {
@Override
public void run() {
objectAParent.move(localB.setY(0));
}
});
} else if (controlA.getCurrentState() == 1 && controlA == this) {
Vector3f localA = worldTranslationB.subtract(worldTranslationA).normalizeLocal();
simpleApp.enqueue(new Runnable() {
@Override
public void run() {
objectBParent.move(localA.setY(0));
}
});
}
}
@Override
public void onContactEnded(long manifoldId) {
}
@Override
public void onContactProcessed(PhysicsCollisionObject pcoA, PhysicsCollisionObject pcoB, long manifoldPointId) {
T100Control controlA = ((Spatial) pcoA.getUserObject()).getParent().getControl(T100Control.class);
T100Control controlB = ((Spatial) pcoB.getUserObject()).getParent().getControl(T100Control.class);
Spatial objectAParent = ((Spatial) pcoA.getUserObject()).getParent();
Spatial objectBParent = ((Spatial) pcoB.getUserObject()).getParent();
Vector3f worldTranslationA = objectAParent.getWorldTranslation();
Vector3f worldTranslationB = objectBParent.getWorldTranslation();
int PhysicsSpace = MinieBulletAppState.bulletAppState.getPhysicsSpace().pairTest(pcoA, pcoB, new PhysicsCollisionListener() {
@Override
public void collision(PhysicsCollisionEvent event) {
}
});
if(PhysicsSpace>0){
collision(controlA,controlB,objectAParent,objectBParent,worldTranslationA,worldTranslationB);
}
}
@Override
public void onContactStarted(long manifoldId) {
}
public void path(float AverageDistance,Vector3f average,RayMap rayMap, Vector3f RightClickMapLocation) {
FloatArray path;
try {
UnitGlobalData.getInstance().addGroup(UnitGlobalData.getInstance().getSelectedUnit());
Vector3f Nodeoffset = this.spatial.getWorldTranslation().subtract(average);
float distance = average.distance(RightClickMapLocation);
System.err.println(distance + ",distance");
if (distance <= 30f) {
Nodeoffset.set(0, 0, 0);
}
if (average.distance(this.spatial.getWorldTranslation()) < AverageDistance * 1.8) {
path = FindPath.getInstance().PathFinding(this.spatial.getWorldTranslation().x, this.spatial.getWorldTranslation().z, RightClickMapLocation.add(Nodeoffset).x, RightClickMapLocation.add(Nodeoffset).z, 2);
this.setPath(path, AverageDistance);
} else {
path = FindPath.getInstance().PathFinding(this.spatial.getWorldTranslation().x, this.spatial.getWorldTranslation().z, RightClickMapLocation.x, RightClickMapLocation.z, 2);
this.setPath(path, AverageDistance);
}
if (path.size <= 0) {
FloatArray path1 = FindPath.getInstance().PathFinding(this.spatial.getWorldTranslation().x, this.spatial.getWorldTranslation().z, RightClickMapLocation.x, RightClickMapLocation.z, 2);
this.setPath(path1, AverageDistance);
if (path1.size <= 0) {
Vector3f vectors = this.spatial.getWorldTranslation().subtract(RightClickMapLocation).normalizeLocal();
//findPath(i,vectors,RightClickMapLocation);
FloatArray path2 = FindPath.getInstance().PathFinding(this.spatial.getWorldTranslation().x, this.spatial.getWorldTranslation().z, RightClickMapLocation.add(vectors).x, RightClickMapLocation.add(vectors).z, 2);
int p = 0;
while (true) {
p++;
System.err.println(p);
if (path2.size <= 0) {
vectors.addLocal(vectors);
path2 = FindPath.getInstance().PathFinding(this.spatial.getWorldTranslation().x, this.spatial.getWorldTranslation().z, RightClickMapLocation.add(vectors).x, RightClickMapLocation.add(vectors).z, 2);
if (p > 500) {
break; // 跳出循环
}
} else if (path2.size > 0) {
this.setPath(path2);
break; // 跳出循环
}
}
}
}
} catch (Exception e) {
System.err.println(e);
}
}
@Override
public void sendRightClickCommand(float AverageDistances,Vector3f average,RayMap rayMap, Vector3f RightClickMapLocation) {
path(AverageDistances,average,rayMap,RightClickMapLocation);
}
@Override
public void collision(PhysicsCollisionEvent event) {
}
/**
* @return the VisionRange
*/
@Override
public ArrayList getVisionRange() {
return VisionRange;
}
}
I use this part of the code to take care of the rotation and tilt
//旋转
Quaternion rotation = spatial.getLocalRotation();
// Vector3f directionToTarget=nextPoint.subtract(currentPoint).normalize();
// Vector3f up = Vector3f.UNIT_Z;
// Vector3f crossProduct = Dir.cross(up);
Vector3f directionToTarget=nextPoint.subtract(currentPoint).normalize();
// Direction of orientation of the current unit (assuming that the direction of orientation is the Z-axis direction)
Vector3f forward = rotation.mult(Vector3f.UNIT_Z);
// Calculate the cross product to determine whether the target is on the left or right side of the orientation.
Vector3f crossProduct = forward.cross(directionToTarget);
System.out.println(crossProduct);
if (crossProduct.y < 0) {
System.out.println("The destination is to the right of the unit.");
targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(1, 0, 1));
rotation.nlerp(targetQua, 10f*tpf);
} else if (crossProduct.y > 0) {
System.out.println("The destination is to the left of the unit.");
targetQua.lookAt(nextPoint.subtract(currentPoint).normalizeLocal(), new Vector3f(-1, 0, -1));
// rotation.nlerp(targetQua, 10f*tpf);
rotation.slerp(targetQua, 1f*tpf);
}
This video is the effect I wanted to create
My English may not be very good, so if you're confused by the questions I'm asking, please point them out