Unity camera rotation around object to a smooth stop - unity3d

I have a script that makes my camera rotate around a target when right click is pressed. Currently, when the right click is released, the rotation comes to a full stop, which is fully expected behavior. I want it to keep rotating for a little while after the mouse button is up, before it comes to a full stop, like if it was decelerating. Here is the code that handles the rotation around the given target:
if (!target)
return;
if (Input.GetMouseButtonDown(1))
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
if (Input.GetMouseButton(1))
{
Vector3 nextDirection = previousPosition - cam.ScreenToViewportPoint(Input.mousePosition);
direction = Vector3.SmoothDamp(direction, nextDirection, ref smoothVelocity, smoothTime);
cam.transform.position = target.position;
cam.transform.Rotate(new Vector3(1, 0, 0), direction.y * 180);
cam.transform.Rotate(new Vector3(0, 1, 0), -direction.x * 180, Space.World);
cam.transform.Translate(new Vector3(0, 0, -distanceFromSphere));
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
}
Here are the needed references:
public Camera cam;
public Vector3 previousPosition;
public Transform target;
public float distanceFromSphere = 100;
public Vector3 direction;
public Vector3 smoothVelocity = Vector3.zero;
public float smoothTime = 3f;
Is there a way to make the camera rotation be accelerated when the mouse button is down, and when the mouse is up, to be decelerated?

What you need is inertia, get the Rotate and Translate calls outside the if statement, and at the end multiply the direction with 0.98 or 0.99 depending on how much intertia you need.
public float inertia = 0.98f;
direction *= inertia;

Chris Ch's solution works fine, but I had already done something different, here is my solution to the original question:
void UpdateWorldRotation()
{
if (!target)
return;
if (Input.GetMouseButtonDown(1))
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
Vector3 currentSmoothVelocity = new Vector3();
if (Input.GetMouseButton(1))
{
nextDirection = previousPosition - cam.ScreenToViewportPoint(Input.mousePosition);
currentSmoothVelocity = smoothVelocity;
}
if (Input.GetMouseButtonUp(1))
{
StartCoroutine(SmoothStop());
currentSmoothVelocity = smoothVelocity / 2;
}
direction = Vector3.SmoothDamp(direction, nextDirection, ref currentSmoothVelocity, smoothTime, 100, 10f * Time.deltaTime);
cam.transform.position = target.position;
cam.transform.Rotate(new Vector3(1, 0, 0), direction.y * 180);
cam.transform.Rotate(new Vector3(0, 1, 0), -direction.x * 180, Space.World);
cam.transform.Translate(new Vector3(0, 0, -distanceFromSphere));
previousPosition = cam.ScreenToViewportPoint(Input.mousePosition);
}
IEnumerator SmoothStop()
{
yield return new WaitForSeconds(smoothStopTime);
nextDirection = Vector3.zero;
}
This way, the sphere keeps rotating for a specific amount of time with a slower velocity before it comes to a full stop.

Related

Unity2D - Enemy shoot at player in a cone shaped pattern

