how do i Rotate and move 3rd person character at Unity - c#

I want to rotate my player for where my mouse is pointing and move the player with "WASD" keys.
I'm actually succesfully rotating my player and moving it, but it doesn't move right depending where my mouse is pointing.. the player just move everytime to the same position.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public int playerSpeed = 5;
public float sensitivity = 5.0f;
public bool blockMouse = true;
private float mouseX;
void Start(){
BlockMouse();
}
void Update() {
Move();
Rotate();
}
void Move()
{
Vector3 movement = new Vector3 (Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
transform.position += movement * playerSpeed * Time.deltaTime;
if(Input.GetKeyDown(KeyCode.LeftShift)) {
playerSpeed=10;
} else if(Input.GetKeyUp(KeyCode.LeftShift)) {
playerSpeed=5;
}
}
void Rotate() {
mouseX += Input.GetAxis("Mouse X") * sensitivity;
transform.eulerAngles = new Vector3(0, mouseX, 0);
}
void BlockMouse() {
if (!blockMouse) {
return;
}
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
}
``

Assuming the rotation is working as you said
transform.position += movement * playerSpeed * Time.deltaTime;
by doing this you change the objects world space absolute position, not taking any rotation into account.
Now there are probably a lot of ways how do rather do this
You could simply take the rotation into account
transform.position += transform.rotation * movement * playerSpeed * Time.deltaTime;
This simply stays in world space but rotates your world space vector accordingly
You could rather use Translate
transform.Translate(movement * playerSpeed * Time.deltaTime);
which basically does the same, takes orientation into account but is not affected by scaling

Related

How to make my character look in the direction of the camera in Unity 3d?

My character has a chinemachine camera attached to it and it is moving perfectly fine. But when I move my mouse to change the camera direction it is not looking in that direction. And I can't figure out how to make it look in that direction.
I have a reference to the original camera at the top of the script by the name cam.
The script has different functions for movement, rotation, animation, etc.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//so that unity recognises the callbacks ctx passed to the movementinput
using UnityEngine.InputSystem;
public class AnimationAndMovController : MonoBehaviour
{
public Transform cam;
public float speed;
//here we are creadting three vars for the animation
//vector2 currentMovementInput stores the input axis of the player
//vector3 store the current position of the player
PlayerInput playerInput;
CharacterController characterController;
Animator animator;
Vector2 currentMovementInput;
Vector3 currentMovement;
Vector3 currentRunMovement;
Vector3 moveDir;
bool isMovementPressed;
bool isRunPressed;
float rotationFactor = 15.0f;
// float turnSmoothtime = 0.1f;
// float turnSmoothVelocity ;
float runMultiplier = 4.0f;
int walkHash ;
int runHash ;
//runs before start function
void Awake(){
playerInput = new PlayerInput();
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
// walkHash = Animator.StringToHash("Walking");
// runHash = Animator.StringToHash("run");
//now instead of writing the logic three times we pass the callback ctx to the movementInput() function
playerInput.CharacterControls.Move.started += movementInput;
playerInput.CharacterControls.Move.canceled += movementInput;
playerInput.CharacterControls.Move.performed += movementInput;
playerInput.CharacterControls.Run.started += handleRun;
playerInput.CharacterControls.Run.canceled += handleRun;
}
void handleRun(InputAction.CallbackContext ctx){
isRunPressed = ctx.ReadValueAsButton();
}
//we are going to handle rotations with quaternions
void handleRotation(){
Vector3 positionToLookAt;
positionToLookAt.x = currentMovement.x;
positionToLookAt.y = 0.0f ;
positionToLookAt.z = currentMovement.z;
Vector3 direction = new Vector3(positionToLookAt.x, 0.0f, positionToLookAt.z).normalized;
Quaternion currentRotation = transform.rotation;
//we take the current rotation and the target rotation and slerp them *FYI : Im still not sure how slerp works
if(isMovementPressed){
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactor * Time.deltaTime);
}
}
//we are passing the callback ctx to this function so that we dont have to call the function everytime we start, cancel or perform the movement
void movementInput(InputAction.CallbackContext ctx){
//we are setting the movement input to the axis of the player
currentMovementInput = ctx.ReadValue<Vector2>();
currentMovement.x = currentMovementInput.x;
//we are setting the z axis to the y axis of the player because we move y axis on keyboard or joystick but in game we move in z axis
currentMovement.z = currentMovementInput.y;
//now we are setting the run movement to the current movement
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
void handleAnimation(){
bool walk = animator.GetBool("walking");
bool run = animator.GetBool("run");
if(isMovementPressed && !walk){
animator.SetBool("walking", true);
}
else if(!isMovementPressed && walk){
animator.SetBool("walking", false);
}
if((isMovementPressed && isRunPressed) && !run){
animator.SetBool("run", true);
}
else if((!isMovementPressed || !isRunPressed)&& run){
animator.SetBool("run", false);
}
}
void handleGravity(){
//we are setting the gravity to -9.8f because we are moving in y axis
if(characterController.isGrounded){
float groundGravity = -0.05f;
currentMovement.y = groundGravity;
currentRunMovement.y = groundGravity;
}
else{
float gravity = -9.8f;
currentMovement.y += gravity * Time.deltaTime;
currentRunMovement.y += gravity * Time.deltaTime;
}
}
// Update is called once per frame
void Update()
{
handleAnimation();
handleRotation();
handleGravity();
if(isRunPressed){
characterController.Move(currentRunMovement * Time.deltaTime);
}
else{
characterController.Move(currentMovement * Time.deltaTime);
}
}
//we are checking if the player script gets enabled or disabled and accordingly we are enabling or disabling the player input
void OnEnable(){
playerInput.CharacterControls.Enable();
}
void OnDisable(){
playerInput.CharacterControls.Disable();
}
}
That quite a lot of code to dive into.
I'd try:
Quaternion cameraRot = Camera.Main.transform.rotation;
transform.rotation = cameraRot;
Or if you have a target Quaternion.LookRotation:
Vector3 relativePos = target.position - transform.position;
// the second argument, upwards, defaults to Vector3.up
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
Hope that helps
Use Transform.LookAt, which points a Game Object's rotation towards a target's position.
In your case, this would be
transform.LookAt(cam);
here is the code that I use..
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCamera : MonoBehaviour
{
public float sensitivity = 1000f;
public float xRotation = 0f;
public Transform playerBody;
public Quaternion localRotate;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float MX = Input.GetAxis("Mouse X")*sensitivity*Time.deltaTime;
float MY = Input.GetAxis("Mouse Y")*sensitivity*Time.deltaTime;
xRotation -= MY;
xRotation = Mathf.Clamp(xRotation,-90f,90f);
transform.localRotation = Quaternion.Euler(xRotation,0f,0f);
localRotate = transform.localRotation;
playerBody.Rotate(Vector3.up * MX);
}
}
the player body you see is the player object to you character...
note that the camera is use is not In. cinema chine and is inside of the player...

