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.
Related
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;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyLookAt : MonoBehaviour
{
public Transform target;
public Vector3 offset;
Transform chest;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void LateUpdate()
{
chest.LookAt(target.position);
ClampRotation(chest.rotation, new Vector3(0, 60, 0));
chest.rotation = chest.rotation * Quaternion.Euler(offset);
}
public static Quaternion ClampRotation(Quaternion q, Vector3 bounds)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan(q.x);
angleX = Mathf.Clamp(angleX, -bounds.x, bounds.x);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
float angleY = 2.0f * Mathf.Rad2Deg * Mathf.Atan(q.y);
angleY = Mathf.Clamp(angleY, -bounds.y, bounds.y);
q.y = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleY);
float angleZ = 2.0f * Mathf.Rad2Deg * Mathf.Atan(q.z);
angleZ = Mathf.Clamp(angleZ, -bounds.z, bounds.z);
q.z = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleZ);
return q.normalized;
}
}
I tried to use the ClampRotation method but it does nothing. The player's head still can be rotated 360 degrees if the target is behind him. I want to limit the rotation to some human natural looking to the sides and maybe also to the up/down.
I tried this testing the Y (up/down)
Vector3 chestAngle = chest.eulerAngles;
chestAngle.y = (chestAngle.y > 180) ? chestAngle.y - 360 : chestAngle.y;
chestAngle.y = Mathf.Clamp(chestAngle.y, -50, 50);
chest.rotation = Quaternion.Euler(chestAngle);
but it's clamping the Z and not the Y. It's clamping the Left not the up/down. I want to clamp up/down and left/right
You're never assigning the clamped value to the rotation.
chest.rotation = ClampRotation(chest.rotation, new Vector3(0, 60, 0));
Forget the ClampRotation Function and try the following code :
Vector3 chestAngle = chest.rotation.eulerAngles;
chestAngle.y = (chestAngle.y > 180) ? chestAngle.y - 360 : chestAngle.y;
chestAngle.y = Mathf.Clamp(chestAngle.y, -50 , 50);
chest.rotation = Quaternion.Euler(chestAngle);
My objective here is to have a smoothed out "follow camera", for my space-fighter proof of concept game. The camera should match roll off the target object in all axis.
To that end I've "stolen" and modified this code from the unity Answers-site, and it works beautifully for X and Y (pitch and yaw), but it refuses to roll.
Code:
public float Distance;
public float Height;
public float RotationDamping;
public GameObject Target;
void LateUpdate()
{
var wantedRotationAngleYaw = Target.transform.eulerAngles.y;
var currentRotationAngleYaw = transform.eulerAngles.y;
var wantedRotationAnglePitch = Target.transform.eulerAngles.x;
var currentRotationAnglePitch = transform.eulerAngles.x;
var wantedRotationAngleRoll = Target.transform.eulerAngles.z;
var currentRotationAngleRoll = transform.eulerAngles.z;
currentRotationAngleYaw = Mathf.LerpAngle(currentRotationAngleYaw, wantedRotationAngleYaw, RotationDamping * Time.deltaTime);
currentRotationAnglePitch = Mathf.LerpAngle(currentRotationAnglePitch, wantedRotationAnglePitch, RotationDamping * Time.deltaTime);
currentRotationAngleRoll = Mathf.LerpAngle(currentRotationAngleRoll, wantedRotationAngleRoll, RotationDamping * Time.deltaTime);
var currentRotation = Quaternion.Euler(currentRotationAnglePitch, currentRotationAngleYaw, currentRotationAngleRoll);
transform.position = Target.transform.position;
transform.position -= currentRotation * Vector3.forward * Distance;
transform.LookAt(Target.transform);
transform.position += transform.up * Height;
}
Image:
I would be more certain about this answer if you explained what you were trying to do, but you should consider moving by Height in the direction of currentRotation * Vector3.up instead of transform.up. Also, consider using currentRotation * Vector3.up to set the local up direction when calling LookAt:
transform.position = Target.transform.position;
transform.position -= currentRotation * Vector3.forward * Distance;
Vector3 currentUp = currentRotation * Vector3.up;
transform.LookAt(Target.transform, currentUp);
transform.position += currentUp * Height;
I am working on a script to move an object back anf forth based on swipe similarly to a game called Sky Rusher on the iOS App Store. The movement in the original game lets you swipe in any direction and an object moves in the same direction. However, the object also "bounces" for lack of a better term. For example, if you swipe to the left, the object will tilt to the left and then tilt back to its original position. For the best example I can give, please take a look at this video for a demonstartion of the game:
Sky Rusher Gameplay
This is the code I currently have (the object also doesn't move back and forth when swiping, not sure what==y that is but have an idea on how to fix it):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePlayer : MonoBehaviour
{
private Vector3 currentPos;
private Vector3 touchPos;
private float screenWidth;
private float screenHeight;
private float touchX;
private float touchY;
private float objectX;
private float objectY;
// Start is called before the first frame update
void Start()
{
touchX = 0;
touchY = 0;
screenWidth = (float)Screen.width / 2.0f;
screenHeight = (float)Screen.height / 2.0f;
currentPos = new Vector3(0.0f, 1.0f, 0.0f);
}
// Update is called once per frame
void Update()
{
if(Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if(touch.phase == TouchPhase.Moved)
{
//touchPos = new Vector3((touch.position.x - screenWidth)/screenWidth, (touch.position.y - screenHeight)/screenHeight + 1, 0.0f);
touchPos = new Vector3(touch.position.x, touch.position.y, 0.0f);
touchX = (touchPos.x - screenWidth)/screenHeight - 1f;
touchY = (touchPos.y - screenHeight)/screenHeight + 1f;
//objectX = ((currentPos.x * screenWidth) - screenWidth)/screenWidth;
//objectY = ((currentPos.y * screenHeight) - screenHeight)/screenHeight;
objectX = currentPos.x;
objectY = currentPos.y;
objectX += (touchX - objectX) * 1.5f;
//objectY += (touchY - objectY) * 1.5f;
if(touchX >= 0.9f)
{
objectX+=0.05f;
}
else if(touchX <= -0.9f)
{
objectX-=0.05f;
}
currentPos = new Vector3(objectX, objectY, 0.0f);
transform.position = currentPos;
}
}
}
void OnGUI()
{
/*
// Compute a fontSize based on the size of the screen width.
GUI.skin.label.fontSize = (int)(Screen.width / 40.0f);
GUI.Label(new Rect(20, 20, screenWidth, screenHeight * 0.25f),
"Pos: x = " + (objectX.ToString("f2")) +
", y = " + objectY.ToString("f2"));
GUI.Label(new Rect(20, 50, screenWidth, screenHeight * 0.25f),
"Touch: x = " + (touchX.ToString("f2")) +
", y = " + (touchY.ToString("f2")));
*/
}
}
I need my object to tilt when moved similarly to how it is done in sky rusher. My game is played in a landscape orientation on an iOS Device using Unity Remote 5 and Unity 2018.3.
Quick way to achieve this effect, if I understood correctly what you mean:
1) Each time touchX >= .9f (you are moving right) apply localRotation along Z axis with some angle.
2) Each time touchX <= -.9f (you are moving left) apply localRotation along Z axis with some negative angle.
To make this look smooth and not jumpy, apply rotation along several frames, first calculating target rotation, then using RotateTowards with some given speed. Here is yourr code slightly modified:
public float tiltEffectAngle = 20;
public float tiltEffectSpeed = 90f;
void Update() {
var targetRotation = Quaternion.identity;
if (Input.touchCount > 0) {
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved) {
//touchPos = new Vector3((touch.position.x - screenWidth)/screenWidth, (touch.position.y - screenHeight)/screenHeight + 1, 0.0f);
touchPos = new Vector3(touch.position.x, touch.position.y, 0.0f);
touchX = (touchPos.x - screenWidth) / screenHeight - 1f;
touchY = (touchPos.y - screenHeight) / screenHeight + 1f;
//objectX = ((currentPos.x * screenWidth) - screenWidth)/screenWidth;
//objectY = ((currentPos.y * screenHeight) - screenHeight)/screenHeight;
objectX = currentPos.x;
objectY = currentPos.y;
objectX += (touchX - objectX) * 1.5f;
//objectY += (touchY - objectY) * 1.5f;
if (touchX >= 0.9f) {
objectX += 0.05f;
targetRotation = Quaternion.Euler(
transform.localEulerAngles.x,
transform.localEulerAngles.y,
tiltEffectAngle);
} else if (touchX <= -0.9f) {
objectX -= 0.05f;
targetRotation = Quaternion.Euler(
transform.localEulerAngles.x,
transform.localEulerAngles.y,
-tiltEffectAngle);
}
currentPos = new Vector3(objectX, objectY, 0.0f);
transform.position = currentPos;
}
}
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, tiltEffectSpeed * Time.deltaTime);
}
I made the precursor to my 3d Agario game. It is a mouse-oriented game. You use the mouse to control most of the movement. This includes the rotation of the Camera.
My problem is the Camera won't stop rotating. This is because it is very hard to center the mouse to the center of the screen, and the way I made the Camera rotate is by using a Sine equation.
Here is my code:
//public
public GameObject player;
public float rotationSpeed;
//v3
private Vector3 mousePos;
private Vector3 playerPos;
private Vector3 camPos;
//float
private float sideX;
private float sideZ;
private float sideC;
private float camX;
private float camZ;
private float camC;
private float rotX;
private float rotZ;
private float rotC;
private float rotAngle;
private Quaternion currRotation;
//camera
private Camera hitCam;
void Start ()
{
transform.rotation = Quaternion.Euler(30, 0, 0);
transform.position = new Vector3(0, 15, 0);
}
void LateUpdate ()
{
mousePos = HitCameraController.mousePos;
playerPos = player.transform.position;
sideX = (mousePos.x - playerPos.x);
sideZ = (mousePos.z - playerPos.z);
sideC = (Mathf.Sqrt(Mathf.Pow(sideX, 2) + Mathf.Pow(sideZ, 2)));
camC = 15;
camX = (camC * sideX) / sideC;
camZ = (camC * sideZ) / sideC;
rotX = (sideX + camX);
rotZ = (sideZ + camZ);
rotC = (Mathf.Sqrt(Mathf.Pow(rotX, 2) + Mathf.Pow(rotZ, 2)));
if (rotX >= 0 && rotZ >= 0)
{
rotAngle = (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
if (rotX >= 0 && rotZ <= 0)
{
rotAngle = 180 - (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
if (rotX <= 0 && rotZ >= 0)
{
rotAngle = (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
if (rotX <= 0 && rotZ <= 0)
{
rotAngle = -180 - (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
camPos = new Vector3((playerPos.x - camX), 15, (playerPos.z - camZ));
currRotation = Quaternion.Euler(30, rotAngle, 0);
// Move Camera
transform.position = camPos;
// Rotate Camera
/*transform.rotation = Quaternion.RotateTowards(
transform.rotation, currRotation,
(rotationSpeed * Time.deltaTime));*/
transform.rotation = currRotation;
}
I want to make a sort of "safe-zone" that will prevent the calculation of the rotating angle. For instance, if I keep my mouse within a certain boundary in the center, the Camera won't rotate.
I tried to make the boundary using an "or" statement, but it didn't give me the result I was looking for (the camera would still rotate even when my mouse was in the boundary. The Camera would stop on some tries, but it would jitter immensely before doing so.)
I know exactly why this is occurring: the ray isn't being cast on a still camera; hence, the mouse coordinate will always change, even if I don't move the mouse. I tried casting the ray to the "Hit" camera (the still Camera), but the follow camera couldn't pick up on the mouse movement. I don't know how to fix this problem other than to keep brainstorming for an intuitive solution, but my brain can only innovate so much.
If you could think of a solution before me, let me know by any means.
[...]
void LateUpdate ()
{
mousePos = HitCameraController.mousePos;
playerPos = player.transform.position;
sideX = (mousePos.x - playerPos.x);
sideZ = (mousePos.z - playerPos.z);
sideC = (Mathf.Sqrt(Mathf.Pow(sideX, 2) + Mathf.Pow(sideZ, 2)));
// New Stuff
sideC -= 5f; // substract the safe-zone-radius
if(sideC < 0f)
{
// Inside safe-zone, do nothing.
sideC = 0f;
sideX = 0f;
sideZ = 0f;
}else{
// Outside safe-zone, correct values to avoid jumping.
float x_ratio = sideX / sideZ; // be careful with "divide by zero"
float z_ratio = sideZ / sideX;
sideX -= 5 * x_ratio;
sideZ -= 5 * z_ratio;
}
// End New Stuff
camC = 15;
camX = (camC * sideX) / sideC;
camZ = (camC * sideZ) / sideC;
rotX = (sideX + camX);
rotZ = (sideZ + camZ);
rotC = (Mathf.Sqrt(Mathf.Pow(rotX, 2) + Mathf.Pow(rotZ, 2)));
if (rotX >= 0 && rotZ >= 0)
{
rotAngle = (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
if (rotX >= 0 && rotZ <= 0)
{
rotAngle = 180 - (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
if (rotX <= 0 && rotZ >= 0)
{
rotAngle = (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
if (rotX <= 0 && rotZ <= 0)
{
rotAngle = -180 - (Mathf.Asin(rotX / rotC) * Mathf.Rad2Deg);
}
camPos = new Vector3((playerPos.x - camX), 15, (playerPos.z - camZ));
currRotation = Quaternion.Euler(30, rotAngle, 0);