I am trying to set up an enemy that will shoot at the player in a cone shape/shotgun shape. If I set the projectile script to transform.position += transform.right * m_Speed * Time.deltaTime; then the cone shape works as intended, just only to the right and not in the direction of the player. With the current setup (below), the projectile will shoot at the player, but all the bullet prefabs will be on top of each other and all going in the same direction, not in a cone shape.
How can I adjust this so the enemy will shoot at the player but retain the cone shape?
Enemy Script
aimAngle = 60f;
for (int i = 0; i < spreadShot; i++)
{
var shotRotation = gameObject.transform.rotation;
shotRotation *= Quaternion.Euler(0, 0, aimAngle);
GameObject clone = Instantiate(projectile, new Vector2(gameObject.transform.position.x, gameObject.transform.position.y), shotRotation);
aimAngle = aimAngle - 30f;
Vector3 direction = (Vector3)((player.transform.position - transform.position));
direction.Normalize();
clone.GetComponent<Projectile>().Setup(direction);
}
Projectile.cs
[SerializeField] float m_Speed;
Vector3 shootDir;
public void Setup(Vector3 shootDir)
{
this.shootDir = shootDir;
}
private void Update()
{
transform.position += shootDir * m_Speed * Time.deltaTime;
}
Not perfect yet but here is a working solution if anyone else has the same question.
Enemy Script
[SerializeField] public float attackSpread;
[SerializeField] private float startShotTime;
[SerializeField] private float delayShotTime;
[HideInInspector] public int spreadShot;
public void Attack() {
Vector2 targetPosition = target.transform.position - aimIndicator.transform.position;
Vector2 dirTowardsTarget = (targetPosition - (Vector2)transform.position);
transform.right = targetPosition.normalized;
Quaternion newRot;
for (int i = 0; i < spreadShot; i++)
{
float addedOffset = (i - (spreadShot / 2)) * attackSpread;
newRot = Quaternion.Euler(transform.localEulerAngles.x,
transform.localEulerAngles.y,
transform.localEulerAngles.z + addedOffset);
Instantiate(projectile).GetComponent<ButcherProjectile>().SpawnBullet(transform.position, newRot);
}
}
Projectile Script
[SerializeField] private float MovementSpeed = 10;
private Vector2 velocity;
public void SpawnBullet(Vector3 position, Quaternion rotation)
{
transform.position = position;
transform.rotation = rotation;
velocity = transform.right.normalized * MovementSpeed;
}
public void Update()
{
Vector2 nextPosition = (Vector2)transform.position + (velocity * Time.deltaTime);
transform.position = nextPosition;
Destroy(gameObject, 2f);
}
At the moment, your code rotates the bullet itself, not the vector of direction towards player. Shot rotation you computed doesn't affect your direction in any way.
To elaborate, if you rotate an object and just move it by transform.position, you changed its position by exactly how you specified, as if you just changed its x, y or z component by hand. Your rotation change to an object would produce desired results if you used transform.Translate(params) as this operation is dependant on object's current rotation and scale.
Apply your rotation to the direction, it should work just fine :)
More reference on how to do it: https://answers.unity.com/questions/46770/rotate-a-vector3-direction.html

Cameras rotation is too slow

I have a game object that moves and rotates. I want the camera to stay behind the object all the time, so when the user presses w, it will look like the gameobject moves forward.
This is my skript for the camera movement.
public Transform target;
public Vector3 offset;
public void FixedUpdate()
{
transform.position = target.TransformPoint(offset);
transform.LookAt(target);
}
But I camera is not rotating around the player fast enough, so it looks like he is moving sidewards.
This is my player movement script, but I don't see any mistake in there.
public float smoothSpeed = 0.125f;
public float forwardSpeed;
public float sideSpeed;
// Start is called before the first frame update
void Start()
{
}
void FixedUpdate()
{
if (Input.GetKey("w"))
{
Vector3 movement = transform.rotation * Vector3.forward / (100 / forwardSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("s"))
{
Vector3 movement = transform.rotation * Vector3.back / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("a"))
{
Vector3 movement = transform.rotation * Vector3.left / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("d"))
{
Vector3 movement = transform.rotation * Vector3.right / (100 / sideSpeed);
transform.Translate(movement);
}
else if (Input.GetKey("e"))
{
transform.Rotate(0, 1, 0);
}
else if (Input.GetKey("q"))
{
transform.Rotate(0, -1, 0);
}
}
Thanks for your help]1
When the object moves sidewards it should move forwards.
Here are my settings in Unity:

unity camera follow rolling box

