Use Mobile Joystick with Unity 3d RigidBody
I am developing a mobile 3D app. I have a game object that has a rigid body and I move it with a joystick.
I got it to the point that I can move the object forward when I take the vertical input and rotate it when I take horizontal input from the joystick.
The problem is that when I rotate the rigid body 90 deg I would expect to use horizontal input to move the object forward or backward and rotate it with vertical joystick input. Basically I want the object to move forward where joystick is being pulled, but with the current set up I have to pull joystick upwards even if object is facing left or right sides. I hope I explained it well. If not know, please let me know, I will explain it more.
public Joystick m_Joystick;
private float m_HorizontalValue;
private float m_VerticalValue;
void Update()
{
m_VerticalValue = m_Joystick.Vertical;
m_HorizontalValue = m_Joystick.Horizontal;
}
// Same as update, but is used fo modifying values that are used to manipulate
// game object's physics
void FixedUpdate()
{
Move();
Turn();
}
void Move()
{
Vector3 movement = transform.forward * m_VerticalValue * m_Speed * Time.deltaTime;
m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
}
void Turn()
{
float turn = m_HorizontalValue * m_TurnSpeed * Time.deltaTime;
Quaternion turnRotation = Quaternion.Euler(0f, turn, 0f);
m_Rigidbody.MoveRotation(m_Rigidbody.rotation * turnRotation);
}
I tried checking the forward vector of my rigid body (x and z values) to inverse the movement of object when joystick is pulled into the desired direction, but it is not working well, as rigid body would stuck when x and z values of forward vector are equal. The code is not complete I was testing only two quaters of x and z coordinate system (first and second quaters).
float GetVerticalOrHorizaontalValueMovement()
{
float xValue = m_Rigidbody.transform.forward.x;
float zValue = m_Rigidbody.transform.forward.z;
float auxX = Mathf.Abs(xValue);
float auxZ = Mathf.Abs(zValue);
if (xValue > -0.1f && zValue > -0.1f)
{
if (auxX <= auxZ)
return m_HorizontalValue;
else if (auxX >= auxZ)
return m_VerticalValue;
}
else if(xValue > -0.1f && zValue < 0.1f)
{
if (auxX >= auxZ)
return m_VerticalValue;
else if (auxX <= auxZ)
return m_HorizontalValue;
}
return 0f;
}
float GetVerticalOrHorizaontalValueRotation()
{
float xValue = m_Rigidbody.transform.forward.x;
float zValue = m_Rigidbody.transform.forward.z;
float auxX = Mathf.Abs(xValue);
float auxZ = Mathf.Abs(zValue);
if (xValue > -0.1f && zValue > -0.1f)
{
if(auxX <= auxZ)
return m_VerticalValue;
else if(auxX >= auxZ)
return m_HorizontalValue;
}
else if(xValue > -0.1f && zValue < 0.1f)
{
if (auxX >= auxZ)
return m_HorizontalValue;
else if (auxX <= auxZ)
return m_VerticalValue;
}
return 0f;
}
The methods will be placed instead of m_VerticalValue and m_HorizontalValue variables in Move() and Turn() methods.
I am open to any solution that would make my game object move as I want with a joystick, but I have to keep it as RigidBody because I want to apply explosive forces on it and other possible forcers. If I did not explain something properly, please let me know.
Answer by DenisIsDenis · Oct 17, 2021 at 03:20 AM
I wrote a small script that you might find useful. I simulated a joystick with keyboard input. Here the movement works in such a way that if the desired direction of movement coincides with the transform.forward
of the player, then the player moves, otherwise the player turns to the given direction.
using UnityEngine;
public class MovementOfPlayer : MonoBehaviour
{
Vector3 movementInput;
Rigidbody playerRigidbody;
void Start()
{
playerRigidbody = GetComponent<Rigidbody>();
playerRigidbody.freezeRotation = true;
}
void FixedUpdate()
{
movementInput = Input.GetAxisRaw("Horizontal") * Vector3.right +
Input.GetAxisRaw("Vertical") * Vector3.forward;
movementInput.Normalize();
float y = playerRigidbody.velocity.y;
if (movementInput != Vector3.zero)
{
if (transform.forward != movementInput)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(movementInput), Time.deltaTime * 180);
playerRigidbody.velocity = Vector3.MoveTowards(playerRigidbody.velocity, Vector3.zero, Time.deltaTime * 30);
}
else
{
playerRigidbody.velocity = Vector3.MoveTowards(playerRigidbody.velocity, movementInput * 10, Time.deltaTime * 30);
}
}
else
{
playerRigidbody.velocity = Vector3.MoveTowards(playerRigidbody.velocity, Vector3.zero, Time.deltaTime * 30);
}
Vector3 velocity = playerRigidbody.velocity;
velocity.y = y;
playerRigidbody.velocity = velocity;
}
}
Just assign this script to any object with collider
and rigidbody
.
Thank you for sharing this with me. I will try it out.
I tried your script and thank you very much. I would need to work on it more I guess as it does not do 100% what I need. What I have noticed is that the game object would not move unless makes a full rotation into the direaction of the movement. I need to work on it more
In order for the player to move immediately, regardless of the rotation, you can replace these lines:
else
{
playerRigidbody.velocity = Vector3.MoveTowards(playerRigidbody.velocity, movementInput * 10, Time.deltaTime * 30);
}
with these:
playerRigidbody.velocity = Vector3.MoveTowards(playerRigidbody.velocity, movementInput * 10, Time.deltaTime * 30);
I modified it to my needs and works as I want. Thanks again!
Your answer
Follow this Question
Related Questions
Rotation on moving using virtual joystick is not working as expected in 3D game. 0 Answers
My player spins when I enter play mode. What am I missing? 0 Answers
Rotate Rigidbody on Y Axis based on Velocity on X and Z axis 3 Answers
Rotate Rigidbody towards target rotation using AddTorque() 0 Answers
Rotate rigid body with mobile joystick 0 Answers