I tried to modify my code for it to be able to move the character by using UI buttons as I am making a mobile game. Before, the code looked incredible and worked, but since I tried to add the stop when the player released the button, it no longer works. There are no errors, but the character doesn't want to jump and move. I tried using ChatGPT to solve this problem, but he ran out of ideas and cycled the same codes. Here is his last written code that causes a problem:
using UnityEngine;
using UnityEngine.UI;
public class CharacterController : MonoBehaviour
{
public float moveSpeed = 5f;
public float jumpForce = 5f;
private bool isJumping = false;
private SpriteRenderer spriteRenderer;
private Animator animator;
private Rigidbody2D rb;
private bool isFalling;
private bool isRunning;
public Button moveLeftButton;
public Button moveRightButton;
public Button jumpButton;
private bool isMovingLeft = false;
private bool isMovingRight = false;
private bool isJumpButtonPressed = false;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
moveLeftButton.onClick.AddListener(OnMoveLeftButtonDown);
moveLeftButton.onClick.AddListener(OnMoveLeftButtonUp);
moveRightButton.onClick.AddListener(OnMoveRightButtonDown);
moveRightButton.onClick.AddListener(OnMoveRightButtonUp);
jumpButton.onClick.AddListener(OnJumpButtonDown);
jumpButton.onClick.AddListener(OnJumpButtonUp);
}
public void OnMoveLeftButtonDown()
{
isMovingLeft = true;
}
public void OnMoveLeftButtonUp()
{
isMovingLeft = false;
}
public void OnMoveRightButtonDown()
{
isMovingRight = true;
}
public void OnMoveRightButtonUp()
{
isMovingRight = false;
}
public void OnJumpButtonDown()
{
isJumpButtonPressed = true;
}
public void OnJumpButtonUp()
{
isJumpButtonPressed = false;
}
private void Update()
{
if (isMovingLeft)
{
rb.velocity = new Vector2(-moveSpeed, rb.velocity.y);
spriteRenderer.flipX = true;
isRunning = true;
animator.SetBool("IsRunning", isRunning);
}
else if (isMovingRight)
{
rb.velocity = new Vector2(moveSpeed, rb.velocity.y);
spriteRenderer.flipX = false;
isRunning = true;
animator.SetBool("IsRunning", isRunning);
}
else
{
rb.velocity = new Vector2(0f, rb.velocity.y);
isRunning = false;
animator.SetBool("IsRunning", isRunning);
}
if (isJumpButtonPressed && !isJumping)
{
Jump();
}
isFalling = rb.velocity.y < 0f && !isJumping;
animator.SetBool("IsFalling", isFalling);
animator.SetBool("IsJumping", isJumping);
}
private void Jump()
{
rb.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
isJumping = true;
animator.SetTrigger("Jump");
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isJumping = false;
animator.SetBool("IsJumping", isJumping);
}
}
}
I debugged this code using Debug.Log and discovered that the
public void OnMoveLeftButtonDown()
{
isMovingLeft = true;
}
public void OnMoveLeftButtonUp()
{
isMovingLeft = false;
}
public void OnMoveRightButtonDown()
{
isMovingRight = true;
}
public void OnMoveRightButtonUp()
{
isMovingRight = false;
}
public void OnJumpButtonDown()
{
isJumpButtonPressed = true;
}
public void OnJumpButtonUp()
{
isJumpButtonPressed = false;
}
Methods are working but not used in the Update method.
Are there any ideas to rewrite this code to work again and add a stop for a character when the player releases it? Thanks for any help!
The issue you are facing is because you are registering on the same event twice in your Start
function:
private void Start()
{
//code
moveLeftButton.onClick.AddListener(OnMoveLeftButtonDown);
moveLeftButton.onClick.AddListener(OnMoveLeftButtonUp);
//More code
}
This will cause both methods to be triggered right as the button is pressed, causing then the reaction of always setting the isMovingLeft
(for instance) to be false.
For the requested behaviour, I'd recommend you to not use the Button
class from UI due to its limitation of reading its state as its main purpose is to fire 'onClick' events, whereas you're looking for something like IPointerUpHandler
and IPointerDownHandler
. To implement EventSystem
interfaces is quite easy:
GraphicsRaycaster
componentEventSystem
GameObject (to create it, right-click on the Scene/Hierarchy then go to UI -> Event System
and it shall be added properly)Both can also be added by creating a Canvas on the scene, so if you have one, you'll probably be set (but worth to check).
Those interfaces shall then be implemented on an UI script of yours, this way you can manage custom UI such as joysticks