in Unity I have a camera as a child of a 2D gameobject (to follow it around). There is an IF statement that lets me move the camera ahead by holding down a key. I need a code to return the camera back to the gameobject after I let go. Thank you for the help.
public class camera : MonoBehaviour
{
public float panspeed = 30f;
public float panBorderThickness = 30f;
public GameObject ship1;
private Vector3 offset;
void Update()
{
if (Input.GetKey("f"))
{
Vector3 pos = transform.position;
if (Input.mousePosition.y >= Screen.height - panBorderThickness)
{
pos.y += panspeed * Time.deltaTime;
}
if (Input.mousePosition.y <= panBorderThickness)
{
pos.y -= panspeed * Time.deltaTime;
}
if (Input.mousePosition.x >= Screen.width - panBorderThickness)
{
pos.x += panspeed * Time.deltaTime;
}
if (Input.mousePosition.x <= panBorderThickness)
{
pos.x -= panspeed * Time.deltaTime;
}
transform.position = pos;
}
//something to return the camera back when i let go of F key
}
}
If I understand correctly you would want to smoothly move the camera back to its original position so I would probably do it like
private void Update ()
{
if (Input.GetKey(KeyCode.F))
{
var pos = transform.position;
if (Input.mousePosition.y >= Screen.height - panBorderThickness)
{
pos.y += panspeed * Time.deltaTime;
}
if (Input.mousePosition.y <= panBorderThickness)
{
pos.y -= panspeed * Time.deltaTime;
}
if (Input.mousePosition.x >= Screen.width - panBorderThickness)
{
pos.x += panspeed * Time.deltaTime;
}
if (Input.mousePosition.x <= panBorderThickness)
{
pos.x -= panspeed * Time.deltaTime;
}
transform.position = pos;
}
else
{
transform.position = Vector3.MoveTowards(transform.position, ship1.transform.position - ship1.transform.forward * 10, panspeed * Time.deltaTime);
}
}
if(Input.GetKeyUp("f")){
transform.position = ship1.transform.position;
}
Sidenote, you can't assign values to only one component of a vector. You need to reassign the entire vector with the new component or add/subtract to the original vector. Your script should look like
if (Input.GetKey("f"))
{
Vector3 pos = transform.position;
if (Input.mousePosition.y >= Screen.height - panBorderThickness)
{
pos += new Vector3(0, panspeed * Time.deltaTime, 0);
}
if (Input.mousePosition.y <= panBorderThickness)
{
pos -= new Vector3(0, panspeed * Time.deltaTime, 0);
}
if (Input.mousePosition.x >= Screen.width - panBorderThickness)
{
pos += new Vector3(panspeed * Time.deltaTime, 0, 0);
}
if (Input.mousePosition.x <= panBorderThickness)
{
pos -= new Vector3(panspeed * Time.deltaTime, 0, 0);
}
transform.position = pos;
}
if(Input.GetKeyUp("f"))
{
transform.position = GameObjectYouWant.transform.position;
}
I'm having an issue with the free roam camera I'm trying to implement. The camera can be rotated via keyboard (only on the Y axis) and via mouse (on the X and Y axis) while holding the middle mouse button. With my current implementation, if I rotate the camera using the keyboard and the rotate it using the mouse, it remove any rotation done by the keyboard as soon as I hit the middle mouse button. Of course I would like to not do that... Code is below. Can someone give tell me what I'm doing wrong?
private void RotateCameraKeyboard()
{
if (Input.GetKey(KeyCode.Q))
{
transform.RotateAround(transform.position, Vector3.up, -rotationSpeed * Time.deltaTime * 30);
}
if (Input.GetKey(KeyCode.E))
{
transform.RotateAround(transform.position, Vector3.up, rotationSpeed * Time.deltaTime * 30);
}
}
private void RotateCameraMouse()
{
if (Input.GetMouseButton(2))
{
pitch -= rotationSpeed * Input.GetAxis("Mouse Y");
yaw += rotationSpeed * Input.GetAxis("Mouse X");
pitch = Mathf.Clamp(pitch, -90f, 90f);
while (yaw < 0f)
{
yaw += 360f;
}
while (yaw >= 360f)
{
yaw -= 360f;
}
transform.eulerAngles = new Vector3(pitch, yaw, 0f);
}
}
Instead of using RotateAround (which in your case of using the transform.position as pivot is redundant anyway .. you could as well just use Rotate) additionally also add the according amount to your pitch and yawn.
I would simply generalize and use the same method for both inputs like e.g.
private void RotateCameraKeyboard()
{
if (Input.GetKey(KeyCode.Q))
{
Rotate(-rotationSpeed * Time.deltaTime * 30, 0);
}
if (Input.GetKey(KeyCode.E))
{
Rotate(rotationSpeed * Time.deltaTime * 30, 0);
}
}
private void RotateCameraMouse()
{
if (Input.GetMouseButton(2))
{
var pitchChange = rotationSpeed * Input.GetAxis("Mouse Y");
var yawChange = rotationSpeed * Input.GetAxis("Mouse X");
Rotate(yawChange, pitchChange);
}
}
private void Rotate(float yawChange, float pitchChange)
{
pitch = Mathf.Clamp(pitch + pitchChange, -90f, 90f);
yaw += yawChange;
while (yaw < 0f)
{
yaw += 360f;
}
while (yaw >= 360f)
{
yaw -= 360f;
}
transform.eulerAngles = new Vector3(pitch, yaw, 0f);
}
Goal:
to create a vehicle with properties similar to that of Mario Kart 8's anti gravity mode, or f- zero; the ability to ride on extreme non horizontal surfaces.
Desired behavior:
the vehicle should not turn unless the thumbstick or arrow keys are pressed/moved; it must keep a straight line of motion with the exception of roll and vertical curvature relative to the camera's view.
Actual behavior:
The vehicle will slowly(sometimes quickly) fall out of line and keep curving until the track stops bending. if placed in an inward facing cylinder and driven around radially, the vehicle will begin to curve towards either global +z or global +y.
(no error messages)
What I've tried:
-setting transform.up to the surface normal then rotating around the normal as an axis
-using quaternion.euler(0, [desired angle], 0) then fromToRotation
The alignment and rotation code:
transform.rotation = Quaternion.Euler(0, rotation, 0);
Quaternion tilt = Quaternion.FromToRotation(Vector3.up, localUp);
transform.rotation = tilt * transform.rotation;
transform.position += velocity * 1.1f;
The entire script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using PhysicsExtensions;
using UnityEngine.Rendering.PostProcessing;
public class Cart : MonoBehaviour
{
Kartphysics inputActions;
public new Transform camera, camTarget, camTargetDrift, Visual;
public ShipType shipType;
public AudioSource Vroom;
public Vector3 localUp = Vector3.up;
Vector3 velocity, camUp, followPos;
public AnimationCurve SteeringControl;
public float steerAmount;
float rotation, rollTarget, roll, fovDifference, vroomPitch = 0, flameLength = 0;
public float normalFov, speedFov, Velocity, rollAmount, speedFactor, forcedAcceleration;
public GameObject[] ships;
public FlamingTrail[] flames;
public PostProcessProfile ppp;
Vector2 JoystickVal;
ChromaticAberration ca;
LensDistortion ld;
Vector3 LastForward;
private void Start()
{
switch (shipType)
{
case ShipType.Carrier:
{
ships[0].SetActive(true);
break;
}
case ShipType.Ram:
{
ships[1].SetActive(true);
break;
}
}
ca = ppp.GetSetting<ChromaticAberration>();
ld = ppp.GetSetting<LensDistortion>();
}
private void Update()
{
UpdateVisuals();
UpdateCamera();
Velocity = velocity.magnitude;
}
private void FixedUpdate()
{
UpdateKart();
}
void SetFlames(float length)
{
for(int i = 0; i < flames.Length; i++)
{
flames[i].length = length;
}
}
void UpdateVisuals()
{
ca.intensity.value = Mathf.Clamp01(forcedAcceleration) * 2;
ld.intensity.value = Mathf.Lerp(0, -70f, Mathf.Clamp(forcedAcceleration, 0, 1));
SetFlames(flameLength);
Vroom.pitch = Mathf.Lerp(Vroom.pitch, vroomPitch, (speedFactor * 0.01f) * 10);
Visual.position = Vector3.Lerp(Visual.position, transform.position, (speedFactor * 0.01f) * 30);
Visual.rotation = Quaternion.Lerp(Visual.rotation, transform.rotation, (speedFactor * 0.01f) * 15);
}
void UpdateCamera()
{
fovDifference = speedFov - normalFov;
Camera.main.fieldOfView = speedFov - (fovDifference * (1 / Mathf.Clamp(velocity.magnitude + 1, 0, Mathf.Infinity)));
camUp = Vector3.Lerp(camUp, localUp.normalized, (speedFactor * 0.01f) * (Vector3.Distance(camera.position, Vector3.Lerp(camTarget.position, camTargetDrift.position, transform.InverseTransformDirection(velocity).x)) + 3));
camera.rotation = Quaternion.Slerp(camera.rotation, Quaternion.LookRotation((transform.position - (transform.right * transform.InverseTransformDirection(velocity).x * 5) + transform.up) - camera.position, camUp), (speedFactor * 0.01f) * 13);
camera.position = Vector3.Lerp(camera.position, Vector3.Lerp(camTarget.position, camTargetDrift.position, transform.InverseTransformDirection(velocity).x), (speedFactor * 0.01f) * Vector3.Distance(camera.position, camTarget.position) * 20);
}
void UpdateKart()
{
JoystickVal = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (Input.GetAxis("Submit") > 0.5)
JoystickVal = new Vector2(JoystickVal.x, 1);
if (Input.GetAxis("Cancel") > 0.5)
JoystickVal = new Vector2(JoystickVal.x, -1);
if (JoystickVal.magnitude > 1)
{
JoystickVal.Normalize();
}
JoystickVal *= (speedFactor * 0.01f) * 0.2f;
JoystickVal /= Mathf.Clamp(velocity.magnitude, 0.7f, Mathf.Infinity);
velocity += ((transform.forward * JoystickVal.y) / Mathf.Clamp(Mathf.Abs(transform.InverseTransformDirection(velocity).x), 0.7f, Mathf.Infinity));
rollTarget = Mathf.Clamp01(SteeringControl.Evaluate(velocity.magnitude)) * JoystickVal.x * rollAmount;
roll = Mathf.MoveTowards(roll, rollTarget, (speedFactor * 0.01f) * 4);
velocity -= localUp * (speedFactor * 0.01f) * 0.7f;
velocity /= 1 + ((speedFactor * 0.01f) / 8);
RaycastHit hit;
CircleCastHit circleHit;
if (Physics.Raycast(transform.position + transform.up, -transform.up + (velocity / 1), out hit))
{
if (hit.distance < 4)
{
transform.position -= hit.normal.normalized * (speedFactor * 0.01f);
localUp = Vector3.MoveTowards(localUp, hit.normal, (speedFactor * 0.01f) * 9);
if (hit.distance < 1.2f)
{
flameLength = Velocity * 2;
if (hit.collider.tag == "SpeedPanel")
forcedAcceleration = 3f;
rotation += SteeringControl.Evaluate(velocity.magnitude * 0.7f) * JoystickVal.x * (speedFactor * 0.01f) * 100 * steerAmount;
transform.position += hit.normal.normalized * (1 - hit.distance);
vroomPitch = velocity.magnitude * 1.5f;
velocity += ((transform.forward * ((JoystickVal.y * 1.3f) + (forcedAcceleration / 100))) / Mathf.Clamp(Mathf.Abs(transform.InverseTransformDirection(velocity).x), 0.7f, Mathf.Infinity));
rotation += SteeringControl.Evaluate((speedFactor * 0.01f) * velocity.magnitude * 50) * JoystickVal.x * 0.3f;
velocity /= 1 + ((speedFactor * 0.01f));
velocity -= transform.right * transform.InverseTransformDirection(velocity).x * 0.2f;
Vector3 force = (hit.normal * -transform.InverseTransformDirection(velocity).y / Mathf.Clamp(hit.distance - 0.1f, 0.5f, 2)) * 1.1f;
if (force.magnitude > 1)
force = force.normalized * 1;
force /= 8;
velocity += force;
}
else
{
vroomPitch = 0;
flameLength = Mathf.MoveTowards(flameLength, 0, 0.03f);
}
}
else
{
localUp = Vector3.MoveTowards(localUp, Vector3.up, (speedFactor * 0.01f) * 1.2f);
vroomPitch = 0;
transform.forward = velocity.normalized;
flameLength = Mathf.MoveTowards(flameLength, 0, 0.03f);
}
}
else
{
localUp = Vector3.MoveTowards(localUp, Vector3.up, (speedFactor * 0.01f) * 2);
vroomPitch = 0;
flameLength = Mathf.MoveTowards(flameLength, 0, 0.03f);
}
if (PhysicsII.CircleCast(transform.position + (transform.up * 0.5f), localUp, 0.7f, 8, out circleHit))
{
Debug.DrawRay(circleHit.nearestHit().point, circleHit.nearestHit().normal, Color.red, 0.1f);
Debug.Log("HIT");
velocity += (transform.position + (transform.up * 0.5f) - circleHit.nearestHit().point) / 3;
if (circleHit.nearestHit().distance < 0.4f)
velocity += (transform.position + (transform.up * 0.5f) - circleHit.nearestHit().point) / 7;
if (circleHit.nearestHit().distance < 0.14f)
velocity += (transform.position + (transform.up * 0.5f) - circleHit.nearestHit().point) / 7;
}
if(Physics.Raycast(transform.position + (transform.up * 0.8f) - velocity, velocity , out hit))
{
if(hit.distance < Velocity * 2)
velocity /= 1 + ((speedFactor * 0.01f) * 2f);
if (hit.distance < Velocity * 1.2f)
velocity = Vector3.Reflect(velocity, hit.normal);
}
forcedAcceleration = Mathf.MoveTowards(forcedAcceleration, 0, 0.1f);
transform.rotation = Quaternion.Euler(0, rotation, 0);
Quaternion tilt = Quaternion.FromToRotation(Vector3.up, localUp);
transform.rotation = tilt * transform.rotation;
transform.position += velocity * 1.1f;
}
public enum ShipType
{
Carrier = 0,
Ram = 1
}
}
Here's a partial answer because I can't test it on my end currently to see if it works. It also appears like "roll" isn't yet used for anything (is it meant to alter the local up of the transform somehow?) so I'm not sure about that.
First, instead of keeping a float rotation to keep track of how the vehicle is turned, you can just use transform.forward or transform.right for those purposes, and measure the modifications to that on a per-frame basis:
void UpdateKart()
{
Vector3 newForward = transform.forward;
float turnAmount = 0f;
// ...
if (hit.distance < 1.2f)
{
flameLength = Velocity * 2;
if (hit.collider.tag == "SpeedPanel")
forcedAcceleration = 3f;
turnAmount += SteeringControl.Evaluate(velocity.magnitude * 0.7f)
* JoystickVal.x * (speedFactor * 0.01f) * 100 * steerAmount;
transform.position += hit.normal.normalized * (1 - hit.distance);
vroomPitch = velocity.magnitude * 1.5f;
velocity += /* too long to bother formatting */
turnAmount += SteeringControl.Evaluate((speedFactor * 0.01f)
* velocity.magnitude * 50) * JoystickVal.x * 0.3f;
// ...
Then when you actually adjust the rotation, apply the turn amount around the local up axis to the current local forward direction. And finally, set the transform's rotation so that its new local up is localUp and it keeps its local forward as constant a direction as possible (cross products followed by Quaternion.LookRotation can be used for this):
forcedAcceleration = Mathf.MoveTowards(forcedAcceleration, 0, 0.1f);
Vector3 turnedForward = Quaternion.AngleAxis(turnAmount - 180, localUp) *
transform.forward;
Vector3 newRight = Vector3.Cross(turnedForward, localUp);
if (newRight == Vector3.zero)
{
/* Ambiguous situation - maybe kart landed with its nose directly in the
direction of localUp or opposite direction. Possible solution: use
velocity as previous forward direction and recalculate, using a random
direction if that doesn't work
*/
newRight = Vector3.Cross(velocity, localUp);
if (newRight == Vector3.zero)
{
newRight = Vector3.ProjectOnPlane(Random.insideUnitSphere,
localUp).normalized;
}
}
Vector3 newForward = Vector3.Cross(newRight, localUp);
transform.rotation = Quaternion.LookRotation(newForward, localUp);
transform.position += velocity * 1.1f;
The reason you're seeing the results you are is that FromToRotation will give you the "smallest" rotation that will move one vector to the other. But you're more concerned with a rotation that will keep the local forward close to what they are before the adjustment (it's difficult to explain why this isn't the same thing). Hence the Cross stuff.
As I said, this is only intended to be a partial solution to get you closer. But, it may be all you need. Let me know what you think in the comments.
I am doing camera navigation (Movement/Rotation) on Update event in this way:
void UpdateMovement()
{
bool accelerate = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
moveDirection =
new
Vector3(
Input.GetAxisRaw("Horizontal") * moveSpeed,
0,
Input.GetAxisRaw("Vertical") * moveSpeed);
//moveDirection = new Vector3(Input.GetAxis("Horizontal") * moveSpeed, 0, Input.GetAxis("Vertical") * moveSpeed);
moveDirection = transform.TransformDirection(moveDirection);
if (Input.GetButton("Up"))
{
moveDirection.y += moveSpeed;
}
else if (Input.GetButton("Down"))
{
moveDirection.y -= moveSpeed;
}
if (Input.GetAxisRaw("Mouse ScrollWheel") > 0)
{
moveDirection.y = moveDirection.y + scrollSpeed;
}
else if (Input.GetAxisRaw("Mouse ScrollWheel") < 0)
{
moveDirection.y = moveDirection.y - scrollSpeed;
}
moveDirection *= (accelerate ? speed : moveSpeed);
controller.Move(moveDirection * Time.deltaTime);
}
void UpdateRotation()
{
if (!Input.GetMouseButton(1))
return;
rotationX += Input.GetAxis("Mouse X") * lookSpeed;
rotationY += Input.GetAxis("Mouse Y") * lookSpeed;
rotationY = Mathf.Clamp(rotationY, -90, 90);
rotationZ = Input.GetAxis("Mouse ScrollWheel");
transform.localRotation = Quaternion.AngleAxis(rotationZ, Vector3.forward);
transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);
transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);
}
All working fine but the problem on WebGL canvas when I rotate the camera using mouse and comes out of the bound of WebGl canvas meanwhile, I also continuously press horizontal or vertical key, then release input key doesn't work. Remember I logged the key[Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical")] input and found that it is not reset to zero on release.
Debug.Log("Hr GetAxisRaw : " + Input.GetAxisRaw("Horizontal"));
Debug.Log("Vertical : " + Input.GetAxisRaw("Vertical"));
Normally when I don't use camera rotation using mouse and during this time, when i release the horizontal/vertical key, it works fine. I was previously using Input.GetAxis now i am using Input.GetAxisRaw but the problem is same.
I want to rotate a object on the x-axis when I move the mouse up or down (increase the x-rotation when moving mouse up, decrease when moving mouse down).
But I don't know how to do this.
I tried this script:
public float mouseSensitivity = 100.0F;
public float clampAngle = 80.0F;
float rotX = 0.0F, rotY = 0.0F;
void Update()
{
// Mouse Look
float mouseX = Input.GetAxis("Mouse X");
float mouseY = Input.GetAxis("Mouse Y");
rotX += mouseY * mouseSensitivity * Time.deltaTime;
rotY += mouseX * mouseSensitivity * Time.deltaTime;
rotX = Mathf.Clamp(rotX, -clampAngle, clampAngle);
Quaternion localRotation = Quaternion.Euler(rotX, 0, 0.0F);
transform.rotation = localRotation;
}
But this controls also rotation on the y axis. I also have rotation on the y-axis, but they are controlled via keyboard input:
if (Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.S))
transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed);
else if (Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime * -moveSpeed);
if (Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.D))
transform.Rotate(Vector3.up * Time.deltaTime * -rotateSpeed, Space.World);
else if (Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.A))
transform.Rotate(Vector3.up * Time.deltaTime * rotateSpeed, Space.World);
and I want the mouse up/down only control the rotation on the x-axis.
If someone can help me, that would be great!
void Update()
{
// Mouse Look
float mouseX = Input.GetAxis("Mouse X");
float mouseY = Input.GetAxis("Mouse Y");
rotX = mouseY * mouseSensitivity;
rotY = mouseX * mouseSensitivity;
transform.rotation *= Quaternion.Euler(rotX, 0, 0.0f);
}