My code below rotates an object and moves them based on the angle of the joystick on the controller:
using UnityEngine;
using System.Collections;
public class PlayerControllerTEST : MonoBehaviour
{
public float moveSpeed;
public float h;
public float v;
public float moveX;
public float moveZ;
public Rigidbody rb;
// Use this for initialization
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
h = Input.GetAxis("Horizontal");
v = Input.GetAxis("Vertical");
moveX = (h * moveSpeed) * Time.deltaTime;
moveZ = (v * moveSpeed) * Time.deltaTime;
transform.Translate(moveX, 0f, moveZ, Space.World);
Quaternion rotate = Quaternion.Euler(0f, (Mathf.Atan2(h, v) * Mathf.Rad2Deg), 0f);
Debug.Log(rotate);
rb.MoveRotation(rotate);
}
}
However when I let go of the joystick, the object is snapping back to an angle of 0 degrees. I'm not sure how I would get it to keep the angle before the joystick is essentially let go.
Related
I recently started on unity and I wanted to make simple movement which can be seen below.
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
//Variables
float speed = 5.0f;
public float turnSpeed = 4.0f;
public float moveSpeed = 2.0f;
public float minTurnAngle = -90.0f;
public float maxTurnAngle = 90.0f;
private float rotX;
//Other
Vector3 Char_velocity;
Rigidbody Physics;
void Start()
{
Physics = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
//Get axis on which we want to move
if (Input.GetButton("Vertical"))
{
//Creating vector which velocity is calculated based on vect3, speed and gets FPS compensation via fixed
//delta time
Char_velocity = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
Physics.MovePosition(transform.position + Char_velocity * speed * Time.fixedDeltaTime);
}
if (Input.GetButton("Horizontal"))
{
Char_velocity = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
Physics.MovePosition(transform.position + Char_velocity * speed * Time.deltaTime);
}
float y = Input.GetAxis("Mouse X") * turnSpeed;
rotX += Input.GetAxis("Mouse Y") * turnSpeed;
rotX = Mathf.Clamp(rotX, minTurnAngle, maxTurnAngle);
transform.eulerAngles = new Vector2(-rotX, transform.eulerAngles.y + y);
}
}
Mouse movement has been the problem for me. I got it to somewhat work but I have 2 issues. The camera should move the whole body while rotating from side to side but instead rotates the body when moving along the Y axis.
Hi I am very new to Unity and only got basic knowledge. I created a player who can move and also a camera which follows the player and according to the mouseX and mouseY acis the camera rotates.
Now I want the camera rotation angle to be the forward position.
If the player press w he moves along x acis but if the camera angle change and the player press w it should move into this direction.
player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DoublePlayer : MonoBehaviour
{
private CharacterController _controller;
public float _jumpHeight = 3f;
[SerializeField]
private float _moveSpeed = 5f;
[SerializeField]
private float _gravity = 9.81f;
private float _directionY;
void Start()
{
_controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
Vector3 direction = new Vector3(horizontalInput, 0, verticalInput);
// set gravity
_directionY -= _gravity * Time.deltaTime;
direction.y = _directionY;
_controller.Move(direction * _moveSpeed * Time.deltaTime);
}
}
camera.cs
public class CameraController : MonoBehaviour
{
public float RotationSpeed = 1;
public Transform Target, Player;
float mouseX, mouseY;
void Start()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void LateUpdate()
{
CamControl();
}
void CamControl()
{
mouseX += Input.GetAxis("Mouse X") * RotationSpeed;
mouseY += Input.GetAxis("Mouse Y") * RotationSpeed;
mouseY = Mathf.Clamp(mouseY, -35, 60);
transform.LookAt(Target);
Target.rotation = Quaternion.Euler(mouseY, mouseX, 0);
Player.rotation = Quaternion.Euler(0, mouseX, 0);
}
}
For Target and Player variable I selected the player object.
Do someone has a simple solution I can understand?
You could simply take the direction and rotate it along with the object that component is attached to using Quaternion * Vector3 operator
var rotatedDirection = transform.rotation * direction;
Or if you rather need the orientation of the other script attached to a different object then do e.g.
// link your camera or whatever shall be used for the orientation via the Inspector
[SerializeField] private Transform directionProvider;
and then
var rotatedDirection = directionProvider.rotation * direction;
Since you're getting the rotation directly from a Transform, you could use Transform.TransformDirection:
Vector3 rotatedDirection = transform.TransformDirection(direction);
I have this script below and I want my player to always move towards the rotation angle, which doesn't happen. It only changes direction when I click.
My purpose is for the player to move at all times and towards the rotation which should be controlled by mouse position/mouse x axis (kind of like auto-run, but always change rotation based on mouse, not just move right or left).
I've tried about 10 different methods, nothing worked so far...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovementController : MonoBehaviour
{
public float speed = 4;
public float rot = 0f;
public float rotSpeed = 80;
public float gravity = 8;
private Camera cam;
Vector3 moveDir = Vector3.zero;
CharacterController controller;
Animator anim;
// Start is called before the first frame update
void Start()
{
controller = GetComponent<CharacterController> ();
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
float horizontalSpeed = 8.0f;
//Get the mouse delta. This is not in the range -1...1
float h = horizontalSpeed * Input.GetAxis("Mouse X");
float z = horizontalSpeed * Input.GetAxis("Mouse Y");
transform.Rotate(0, h, 0);
//Move Input
if(controller.isGrounded){
if(Input.GetMouseButtonUp(1))
{
anim.SetInteger ("condition", 1);
moveDir = new Vector3 (0,0,1) * speed;
// moveDir *= speed;
moveDir = transform.TransformDirection(moveDir);
}
if(Input.GetMouseButtonDown(1))
{
anim.SetInteger("condition", 0);
moveDir = Vector3.zero;
}
}
moveDir.y -= gravity * Time.deltaTime;
controller.Move(moveDir * Time.deltaTime);
}
}
Transform.LookAt
Just get a cursor position and that's it
Vector3 direction = target.position - player.transform.position;
Quaternion finalPlayerRotation = Quaternion.LookRotation(direction);
player.transform.rotation = finalPlayerRotation;
This also works in some cases:
Vector3 direction = target.position - player.transform.position;
player.transform.right /*You may need to change the Right to upper, -upper, -Right depend on the player rotation and the target position*/ = direction;
I've been trying to code a car in Unity 5 which can move like a normal car but have the camera orbit around it. I have this working but the camera does not keep it's orbit position when the car turns. Example: I'm looking at the back of the car, and I turn right. I will now be looking at the right side of the car. Is there any way to make the camera still be in the same position, relative to the car.
I got the car movement from this tutorial, but I didn't like the camera movement in it, I wanted the camera to orbit the car. I followed this one for the camera movement. However, I am trying to modify it so the camera turns with the car and doesn't reset to the back of the car
CameraManager.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraManager : MonoBehaviour
{
public InputManager im;
public bool lockCursor;
public float distance = 5f;
public float mouseSensitivity = 10f;
public Transform target;
public Vector2 pitchMinMax = new Vector2 (-40, 85);
public float rotationSmoothTime = 0.12f;
Vector3 rotationSmoothVelocity;
Vector3 currentRotation;
float yaw;
float pitch;
void Start()
{
im = GetComponent<InputManager>();
if (lockCursor)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
// Update is called once per frame
void LateUpdate()
{
yaw += (Input.GetAxis("Mouse X")) * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchMinMax.x, pitchMinMax.y);
currentRotation = Vector3.SmoothDamp(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
transform.eulerAngles = currentRotation;
print(target.transform.forward);
transform.position = target.position - transform.forward * distance;
}
}
InputManager.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InputManager : MonoBehaviour
{
public float throttle;
public float steer;
// Update is called once per frame
void Update()
{
throttle = Input.GetAxis("Vertical");
steer = Input.GetAxis("Horizontal");
print(steer);
}
}
CarController.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(InputManager))]
[RequireComponent(typeof(Rigidbody))]
public class CarController : MonoBehaviour
{
public InputManager im;
public List<WheelCollider> throttleWheels;
public List<WheelCollider> steeringWheels;
public float strengthCo = 10000f; //Strength Coefficent
public float maxTurn = 20f;
public Transform CM;
public Rigidbody rb;
// Start is called before the first frame update
void Start()
{
im = GetComponent<InputManager>();
rb = GetComponent<Rigidbody>();
if (CM)
{
rb.centerOfMass = CM.position;
}
}
// Update is called once per frame
void FixedUpdate()
{
foreach (WheelCollider wheel in throttleWheels)
{
wheel.motorTorque = strengthCo * Time.deltaTime * im.throttle;
}
foreach (WheelCollider wheel in steeringWheels)
{
wheel.steerAngle = maxTurn * im.steer;
}
}
}
You can use Quaternion.Euler(currentRotation) as a relative rotation to apply to target.rotation, and apply it with target.rotation * Quaternion.Euler(currentRotation):
void LateUpdate()
{
yaw += (Input.GetAxis("Mouse X")) * mouseSensitivity;
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
pitch = Mathf.Clamp(pitch, pitchMinMax.x, pitchMinMax.y);
currentRotation = Vector3.SmoothDamp(currentRotation, new Vector3(pitch, yaw), ref rotationSmoothVelocity, rotationSmoothTime);
transform.rotation = target.rotation * Quaternion.Euler(currentRotation);
print(target.transform.forward);
transform.position = target.position - transform.forward * distance;
}
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);
}
}