Unity 3D - Camera follow behind main character + offset - unity3d

I use the attached c# script to control the camera.
Mouse scroll (pulley/roller/wheel): Zooming in and out of the main character
Up Arrow (or W key) and Down Arrow (or X key): Raise and Lower the camera
Right arrow (or D key) and Left arrow (or A key): Rotate the camera around the main character
I try to get the camera to follow the back of the main character, and add it the offset that player defined by using mouse and arrows.
This line correctly moves the camera according to the input from the mouse and arrows:
transform.position = target.position + offset * currentZoom;
This line correctly moves the camera so that it will follow the back of the main character:
transform.position = target.position - target.forward + Vector3.up;
But each of them works correctly only if the other is canceled. If I try to merge them into one line, like:
transform.position = target.position - target.forward + Vector3.up + offset * currentZoom;
then the camera doesn't move properly:
Using the left and right arrows moves the camera around the main
character in ellipse/oval shape instead of in a circle
When the character moves, the offsset set by the right and left
arrows isn't saved but the camera returns to being exactly behind
the back of the main character
What do I need to do to combine the two lines so that camera does move properly?
using UnityEngine;
public class CameraController : MonoBehaviour
{
public Transform target;
public Vector3 offset = new Vector3(10f, 6f, 0f);
public float RotationX = .5f;
public float rightLeftSpeed = 5f;
public float currentZoom = .13f;
public float minZoom = .1f;
public float maxZoom = 1f;
public float speedZoom = .1f;
public float currentHeight = 6f;
public float minHeight = 0f;
public float maxHeight = 10f;
public float speedHeight = 1f;
void Update()
{
currentZoom -= Input.GetAxis("Mouse ScrollWheel") * speedZoom;
currentZoom = Mathf.Clamp(currentZoom, minZoom, maxZoom);
currentHeight += Input.GetAxis("Vertical") * speedHeight * Time.deltaTime;
currentHeight = Mathf.Clamp(currentHeight, minHeight, maxHeight);
offset.y = currentHeight;
offset = Quaternion.AngleAxis(-Input.GetAxis("Horizontal") * rightLeftSpeed, Vector3.up) * offset;
}
void LateUpdate()
{
transform.position = target.position + offset * currentZoom;
transform.position = target.position - target.forward + Vector3.up;
transform.LookAt(target.position + Vector3.up * RotationX);
}
}

I tested your code and adjusted it til it worked like you were trying to have it work. Instead of using offset, I used an angle. Then after setting the position, I rotate around the object by that angle. I set the height as part of setting the position. Lastly, I multiplied the target.forward by currentZoom to make it the distance the camera is from the object. I also adjusted the default values since these changes would make it really close otherwise. I'm pretty sure there are ways to simplify this a bit, but this works!
public class CameraController : MonoBehaviour {
public Transform target;
public float angle;
public float RotationX = .5f;
public float rightLeftSpeed = 5f;
public float currentZoom = 5f;
public float minZoom = 2f;
public float maxZoom = 8f;
public float speedZoom = .5f;
public float currentHeight = 6f;
public float minHeight = 3f;
public float maxHeight = 7f;
public float speedHeight = 1f;
void Update() {
currentZoom -= Input.GetAxis("Mouse ScrollWheel") * speedZoom * Time.deltaTime * 60f;
currentZoom = Mathf.Clamp(currentZoom, minZoom, maxZoom);
currentHeight += Input.GetAxis("Vertical") * speedHeight * Time.deltaTime * 60f;
currentHeight = Mathf.Clamp(currentHeight, minHeight, maxHeight);
angle -= Input.GetAxis("Horizontal") * rightLeftSpeed * Time.deltaTime * 60f;
}
void LateUpdate() {
var newPosition = target.position - (target.forward * currentZoom) + Vector3.up;
newPosition.y = target.position.y + currentHeight;
transform.position = newPosition;
transform.RotateAround(target.position, Vector3.up, angle);
transform.LookAt(target.position + Vector3.up * RotationX);
}
}

