Previous posts here did not seem to address my problem.
I'm trying to get my camera to move around a specific point called "target". Target is an empty gameobject set at the center of my game. The idea is that the camera would not move any closer to or farther from target and would simply rotate around the target as though it were moving around an invisible sphere. The camera should always point at target. transform.LookAt(target) does just fine keeping the camera trained on the target, but I cant get the movement correct. Whether I'm moving along the horizontal or vertical axes, it always spirals directly into the target rather than just moving around it. Any ideas?
public class CameraController : MonoBehaviour {
public float speed;
public Transform target;
void Update () {
transform.LookAt(target);
if(Input.GetAxis("Vertical") != 0)
{
transform.Translate(transform.up * Input.GetAxis("Vertical") * Time.deltaTime * speed); //.up = positive y
}
if(Input.GetAxis("Horizontal") != 0)
{
transform.Translate(transform.right * Input.GetAxis("Horizontal") * Time.deltaTime * speed); //.right = positive x
}
}
}
To rotate around a specific point I use Transform.RotateAround:
transform.RotateAround(target.position, transform.right, -Input.GetAxis("Mouse Y") * speed);
transform.RotateAround(target.position, transform.up, -Input.GetAxis("Mouse X") * speed);
Or, if your target moves and you want to keep the same distance between the camera and your target, you can use this piece of code from my answers.unity3d.com page :
public class SphericalCam
: MonoBehaviour
{
public float MinDist, CurrentDist, MaxDist, TranslateSpeed, AngleH, AngleV;
public Transform Target;
public void Update()
{
AngleH += Input.GetAxis("Mouse X");
AngleV -= Input.GetAxis("Mouse Y");
CurrentDist += Input.GetAxis("Mouse ScrollWheel");
}
public void LateUpdate()
{
Vector3 tmp;
tmp.x = (Mathf.Cos(AngleH * (Mathf.PI / 180)) * Mathf.Sin(AngleV * (Mathf.PI / 180)) * CurrentDist + Target.position.x;
tmp.z = (Mathf.Sin(AngleH * (Mathf.PI / 180)) * Mathf.Sin(AngleV * (Mathf.PI / 180)) * CurrentDist + Target.position.z;
tmp.y = Mathf.Sin(AngleV * (Mathf.PI / 180)) * CurrentDist + Target.position.y;
transform.position = Vector3.Slerp(transform.position, tmp, TranslateSpeed * Time.deltaTime);
transform.LookAt(Target);
}
}
Camera rotation around target horizontally:
transform.RotateAround(target.position, target.forward, Time.deltaTime * speed);
Vertically:
transform.RotateAround(target.position, target.right, Time.deltaTime * speed);
Related
I'm trying to use the Character Controller component in Unity and I managed to make the movement code, however, I was unable to add jumping and gravity or at least have them work together so my temporary solution was to just break them into 2 different methods. This probably isn't ideal so how could I get this to work properly?
void Update()
{
GetInput();
JumpingCode();
MovementCode();
}
void JumpingCode()
{
// Jumping
if (jumpPressed && characterController.isGrounded)
velocityY = Mathf.Sqrt(jumpHeight * -2f * (gravity * gravityScale));
// Gravity
velocityY += gravity * gravityScale * Time.deltaTime;
Vector3 direction = new Vector3(horizontalInput, velocityY, verticalInput).normalized;
characterController.Move(direction * walkSpeed * Time.deltaTime);
}
void MovementCode()
{
Vector3 direction = new Vector3(horizontalInput, 0f, verticalInput).normalized;
if (direction.magnitude > 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + playerCamera.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
transform.rotation = Quaternion.Euler(0f, angle, 0f);
characterController.Move(moveDirection.normalized * walkSpeed * Time.deltaTime);
}
}
I can't understand how you're arriving at the values you're using there, but the solution would be to accumulate the outputs and then do the .Move() action once at the end, like:
void Update()
{
Vector3 motion;
GetInput();
motion += JumpingCode();
motion += MovementCode();
characterController.Move(motion*Time.deltaTime);
}
private Vector3 JumpingCode()
{
// stuff
return direction * walkSpeed;
}
private Vector3 MovementCode()
{
// stuff
return direction * walkSpeed;
}
Noteworthy there is that I dropped Time.deltaTime from your functions, but I don't know how you were using it in the code you provided.
My Project is a First Person Jump&Run, I want my Player to Sprint by pressing Horizonzal or Vertical combined with Shift.
I already made a new Input, called Sprint, with negative Button "left shift"
My Player does normal move, but he doesn't Sprint.
Thanks a lot.
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
public float speed = 12f;
public float sprint;
public float gravity = -9.81f;
public float jumpHeight = 3f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
Vector3 velocity;
bool isGrounded;
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if(isGrounded && velocity.y < 0) {
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
// Noch nicht fertig -> Noch ausstehend
if (Input.GetButtonDown("Horizontal") && Input.GetButtonDown("Sprint") || Input.GetButtonDown("Vertical") && Input.GetButtonDown("Sprint"))
{
controller.Move(move * (speed + sprint) * Time.deltaTime);
}
}
There are most likely problems with how the Input is being handled.
My assumption is that GetButtonDown only returns true for the single frame when you press shift down. Use GetKey instead:
Input.GetKey(KeyCode.LeftShift)
If that doesn't work, try those 2 instead:
Input.GetKeyDown("left shift")
Input.GetKeyDown(KeyCode.LeftShift)
But there might be the same problem with those 2 as with "GetButtonDown".
Also, I think it'd help people understand your code better if you use english comments instead of german. I'm able to read it but most probably don't. Don't worry though, that also happened to me!
I am trying to determine the direction of a transform. I originally tried to do this by tracking the rigidbody.velocity but that property seems unreliable so I am having to calculate the direction manually. The yellow line draws fine and it does point in the wrong direction however it appears to be delayed
I am calling the following method in my update method:
void DetermineMovementDirection()
{
currentLoc = (transform.position - prevLoc) / Time.deltaTime;
Vector3 t = (prevLoc + currentLoc).normalized;
Debug.DrawLine(transform.position, transform.position + t * 5, Color.yellow);
}
I would expect the yellow line to always point in the direction the player was moving rather than have a long delay. How can I fix this?
As requested the movement function:
void Update()
{
float inputZ = Input.GetAxis("Horizontal");
float inputX = Input.GetAxis("Vertical");
if (movementAllowed)
if (inputZ != 0 || inputX != 0)
{
transform.eulerAngles = new Vector3(0, Mathf.Atan2(inputZ, inputX) * 180 / Mathf.PI, 0);
transform.Translate(moveSpeed * inputZ * Time.deltaTime, 0f, moveSpeed * inputX * Time.deltaTime, Space.World);
}
}
And I am simply updating at the end of the update method:
prevLoc = transform.position;
I'm having a bit of an issue with a BoxCollider2D I have on my GameObject. When I rotate the GameObject, the BoxCollider2D rotates with it, but not as fast. Is there a way to get the BoxCollider2D to move at the same rate as the GameObject? I feel like I'm missing something obvious.
Before Rotation
After Rotation
Below is my code for the movement of the player:
Animator anim;
Rigidbody2D rbody;
float speed = 0f;
public float moveSpeed = 0.6f;
public float acceleration = 0.2f;
public int turnSpeed = 20;
bool sails = false;
// Use this for initialization
void Start () {
anim = GetComponentInChildren<Animator> ();
rbody = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void Update () {
if (sails) {
rbody.transform.Translate (transform.right * (speed * Time.deltaTime));
speed += acceleration * Time.deltaTime;
if (speed > moveSpeed)
speed = moveSpeed;
if (Input.GetKey (KeyCode.LeftArrow)) {
rbody.transform.Rotate (0,0,turnSpeed * Time.deltaTime);
}
if (Input.GetKey (KeyCode.RightArrow)) {
rbody.transform.Rotate (0,0,-turnSpeed * Time.deltaTime);
}
}
if (!sails) {
rbody.transform.Translate (transform.right * (speed * Time.deltaTime));
speed += -acceleration * Time.deltaTime;
if (speed < 0f)
speed = 0f;
}
if (Input.GetKeyDown (KeyCode.Space)) {
sails = !sails;
anim.SetBool ("sailsDown", sails);
}
}
The problem is not your rotation, but how you are applying the the movement.
You are using transform.right which is the local right of the object. But then, when applying the translate you apply it to the object locally too.
For example, if your ship is facing down (rotation.Z = -90), transform.right value is (0,-1,0), in World coordinates this is equal to "down".
But then you use rbody.transform.Translate(vector) which will translate the object using local coordinates. This means that if you pass it the "down" vector, it will be moving down locally, which in the case of being rotated -90 inthe Z axis, means moving "left" relative to the world.
You have to change this line:
rbody.transform.Translate(transform.right * (speed * Time.deltaTime));
To:
rbody.transform.Translate(transform.right * (speed * Time.deltaTime),Space.World);
Or:
rbody.transform.Translate(Vector2.right * (speed * Time.deltaTime));
I have problem I want to make my player move in 4 directions: UP,DOWN,LEFT AND RIGHT ... here is my script
using UnityEngine;
using System.Collections;
public class MovingPlayer : MonoBehaviour {
float speed = 4f;
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.A)) {
transform.Translate(Vector2.right * speed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.D)) {
transform.Translate(-Vector2.right * speed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.W)) {
transform.Translate(Vector2.up * speed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.S)) {
transform.Translate(-Vector2.up * speed * Time.deltaTime);
}
}
}
And it is working just for left and right , not up and down !?
Your code uses else if for all four directions. This means that the character can only move in one direction at a time. If 'A' is pressed, then all of the else branches are ignored. If 'D' is pressed the 'W' and 'S' branches are ignored.
It makes sense to use else if when swapping between left and right, or between up and down, since the player should only be able to move one direction on a given axis at a time. But the horizontal and vertical sections should be independent if conditions:
if (Input.GetKey (KeyCode.A)) {
transform.Translate(Vector2.right * speed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.D)) {
transform.Translate(-Vector2.right * speed * Time.deltaTime);
}
if (Input.GetKey (KeyCode.W)) {
transform.Translate(Vector2.up * speed * Time.deltaTime);
}
else if (Input.GetKey (KeyCode.S)) {
transform.Translate(-Vector2.up * speed * Time.deltaTime);
}
I would also recommend looking at the Input class in the unity documentation. The input manager allows you to define input axes (based on keyboard, mouse, or joystick input), and read them as a continuous value on the range [-1, 1]. Unity defines two default axes called "Horizontal" and "Vertical" which read input from AD and WS respectively. To use virtual axes, you can use:
transform.Translate(Vector2.right * Input.GetAxis("Horizontal") * Time.deltaTime);
transform.Translate(Vector2.up * Input.GetAxis("Vertical") * Time.deltaTime);
Try this, it moves the object relating to the global coordinates:
(...)
else if (Input.GetKey (KeyCode.W)) {
transform.Translate(0, Vector2.up * speed * Time.deltaTime, Space.World);
}
else if (Input.GetKey (KeyCode.S)) {
transform.Translate(0, -Vector2.up * speed * Time.deltaTime, Space.World);
}