Camera Zoom Lerp - c#

I am struggling to use Lerp to smooth out my camera zoom. The following code is a snippet of what I have written to zoom the camera in and out. I know that I should be making the Lerp during
transform.position = cameraTarget.position - (transform.rotation * Vector3.forward * distance);
within the LateUpdate function but I cant for the life of me figure out where I am going wrong!
public class CameraController : MonoBehaviour
{
[SerializeField] private Transform cameraTarget;
[SerializeField] private Transform cameraMain;
[Header("Distance from camera to target")]
public float minDistance = 6;
public float maxDistance = 20;
public float distance = 20;
[Header("Zoom and scroll variables")]
public KeyCode scrollButton = KeyCode.Mouse2;
[Range(0.5f, 1.5f)] public float zoomSpeed = 1;
[Range(0.5f, 1.5f)] public float rotationSpeed = 1;
public float xMinAngle = 25;
public float xMaxAngle = 80;
void LateUpdate()
{
if (!cameraTarget) return;
CameraZoom();
transform.position = cameraTarget.position - (transform.rotation * Vector3.forward * distance);
}
private void CameraZoom()
{
//Add a lerp function to smooth the zoom
float step = GetAxisRawScrollUniversal() * zoomSpeed;
distance = Mathf.Clamp(distance - step, minDistance, maxDistance);
}
public static float GetAxisRawScrollUniversal()
{
float scroll = Input.GetAxisRaw("Mouse ScrollWheel");
if (scroll < 0) return -1;
if (scroll > 0) return 1;
return 0;
}
}

Define a zoomLerpFactor field, then use Vector3.Lerp to go from the current position towards the position you would have set to transform.position.
[Range(0f, 1f)] public float zoomLerpFactor = 0.3f;
...
Vector3 goalPosition = cameraTarget.position
- (transform.rotation * Vector3.forward * distance);
transform.position = Vector3.Lerp(transform.position, goalPosition, zoomLerpFactor);
Just be aware, using Lerp alone may not guarantee that the position equals the goalPosition. So, you may want to just set the transform.position = goalPosition; if it's "close enough".

Related

How I can put limits on the rotation of the camera on the Y axis? Help me ยง

I can't put a limit on the rotation on the Y axis and also I would have my player look in the direction he is moving , I have already tried to put Mathf.calmp for the Touchfiled.Touchdist.y (camera Y axis) but it doesn't work I don't know where the problem comes from but I would like to solve it so please help me.
here is my code :
public FloatingJoystick joystick;
public TouchField touchField;
public GameObject FocusPoint;
[HideInInspector] public CharacterController characterController;
[HideInInspector] public Vector3 motionVector , gravityVector, RelativeVector;
[Header("Player Settings")]
[Range(0,6)] public float PlayerSpeed = 2.5f;
[Range(0, 100)] public float Sensivility = 50;
[Range(0, 0.5f)] public float groundClearance;
private float gravityForce = -9.18f;
private float gravityPower = -9.8f;
private float JumpValue = 9.8f;
private float TurnDiraction;
private void Start()
{
characterController = GetComponent<CharacterController>();
}
private void Update()
{
Movment();
CameraController();
if (characterController.isGrounded)
{
print("Grounded");
}
}
public void CameraController()
{
RelativeVector = transform.InverseTransformPoint(FocusPoint.transform.position);
RelativeVector /= RelativeVector.magnitude;
TurnDiraction = (RelativeVector.x / RelativeVector.magnitude);
FocusPoint.transform.eulerAngles = new Vector3(FocusPoint.transform.eulerAngles.x + touchField.TouchDist.y, FocusPoint.transform.eulerAngles.y, 0) ;
FocusPoint.transform.parent.Rotate(transform.up * touchField.TouchDist.x * Sensivility * Time.deltaTime);
}
public void Movment()
{
if (characterController.isGrounded && gravityVector.y < 0)
{
gravityVector.y = -2;
}
gravityVector.y += gravityPower * Time.deltaTime;
characterController.Move(gravityVector * Time.deltaTime);
if (characterController.isGrounded)
{
motionVector = transform.right * joystick.Horizontal + transform.forward * joystick.Vertical;
characterController.Move(motionVector * PlayerSpeed * Time.deltaTime);
if(joystick.Vertical > 0)
{
transform.Rotate(transform.up * TurnDiraction * 800 * Time.deltaTime);
FocusPoint.transform.parent.Rotate(transform.up * -TurnDiraction * 800 * Time.deltaTime);
}
}
}
You rotate in 2 steps, and in the second and in the second one you do:
FocusPoint.transform.parent.Rotate(transform.up * touchField.TouchDist.x * Sensivility * Time.deltaTime);
If you rotate the parent respect the y axis all the children turn along with the rotation given to the parent in the hierarchy.
So it does not matter that you clamp the y rotation in the previous step
FocusPoint.transform.eulerAngles = new Vector3(FocusPoint.transform.eulerAngles.x + touchField.TouchDist.y, FocusPoint.transform.eulerAngles.y, 0);
if the gameobject is going to be rotated respect y axis after.
Try rotating at once according to your limits, or take into account those limits for all the rotation steps.
On the other hand, gravity is neither a power, nor a force, but an acceleration :)