i have a cube that rolls with the arrow keys or control pad
up goes up, left turns left, and right turns right, so only the up makes it roll
im trying to get a camera to follow but not really getting anywhere
i found this script cant rember where that im trying to alter
but as i roll the cube forward the camera spins
simple video showing movment
https://imgur.com/a/BfoR1VF
any pointers in the right direction sorry about the pun would be good
simple lookat script
public Transform player;
void Start()
{
}
void Update()
{
Vector3 targetPostion = new Vector3(player.transform.position.x, transform.position.y,player.transform.position.z);
transform.LookAt(targetPostion);
}
and the follow script
// The target we are following
public Transform target;
// The distance in the x-z plane to the target
//So this would be your offset
public float distance = 10.0f;
// the height we want the camera to be above the target
public float height = 5.0f;
// How much we
public float heightDamping = 2.0f;
public float rotationDamping = 3.0f;
void LateUpdate()
{
// Early out if we don't have a target
if (!target) return;
// Calculate the current rotation angles
float wantedRotationAngle = target.eulerAngles.y;
float wantedHeight = target.position.y + height;
float currentRotationAngle = transform.eulerAngles.y;
float currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position = new Vector3(transform.position.x, currentHeight, transform.position.z);
// Always look at the target
Vector3 thetargetPostition = new Vector3(0, target.position.y,0);
transform.LookAt(target.position);
//transform.LookAt(thetargetPostition);

How do I make the border of a map and the panning of that map the same?

I am using a map bigger than the screen I viewing. Therefore I need to be able to pan around that map. I am having a problem with clamping the camera and the map. I want to be able to use the demension of the image as the width and height of the clamp. The problem is the units.
The image is 2144 x 1708
The camera transposition is in single digits (14 x 7) or something like that.
All of the code I am using is below.
private Vector3 mouseOrigin; // Position of cursor when mouse dragging starts
private bool isPanning; // Is the camera being panned?
public bool useBoundary = true;
public Vector2 boundaryMin;
public Vector2 boundaryMax;
public Image map;
private void Start()
{
Camera cam = Camera.main;
float mapRatio = map.rectTransform.rect.width / map.rectTransform.rect.height;
float mapScreenHeight = (1.5f * cam.orthographicSize);
float mapScreenWidth = (3f * mapScreenHeight) * cam.aspect;
boundaryMin = new Vector2(0, 1);
boundaryMax = new Vector2(map.rectTransform.rect.width, map.rectTransform.rect.height);
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
mouseOrigin = Input.mousePosition;
isPanning = true;
}
// Disable movements on button release
if (!Input.GetMouseButton(0))
isPanning = false;
if (isPanning)
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
Vector3 move = new Vector3(pos.x * panSpeed, pos.y * panSpeed, 0);
transform.Translate(move, Space.Self);
BoundaryCheck();
}
}
private void BoundaryCheck()
{
if (!useBoundary)
return;
Vector3 newPos = transform.position;
newPos.x = Mathf.Clamp(newPos.x, boundaryMin.x, boundaryMax.x);
newPos.y = Mathf.Clamp(newPos.y, boundaryMin.y, boundaryMax.y);
transform.position = newPos;
}
}
Any help would be greatly appreciated.
You can do this using Unity UI - Scroll Rect.
Check out Unity UI - Scroll Rect - Introduction
In my opinion you should need to use below script for camera panning, zooming and rotating. You can off any undesirable function. Now according to your question you have to restrict the movement(according to your image border). simply you can restrict the camera movements on differet axis according to your limitations. You should place cubes into the borders of the map and use their positions as the limit of camera movement and panning etc.
using UnityEngine;
using System.Collections;
public class CamMovementManager : MonoBehaviour
{
#region Vars
public float turnSpeed = 1.0f; // Speed of camera turning when mouse moves in along an axis
public float panSpeed = 4.0f; // Speed of the camera when being panned
public float zoomSpeed = 4.0f; // Speed of the camera going back and forth
private Vector3 mouseOrigin; // Position of cursor when mouse dragging starts
private bool isPanning; // Is the camera being panned?
private bool isRotating; // Is the camera being rotated?
private bool isZooming; // Is the camera zooming?
private float pannPosLimit = 300f;
private int fovMin = 15;
private int fovMax = 90;
#endregion Vars
#region UnityEvents
void Update()
{
// Get the left mouse button
if (Input.GetMouseButtonDown(0))
{
// Get mouse origin
mouseOrigin = Input.mousePosition;
isRotating = true;
}
// Get the right mouse button
if (Input.GetMouseButtonDown(1))
{
// Get mouse origin
mouseOrigin = Input.mousePosition;
isPanning = true;
}
// Get the middle mouse button
if (Input.GetMouseButtonDown(2))
{
// Get mouse origin
//mouseOrigin = Input.mousePosition;
//isZooming = true;
}
//changing fov on mouse scroll to zoomIn/out
float fov = Camera.main.fieldOfView;
fov += Input.GetAxis("Mouse ScrollWheel") * 10f;
fov = Mathf.Clamp(fov, fovMin, fovMax);
Camera.main.fieldOfView = fov;//*/
// Disable movements on button release
if (!Input.GetMouseButton(0)) isRotating = false;
if (!Input.GetMouseButton(1)) isPanning = false;
if (!Input.GetMouseButton(2)) isZooming = false;
// Rotate camera along X and Y axis
if (isRotating)
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
//Debug.Log("rotate pos : " + pos);
transform.RotateAround(transform.position, transform.right, -pos.y * turnSpeed);
transform.RotateAround(transform.position, Vector3.up, pos.x * turnSpeed);
}
// Move the camera on it's XY plane
if (isPanning)
{
if (Input.mousePosition.y > pannPosLimit)
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
Vector3 move = new Vector3(pos.x * panSpeed, pos.y * panSpeed, 0);
transform.Translate(move, Space.Self);
}
}
// Move the camera linearly along Z axis
if (isZooming)
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
Vector3 move = pos.y * zoomSpeed * transform.forward;
transform.Translate(move, Space.World);
}
}
#endregion
#region CustomMethods
public void CamRotating()
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
transform.RotateAround(transform.position, transform.right, -pos.y * turnSpeed);
transform.RotateAround(transform.position, Vector3.up, pos.x * turnSpeed);
}
public void CamPanning()
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
Vector3 move = new Vector3(pos.x * panSpeed, pos.y * panSpeed, 0);
transform.Translate(move, Space.Self);
}
public void CamZooming()
{
Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - mouseOrigin);
Vector3 move = pos.y * zoomSpeed * transform.forward;
transform.Translate(move, Space.World);
}
#endregion CustomMethods
}