Related

is there a way to fix the constraints causing a player not to be able to walk off screen in unity 3d

I am trying to stop/clamp the z position of my object to stop it being able to walk off screen, however I am also trying to make it change the constraints automatically, however if i make the screen too small, it messes up.
The code that I have tried is:
public float speed = 10.0f;
public float rightConstraintRatio = 0.8f;
private float screenWidth;
private float leftConstraint;
private float rightConstraint;
private Rigidbody rigidBody;
private bool isGrounded = false;
public float offset = -2.63f;
void Start()
{
rigidBody = GetComponent<Rigidbody>();
screenWidth = Camera.main.orthographicSize * 2.0f * Camera.main.aspect;
}
void Update()
{
leftConstraint = -screenWidth / 2.0f - offset;
rightConstraint = screenWidth / 2.0f * rightConstraintRatio - offset;
float horizontal = Input.GetAxis("Horizontal");
Vector3 newPosition = transform.position + new Vector3(0, 0, horizontal) * speed * Time.deltaTime;
newPosition.z = Mathf.Clamp(newPosition.z, leftConstraint, rightConstraint);
transform.position = newPosition;
however this causes the constraints to be off when the screen changes too much

I wrote a script for movement and mouse look, movement works but mouse look does not

I am writing a script for movement and mouselook, the movement works but the mouse look does not. I start the game, the cursor locks into the game screen and I can move but I can't look around and there are no bugs. can someone help?
Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Controller : MonoBehaviour
{
[SerializeField]private float _speed = 7f;
[SerializeField]private float _mouseSensitivity = 50f;
[SerializeField]private float _minCameraview = -70f, _maxCameraview = 80f;
private CharacterController _charController;
private Camera _camera;
private float xRotation = 0f;
// Start is called before the first frame update
void Start()
{
_charController = GetComponent<CharacterController>();
_camera = Camera.main;
if(_charController == null)
Debug.Log("No Character Controller Attached to Player");
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
//Get WASD Input for Player
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
//move player based on WASD Input
Vector3 movement = Vector3.forward * vertical + Vector3.right * horizontal;
_charController.Move(movement * Time.deltaTime * _speed);
//Get Mouse position Input
float mouseX = Input.GetAxis("Mouse X") * _mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * _mouseSensitivity * Time.deltaTime;
//Rotate the camera based on the Y input of the mouse
xRotation -= mouseY;
//clamp the camera rotation between 80 and -70 degrees
xRotation = Mathf.Clamp(xRotation, _minCameraview, _maxCameraview);
_camera.transform.localRotation = Quaternion.Euler(xRotation, 0, 0);
//Rotate the player based on the X input of the mouse
transform.Rotate(Vector3.up * mouseX * 3);
}
}
The problem is that you are multiplying the mouse input by Time.deltaTime. Time.deltaTime is used when you want to have different devices with different frame rates. This is because when multiplying by Time.deltaTime, you get a constant speed of one unit per second:
float speed = 10f;
float movement = speed * Time.deltaTime;
If you have a frame rate of 10fps (hopefully you don't), you would have each frame in 0.1 second. Each frame is 0.1 second, so when multiplying it by 10 (the speed), you get a value of one. If you speed the frame rate up, you would also get 10 units a second (1 x 10 = 10).
The mouse movement doesn’t need this because mouse movement is not handled by the computer. In other words, when you are moving the mouse, it isn’t changing by the frame rate, so you don’t need ‘Time.deltaTime`.
I also noticed that your movement was based on Vector3. What I mean by this is that you were using global coordinates rather than local (transform). This means if the play rotates, Vector3.forward will be different than the player’s forward. You should use transform.forward instead to use local coordinates.
You should change the script to this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Controller : MonoBehaviour
{
[SerializeField]private float _speed = 7f;
[SerializeField]private float _mouseSensitivity = 50f;
[SerializeField]private float _minCameraview = -70f, _maxCameraview = 80f;
private CharacterController _charController;
private Camera _camera;
private float xRotation = 0f;
// Start is called before the first frame update
void Start()
{
_charController = GetComponent<CharacterController>();
_camera = Camera.main;
if(_charController == null)
Debug.Log("No Character Controller Attached to Player");
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
//Get WASD Input for Player
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
//move player based on WASD Input
Vector3 movement = transform.forward * vertical + transform.right * horizontal; //changed this line.
_charController.Move(movement * Time.deltaTime * _speed);
//Get Mouse position Input
float mouseX = Input.GetAxis("Mouse X") * _mouseSensitivity; //changed this line.
float mouseY = Input.GetAxis("Mouse Y") * _mouseSensitivity; //changed this line.
//Rotate the camera based on the Y input of the mouse
xRotation -= mouseY;
//clamp the camera rotation between 80 and -70 degrees
xRotation = Mathf.Clamp(xRotation, _minCameraview, _maxCameraview);
_camera.transform.localRotation = Quaternion.Euler(xRotation, 0, 0);
//Rotate the player based on the X input of the mouse
transform.Rotate(Vector3.up * mouseX * 3);
}
}
This is a script for both movement and looking
[RequireComponent(typeof(CharacterController))]
public class NewBehaviourScript : MonoBehaviour
{
public float walkingSpeed = 7.5f;
public float runningSpeed = 11.5f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
public Camera playerCamera;
public float lookSpeed = 2.0f;
public float lookXLimit = 45.0f;
CharacterController characterController;
Vector3 moveDirection = Vector3.zero;
float rotationX = 0;
[HideInInspector]
public bool canMove = true;
// Start is called before the first frame update
void Start()
{
characterController = GetComponent<CharacterController>();
// Lock cursor
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
// We are grounded, so recalculate move direction based on axes
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 right = transform.TransformDirection(Vector3.right);
// Press Left Shift to run
bool isRunning = Input.GetKey(KeyCode.LeftShift);
float curSpeedX = canMove ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Vertical") : 0;
float curSpeedY = canMove ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Horizontal") : 0;
float movementDirectionY = moveDirection.y;
moveDirection = (forward * curSpeedX) + (right * curSpeedY);
if (Input.GetButton("Jump") && canMove && characterController.isGrounded)
{
moveDirection.y = jumpSpeed;
}
else
{
moveDirection.y = movementDirectionY;
}
// Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below
// when the moveDirection is multiplied by deltaTime). This is because gravity should be applied
// as an acceleration (ms^-2)
if (!characterController.isGrounded)
{
moveDirection.y -= gravity * Time.deltaTime;
}
// Move the controller
characterController.Move(moveDirection * Time.deltaTime);
// Player and Camera rotation
if (canMove)
{
rotationX += -Input.GetAxis("Mouse Y") * lookSpeed;
rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit);
playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0);
transform.rotation *= Quaternion.Euler(0, Input.GetAxis("Mouse X") * lookSpeed, 0);
}
}
}

CharacterController jump in unity

Hello I was trying to do movement script in Unity. Also I wanted to add jump, but everytime when I jump it moves up for like 0.025 on Y direction and stops the player in air*(if I am on 0 and I jump it moves on 0.02545 then 0.0543 etc...)* and I can spam Space to move player up. I added gravity but it looks it doesn't work.. I don't know how to fix it. I hope someone can help me with my problem...
Here is the function what I am using...
Vector3 moveDirection = Vector3.zero;
public float walkingSpeed = 10.0f;
public bool canJump = true;
public float jumpSpeed = 8.0f;
public float gravity = 10.0f;
CharacterController characterController;
void Movement()
{
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 right = transform.TransformDirection(Vector3.right);
float moveX = walkingSpeed * Input.GetAxis("Vertical");
float moveY = walkingSpeed * Input.GetAxis("Horizontal");
float MovementY = moveDirection.y;
moveDirection = (forward * moveX) + (right * moveY);
if (Input.GetButtonDown("Jump") && canJump)
{
moveDirection.y = jumpSpeed;
}
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
}
Because you are resetting moveDirection every frame (when you call moveDirection = (forward * moveX) + (right * moveY) you aren't letting the gravity accumulate. You should instead save the vertical speed separately and add it every frame.
Something like the following:
Vector3 moveDirection = Vector3.zero;
public float walkingSpeed = 10.0f;
public bool canJump = true;
public float jumpSpeed = 8.0f;
public float gravity = 10.0f;
CharacterController characterController;
private float verticalSpeed;
void Movement()
{
float moveX = walkingSpeed * Input.GetAxis("Vertical");
float moveY = walkingSpeed * Input.GetAxis("Horizontal");
verticalSpeed -= gravity * Time.deltaTime;
if (Input.GetButtonDown("Jump") && canJump)
{
verticalSpeed = jumpSpeed;
}
characterController.Move((moveX * transform.forward + moveY * transform.right + verticalSpeed * transform.up)
* Time.deltaTime);
}
transform.forward is equivalent to transform.TransformDirection(Vector3.forward)

How to make my stick rotating after bouncing with button long pressed?

Basically I want to make bouncing stick and rotate control, with the left-right button.i'm facing an issue that the rotate not good as I expected because it won't follow my button like being affected by something after bouncing,
I'm using 2d physics material with friction = 1 and Bounciness = 0.9797 for perfect bouncing also attached to rigidbody2d.
I don't know, should I attach it on collider?
here my Player control Script:
public Rigidbody2D r2d;
public float vertical;
public float horizontal;
public Joystick joystick;
private void Start() {
r2d = gameObject.GetComponent < Rigidbody2D > ();
joystick = FindObjectOfType < Joystick > ();
}
private void Update() {
Movement();
}
public void Movement() {
r2d.velocity = r2d.velocity.normalized * 7f;
//horizontal = joystick.Horizontal;
//vertical = joystick.Vertical;
//if (horizontal == 0 && vertical == 0)
//{
// Vector3 curRot = transform.localEulerAngles;
// Vector3 homeRot = transform.localEulerAngles;
// transform.localEulerAngles = Vector3.Slerp(curRot, homeRot, Time.deltaTime * 2);
//}
//else
//{
// transform.localEulerAngles = new Vector3(0f, 0f, Mathf.Atan2(horizontal, vertical) * -180 / Mathf.PI);
//}
}
public Vector3 target;
public float rotationSpeed = 10f;
public float offset = 5;
public void turnLeft() {
Vector3 dir = target - transform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.Euler(new Vector3(0, 0, angle + offset));
transform.rotation = Quaternion.Slerp(transform.rotation, -rotation, rotationSpeed * Time.deltaTime);
}
public void turnRight() {
Vector3 dir = target - transform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.Euler(new Vector3(0, 0, angle + offset));
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, rotationSpeed * Time.deltaTime);
}
Whenever there is a Rigidbody/Rigidbody2D involved you do not want to manipulate anything via the .transform component!
This breaks the physics, collision detection and leads to strange movements basically the transform "fighting" against physics for priority.
What you rather want to do would be e.g. adjusting the Rigidbody2D.angularVelocity
public void turnLeft()
{
// Note that Time.deltaTime only makes sense if this is actually called every frame!
r2d.angularVelocity -= rotationSpeed * Time.deltaTime;
}
public void turnRight()
{
r2d.angularVelocity += rotationSpeed * Time.deltaTime;
}

How to make player to be able to rotate camera around cube in Unity?

I have created new Unity project, have added a cube into the center and now want to make player to be able to rotate camera around this cube by swipes and/or mouse drags.
Please, name simple steps to implement this or keywords to find an answer or where to read about it?
public Transform Target;
public float distance = 2.0f;
public float xSpeed = 20.0f;
public float ySpeed = 20.0f;
public float yMinLimit = -90f;
public float yMaxLimit = 90f;
public float distanceMin = 10f;
public float distanceMax = 10f;
public float smoothTime = 2f;
float rotationYAxis = 0.0f;
float rotationXAxis = 0.0f;
float velocityX = 0.0f;
float velocityY = 0.0f;
void Update()
{
if (Input.GetMouseButton(0))
{
velocityX += xSpeed * Input.GetAxis("Mouse X") * distance * 0.02f;
velocityY += ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
}
rotationYAxis += velocityX;
rotationXAxis -= velocityY;
rotationXAxis = ClampAngle(rotationXAxis, yMinLimit, yMaxLimit);
Quaternion rotation = Quaternion.Euler(rotationXAxis, rotationYAxis, 0);
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + Target.position;
transform.rotation = rotation;
transform.position = position;
velocityX = Mathf.Lerp(velocityX, 0, Time.deltaTime * smoothTime);
velocityY = Mathf.Lerp(velocityY, 0, Time.deltaTime * smoothTime);
}
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);
}
Taken from https://answers.unity.com/questions/1257281/how-to-rotate-camera-orbit-around-a-game-object-on.html
If you only want to rotate around a specific axis, for example around Y, you could basicly just do this
this.transform.RotateAround(Target.transform.position, Vector3.up, Input.GetAxis("Mouse X")*20.0f);
Create a new C# Script called "CameraRotate", open it and paste this script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraRotate : MonoBehaviour {
public Transform cube;
public float sensitivityX;
public float sensitivityY;
GameObject pivot;
void Start () {
pivot = new GameObject ("pivot");
pivot.transform.position = cube.position;
transform.SetParent (pivot.transform);
}
void Update () {
pivot.transform.eulerAngles += new Vector3 (Input.GetAxis ("Mouse Y") * -sensitivityX * Time.deltaTime, Input.GetAxis ("Mouse X") * sensitivityY * Time.deltaTime, 0);
}
}
Assign this script to your camera, then in Inspector Tab, with the camera selected, assign your Cube (drag) into the "cube" slot, and assign a value to the sensitivity fields (i used something about 500), press play and test.
What does this script do?
It creates a new GameObject at the center of the Cube to be a reference of rotation, it's called pivot. So it sets the Camera as a child of the pivot, and rotates the pivot according with your mouse axis.
I wrote this way:
float mouseX = -Input.GetAxis("Mouse X");
float mouseY = -Input.GetAxis("Mouse Y");
float magnitude = transform.position.magnitude;
Vector3 mouseSwipe = new Vector3(mouseX, mouseY, 0);
Vector3 startPoint = new Vector3((float)camera.pixelWidth / 2, (float)camera.pixelHeight / 2, magnitude - 1);
Vector3 startPointWorld = camera.ScreenToViewportPoint(startPoint);
Vector3 endPointWord = camera.ScreenToViewportPoint(startPoint + mouseSwipe);
Vector3 mouseSwipeWord = endPointWord - startPointWorld;
float dragLat = mouseSwipeWord.y;
float dragLng = mouseSwipeWord.x;
Vector3 oldPosition = transform.position / magnitude;
float lat = Mathf.Asin(oldPosition.y);
float rsmall = Mathf.Acos(oldPosition.y);
float lng = Mathf.Atan2(oldPosition.z / rsmall, oldPosition.x / rsmall);
lat += dragLat * 10 * 2 * Mathf.PI;
if( lat*180/Mathf.PI > 80 )
{
lat = 80 * Mathf.PI / 180;
}
else if( lat*180/Mathf.PI < -80)
{
lat = -80 * Mathf.PI / 180;
}
lng += dragLng * 10 * 2 * Mathf.PI * 2;
float y = Mathf.Sin(lat);
rsmall = Mathf.Cos(lat);
float x = rsmall * Mathf.Cos(lng);
float z = rsmall * Mathf.Sin(lng);
Vector3 newPosition = new Vector3(x, y, z);
newPosition *= magnitude;
transform.position = newPosition;
LookAtTarget();
The goal was to simulate mouse is rotation object by drag.