Problem with Mathf.Clamp and rotation in Unity

I have a problem with my camera movement. I want to limit my camera rotation, but I don't know how to do this. I searched for a solution, but I was not able to find one.
In my current code, my camera rotates rapidly in any direction and I don't know how to implement the Mathf.Clamp correctly.
Here is my code:
public float rightSpeed = 20.0f;
public float leftSpeed = -20.0f;
public float rotationLimit = 0.0f;
void Update()
{
//EdgeScrolling
float edgeSize = 40f;
if (Input.mousePosition.x > Screen.width - edgeSize)
{
//EdgeRight
transform.RotateAround(this.transform.position, Vector3.up, rotationLimit += rightSpeed * Time.deltaTime);
}
if (Input.mousePosition.x < edgeSize)
{
//EdgeLeft
transform.RotateAround(this.transform.position, Vector3.up, rotationLimit -= leftSpeed * Time.deltaTime);
}
rotationLimit = Mathf.Clamp(rotationLimit, 50f, 130f);
}
RotateAround method rotates by an angle. It doesn't assign the angle value you pass it. In this case I would suggest using a different approach. Instead of RotateAround method use the eulerAngles property and assign the rotation values directly.
Example
using UnityEngine;
public class TestScript : MonoBehaviour
{
public float rightSpeed = 20.0f;
public float leftSpeed = -20.0f;
private void Update()
{
float edgeSize = 40f;
if (Input.mousePosition.x > Screen.width - edgeSize)
RotateByY(rightSpeed * Time.deltaTime);
else if (Input.mousePosition.x < edgeSize)
RotateByY(leftSpeed * Time.deltaTime);
}
public void RotateByY(float angle)
{
float newAngle = transform.eulerAngles.y + angle;
transform.eulerAngles = new Vector3(
transform.eulerAngles.x,
Mathf.Clamp(newAngle, 50f, 130f),
transform.eulerAngles.z);
}
}

how to make a predictive trajectory arc while aiming?

