Stuttering movement in Unity 2D - c#

So basically I am trying to make player movement system like one in RPG Maker with 8 directions. Somehow I succeded, but only partially. When I am trying to suddenly change direction for ex. from up to left, character stutter and do not want to move without releasing all keys first.
Gravity scale is disabled or more like set to 0, body type is dynamic.
Here is a code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveChar : MonoBehaviour {
Rigidbody2D rigid;
public float Speed;
// Use this for initialization
void Start () {
rigid = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
// float horiz = Input.GetAxis("Horizontal");
// float vert = Input.GetAxis("Vertical");
if(Input.GetKeyDown(KeyCode.W)) //________________________________________MOVING UP
{
rigid.velocity = new Vector2(rigid.velocity.x, 1 * Speed);
}
else if(Input.GetKeyUp(KeyCode.W))
{
rigid.velocity = new Vector2(0, 0);
}
if (Input.GetKeyDown(KeyCode.S)) //_______________________________________MOVING DOWN
{
rigid.velocity = new Vector2(rigid.velocity.x, -1 * Speed);
}
else if (Input.GetKeyUp(KeyCode.S))
{
rigid.velocity = new Vector2(0, 0);
}
if (Input.GetKeyDown(KeyCode.A)) //_______________________________________MOVING LEFT
{
rigid.velocity = new Vector2(-1 * Speed, rigid.velocity.y);
}
else if (Input.GetKeyUp(KeyCode.A))
{
rigid.velocity = new Vector2(0, 0);
}
if (Input.GetKeyDown(KeyCode.D)) //_______________________________________MOVING RIGHT
{
rigid.velocity = new Vector2(1 * Speed, rigid.velocity.y);
}
else if (Input.GetKeyUp(KeyCode.D))
{
rigid.velocity = new Vector2(0, 0);
}
}

Use Input.GetAxis(axisName) to avoid conflicting cases in your input code. Also, use AddForce to play nicely with other rigidbodies.
Vector2 oldV = rigid.velocity;
float horiz = Input.GetAxis("Horizontal");
float vert = Input.GetAxis("Vertical");
Vector2 newV = new Vector2(horiz * Speed, vert * Speed);
rigid.AddForce(newV-oldV, ForceMode2D.Impulse);
Alternatively, keep track of your own axes when keys are lifted/pressed down
public float horiz;
public float vert;
void Start() {
horiz = 0f;
vert = 0f;
if (Input.GetKey(KeyCode.A)) horiz -= 1f;
if (Input.GetKey(KeyCode.D)) horiz += 1f;
if (Input.GetKey(KeyCode.S)) vert -= 1f;
if (Input.GetKey(KeyCode.W)) vert += 1f;
}
void Update () {
Vector2 oldV = rigid.velocity;
if(Input.GetKeyDown(KeyCode.W)) vert += 1f;
else if(Input.GetKeyUp(KeyCode.W)) vert -= 1f;
if (Input.GetKeyDown(KeyCode.S)) vert -= 1f;
else if (Input.GetKeyUp(KeyCode.S)) vert += 1f;
if (Input.GetKeyDown(KeyCode.A)) horiz -= 1f;
else if (Input.GetKeyUp(KeyCode.A)) horiz += 1f;
if (Input.GetKeyDown(KeyCode.D)) horiz += 1f;
else if (Input.GetKeyUp(KeyCode.D)) horiz -= 1f;
Vector2 newV = new Vector2(horiz * Speed, vert * Speed);
rigid.AddForce(newV-oldV, ForceMode2D.Impulse);
}

There is only a small problem with releasing the button. Add the original force in the direction that is not affected by the key. The whole script should look like this:
void Update()
{
if (Input.GetKeyDown(KeyCode.W)) //________________________________________MOVING UP
{
rigid.velocity = new Vector2(rigid.velocity.x, 1 * Speed);
}
else if (Input.GetKeyUp(KeyCode.W))
{
rigid.velocity = new Vector2(rigid.velocity.x, 0);
}
if (Input.GetKeyDown(KeyCode.S)) //_______________________________________MOVING DOWN
{
rigid.velocity = new Vector2(rigid.velocity.x, -1 * Speed);
}
else if (Input.GetKeyUp(KeyCode.S))
{
rigid.velocity = new Vector2(rigid.velocity.x, 0);
}
if (Input.GetKeyDown(KeyCode.A)) //_______________________________________MOVING LEFT
{
rigid.velocity = new Vector2(-1 * Speed, rigid.velocity.y);
}
else if (Input.GetKeyUp(KeyCode.A))
{
rigid.velocity = new Vector2(0, rigid.velocity.y);
}
if (Input.GetKeyDown(KeyCode.D)) //_______________________________________MOVING RIGHT
{
rigid.velocity = new Vector2(1 * Speed, rigid.velocity.y);
}
else if (Input.GetKeyUp(KeyCode.D))
{
rigid.velocity = new Vector2(0, rigid.velocity.y);
}
}
I hope this helps you.

Related

How to make a boundary in 2d

I an trying to keep my charecter inside boundaries but I was only able to get it to work for the side walls and not the bottem and top walls. Here is my code for moving and the boundaries.
{
public float verticalInput;
public float horizontalInput;
public float speed = 10.0f;
public float Xrange = 9.5f;
public float Yrange = 4.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
horizontalInput = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * horizontalInput * Time.deltaTime * speed);
verticalInput = Input.GetAxis("Vertical");
transform.Translate(Vector3.up * verticalInput * Time.deltaTime * speed);
if (transform.position.x < -Xrange)
{
transform.position = new Vector3(-Xrange, transform.position.y, transform.position.z);
}
if (transform.position.x > Xrange)
{
transform.position = new Vector3(Xrange, transform.position.y, transform.position.z);
}
if (transform.position.y < -Yrange)
{
transform.position = new Vector3(-Yrange, transform.position.x, transform.position.z);
}
if (transform.position.y > Yrange)
{
transform.position = new Vector3(Yrange, transform.position.x, transform.position.z);
} ```

Unity - Make character look at mouse with New input system/Character Controller

Been following this guide https://youtu.be/bXNFxQpp2qk?t=1280 for Character Controller.
This got me getting basic movement working and at time 21:20 he creates a way to rotate the player.
https://youtu.be/b0AQg5ZTpac and this video for the player facing the mouse position.
At the 7:15 mark she explains how to get the mousePosition in which I stored it in positionToLookAt
I want my character's rotation to be done with the mouse and have a field of view like here: https://youtu.be/rQG9aUWarwE
Been trying to to get it so that the player is facing the direction of the mouse position, but haven't been getting the result. With here showing https://imgur.com/gallery/mPPWogi the video results and my PlayerInputs.
Some peers mentioned replacing
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
by
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt - transform.position);
But it doesn't work and produced the same results in the imgur.
Can anyone help me out here? I'm stuck and I have no idea how to make this character look at the mouse instead.
here's the snippet of the method
void handleRotation()
{
Vector3 positionToLookAt;
// get mouse position
Vector2 mousePosition = playerInput.CharacterControls.MousePosition.ReadValue<Vector2>();
mousePosition = Camera.main.ScreenToWorldPoint(mousePosition);
// insert mouse position to looking position
positionToLookAt.x = currentMovement.x;
//positionToLookAt.x = mousePosition.x;
positionToLookAt.y = 0.0f;
positionToLookAt.z = currentMovement.z;
//positionToLookAt.z = mousePosition.y;
Quaternion currentRotation = transform.rotation;
if (isMovementPressed)
{
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
}
}
And if anyone wants my full code, here.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class AnimationAndMovementController : MonoBehaviour
{
PlayerInput playerInput;
UnityEngine.CharacterController characterController;
Animator animator;
int isWalkingHash;
int isRunningHash;
Vector2 currentMovementInput;
Vector3 currentMovement;
Vector3 currentRunMovement;
bool isMovementPressed;
bool isRunPressed;
float rotationFactorPerFrame = 15.0f;
float runMultiplier = 3.0f;
//Debug.Log(context.ReadValue<Vector2>());
void Start()
{
}
void Awake()
{
playerInput = new PlayerInput();
characterController = GetComponent<UnityEngine.CharacterController>();
animator = GetComponent<Animator>();
isWalkingHash = Animator.StringToHash("isWalking");
isRunningHash = Animator.StringToHash("isRunning");
playerInput.CharacterControls.Move.started += onMovementInput;
playerInput.CharacterControls.Move.canceled += onMovementInput;
playerInput.CharacterControls.Move.performed += onMovementInput;
playerInput.CharacterControls.Run.started += onRun;
playerInput.CharacterControls.Run.canceled += onRun;
}
void onRun(InputAction.CallbackContext context)
{
isRunPressed = context.ReadValueAsButton();
}
void onMovementInput (InputAction.CallbackContext context)
{
currentMovementInput = context.ReadValue<Vector2>();
currentMovement.x = currentMovementInput.x;
currentMovement.z = currentMovementInput.y;
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
void handleRotation()
{
Vector3 positionToLookAt;
Vector2 mousePosition = playerInput.CharacterControls.MousePosition.ReadValue<Vector2>();
mousePosition = Camera.main.ScreenToWorldPoint(mousePosition);
positionToLookAt.x = currentMovement.x;
//positionToLookAt.x = mousePosition.x;
positionToLookAt.y = 0.0f;
positionToLookAt.z = currentMovement.z;
//positionToLookAt.z = mousePosition.y;
Quaternion currentRotation = transform.rotation;
if (isMovementPressed)
{
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
}
}
void handleAnimation()
{
bool isWalking = animator.GetBool(isWalkingHash);
bool isRunning = animator.GetBool(isRunningHash);
if (isMovementPressed && !isWalking) {
animator.SetBool(isWalkingHash, true);
}
else if (!isMovementPressed && isWalking){
animator.SetBool(isWalkingHash, false);
}
if ((isMovementPressed && isRunPressed) && !isRunning)
{
animator.SetBool(isRunningHash, true);
}
else if ((!isMovementPressed && !isRunPressed) && isRunning)
{
animator.SetBool(isRunningHash, false);
}
else if ((isMovementPressed && !isRunPressed) && isRunning)
{
animator.SetBool(isRunningHash, false);
}
}
void handleGravity()
{
if (characterController.isGrounded) {
float groundedGravity = -0.05f;
currentMovement.y = groundedGravity;
currentRunMovement.y = groundedGravity;
} else {
float gravity = -9.8f;
currentMovement.y = gravity;
currentRunMovement.y = gravity;
}
}
// Update is called once per frame
void Update()
{
handleRotation();
handleAnimation();
handleGravity();
if (isRunPressed) {
characterController.Move(currentRunMovement * Time.deltaTime);
}
else {
characterController.Move(currentMovement * Time.deltaTime);
}
}
void OnEnable()
{
playerInput.CharacterControls.Enable();
}
void OnDisable()
{
playerInput.CharacterControls.Disable();
}
}
EDIT
Updated full code and handleRotation() is where Rotation is being handled:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class AnimationAndMovementController : MonoBehaviour
{
PlayerInput playerInput;
CharacterController characterController;
Animator animator;
int isWalkingHash;
int isRunningHash;
Camera _camera;
Vector2 currentMovementInput;
Vector3 currentMovement;
Vector3 currentRunMovement;
bool isMovementPressed;
bool isRunPressed;
//float rotationFactorPerFrame = 15.0f;
float runMultiplier = 3.0f;
// Start is called before the first frame update
void Start()
{
_camera = Camera.main;
}
void Awake()
{
playerInput = new PlayerInput();
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
isWalkingHash = Animator.StringToHash("isWalking");
isRunningHash = Animator.StringToHash("isRunning");
playerInput.CharacterControls.Move.started += onMovementInput;
playerInput.CharacterControls.Move.canceled += onMovementInput;
playerInput.CharacterControls.Move.performed += onMovementInput;
playerInput.CharacterControls.Run.started += onRun;
playerInput.CharacterControls.Run.canceled += onRun;
}
void onRun(InputAction.CallbackContext context)
{
isRunPressed = context.ReadValueAsButton();
}
void onMovementInput(InputAction.CallbackContext context)
{
currentMovementInput = context.ReadValue<Vector2>();
currentMovement.x = currentMovementInput.x;
currentMovement.z = currentMovementInput.y;
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
void handleAnimation()
{
bool isWalking = animator.GetBool(isWalkingHash);
bool isRunning = animator.GetBool(isRunningHash);
if (isMovementPressed && !isWalking)
{
animator.SetBool(isWalkingHash, true);
}
else if (!isMovementPressed && isWalking)
{
animator.SetBool(isWalkingHash, false);
}
if ((isMovementPressed && isRunPressed) && !isRunning)
{
animator.SetBool(isRunningHash, true);
}
else if ((!isMovementPressed && !isRunPressed) && isRunning)
{
animator.SetBool(isRunningHash, false);
}
else if ((isMovementPressed && !isRunPressed) && isRunning)
{
animator.SetBool(isRunningHash, false);
}
}
void handleGravity()
{
if (characterController.isGrounded)
{
float groundedGravity = -0.05f;
currentMovement.y = groundedGravity;
currentRunMovement.y = groundedGravity;
}
else
{
float gravity = -9.8f;
currentMovement.y = gravity;
currentRunMovement.y = gravity;
}
}
void handleRotation()
{
// We're getting a Vector2, whereas we will need a Vector3
// Get a z value based on camera, and include it in a Vector3
var mousePosition = playerInput.CharacterControls.MousePosition.ReadValue<Vector2>();
var mousePositionZ = _camera.farClipPlane * .5f;
var mouseViewportPosition = _camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, mousePositionZ));
// Do the same with the object's position
var positionOnViewport = Camera.main.WorldToViewportPoint(transform.position);
// Get the angle between the points
var angle = AngleBetweenTwoPoints(positionOnViewport, mouseViewportPosition);
// Apply the angle as the rotation of the object
transform.rotation = Quaternion.Euler(new Vector3(0f, -angle, 0f));
}
float AngleBetweenTwoPoints(Vector3 a, Vector3 b)
{
return Mathf.Atan2(b.y - a.y, b.x - a.x) * Mathf.Rad2Deg;
}
// Update is called once per frame
void Update()
{
handleRotation();
handleAnimation();
handleGravity();
if (isRunPressed)
{
characterController.Move(currentRunMovement * Time.deltaTime);
}
else
{
characterController.Move(currentMovement * Time.deltaTime);
}
}
void OnEnable()
{
playerInput.CharacterControls.Enable();
}
void OnDisable()
{
playerInput.CharacterControls.Disable();
}
}
EDIT 2: with current iteration
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class AnimationAndMovementController : MonoBehaviour
{
PlayerInput playerInput;
CharacterController characterController;
Animator animator;
int isWalkingHash;
int isRunningHash;
Camera _camera;
Vector2 currentMovementInput;
Vector3 currentMovement;
Vector3 currentRunMovement;
bool isMovementPressed;
bool isRunPressed;
float rotationFactorPerFrame = 15.0f;
float runMultiplier = 3.0f;
// Start is called before the first frame update
void Start()
{
_camera = Camera.main;
}
void Awake()
{
playerInput = new PlayerInput();
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
isWalkingHash = Animator.StringToHash("isWalking");
isRunningHash = Animator.StringToHash("isRunning");
playerInput.CharacterControls.Move.started += onMovementInput;
playerInput.CharacterControls.Move.canceled += onMovementInput;
playerInput.CharacterControls.Move.performed += onMovementInput;
playerInput.CharacterControls.Run.started += onRun;
playerInput.CharacterControls.Run.canceled += onRun;
}
void onRun(InputAction.CallbackContext context)
{
isRunPressed = context.ReadValueAsButton();
}
void onMovementInput(InputAction.CallbackContext context)
{
currentMovementInput = context.ReadValue<Vector2>();
currentMovement.x = currentMovementInput.x;
currentMovement.z = currentMovementInput.y;
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
void handleAnimation()
{
bool isWalking = animator.GetBool(isWalkingHash);
bool isRunning = animator.GetBool(isRunningHash);
if (isMovementPressed && !isWalking)
{
animator.SetBool(isWalkingHash, true);
}
else if (!isMovementPressed && isWalking)
{
animator.SetBool(isWalkingHash, false);
}
if ((isMovementPressed && isRunPressed) && !isRunning)
{
animator.SetBool(isRunningHash, true);
}
else if ((!isMovementPressed && !isRunPressed) && isRunning)
{
animator.SetBool(isRunningHash, false);
}
else if ((isMovementPressed && !isRunPressed) && isRunning)
{
animator.SetBool(isRunningHash, false);
}
}
void handleGravity()
{
if (characterController.isGrounded)
{
float groundedGravity = -0.05f;
currentMovement.y = groundedGravity;
currentRunMovement.y = groundedGravity;
}
else
{
float gravity = -9.8f;
currentMovement.y = gravity;
currentRunMovement.y = gravity;
}
}
void handle_isRunPressed()
{
if (isRunPressed)
{
characterController.Move(currentRunMovement * Time.deltaTime);
}
else
{
characterController.Move(currentMovement * Time.deltaTime);
}
}
void handleRotation()
{
var mousePosition = playerInput.CharacterControls.MousePosition.ReadValue<Vector2>();
var mousePositionZ = _camera.farClipPlane * .5f;
var mouseWorldPosition = _camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, mousePositionZ)); // _camera.ScreenToViewportPoint(mousePosition);
// Get the angle between the points
// Use the x and z from the object/mouse, since we're looking along the y axis
var angle = AngleBetweenTwoPoints(new Vector2(transform.position.x, transform.position.z), new Vector2(mouseWorldPosition.x, mouseWorldPosition.z));
transform.rotation = Quaternion.Euler(new Vector3(0f, -angle, 0f));
}
float AngleBetweenTwoPoints(Vector3 a, Vector3 b)
{
return Mathf.Atan2(b.y - a.y, b.x - a.x) * Mathf.Rad2Deg;
}
// Update is called once per frame
void Update()
{
handleRotation();
handleAnimation();
handleGravity();
handle_isRunPressed();
}
void OnEnable()
{
playerInput.CharacterControls.Enable();
}
void OnDisable()
{
playerInput.CharacterControls.Disable();
}
}
Rotation still not working as intended with my code unforunately within handleRotation()
EDIT 3:
void handleRotation()
{
// We're getting a Vector2, whereas we will need a Vector3
// Get a z value based on camera, and include it in a Vector3
Vector2 mousePosition = playerInput.CharacterControls.MousePosition.ReadValue<Vector2>();
var mousePositionZ = _camera.farClipPlane * .5f;
Vector3 mouseViewportPosition = _camera.ViewportToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, _camera.transform.position.y));
Debug.Log("MousePos: " + mouseViewportPosition);
Vector3 positionToLookAt;
positionToLookAt.x = mouseViewportPosition.x;
positionToLookAt.y = 0.0f;
//positionToLookAt.z = currentMovement.z;
positionToLookAt.z = mouseViewportPosition.z;
Quaternion currentRotation = transform.rotation;
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt - transform.position);
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
}
IT'S ROTATING. But not correctly.
UPDATE Take 2
Here is the full code I have in my Update():
var mousePosition = _playerInput.Player.MousePosition.ReadValue<Vector2>();
var mousePositionZ = _camera.farClipPlane * .5f;
var mouseWorldPosition = _camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, mousePositionZ)); // _camera.ScreenToViewportPoint(mousePosition);
// Get the angle between the points
// Use the x and z from the object/mouse, since we're looking along the y axis
var angle = AngleBetweenTwoPoints(new Vector2(transform.position.x, transform.position.z), new Vector2(mouseWorldPosition.x, mouseWorldPosition.z));
transform.rotation = Quaternion.Euler(new Vector3(0f, -angle, 0f));
and the helper function is the same:
float AngleBetweenTwoPoints(Vector2 a, Vector2 b)
{
return Mathf.Atan2(b.y - a.y, b.x - a.x) * Mathf.Rad2Deg;
}
UPDATE
I figured out how to do this in the way that Joseph was originally trying.
ScreenToWorldPoint does indeed work correctly with the new input system. The issue is the way we're trying to use it. It needs a Vector3!
You CAN'T do this:
// Don't do this, it wont work!
var mousePosition = _playerInput.Player.MousePosition.ReadValue<Vector2>();
var mouseViewportPosition = _camera.ScreenToWorldPoint(mousePosition);
You need to do this:
// We're getting a Vector2, whereas we will need a Vector3
// Get a z value based on camera, and include it in a Vector3
var mousePosition = _playerInput.Player.MousePosition.ReadValue<Vector2>();
var mousePositionZ = _camera.farClipPlane * .5f;
var mouseViewportPosition = _camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, mousePositionZ));
Original answer:
Your example had some issues... I think you were in the middle of editing it to make the rotation based on the movement direction? There may be an issue with the mouse position stuff right now in the engine... I noticed some other threads complaining that the input values weren't the same, but I'm not sure to what extent. Maybe the conversion to world coordinates isn't working?
For some reason, this does not work for me, it always spits out (0.0, 10.0, 0.0):
var mouseWorldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
This is what I was able to get working:
// Get the mouse position from the NEW input system
var mousePosition = _playerInput.Player.MousePosition.ReadValue<Vector2>();
// Convert the mousePosition to the VIEWPORT
var mouseViewportPosition = Camera.main.ScreenToViewportPoint(mousePosition);
// Do the same with the object's position
var positionOnViewport = Camera.main.WorldToViewportPoint(transform.position);
// Get the angle between the points
var angle = AngleBetweenTwoPoints(positionOnViewport, mouseViewportPosition);
// Apply the angle as the rotation of the object
transform.rotation = Quaternion.Euler(new Vector3(0f, -angle, 0f));
The general idea was from here, including this function (https://answers.unity.com/questions/855976/make-a-player-model-rotate-towards-mouse-location.html):
float AngleBetweenTwoPoints(Vector3 a, Vector3 b)
{
return Mathf.Atan2(b.y - a.y, b.x - a.x) * Mathf.Rad2Deg;
}
Note that this isn't perfect... the angle is slightly off... not sure why that is. You can see it exaggerated a little here:
I think the moral of the story here is to check the input at each stage to see what it looks like and how it gets/got transformed. Now that we know some of the new input values may be off, you can either use the old system's mouse position, or combine my example with some of the other methods you mentioned.
Adding a new answer because this will just use Quaternions like you're trying to do.
The first step is to convert the mouse from screen coordinates, to world coordinates:
// Read the mouse position from the new input system
var mousePosition = _playerInput.Player.MousePosition.ReadValue<Vector2>();
// Ensure that there is a "valid" z value so that the conversion works properly
var mousePositionZ = _camera.farClipPlane * .5f;
// Convert!
var mouseWorldPosition = _camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, mousePositionZ));
Now that we have the mouse position in world coordinates, we can compare it to the object's (player's) position, and rotate based on that difference:
// Calculate the difference between the positions
var positionVector = mouseWorldPosition - transform.position;
// Match the new y value to the object's Y value.
// This ensures that the rotation is calculated only with the X and Z
// I would love to know why this is happening... but I didn't find anything in my initial research
positionVector.y = transform.position.y;
// Now we calculate the rotation
var targetRotation = Quaternion.LookRotation(positionVector);
// FYI, if your object's final rotation is off by 90 degrees, you can do the following
// I think it has to do with what the system thinks "forward" is, and which way your model is facing by default.
// So you can either fix it in your model, or add/subtract 90 degrees
// Note that **multiplying** Quaternions together effectively **combines** them
// var targetRotation = Quaternion.LookRotation(positionVector) * Quaternion.Euler(0, -90, 0);
// And smoothly transition to the new angle using Slerp
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
I was having the same issue and finally i come up with smoother look at mouse solution for 3D Top-Down games. This is what my whole code looks like. I hope it helps.
[SerializeField] float moveSpeed = 5f;
[SerializeField] float turnSpeed = 2f;
Vector2 _moveInput;
Vector2 _mousePos;
void Update()
{
HandleMovement();
HandleRotation();
}
void OnMove(InputValue moveInput)
{
_moveInput = moveInput.Get<Vector2>();
}
void HandleMovement()
{
Vector3 deltaPos = new Vector3(_moveInput.x, 0f, _moveInput.y) * moveSpeed * Time.deltaTime;
transform.position += deltaPos;
}
void OnAim(InputValue currentMousePos)
{
_mousePos = currentMousePos.Get<Vector2>();
}
void HandleRotation()
{
Ray ray = Camera.main.ScreenPointToRay(_mousePos);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayDistance;
if (groundPlane.Raycast(ray, out rayDistance))
{
Vector3 point = ray.GetPoint(rayDistance);
LookAt(point);
}
}
void LookAt(Vector3 lookPoint)
{
Vector3 direction = (lookPoint - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0f, direction.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * turnSpeed);
}
And this is PlayerInput setup
Also you can check this tutorial video for more detail

Rotation smooth in editor but isn't in device

I have a 3D object that I want to rotate with mouse/finger swipe, so I made the script below.
The object's rotation looks smooth on editor, but when playing the game on real device (android), the rotation didn't follow the finger movement immediately, it takes some milliseconds to follow finger, it isn't smooth and the controls become hard and frustrating!
float sensitivity = 0.8f;
Vector2 firstPressPos;
Vector2 secondPressPos;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//save began touch 2d point
firstPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
}
if (Input.GetMouseButton(0))
{
//save ended touch 2d point
secondPressPos = new Vector3(Input.mousePosition.x, Input.mousePosition.y);
if (firstPressPos != secondPressPos)
{
float RotX = Input.GetAxis("Mouse X") * sensitivity * Time.deltaTime;
float RotY = Input.GetAxis("Mouse Y") * sensitivity * Time.deltaTime;
transform.RotateAround(Vector3.up, RotX);
transform.RotateAround(Vector3.right, -RotY);
}
}
}
try this code
// Screen Touches
Vector2?[] oldTouchPositions = {
null,
null
};
// Rotation Speed
public float rotSpeed = 0.5f;
public void Update()
{
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Vector2 newTouchPosition = Input.GetTouch(0).position;
float distanceX = (oldTouchPositions[0] - newTouchPosition).Value.x;
float distanceY = (oldTouchPositions[0] - newTouchPosition).Value.y;
float rotX = distanceX * rotSpeed * Mathf.Deg2Rad;
float rotY = distanceY * rotSpeed * Mathf.Deg2Rad;
transform.Rotate(Vector3.up, rotX * 5, Space.Self);
transform.Rotate(Vector3.left, rotY * 5, Space.Self);
oldTouchPositions[0] = newTouchPosition;
}
}
else
{
if (oldTouchPositions[1] == null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
}
else
{
}
}
}
Here's a script I found a few years back that manipulates X axis spin with Mouse or Touches. It seems to work well with touches, but not as good with Mouse. Try it and let me know if it behaves a bit better. This one should adjust the spinning speed dynamically:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinDrag : MonoBehaviour {
float f_lastX = 0.0f;
float f_difX = 0.5f;
float f_steps = 0.0f;
int i_direction = 1;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
f_difX = 0.0f;
}
else if (Input.GetMouseButton(0))
{
f_difX = Mathf.Abs(f_lastX - Input.GetAxis("Mouse X"));
if (f_lastX < Input.GetAxis("Mouse X"))
{
i_direction = -1;
transform.Rotate(Vector3.up, -f_difX);
}
if (f_lastX > Input.GetAxis("Mouse X"))
{
i_direction = 1;
transform.Rotate(Vector3.up, f_difX);
}
f_lastX = -Input.GetAxis("Mouse X");
}
else
{
if (f_difX > 0.5f) f_difX -= 0.05f;
if (f_difX < 0.5f) f_difX += 0.05f;
transform.Rotate(Vector3.up, f_difX * i_direction);
}
}
}

Unity 2018 C# - Fbx Running animation scaling with Input?

I have figured out how to get fbx animations working in Unity for my character in my adventure game, but now I wish to have my character's running animation move with its speed of motion being in relation to the input of the control stick on an xbox controller.
In addition, when I add a walking animation in the future I wish to make a threshold for the control stick input so that the character walks when there is minimal input from the control stick and running when there is more input from the control stick. Any advice?
Here is my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCharacterController : MonoBehaviour {
static Animator anim;
public bool walking;
public GameObject playerModel, Hero;
//Transforms
public Transform playerCam, character, centerPoint;
private Vector3 moveDirection;
//character controller declaration
CharacterController player;
//Mouse Rotation
private float rotX, rotY;
//Mouse Y Position
public float mouseYPosition = 1f;
//Mouse Sensitivity
public float Sensitivity = 10f;
//Mouse Zoom
private float zoom;
public float zoomSpeed = 2;
//Clamping Zoom
public float zoomMin = -2f;
public float zoomMax = -10f;
public float rotationSpeed = 5f;
//Move Front Back left & Right
private float moveFB, moveLR;
//Movement Speed
public float Speed = 2f;
//Velocity of Gravity
public float verticalVelocity;
//Jump Distance
public float jumpDist = 5f;
//Multiple Jumps
int jumpTimes;
//To use with Dialogue Manager
public DialogueManager DiagM;
public AudioClip jumpSound;
public AudioClip HurtSound;
AudioSource audioSource;
//knockback
public float knockBackForce;
public float knockBackTime;
private float knockBackCounter;
// Use this for initialization
void Start ()
{
//character controller
player = GameObject.Find("Player").GetComponent<CharacterController> ();
anim = GetComponent<Animator>();
//mouse zoom
zoom = -3;
centerPoint.transform.position = playerCam.transform.position;
centerPoint.transform.parent = null;
audioSource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update ()
{
//if (DiagM.StartDialogue)
//{ return; }
//Mouse Zoom Input
zoom += Input.GetAxis ("Mouse ScrollWheel") * zoomSpeed;
if (zoom > zoomMin)
zoom = zoomMin;
if (zoom < zoomMax)
zoom = zoomMax;
//Mouse Camera Input
playerCam.transform.localPosition = new Vector3 (0, 0, zoom);
//Mouse Rotation
rotX += Input.GetAxis ("Mouse X") * Sensitivity;
rotY -= Input.GetAxis ("Mouse Y") * Sensitivity;
//Clamp Camera
rotY = Mathf.Clamp (rotY, -60f, 60f);
playerCam.LookAt (centerPoint);
centerPoint.localRotation = Quaternion.Euler (rotY, rotX, 0);
//Movement Speed
if (knockBackCounter <= 0)
{
moveDirection = (transform.forward * Input.GetAxis("Vertical")) + (transform.right * Input.GetAxis("Horizontal"));
moveDirection = moveDirection * Speed;
moveDirection.y = verticalVelocity;
player.Move(moveDirection * Time.deltaTime);
//Movement Rotation
centerPoint.position = new Vector3 (character.position.x, character.position.y + mouseYPosition, character.position.z);
//knockback disable
//Movement Input
if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
{
transform.rotation = Quaternion.Euler(0f, centerPoint.rotation.eulerAngles.y, 0f);
Quaternion turnAngle = Quaternion.LookRotation(new Vector3(moveDirection.x, 0f, moveDirection.z));
playerModel.transform.rotation = Quaternion.Slerp(playerModel.transform.rotation, turnAngle, Time.deltaTime * rotationSpeed);
if (player.isGrounded == true)
{
anim.Play("Running");
}
}
else
{
if (player.isGrounded == true)
{ anim.Play("Idle"); }
}
if (player.isGrounded == true)
{
jumpTimes = 0;
verticalVelocity = -Physics.gravity.y * Time.deltaTime;
}
else
{
verticalVelocity += Physics.gravity.y * Time.deltaTime;
}
if (Input.GetButtonDown("Submit"))
{
anim.Play("Hello");
}
if (jumpTimes < 1)
{
if (Input.GetButtonDown("Jump"))
{
verticalVelocity += jumpDist;
anim.Play("Jump");
audioSource.PlayOneShot(jumpSound, 1F);
jumpTimes += 1;
}
}
}
else
{
knockBackCounter -= Time.deltaTime;
}
}
public void Knockback(Vector3 direction)
{
knockBackCounter = knockBackTime;
anim.SetTrigger("isJumping");
audioSource.PlayOneShot(HurtSound, 50F);
moveDirection = direction * knockBackForce;
moveDirection.y = knockBackForce;
}
}

Unity - How to make the accelerometer of object move more smoothly?

I want to make my character to move smoothly when I tilt my phone. How I can make it to move smoothly and the velocity and the speed increases as the slope of the phone?
void AccelerometerMove()
{
float x = Input.acceleration.x;
Debug.Log("X = " + x);
if (x < -0.1f)
{
MoveLeft();
}
else if (x > 0.1f)
{
MoveRight();
}
else
{
SetVelocityZero();
}
}
public void SetVelocityZero()
{
rb.velocity = Vector2.zero;
}
public void MoveLeft()
{
rb.velocity = new Vector2(-speed, 0);
//transform.Translate(Vector2.right * speed * Time.deltaTime);
transform.eulerAngles = new Vector2(0, 180);
}
public void MoveRight()
{
rb.velocity = new Vector2(speed, 0);
//transform.Translate(Vector2.right * speed * Time.deltaTime);
transform.eulerAngles = new Vector2(0, 0);
}
Check out this answer about using a moving average/low-pass filter here
You could achieve a similar effect by using the Vector3.Lerp function.

Categories

Resources