- Home /
How do I change Raycast's direction based on movement input?
Hey everyone!
I'm making a game where when the player presses one of the WASD keys, the character moves in the direction associated with the key until it collides with an object in front. (A bit like Tomb of The Mask)
I got the movement part down, but my problem is, I want to limit the player, to only be able to move while stationary (when he hit an object in front of it). I was thinking a Ray-cast is probably the best way to go here, but I don't know how to set it up so it's direction changes depending on which key was pressed.
I know the "isMoving" thing is kinda doing that, but it's working a bit choppy and it creates a little wait time between 2 inputs bc the velocity of the object doesn't go down to 0 instantly
Here's my code so far:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// PRIVATE GET COMPONENTS
Collider2D _boxCollider2d;
Rigidbody2D _rigidBody;
// PUBLIC COMPONENTS
// PUBLIC VARIABLES
public float moveSpeed = 200;
// PRIVATE VARIABLES
Vector2 movement;
bool isMoving;
// BUILT IN FUNCTIONS
//###################################################################//
private void Start()
{
_boxCollider2d = GetComponent<Collider2D>();
_rigidBody = GetComponent<Rigidbody2D>();
}
private void Update()
{
CheckMovement();
}
private void FixedUpdate()
{
PlayerMovement();
}
private void OnCollisionEnter2D(Collision2D other)
{
_rigidBody.velocity = new Vector2(0, 0);
}
// CUSTOM FUNCTIONS //
//###################################################################//
void PlayerMovement()
{
bool leftDir = Input.GetKeyDown(KeyCode.A);
bool rightDir = Input.GetKeyDown(KeyCode.D);
bool upDir = Input.GetKeyDown(KeyCode.W);
bool downDir = Input.GetKeyDown(KeyCode.S);
if (leftDir && !isMoving)
{
_rigidBody.velocity = Vector2.left * moveSpeed * Time.deltaTime;
}
if (rightDir && !isMoving)
{
_rigidBody.velocity = Vector2.right * moveSpeed * Time.deltaTime;
}
if (upDir && !isMoving)
{
_rigidBody.velocity = Vector2.up * moveSpeed * Time.deltaTime;
}
if (downDir && !isMoving)
{
_rigidBody.velocity = Vector2.down * moveSpeed * Time.deltaTime;
}
}
void CheckMovement()
{
movement = new Vector2(Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical"));
if (_rigidBody.velocity.x != 0 || _rigidBody.velocity.y != 0)
{
isMoving = true;
}
else
{
isMoving = false;
}
}
}
Answer by jackmw94 · May 15 at 10:29 PM
I think you should look at using a state machine here. This is a system that has a limited number of 'states', the system will be in one state of these states at a given time. Assuming I'm understanding the question correctly, it seems your player will be in one of two states; waiting to move or moving. When your player is moving then they will not receive input, their position (or velocity, as you're using) would be updated and they'll transition back to the waiting state when a collision is detected. When they are waiting to move then they'll monitor input which would transition them to their moving state.
By using these instead of having various flags that are set/unset to determine the state, you'll make the code much cleaner and you'll thank yourself when it comes to debugging. If you find that you have an issue with your moving state, you'll know that the problem can only exist in your short move-state update function instead of anywhere within the class! Also it will mean that you have a very clear distinction about what your player should be doing at any given time.
Unity have a tutorial on finite state machines here:
https://learn.unity.com/tutorial/finite-state-machines-1
Your answer
Follow this Question
Related Questions
Raycasthit2d isnt working. 2 Answers
2d game end level with trigger and colission with trigger who to make a if condition 1 Answer
Surface interaction between rotating RigidBodies? 0 Answers
How do i prevent the player from dragging a ui element off screen? 1 Answer
Possible to Give Rigid bodies collision bounding boxes? 0 Answers