I am trying to build a trajectory arc that would predict the trajectory path of the object, the drag and shoot seem fine but the arc is not working. initially I used an arrow for showing the direction of the movement of the object but later I tried to do the same using an array which would store 2 points and would keep updating after every iteration and it would result in an arc since I used the equations of motion to predict the positions after each frame.
***
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement: MonoBehaviour
{
public float velocity;
float time;
float x;
float y;
float tt;
float g;
Vector2 force;
public float power = 2.0f;
Vector3 startpoint;
Vector3 endpoint;
Camera cam;
public Vector2 maxpower;
public Vector2 minpower;
public Rigidbody2D rb;
Vector3 currentposition;
Vector3 sp;
LineRenderer lr;
int resolution = 10;
Vector3 newpoint;
// Start is called before the first frame update
void Start()
{
time = 0f;
g = Mathf.Abs(Physics2D.gravity.y);
cam = Camera.main;
lr = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
time += Time.deltaTime;
x = gameObject.transform.position.x + velocity * time;
tt = time * time;
y = gameObject.transform.position.y + (g * tt) / 2f;
if(Input.GetMouseButtonDown(0))
{
startpoint = cam.ScreenToWorldPoint(Input.mousePosition);
startpoint.z = 5;
}
if(Input.GetMouseButton(0))
{
sp = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, 5);
currentposition = cam.ScreenToWorldPoint(Input.mousePosition);
currentposition.z = 5;
LineRenderer(sp);
}
if (Input.GetMouseButtonUp(0))
{
endpoint = cam.ScreenToWorldPoint(Input.mousePosition);
endpoint.z = 5;
force = new Vector2(Mathf.Clamp(startpoint.x - endpoint.x, minpower.x, maxpower.x), Mathf.Clamp(startpoint.y - endpoint.y, minpower.y, maxpower.y));
rb.AddForce(force * power, ForceMode2D.Impulse);
x = x + velocity * time;
y = y + (g * tt) / 2f;
EndLine();
}
}
public void LineRenderer(Vector3 p)
{
lr.positionCount = resolution;
Vector3 arc = p;
for(int i=0;i<resolution;i++)
{
newpoint = calculate(arc, i / (float)resolution);
lr.SetPosition(i, newpoint);
arc = newpoint;
}
}
public Vector3 calculate(Vector3 point, float t)
{
point.x += velocity * t;
point.y += 0.5f * g * t * t;
return point;
}
public void EndLine()
{
lr.positionCount = 0;
}
}
***
This the code, any help is appreciated.
A bug that I see is your delta-time:
You call Calculate(arc, i/resolution), with i and resolution both being integers.
The parameter might be float time, but C# will first calculate i/resolution as an integer division, then convert the result to float. The result will be zero as long as i is less than resolution.
Change it to: i/(float)resolution to force a floating-point division.

Rotate GameObject based on key presses and based on Terrain slope/curvature