3rd person camera follower in Unity3D

I try to make a 3rd person camera, which follows my player and the camera should rotate, but not the player, if I use the right analog Stick of my controller. I followed this tutorial
My code:
void adjustCameraToPlayer()
{
Quaternion rotation = Quaternion.identity;
if (Input.GetAxis("RightStickX") != 0f)
{
float horizontal = Input.GetAxis("RightStickX") / 100f;
transform.Rotate(0, horizontal, 0);
float desiredAngle = transform.eulerAngles.y;
rotation = Quaternion.Euler(0, desiredAngle, 0);
}
transform.position = player.transform.position-(rotation * offset);
transform.LookAt(player.transform);
}
My problem is that the camera rotates way too fast, I tried to change the dividend of the horizontal value but it did not help.
That's why you always should incorporate deltaTime into transform operations that happen every frame. That way you aren't rotating it at magnitude every single frame, but instead over time. Also you should incorporate a speed variable which can be manipulated in real time, so you can tweak it just how you want:
public float speed = 5f;
void adjustCameraToPlayer()
{
Quaternion rotation = Quaternion.identity;
if (Input.GetAxis("RightStickX") != 0f)
{
float horizontal = Input.GetAxis("RightStickX");
transform.Rotate(Vector3.up * horizontal * speed * Time.deltaTime);
float desiredAngle = transform.eulerAngles.y;
rotation = Quaternion.Euler(0, desiredAngle, 0);
}
transform.position = player.transform.position-(rotation * offset);
transform.LookAt(player.transform);
}