The following is the full control script that I wrote after finding the solution. It's a strong basis for the 3d-space controller I was looking for - and fun to fly around with! For best testing results, I suggest setting your rigid body `Mass`, `Drag` and `Angular Drag` all to `1`; also, make sure `Gravity`, `Is Kinematic` and `Freeze Rotation` are all disabled.
var speed : int = 10; // Relative force applied for standard ws,ad,zx,qe movement.
var mouseSensativity : int = 15; // Speed of mouse movements for X/Y rotation, looking around.
var invertPitch : boolean = false; // Invert the X rotation axis. False: MouseDown=LookDown, True:MouseDown=LookUp
// Whether to use transform.Rotate() or rigidbody.AddRelativeTorque();
enum rotationMethods { Torque = 0, Rotate = 1 };
var rotationMethod = rotationMethods.Rotate;
function FixedUpdate() {
// This probably could be turned into a constant, instead of checking every update, but doing so lets the user change the setting on the fly without repercussions.
var invertPitchInt;
if (invertPitch) invertPitchInt = -1;
else invertPitchInt = 1;
// Standard translate/position controls.
if (Input.GetKey("w")) { rigidbody.AddRelativeForce (Vector3.forward * speed); }
if (Input.GetKey("s")) { rigidbody.AddRelativeForce (Vector3.forward * -1 * speed); }
if (Input.GetKey("a")) { rigidbody.AddRelativeForce (Vector3.left * speed); }
if (Input.GetKey("d")) { rigidbody.AddRelativeForce (Vector3.right * speed); }
if (Input.GetKey("z")) { rigidbody.AddRelativeForce (Vector3.down* speed); }
if (Input.GetKey("x")) { rigidbody.AddRelativeForce (Vector3.up * speed); }
// Keyboard controls to mimic mouse movements.
if (Input.GetKey("i")) { // Simulate increasing the X axis, mouse movement up.
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque (invertPitchInt * -mouseSensativity * Time.deltaTime, 0, 0); }
else { transform.Rotate(invertPitchInt * -mouseSensativity * Time.deltaTime, 0, 0); }
}
if (Input.GetKey("k")) { // Simulate decreasing the X axis, mouse movement down.
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque (invertPitchInt * mouseSensativity * Time.deltaTime, 0, 0); }
else { transform.Rotate(invertPitchInt * mouseSensativity * Time.deltaTime,0,0); }
}
if (Input.GetKey("j")) { // Simulate increasing the Y axis, mouse movement left.
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque (0, -mouseSensativity * Time.deltaTime, 0); }
else { transform.Rotate(0, -mouseSensativity * Time.deltaTime, 0); }
}
if (Input.GetKey("l")) { // Simulate decreasing the Y axis, mouse movement right.
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque (0, mouseSensativity * Time.deltaTime, 0); }
else { transform.Rotate(0, mouseSensativity * Time.deltaTime, 0); }
}
// Actual mouse movement controls
if (Input.GetAxis("Mouse X")) {
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque( 0, Input.GetAxis("Mouse X") * mouseSensativity, 0); }
else { transform.Rotate(0, Input.GetAxis("Mouse X") * mouseSensativity, 0); }
}
if (Input.GetAxis("Mouse Y")) {
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque( invertPitchInt * Input.GetAxis("Mouse Y") * -mouseSensativity, 0, 0); }
else { transform.Rotate(invertPitchInt * Input.GetAxis("Mouse Y") * -mouseSensativity, 0, 0); }
}
// Roll controls
if (Input.GetKey("q")) {
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque(0, 0, speed * Time.deltaTime); }
else { transform.Rotate( 0, 0, -speed * Time.deltaTime); }
}
if (Input.GetKey("e")) {
if (rotationMethod == rotationMethods.Torque) { rigidbody.AddRelativeTorque(0, 0, -speed * Time.deltaTime); }
else { transform.Rotate( 0, 0, speed * Time.deltaTime); }
}
}
I don't know if it's "proper" to post this, too, but I think it can be removed if overkill. This is the test script I was working with, so others that might have similar issues can see what I tested, and why it didn't work. It's not very pretty, but hopefully the comments explain my thought process. I'm still getting used to this, though, so my apologies if it's not very clear.
var speed : int = 10; // Relative force applied for standard ws,ad,zx movement.
var mouseSensativity : int = 15;
// Rotation method used for rolling. {q/e}
enum rollMethods { Torque = 0, Rotate = 1 };
var rollMethod = rollMethods.Rotate;
// Rotation method used for mouse, or mouse-simulated key strokes {ik,jl}
enum rotationTypes { Torque = 0, Rotate = 1 };
var rotationType = rotationTypes.Rotate;
// Option to roll before or after the X/Y mouse rotations.
enum whenToRollOptions {BeforeMouseLook = 0, DuringMouseLook = 1, AfterMouseLook = 2};
var whenToRoll = whenToRollOptions.DuringMouseLook;
// Switch between the mouse-simulated keyboard, or actual mouse movement.
var useKeyboardMouseSimulator : boolean = false;
// Select which test result to use.
enum mouseLookTests { TestA = 0, TestB = 1, TestC = 3, TestD = 4, TestE = 5, TestF = 6, TestG = 7, TestH = 8 }
var mouseLookTest = mouseLookTests.TestA;
var clampedRotationX : float = 0.0;
var clampedRotationY : float = 0.0;
var clampedRotationZ : float = 0.0;
function FixedUpdate() {
// Standard translate/position controls.
if (Input.GetKey("w")) { rigidbody.AddRelativeForce (Vector3.forward * speed); }
/*else*/ if (Input.GetKey("s")) { rigidbody.AddRelativeForce (Vector3.forward * -1 * speed); }
if (Input.GetKey("a")) { rigidbody.AddRelativeForce (Vector3.left * speed); }
/*else*/ if (Input.GetKey("d")) { rigidbody.AddRelativeForce (Vector3.right * speed); }
if (Input.GetKey("z")) { rigidbody.AddRelativeForce (Vector3.down* speed); }
/*else*/ if (Input.GetKey("x")) { rigidbody.AddRelativeForce (Vector3.up * speed); }
if (useKeyboardMouseSimulator) { // Manual key controls simulating mouse movement.
if (Input.GetKey("q")) {
if (rollMethod == rollMethods.Torque) { rigidbody.AddRelativeTorque(0,0,speed * Time.deltaTime); }
else { transform.Rotate(0,0,speed * Time.deltaTime); }
} else if (Input.GetKey("e")) {
if (rollMethod == rollMethods.Torque) { rigidbody.AddRelativeTorque(0,0,-speed * Time.deltaTime); }
else { transform.Rotate(0,0,-speed * Time.deltaTime); }
}
// ** -- Converting this block to accept Mouse input should be the solution I'm looking for -- **
// The result these keys produce is the exact same result the mouse movement should produce: i=MouseDown, k=MouseUp, j=MouseLeft, k=MouseRight
// Using Rotate is much more responsive, and likely the best result for user controlled mouse-like movement, and probobly is the result I'm most likely to desire to use.
// However, I'd also like to have the option to use the Torque method, if it would be possible to impliment - just to see how it functions.
if (Input.GetKey("i")) { // Simulate increasing the X axis, mouse movement up.
if (rotationType == rotationTypes.Torque) { rigidbody.AddRelativeTorque (speed * Time.deltaTime, 0, 0); }
else { transform.Rotate(speed * Time.deltaTime, 0, 0); }
} else if (Input.GetKey("k")) { // Simulate decreasing the X axis, mouse movement down.
if (rotationType == rotationTypes.Torque) { rigidbody.AddRelativeTorque (-speed * Time.deltaTime, 0, 0); }
else { transform.Rotate(-speed * Time.deltaTime,0,0); }
}
if (Input.GetKey("j")) { // Simulate increasing the Y axis, mouse movement left.
if (rotationType == rotationTypes.Torque) { rigidbody.AddRelativeTorque (0, -speed * Time.deltaTime, 0); }
else { transform.Rotate(0, -speed * Time.deltaTime, 0); }
} else if (Input.GetKey("l")) { // Simulate decreasing the Y axis, mouse movement right.
if (rotationType == rotationTypes.Torque) { rigidbody.AddRelativeTorque (0, speed * Time.deltaTime, 0); }
else { transform.Rotate(0, speed * Time.deltaTime, 0); }
}
} else { // This block contains my various attempts to achieve the goal I'm after.
clampedRotationX = ClampAngle(clampedRotationX + (Input.GetAxis("Mouse X") * mouseSensativity), -360, 360);
clampedRotationY = ClampAngle(clampedRotationY + (Input.GetAxis("Mouse Y") * mouseSensativity), -360, 360);
if (Input.GetKey("q")) { clampedRotationZ = ClampAngle(clampedRotationZ + (speed * Time.deltaTime), -360, 360); }
else if (Input.GetKey("e")) { clampedRotationZ = ClampAngle(clampedRotationZ + (-speed * Time.deltaTime), -360, 360); }
if (mouseLookTest == mouseLookTests.TestA) {
// This test works almost perfectly, except that the mouse movements do not follow the Z rotation propperly.
// Moving the mouse up/down looks up/down as expected when Z=0, but as Z changes the up/down movement does not follow.
// Basically if Z=90, moving the mouse up/down looks left/right. This is not the desired effect. Moving the mouse up/down, should always look up/down.
transform.localRotation = Quaternion.Euler(-clampedRotationY, clampedRotationX, clampedRotationZ);
} else if (mouseLookTest == mouseLookTests.TestB) {
// This seems to have the same result as TestA.
transform.localRotation = Quaternion.AngleAxis(clampedRotationX, Vector3.up) * Quaternion.AngleAxis(clampedRotationY, Vector3.left) * Quaternion.AngleAxis(clampedRotationZ, Vector3.forward);
} else if (mouseLookTest == mouseLookTests.TestC) {
// This freaks out beyond my understanding.
transform.localRotation.x = clampedRotationX; // clampedRotationY;
transform.localRotation.y = clampedRotationY; // clampedRotationX;
transform.localRotation.z = clampedRotationZ;
} else if (mouseLookTest == mouseLookTests.TestD) {
// This applies a constant rotation to the object, meaning it will always be rotating as long as clampedRotationX/Y/Z have non-zero values.
// Effectively this makes it impossible to control, since the camera will just start spinning.
transform.Rotate(clampedRotationY, clampedRotationX, clampedRotationZ);
} else if (mouseLookTest == mouseLookTests.TestE) {
// Same as TestD, just with Torque/force instead of direct rotation.
rigidbody.AddRelativeTorque(clampedRotationY, clampedRotationX, clampedRotationZ);
} else if (mouseLookTest == mouseLookTest.TestF) {
// This works perfectly! Used without torque, best used with 'Freeze Rotation' enabled to avoid Torque forces interfearing with your rotational axis.
if (Input.GetKey("q")) { transform.Rotate(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, speed * Time.deltaTime); }
else if (Input.GetKey("e")) { transform.Rotate(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, -speed * Time.deltaTime); }
else { transform.Rotate(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, 0); }
} else if (mouseLookTest == mouseLookTest.TestG) {
// This works perfectly! This is truely what I was after, with 'Freeze Rotation' disabled, Torque forces apply beautifully.
if (Input.GetKey("q")) { rigidbody.AddRelativeTorque(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, speed * Time.deltaTime); }
else if (Input.GetKey("e")) { rigidbody.AddRelativeTorque(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, -speed * Time.deltaTime); }
else { rigidbody.AddRelativeTorque(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, 0); }
} else if (mouseLookTest == mouseLookTests.TestH) {
// This also works as expected, and accepts the roll/rotate options accurately.
// This was used to test/prove that X/Y rotation for looking can be 'quick' using transform.Rotate(), while leaving Z roll effected by physics/torque/drag, producing an interesting control result.
// Set rollMethod=Torque and rotationMethod=Rotate to test. -- Though I've read that using Rotate() on a Torque controlled objct, can have unpredictable results.
if (rotationType == rotationTypes.Torque) { rigidbody.AddRelativeTorque(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, 0); }
else { transform.Rotate(Input.GetAxis("Mouse Y") * -mouseSensativity, Input.GetAxis("Mouse X") * mouseSensativity, 0); }
if (Input.GetKey("q")) {
if (rollMethod == rollMethods.Torque) { rigidbody.AddRelativeTorque(0, 0, -speed * Time.deltaTime); }
else { transform.Rotate(0, 0, -speed * Time.deltaTime); }
}
if (Input.GetKey("e")) {
if (rollMethod == rollMethods.Torque) { rigidbody.AddRelativeTorque(0, 0, speed * Time.deltaTime); }
else { transform.Rotate(0, 0, speed * Time.deltaTime); }
}
}
}
}
function ClampAngle (angle : float, min : float, max : float) {
if (angle < -360) angle += 360;
if (angle > 360) angle -= 360;
return Mathf.Clamp (angle, min, max);
}
Hopefully this helps someone else sometime!
~Badger