I have code in C# in a game in Unity that needs to rotate the player based on the slope of the terrain but the RotateTowards function(calculates the slope and angle) doesn't allow the object to be rotated sideway to move it in different directions. If I take out the rotateTowards function, rotations sideways work. If I dont, the correct slope rotation works but player won'r rotate sideways when buttons are pressed.
How could I fix this so the player could rotate in both ways?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController1 : MonoBehaviour
{
[System.Serializable]
public class MoveSettings
{
public float forwardVel = 10f; // walk speed
public float rotateVel = 100; // character rotation speed, character can walk 360 degree
public float jumpVel = 25f;
public LayerMask ground;
public Transform backLeft; // back left feet
public Transform backRight; // back right feet
public Transform frontLeft; // front left feet
public Transform frontRight; // front left feet
}
[System.Serializable]
public class PhysicsSettings
{
public float downAccel = 0.75f; // down speed when not grounded
}
public GameObject Model;
public GameObject Origin;
public MoveSettings moveSettings = new MoveSettings();
public PhysicsSettings physicsSettings = new PhysicsSettings();
private Vector3 velocity = Vector3.zero;
private Quaternion targetRotation;
private CharacterController cc;
private float forwardInput, turnInput, jumpInput = 0;
private RaycastHit lr;
private RaycastHit rr;
private RaycastHit lf;
private RaycastHit rf;
private Vector3 upDir;
private Animator Anim; // global private variable
private void Start()
{
Anim = GetComponent<Animator>(); // in the Start function
targetRotation = transform.rotation;
cc = GetComponent<CharacterController>();
}
public bool Grounded()
{
return cc.isGrounded;
}
private void FixedUpdate()
{
Run(); // calculate the velocity to be applied on character controller, stored in the velocity variable
Jump(); // code for jumping
GetInput(); // movement input keys
Turn(); // character movement direction input
cc.Move(transform.TransformDirection(velocity) * Time.deltaTime);
RotateTowardsGround();
}
private void GetInput()
{
Anim.SetFloat("vSpeed", forwardInput); // in the GetInput() function
Anim.SetFloat("Direction", 1f);
forwardInput = Input.GetAxis("Vertical");
turnInput = Input.GetAxis("Horizontal");
jumpInput = Input.GetAxisRaw("Jump");
}
private void Turn()
{
targetRotation *= Quaternion.AngleAxis(moveSettings.rotateVel * turnInput * Time.deltaTime, Vector3.up);
transform.rotation = targetRotation;
}
public void Jump()
{
if (jumpInput > 0 && Grounded())
{
velocity.y = moveSettings.jumpVel;
}
else if (jumpInput == 0 && Grounded())
{
velocity.y = 0;
}
else
{
velocity.y -= physicsSettings.downAccel;
}
}
private void Run()
{
velocity.z = moveSettings.forwardVel * forwardInput;
}
public void RotateTowardsGround()
{
// we have four feet
Physics.Raycast(moveSettings.backLeft.position + Vector3.up, Vector3.down, out lr);
Physics.Raycast(moveSettings.backRight.position + Vector3.up, Vector3.down, out rr);
Physics.Raycast(moveSettings.frontLeft.position + Vector3.up, Vector3.down, out lf);
Physics.Raycast(moveSettings.frontRight.position + Vector3.up, Vector3.down, out rf);
upDir = (Vector3.Cross(rr.point - Vector3.up, lr.point - Vector3.up) +
Vector3.Cross(lr.point - Vector3.up, lf.point - Vector3.up) +
Vector3.Cross(lf.point - Vector3.up, rf.point - Vector3.up) +
Vector3.Cross(rf.point - Vector3.up, rr.point - Vector3.up)
).normalized;
Debug.DrawRay(rr.point, Vector3.up);
Debug.DrawRay(lr.point, Vector3.up);
Debug.DrawRay(lf.point, Vector3.up);
Debug.DrawRay(rf.point, Vector3.up);
Model.transform.up = upDir;
}
}
The proper way to rotate object based on Terrain slope/curvature is to first throw raycast then obtain the returned RaycastHit.normal value and assign it your to the object's transform.up. It's better to use Lerp or Slerp to do this form smooth ration.
As for the position of the object, you can calculate that with Terrain.activeTerrain.SampleHeight as described in this post or you can use RaycastHit.point like you did in the code from your question.
Below is an example of what I described above. It is a minimal code to move/rotate object over a terrain. You can modify it to fit your four character legs scenario.
public class Hover : MonoBehaviour
{
public Transform objectToMove;
public float maxSpeed = 10f;
public float angleSpeed = 5f;
public float groundDistOffset = 2f;
private Vector3 toUpPos = Vector3.zero;
void Update()
{
float hInput = Input.GetAxis("Horizontal");
float vInput = Input.GetAxis("Vertical");
Vector3 objPos = objectToMove.position;
objPos += objectToMove.forward * vInput * maxSpeed * Time.deltaTime;
objPos += objectToMove.right * hInput * maxSpeed * Time.deltaTime;
RaycastHit hit;
if (Physics.Raycast(objectToMove.position, -Vector3.up, out hit))
{
//Get y position
objPos.y = (hit.point + Vector3.up * groundDistOffset).y;
//Get rotation
toUpPos = hit.normal;
}
//Assign position of the Object
objectToMove.position = objPos;
//Assign rotation/axis of the Object
objectToMove.up = Vector3.Slerp(objectToMove.up, toUpPos, angleSpeed * Time.deltaTime);
}
}

C# with Unity 3D: How do I make a camera move around an object when user moves mouse

