#Solved
The issue seemed to be outside JME. Restarting my PC fixed it, I think.
Hi. The last few days I’ve been working on implementing an RTS-style camera controller. I still suffer for these strange glitches.
The glitches have an interesting pattern… everytime I change the source code, the glitches appear on the next run. However, if I re-run it a second time, they’re gone. Until I change the source code and cause JME to recompile some stuff.
What sorcery is this? Heres a video of the glitches: https://youtu.be/l1z-7MjsZIs
Towards the 50 second mark you see me realizing the pattern (first run after a compile causes glitch)
What sorcery is this… Anyway, if you want to help, here’s the source code. Tell me if there’s anything
I create a CameraNode, with my own RTSCameraControl script attached, like so:
//reset camera location
camera.setLocation(new Vector3f(0,0,0));
//add a cameraNode, with the RTSCameraControl attached
CameraNode cameraNode = new CameraNode("camera_main", camera);
cameraNode.addControl(new RTSCameraControl());
//register inputs for the camera control
cameraNode.getControl(RTSCameraControl.class).registerInputs(inputManager);
//add it
rootNode.attachChild(cameraNode);
I also disable flycam with flyCam.setEnabled(false);
of course.
Here’s the RTSCameraController class:
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.InputManager;
import com.jme3.input.controls.ActionListener;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
public class RTSCameraControl extends AbstractControl implements ActionListener {
public static Vector3f down = new Vector3f(0, -1f, 0);
private Geometry terrain;
private boolean isMovingLeft;
private boolean isMovingRight;
private boolean isMovingUp;
private boolean isMovingDown;
private boolean isRotatingLeft;
private boolean isRotatingRight;
private boolean isZoomingIn;
private boolean isZoomingOut;
private Vector3f velocity = new Vector3f();
private float accel = 5f;
private float maxSpeed = 50f;
public float minX = 0f;
public float maxX = 200f;
public float minZ = -10f;
public float maxZ = 200f;
public float zoom = 60f;
public float minZoom = 10f;
public float maxZoom = 200f;
public float zoomVel = 0f;
public float zoomAccel = 10f;
public float zoomMaxSpeed = 100f;
public float tilt = 75f / 180 * FastMath.PI;
private float rotation = 0f;
public float rotVel = 0f;
public float rotAccel = 0.1f;
public float rotMaxVel = 1f;
@Override
public void setSpatial(Spatial spatial) {
super.setSpatial(spatial);
spatial.setLocalTranslation(0f, maxZoom, -10f);
spatial.setLocalRotation(new Quaternion().fromAngles(tilt, 0, 0));
}
public void setTerrain(Geometry terrain) {
this.terrain = terrain;
}
@Override
protected void controlUpdate(float tpf) {
//detect terrain height
float terrainHeight = 0f;
if (terrain != null) {
Ray ray = new Ray(spatial.getWorldTranslation(), down);
CollisionResults results = new CollisionResults();
terrain.collideWith(ray, results);
CollisionResult result = results.getClosestCollision();
if (result != null) {
terrainHeight = result.getContactPoint().y;
}
}
//reset rotation
spatial.setLocalRotation(new Quaternion().fromAngles(0, 0, 0));
//accelerate
if (isMovingLeft) velocity.x += accel * tpf;
if (isMovingRight) velocity.x -= accel * tpf;
if (isMovingUp) velocity.z += accel * tpf;
if (isMovingDown) velocity.z -= accel * tpf;
if (isZoomingIn) zoomVel += zoomAccel * tpf;
if (isZoomingOut) zoomVel -= zoomAccel * tpf;
if (isRotatingLeft) rotVel += rotAccel * tpf;
if (isRotatingRight) rotVel -= rotAccel * tpf;
//clamp
if (velocity.x > maxSpeed) velocity.x = maxSpeed;
if (velocity.x < -maxSpeed) velocity.x = -maxSpeed;
if (velocity.z > maxSpeed) velocity.z = maxSpeed;
if (velocity.z < -maxSpeed) velocity.z = -maxSpeed;
if (zoomVel > zoomMaxSpeed) zoomVel = zoomMaxSpeed;
if (zoomVel < -zoomMaxSpeed) zoomVel = -zoomMaxSpeed;
if (rotVel > rotMaxVel) rotVel = rotMaxVel;
if (rotVel < -rotMaxVel) rotVel = -rotMaxVel;
//zoom
zoom += zoomVel;
//clamp zoom value
if (zoom > maxZoom) zoom = maxZoom;
if (zoom < minZoom) zoom = minZoom;
rotation += rotVel;
//apply rotation
spatial.rotate(0, rotation, 0);
//move relative to Y rotation
spatial.move(spatial.getLocalRotation().mult(velocity));
//set Y location (height)
Vector3f loc = spatial.getLocalTranslation();
loc.setY(terrainHeight + zoom);
//clamp position within bounds
if (loc.x > maxX) loc.x = maxX;
if (loc.x < minX) loc.x = minX;
if (loc.z > maxZ) loc.z = maxZ;
if (loc.z < minZ) loc.z = minZ;
//apply tilt
spatial.rotate(tilt, 0, 0);
//apply friction
velocity.interpolate(Vector3f.ZERO, 0.1f * tpf);
rotVel = FastMath.interpolateLinear(0.1f * tpf, rotVel, 0f);
zoomVel = FastMath.interpolateLinear(0.1f * tpf, zoomVel, 0f);
//reset isZoom* variables
isZoomingIn = isZoomingOut = false;
}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
public void registerInputs(InputManager inputManager) {
inputManager.addListener(this, "camera.move_left", "camera.move_right", "camera.move_up", "camera.move_down", "camera.rotate_left", "camera.rotate_right", "camera.zoom_in", "camera.zoom_out");
}
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("camera.move_left")) isMovingLeft = isPressed;
if (name.equals("camera.move_right")) isMovingRight = isPressed;
if (name.equals("camera.move_up")) isMovingUp = isPressed;
if (name.equals("camera.move_down")) isMovingDown = isPressed;
if (name.equals("camera.rotate_left")) isRotatingLeft = isPressed;
if (name.equals("camera.rotate_right")) isRotatingRight = isPressed;
if (name.equals("camera.zoom_in")) isZoomingIn = isPressed;
if (name.equals("camera.zoom_out")) isZoomingOut = isPressed;
}
}