Have enemy accelerate towards player in Unity

I have a script that has the enemy move towards the player at the same speed, but I am trying to make the enemy slow down then accelerate when he is switching directions. The enemy currently just moves left and write towards the player's position.
Here is my code from the script that my boss is attached to in the update function:
Vector2 targetPosition = new Vector2 (player.transform.position.x, transform.position.y);
transform.position = Vector2.MoveTowards (transform.position, targetPosition, moveSpeed * Time.deltaTime);
I have also tried using Lerp and using the transform.position as the first parameter, but the boss goes slower when the player is closer, and faster when the player is faster away.
transform.position = Vector2.Lerp (transform.position, targetPosition, moveSpeed * Time.deltaTime);
Does anyone know how to make the enemy slow down, then gradually increase his speed as he change direction, then return to normal speed after he has finished changing directions
**EDIT: ** full script below
using UnityEngine;
public class Roll : StateMachineBehaviour
{
[SerializeField] private float moveSpeed = 2.4f;
[SerializeField] private float rotateSpeed = 100f;
[SerializeField] private float minRollTime = 6f;
[SerializeField] private float maxRollTime = 8f;
private float rollTimer = 0f;
[SerializeField] private float rightBoundary = 5f;
[SerializeField] private float leftBoundary = -5f;
private Transform playerTransform = null;
private BossHealth bossHealth = null;
private Transform bossTransform = null;
private Transform bodyTransform = null;
private Transform earsTransform = null;
private Vector2 targetPosition = Vector2.zero;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
playerTransform = GameObject.FindWithTag("Player").transform;
bossHealth = animator.GetComponent<BossHealth>();
Boss01 boss = FindObjectOfType<Boss01>();
bossTransform = boss.bossTransform;
bodyTransform = boss.bodyTransform;
earsTransform = boss.earsTransform;
rollTimer = Random.Range (minRollTime, maxRollTime);
}
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (bossTransform.position.x >= leftBoundary && bossTransform.position.x <= rightBoundary)
{
targetPosition = new Vector2(playerTransform.position.x, bossTransform.position.y);
bossTransform.position = Vector2.MoveTowards(bossTransform.position, targetPosition, moveSpeed * Time.deltaTime);
if (playerTransform.position.x > 0)
bodyTransform.Rotate(0f, 0f, -rotateSpeed * Time.deltaTime);
else
bodyTransform.Rotate(0f, 0f, rotateSpeed * Time.deltaTime);
}
else if (bossTransform.position.x < leftBoundary)
{
if (playerTransform.position.x > bossTransform.position.x)
{
targetPosition = new Vector2(playerTransform.position.x, bossTransform.position.y);
bossTransform.position = Vector2.MoveTowards(bossTransform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
else
{
if (playerTransform.position.x < bossTransform.position.x)
{
targetPosition = new Vector2(playerTransform.position.x, bossTransform.position.y);
bossTransform.position = Vector2.MoveTowards(bossTransform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
if (rollTimer <= 0f)
animator.SetTrigger ("aim");
else
rollTimer -= Time.deltaTime;
if (bossHealth.CheckHealth())
animator.SetTrigger ("transition");
if (earsTransform.rotation != Quaternion.Euler (0f, 0f, 0f))
earsTransform.rotation = Quaternion.Slerp(earsTransform.rotation, Quaternion.Euler(0f, 0f, 0f), 1f * Time.deltaTime);
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.ResetTrigger ("aim");
animator.ResetTrigger ("transition");
}
}
To achieve the position (meters/second) you multiply the speed * Time.deltatime, so you achieve the meters. To handle acceleration, you need to handle variable speed. Acceleration is m/s2, multiplied * Time.deltatime you will have the instant speed, and that speed * Time.deltaTime will give you the position.
Here some pseudocode (step and speed should be class varibles and this modifieed in the update. accel is the constant acceleration, that should be constans for the simplicity's sake, I guess that you need uniformingly accelerated movement):
speed += accel * Time.deltaTime; // instant speed
step = speed * Time.deltaTime; // calculate distance to move
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
With the sign of the accel + or - you will determine if the entities speed is increasing (accelerating) or decreasing (decelerating).
Hope that helps
Edit:
Full script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveTowards : MonoBehaviour
{
public Transform target;
private float step = 0f;
private float speed = 0f;
public float accel = 0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
speed += accel * Time.deltaTime; // instant speed
step = speed * Time.deltaTime; // calculate distance to move
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
}
Screenshot of script attached in editor:
Attached the script to the game object you want to move, and attach the transform of the target in the public fielld. The choose your acceleration, positive to accelerate towards an negative to accelerate backwars, and there you got it.

Unity3D Player movement: Looking up makes my player jump

If I move forward while looking up my player jumps or at least attempts to fly. If I press Space bar and do move forward while looking up my player jumps even higher. I honestly have no idea on whats's going on. My prediction is the forward. If I look up Forward is relative to where I'm looking.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class P_MOVEMENT : MonoBehaviour
{
private float ACCELERATION = 10.0f;
private float GRAVITY = -5.0f;
private float SPEED = 5.0f;
private float RUNNING_SPEED = 2.0f;
private float JUMP_IMPULSE = 2.5f;
private bool isRunning = false;
CharacterController P_CC;
Vector3 P_MOVE;
//Camera Moving Mouse
private float X_AXIS = 0.0f;
private float Y_AXIS = 0.0f;
private float CAMERA_SPEED = 2.0f;
// Start is called before the first frame update
void Start()
{
P_CC = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
if(P_CC.isGrounded)
{
// Player Movement
P_MOVE = transform.forward * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal");
// Special Cases Check
// Running
isRunning = ( Input.GetKey(KeyCode.LeftShift) ) ? true : false;
P_MOVE = (isRunning) ? P_MOVE * SPEED * RUNNING_SPEED : P_MOVE * SPEED;
// Jumping
if(Input.GetAxis("Jump") > 0)
{
P_MOVE += Vector3.up * JUMP_IMPULSE;
}
}
else
{
P_MOVE += Vector3.up * GRAVITY * Time.deltaTime;
}
// Player Camera Movement
X_AXIS += CAMERA_SPEED * Input.GetAxis("Mouse X");
Y_AXIS -= CAMERA_SPEED * Input.GetAxis("Mouse Y");
// Restrict 90 Degree Up and Down
Y_AXIS = Mathf.Clamp(Y_AXIS, -60f, 90f);
// Update Rotation
transform.eulerAngles = new Vector3(Y_AXIS, X_AXIS, 0.0f);
}
void FixedUpdate()
{
P_CC.Move(P_MOVE * Time.deltaTime);
}
}
You are probably right. Your transform.forward is about the local GameObject coordinates instead of the global ones.
You could try to update only transform.forward.x and transform.forward.z. So you will ignore transform.forward.y. This way the player should not move up.
Something like this:
P_MOVE = transfrom.forward.x * Input.GetAxis("Vertical") + transform.forward.z * Input.GetAxis("Vertical") + transform.right * Input.GetAxis("Horizontal");

Make GameObject hover above a plane? - Unity3D C#

So I'm trying to make an FPS-type game and is it possible to have a GameObject locked on the Y-axis/not able to move up or down? The GameObject is a model of an AWP from Counter Strike, I am making it move around the plane with the WASD keys, and when I use the mouse to look up/down, the AWP goes diagonally to where I'm looking, and I don't want that. My game looks like this: Screenshot
Here's the code I have for the AWP if it helps:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class AWPscript : MonoBehaviour {
public float speed = 5f;
// public float sensitivityX = 15.0f;
// public float sensitivityY = 15.0f;
public Camera MainCamera;
public Camera scopeCamera;
public float lookSensitivity = 10f;
public float xRotation ;
public float yRotation ;
public float currentXRotation;
public float currentYRotation;
public float xRotationV;
public float yRotationV;
public GameObject Scopepng;
public float lookSmoothDamp = 0.1f;
public Image ScopePNG;
public AudioClip sound;
// Use this for initialization
void Start () {
speed = 7.5f;
}
// Update is called once per frame
void Update () {
if(Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime*speed);
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.back * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.A))
transform.Translate(Vector3.left * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.D))
transform.Translate(Vector3.right * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.LeftControl))
speed = 15f;
lookAround();
scope();
}
void scope()
{
if (Input.GetMouseButton(1))
{
MainCamera.enabled = false;
scopeCamera.enabled = true;
ScopePNG.enabled = true;
}
else
{
MainCamera.enabled = true;
scopeCamera.enabled = false;
ScopePNG.enabled = false;
}
}
void lookAround()
{
xRotation -= Input.GetAxis("Mouse Y") * lookSensitivity;
yRotation += Input.GetAxis("Mouse X") * lookSensitivity;
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
}
}
Here's probably the simplest solution:
void Update () {
if(Input.GetKey(KeyCode.W))
transform.Translate(Vector3.forward * Time.deltaTime*speed);
if (Input.GetKey(KeyCode.S))
transform.Translate(Vector3.back * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.A))
transform.Translate(Vector3.left * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.D))
transform.Translate(Vector3.right * Time.deltaTime * speed);
if (Input.GetKey(KeyCode.LeftControl))
speed = 15f;
LookAround();
Scope();
JoeFix();
}
public float fixedFloatingHeightMeters; // set to say 1.4 in the editor
private void JoeFix()
{
Vector3 p = transform.position;
p.y = fixedFloatingHeightMeters;
transform.position = p;
}
PS! you really MUST rename lookAround to LookAround and scope to Scope. It can affect things later
Here's kind of an advanced piece of information that may be more what you want. Please try this also!
Currently you have a vector that is the NOSE OF THE OBJECT pointing.
Say the thing is heading NORTH, ok?
So, transform.forward is pointing North BUT, IT IS POINTING "DOWN A BIT".
Although it is pointing north, if you saw it from the side that vector is pointing DOWN A BIT.
What you really want is that vector, but FLAT, NOT POINTING DOWN OR UP. Right?!
In fact here's the magic to do that:
Vector3 correctDirectionButPossiblyDownOrUp = transform.forward;
Vector3 correctDirectionButFlatNoDownOrUp;
correctDirectionButFlatNoDownOrUp
= Vector3.ProjectOnPlane(
correctDirectionButPossiblyDownOrUp,
Vector3.up );
correctDirectionButFlatNoDownOrUp.Normalize();
correctDirectionButFlatNoDownOrUp is now the "magic" vector you want.
But, don't forget Translate works in LOCAL SPACE. (the "object's" idea of the world.) You very much want to move it in world space, which is easy. Notice the last argument: https://docs.unity3d.com/ScriptReference/Transform.Translate.html
transform.Translate(
correctDirectionButFlatNoDownOrUp * Time.deltaTime*speed,
Space.World);
So that's it !
footnote Don't forget "Vector3.up" has absolutely no connection to "Vector3".
If you don't need the gravity then removing the RigidBody component will stop Unity applying gravity and it will hover.

move in deirection of the Camera but ignore Y-Axis

I'm using the following code to move the camera in whatever direction it is facing. It is working fine.
public class moveCam : MonoBehaviour {
public float walkSpeed = 0.9f;
void Start () {
}
void Update () {
//Walk In Direction Of Camera
transform.position += transform.forward * walkSpeed * Time.deltaTime;
}
}
The only problem I want to restrict my camera to ground level(i.e a constant position at Y), the work around for this is negate the calculate Y by resetting it, for which I am doing this
void Update () {
//Walk In Direction Of Camera
transform.position += transform.forward * walkSpeed * Time.deltaTime;
transform.position = new Vector3(transform.position.x,0.7f,transform.position.z);
}
what I want to know is, Is there a better way to achieve this.
Just reset the Y position after the change like the following
void Update(){
//Code to move in any particular direction
transform.position = new Vector3(transform.position.x,FIXED_Y_VALUE,transform.position.z);
}
or don't change Y direction at all -
void Update(){
Vector3 newCameraPosition = transform.position + transform.forward * walkSpeed * Time.deltaTime;
transform.position = new Vector3(newCameraPosition.x,transform.position.y,newCameraPosition.z);
}

Categories