I am trying to make a 3d viewing simulation in Unity 4 where the user can select an object and move their mouse to rotate around it (360 degrees) I have taken many shots to try get it to work, but I fail each time, any help will be appreciated and if it is written in C# that would be great! (But it doesn't have to)
Thanks in advance!
This is a different and interesting way :) (I use it)
(Here, the cube is the target)
1) Create sphere - Name: "Camera Orbit" - Add material: Transparent (Alpha = 0) - As scale as you want - Rotation: (0,0,0.1f)
2) Add the camera as a "child" to Camera Orbit's surface. Position = (0,"y = camera orbit scale",0)
Rotation = (90,0,0)
3) Create empty GameObject - Name: Input Control.
InputControl.cs:
public class InputControl : MonoBehaviour
{
public GameObject cameraOrbit;
public float rotateSpeed = 8f;
void Update()
{
if (Input.GetMouseButton(0))
{
float h = rotateSpeed * Input.GetAxis("Mouse X");
float v = rotateSpeed * Input.GetAxis("Mouse Y");
if (cameraOrbit.transform.eulerAngles.z + v <= 0.1f || cameraOrbit.transform.eulerAngles.z + v >= 179.9f)
v = 0;
cameraOrbit.transform.eulerAngles = new Vector3(cameraOrbit.transform.eulerAngles.x, cameraOrbit.transform.eulerAngles.y + h, cameraOrbit.transform.eulerAngles.z + v);
}
float scrollFactor = Input.GetAxis("Mouse ScrollWheel");
if (scrollFactor != 0)
{
cameraOrbit.transform.localScale = cameraOrbit.transform.localScale * (1f - scrollFactor);
}
}
}
CameraController.cs:
public class CameraController : MonoBehaviour
{
public Transform cameraOrbit;
public Transform target;
void Start()
{
cameraOrbit.position = target.position;
}
void Update()
{
transform.rotation = Quaternion.Euler(transform.rotation.x, transform.rotation.y, 0);
transform.LookAt(target.position);
}
}
4) Add CameraController.cs to Camera.
5) Add InputControl.cs to Input Control.
6) Set public variables in scripts. ("Camera Orbit" and "Target")
That's all. Mouse click and drag: Rotate - Mouse whell: Zoom in-out.
ps. If you want, you can change target as runtime.
The MouseOrbit script do that:
http://wiki.unity3d.com/index.php?title=MouseOrbitImproved#Code_C.23
Just attach this script into your Camera Object, and link the target object in inspector.
-- Use this for the Mouse Press down and drag
-- I modified the code here: http://wiki.unity3d.com/index.php?title=MouseOrbitImproved#Code_C.23
public Transform target;
public float distance = 5.0f;
public float xSpeed = 120.0f;
public float ySpeed = 120.0f;
public float yMinLimit = -20f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
private Rigidbody rigidbody;
float x = 0.0f;
float y = 0.0f;
float mouseX = 0f;
float mouseY = 0f;
// Use this for initialization
void Start()
{
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody != null)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate()
{
if (target)
{
GetMouseButtonDown_XY();
x += mouseX * xSpeed * distance * 0.02f;
y -= mouseY * ySpeed * 0.02f;
y = ClampAngle(y, yMinLimit, yMaxLimit);
Quaternion rotation = Quaternion.Euler(y, x, 0);
distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel") * 5, distanceMin, distanceMax);
RaycastHit hit;
if (Physics.Linecast(target.position, transform.position, out hit))
{
distance -= hit.distance;
}
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
}
}
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360F)
angle += 360F;
if (angle > 360F)
angle -= 360F;
return Mathf.Clamp(angle, min, max);
}
Vector3 mousePosPrev;
void GetMouseButtonDown_XY()
{
if (Input.GetMouseButtonDown(0))
{
mousePosPrev = Camera.main.ScreenToViewportPoint(Input.mousePosition);
}
if (Input.GetMouseButton(0))
{
Vector3 newMousePos = Camera.main.ScreenToViewportPoint(Input.mousePosition);
if (newMousePos.x < mousePosPrev.x)
{
mouseX = -1;
} else if (newMousePos.x > mousePosPrev.x)
{
mouseX = 1;
} else
{
mouseX = -0;
}
if (newMousePos.y < mousePosPrev.y)
{
mouseY = -1;
}
else if (newMousePos.y > mousePosPrev.y)
{
mouseY = 1;
}
else
{
mouseY = -0;
}
mousePosPrev = Camera.main.ScreenToViewportPoint(Input.mousePosition);
}
}
This is perfect. The only change I made is to add a script to the Camera Orbit:
public class FollowPlayer : MonoBehaviour {
public GameObject player;
private Vector3 playerPos;
// Update is called once per frame
void Update () {
if (this.transform.localScale.x <= 1)
{
this.transform.localScale = new Vector3(1, 1, 1);
}
if (this.transform.localScale.x >= 15)
{
this.transform.localScale = new Vector3(15, 15, 15);
}
playerPos = player.transform.position;
this.transform.position = playerPos;
}
}
Then attach your "player" object to the Input Control, and the input control will go where ever the player does, allowing you to track the player, as well as rotate and mouse wheel zoom. Fancy.
The localScale if statements means you can only zoom in and out so far.
The only problem with this script now is that if you zoom out to 15 and then keep trying to zoom out, the camera bounces. I'm sure that's an easy fix, though, I just haven't put the time in yet.
You don't need the CameraController at all, just set the camera's z rotation to -90.

Categories

Resources