I am making a script to rotate my camera around a sphere but I need to clamp the y axis so the camera does not co over the polls of the sphere I am using rotate around to move my camera.
Thanks!
My current code
public float sensitivity = 1;
public float moveSpeed = 10;
public float maxUp = 45f;
public float maxDown = -45f;
public Transform target;
void Update()
{
transform.LookAt(target);
float HorizontalAxis = Input.GetAxis("Horizontal") * moveSpeed;
float VerticalAxis = Input.GetAxis("Vertical") * moveSpeed;
if (HorizontalAxis >= 1 || VerticalAxis >= 1 || HorizontalAxis <= -1 || VerticalAxis <= -1)
{
Quaternion targetPos = transform.rotation;
targetPos.x += HorizontalAxis * sensitivity;
targetPos.y += VerticalAxis * sensitivity;
transform.RotateAround(target.position, Vector3.left, targetPos.y);
transform.RotateAround(target.position, Vector3.up, targetPos.x);
}
}
Your code makes no sense to begin with.
You do
Quaternion targetPos = transform.rotation;
targetPos.x += HorizontalAxis * sensitivity;
targetPos.y += VerticalAxis * sensitivity;
Just to then use these as parameters in
transform.RotateAround(target.position, Vector3.left, targetPos.y);
transform.RotateAround(target.position, Vector3.up, targetPos.x);
A Quaternion has not three but four components x, y, z and w and they move in ranges between -1 and 1. You never touch the individual component of a Quaternion except you really know exactly what you are doing!
You rather simply want to use the HorizontalAxis and VerticalAxis directly as the parameters to RotateAround.
You could rather simply remember and clamp how much you already rotated like e.g.
private float rotatedY;
private void Update()
{
transform.LookAt(target);
// why two different multipliers anyway though?
var HorizontalAxis = Input.GetAxis("Horizontal") * moveSpeed * sensitivity;
var VerticalAxis = Input.GetAxis("Vertical") * moveSpeed * sensitivity;
// would a positive rotation exceed the maxUp?
if(rotatedY + VerticalAxis > maxUp)
{
// then rotate only so much that you terminate exactly on maxUp
VerticalAxis = maxUp - rotatedY;
}
// would a negative rotation exceed the maxDown?
else if(rotatedY + VerticalAxis < maxDown)
{
// then you rotate only that much that you terminate exactly on maxDown
VerticalAxis = maxDown - rotatedY;
}
transform.RotateAround(target.position, Vector3.left, VerticalAxis);
transform.RotateAround(target.position, Vector3.up, HorizontalAxis);
// sum up how much you already rotated vertically
rotatedY += VerticalAxis;
}
Related
I tried the last few weeks fix the problem with the camera. Like the title says, the players camera wont look left and right. And why? Because when I move the mouse left and right, the players y rotation rotates the right direction. But the Cameras y rotation is equal to the Players y rotation as a negative number. so, can anyone help me?
I tried literally everything. I expect the camera to rotate in all direction.
Here is the movement and look code:
mX += Input.GetAxis("Mouse X") * Sensivity * Time.deltaTime;
mY -= Input.GetAxis("Mouse Y") * Sensivity * Time.deltaTime;
mY = Mathf.Clamp(mY, -89.9f, 89.9f);
transform.eulerAngles = Vector3.up * mX/2;
cam.eulerAngles = Vector3.up * mX/2;
cam.eulerAngles = Vector3.right * mY;
float inputX = Input.GetAxis("Horizontal");
float inputY = Input.GetAxis("Fly");
float inputZ = Input.GetAxis("Vertical");
Vector3 dirForward = Vector3.ProjectOnPlane(transform.forward, Vector3.up).normalized;
Vector3 dirSide = transform.right;
Vector3 dirUp = Vector3.up;
Vector3 moveDir = (inputX * dirSide) + (inputY * dirUp) + (inputZ * dirForward);
transform.position += moveDir * Speed * Time.deltaTime;
I'm using this code for my 3d movements. Try it, it should work
public class free_cam_view : MonoBehaviour
{
public float mouseSensitivity = 100f;
float xr_1 = 0f;
void Update()
{
float y = 2 * Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
xr_1 -= y;
xr_1 = Mathf.Clamp(xr_1, -90f, 63f);
transform.localRotation = Quaternion.Euler(xr_1, 0f, 0f);
}
}
Just add code to move forward by pressing "w"
I'm working on a 3D fps, and want a dash. The player uses a character controller, and no rigidbody. My original implementation:
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength ) //dashes for a set time period
{
currentDashLength += Time.deltaTime;
velocity.y = 0; //keeps you up in the air
controller.Move(move * Time.deltaTime * dashSpeed);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
This dash works fine, but I realized that if you had pressed shift right after starting to move, the dash would be significantly weaker. I assumed this was due to the fact that my current velocity was low, so the acceleration from the Move function didn't make me reach the speed I would when already moving at terminal velocity. I tried to fix this by multiplying the Move function inputs by 1/(the horizontal velocity of the player) but this didn't fix the issue. My full dashing code:
float dispX = transform.position.x - posX; //gets chnage in position since last frame, this is important to caluclate velocity, since the player isnt using a rigidbody
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal"); //just gets ur wasd inputs by default
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z; //creates a movement vector
controller.Move(move * speed * Time.deltaTime); //moves the player
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
if(horizontalVelocity == 0)
{
Debug.Log("Cannot dash while standing still");
}
else
{
controller.Move(move * Time.deltaTime * dashSpeed * (1 / horizontalVelocity));
}
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
How would I go about ensuring that the dash speed is constant?
(I tried to post this on unity answers, but the website isn't responding to me)
To get the desired behaviour I have re-written your original script by quite a lot, hope that is okay! This code only give you movement and dash control, and nothing else. You'll have to add your crouch check and health stuff back in.
Essentially, we check if the player is dashing before applying any movement, this way we don't add the dash to the current movement. If the player is dashing, we ignore their forward input and apply forward movement based on the predetermined dash. If we aren't dashing then we apply the calculated movement as usual.
private CharacterController controller;
public float speed = 10.0f;
public float dashSpeed = 20.0f;
public float dashLength = 0.5f;
private float currentDashLength = 0;
private bool isDashing = false;
private void Start()
{
controller = GetComponent<CharacterController>();
}
private void Update()
{
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
// Same as before
Vector3 move = new Vector3(x, 0, z);
// gets the move direction
// before we move, check if dashing
if (isDashing)
{
currentDashLength += Time.deltaTime;
move = new Vector3(move.x * dashSpeed, move.y, 1 * dashSpeed);
// this gets the current player movement, and replaces the forward velocity rather than adding to it. We add to the sideways velocity to allow for slight directional control.
// do this instead if you want the dash to only move the player in the forward direction, and prevent strafing: move = new Vector3(move.x, move.y, 1 * dashSpeed);
if (currentDashLength >= dashLength) // when we run out of time, set dash to false
{
isDashing = false;
}
}
else // if we are not dashing then move as normal
{
move *= speed;
if (Input.GetKeyDown(KeyCode.LeftShift) && move.magnitude > 0) // stops the dash ability being used when stationary
{
isDashing = true;
currentDashLength = 0;
}
}
controller.Move(move * Time.deltaTime);
}
float dispX = transform.position.x - posX;
float dispY = transform.position.y - posY;
float dispZ = transform.position.z - posZ;
posX = transform.position.x;
posY = transform.position.y;
posZ = transform.position.z;
float horizontalVelocity = Mathf.Sqrt(dispX*dispX + dispZ*dispZ) / Time.deltaTime;
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (currentDashLength < dashLength )
{
currentDashLength += Time.deltaTime;
velocity.y = 0;
Vector3 dashMove = move * Time.deltaTime * dashSpeed; // Calculates the dash movement vector
// Move the player based on the dash movement vector
controller.Move(dashMove);
}
else
{
currentDashLength = dashLength;
isDashing = false;
}
if (Input.GetKeyDown(KeyCode.LeftShift) && dashTimer >= 1 && !isCrouching)
{
isDashing = true;
dashTimer -= 1;
currentDashLength = 0f;
health.GiveIFrames(dashLength);
}
By calculating the dash movement vector independently from the player's horizontal velocity, you can ensure that the dash speed remains constant regardless of whether the player is moving before dashing or not.
I think this is what you were trying to achieve? Hope it helps!
I understand there are many answers to this online but I was unable to apply them correctly to my code.
I have tried using pre-made player assets but could not get that to work.
Vector3 pos = transform.position;
public float X;
public float Y;
public float Z;
// Used to tilt camera up and down
float tilt = 0;
if (Input.GetMouseButton(1))
{
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.rotation.eulerAngles.x;
Y = transform.rotation.eulerAngles.y;
Z = transform.rotation.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
//Spaceship does not go in direction it is facing once panned
if (Input.GetKey("w"))
{
//transform.rotation = Quaternion.Euler(0, Y, tilt);
pos.z += speed * Time.deltaTime;
}
if (Input.GetKey("s"))
{
pos.z -= speed * Time.deltaTime;
}
if (Input.GetKey("d"))
{
pos.x += speed * Time.deltaTime;
// DEBUG Does not work properly while mouse held down
//transform.Rotate(-1, 0, 0);
}
if (Input.GetKey("a"))
{
pos.x -= speed * Time.deltaTime;
}
transform.position = pos;
Assuming here the "Camera" equals transform you can simply use its local axis transform.forward
Returns a normalized vector representing the blue axis of the transform in world space.
and transform.right
Returns a normalized vector representing the red axis of the transform in world space.
like e.g.
private void Update()
{
if (Input.GetMouseButton(1))
{
// NOTE: I DON'T UNDERSTAND THIS CODE BLOCK YET
// YOU KNOW E.G. THAT IF YOU "transform.eulerAngles.x" ALREADY IS "45°"
// THE "tilt" WOULD JUMP EVERY FRAME IN HUGER STEPS (45 -> 90 -> 180 - 360 ....)
// ALSO WHY ROTATE IN X AXIS IF AFTERWARDS YOU RESET THE X ROTATION
// AND RATHER APPLY IT TO Z?
transform.Rotate(new Vector3(Input.GetAxis("Mouse Y") * panSpeed, Input.GetAxis("Mouse X") * panSpeed, 0));
X = transform.eulerAngles.x;
Y = transform.eulerAngles.y;
Z = transform.eulerAngles.z;
// Add current position of mouse input
tilt += X;
transform.rotation = Quaternion.Euler(0, Y, tilt);
}
Vector3 movement = Vector3.zero;
if (Input.GetKey(KeyCode.W))
{
movement += transform.forward;
}
if (Input.GetKey(KeyCode.S))
{
movement -= transform.forward;
}
if (Input.GetKey(KeyCode.D))
{
movement += transform.right;
}
if (Input.GetKey(KeyCode.A))
{
movement -= transform.right;
}
// I would do it like this to make sure that diagonal movement
// does not move faster
transform.position = movement.normalized * speed * Time.deltaTime;
}
How to make a bullet fly in an arc when shooting and hit the player.
As in this picture . I tried to use formulas from physics, the body is thrown at an angle to the horizon, that's what came of it . But the bullet flies away into the void
velocity = Mathf.Round(Vector3.Distance(lastpos, transform.position) / Time.deltaTime);
lastpos = transform.position;
Vector3 direction = PlayeCar.position - Vector3.zero;
float angle = Mathf.Atan2(direction.y, direction.x); // радианы
float x = velocity * Mathf.Cos(angle) + gravity * (time* time) / 2;
float y = velocity * Mathf.Sin(angle);
transform.position = new Vector2(x, y)
;
Sample orientative method could be (The script would be attached to the gun that shots, so when the code referes to transform, refers to the gun's transfom):
public void LaunchTarget()
{
Vector3 initialSpeed = transform.forward; //shot direction, gun's forward
GameObject go = GameObject.Instantiate(m_bullet);//reference to bullet prefab
//in case you need to randomize the shot speed
initialSpeed = transform.forward * Random.Range(m_minLaunchSpeed, m_maxLaunchSpeed);
//set the initial position of the bullet in the gun
go.transform.position = transform.position;
// shoot (give speed to the bullets rigidbody)
go.GetComponent<Rigidbody>().velocity = initialSpeed;
//initially disabled soas to see the bullet when shot
go.SetActive(true);
}
Hope that helps
I did it !!!! at the time of the bullet’s flight, I turn it toward the player in an intermittent manner. And after a while I delete it
void Start()
{
rigidbodyBullet = GetComponent<Rigidbody2D>();
Player = GameObject.Find("carPlayer").GetComponent<Transform>();
_distance = Vector3.Distance(Player.position, transform.position);
Invoke("DestroyArcBullet", 1.5f);
limitDistance = _distance / 1.3f;
}
void Update()
{
transform.position += transform.up * Time.deltaTime * 5f;
_distance = Vector3.Distance(Player.position, transform.position);
if (_distance < limitDistance)
{
var turn = Quaternion.Lerp(transform.rotation,
Quaternion.LookRotation(Vector3.forward, Player.position - transform.position), Time.deltaTime * 2);
rigidbodyBullet.MoveRotation(turn.eulerAngles.z);
}
if (this.transform.position.y + this.transform.position.y <= -10 || this.transform.position.y + this.transform.position.y >= 10
|| this.transform.position.x + this.transform.position.x <= -10 || this.transform.position.x + this.transform.position.x >= 10)
{
Destroy(gameObject);
}
}
I have a camera that I want to rotate around a point (0,0,0) in all directions, but I want to put a clamp on it so that it can't go too far above or below the point. I have seen this question answered for the left and right directions before but never for the vertical one.
I have tried converting the code from these two questions (that basically say the same thing) to work in the vertical direction, but it bugs out at some points along the rotation, and I can't figure out why.
First Question, Second Question
And this is how I tried to convert it:
//how much we want to rotate by this frame
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed; //(before clamping)
//find current direction
Vector3 currentDirection = transform.position - Vector3.zero;
//find current angle between basis for clamp & where we are now
float angle = Vector3.Angle(Vector3.forward, currentDirection);
//finds out if it's up or down
if (Vector3.Cross(Vector3.forward, currentDirection).x < 0) angle = -angle;
//find out how much you can move without violating limits
float newAngle = Mathf.Clamp(angle + rotY, yMinLimit, yMaxLimit);
//grabs how much you are allowed to move the angle from the current angle
rotY = newAngle - angle;
//spinning the garden
transform.RotateAround(Vector3.zero, Vector3.up, rotX);
transform.RotateAround(Vector3.zero, transform.TransformDirection(Vector3.right), -rotY); //vertical rotation
If anyone knows of the correct way to make this work for the Y axis, or a different way to clamp the vertical rotation, I would be super excited to hear it! Ty!
I have a class here that do exactly what you want. It rotates a camera around a target and clamps the Y rotation. It uses the left button to rotate and the scroll press button to translate the target.
You can edit it to adjust to your specific needs - you might want to change the target to a Vector3 so you can set it to (0,0,0) without the need of an object. Hope it helps.
using UnityEngine;
public class RotateAroundCamera : MonoBehaviour
{
Camera cam;
public bool isControlable;
private Vector3 screenPoint;
private Vector3 offset;
public Transform target;
public float distance = 5.0f;
public float xSpeed = 50.0f;
public float ySpeed = 50.0f;
public float yMinLimit = -80f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
public float smoothTime = 2f;
public float rotationYAxis = 0.0f;
float rotationXAxis = 0.0f;
float velocityX = 0.0f;
float velocityY = 0.0f;
float moveDirection = -1;
public void SetControllable(bool value)
{
isControlable = value;
}
// Use this for initialization
void Start()
{
cam = GetComponentInChildren<Camera>();
Vector3 angles = transform.eulerAngles;
rotationYAxis = (rotationYAxis == 0) ? angles.y : rotationYAxis;
rotationXAxis = angles.x;
Rigidbody rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate()
{
if (target)
{
if (Input.GetMouseButton(1) && isControlable)
{
velocityX += xSpeed * Input.GetAxis("Mouse X") * 0.02f;
velocityY += ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
}
if (Input.GetMouseButton(2) && isControlable)
{
Vector3 curScreenPoint = new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = cam.ScreenToWorldPoint(curScreenPoint) + offset;
target.transform.position = curPosition;
}
if (Input.GetKeyDown(KeyCode.R) && isControlable)
{
target.transform.position = Vector3.zero;
}
if (Input.GetKeyDown(KeyCode.T) && isControlable)
{
moveDirection *= -1;
}
if (isControlable)
{
distance -= Input.GetAxis("Mouse ScrollWheel");
if (distance > distanceMax)
{
distance = distanceMax;
}
else if (distance < distanceMin)
{
distance = distanceMin;
}
}
rotationYAxis += velocityX;
rotationXAxis -= velocityY;
rotationXAxis = ClampAngle(rotationXAxis, yMinLimit, yMaxLimit);
Quaternion fromRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
Quaternion toRotation = Quaternion.Euler(rotationXAxis, rotationYAxis, 0);
Quaternion rotation = toRotation;
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);
screenPoint = cam.WorldToScreenPoint(target.transform.position);
offset = target.transform.position - cam.ScreenToWorldPoint(new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z));
}
}
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);
}
}