Continuously run code while UI button pressed

大憨熊 提交于 2021-01-28 21:22:27

问题


I am making a platform game in Unity, where the ball is moved with three buttons:

  • move right
  • move left
  • jump

I already have all the functions that work now, but to move the character i need to keep spamming a button, instead of holding it as i would want to. I have tried a few ways I found on tutorials but, as i am still a very beginner, i did not manage to make them work.

This is the code of my Move2D script attatched to the character:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move2D : MonoBehaviour
{
    public float moveSpeed = 5f;
    public bool isGrounded = false;

    [SerializeField] private Rigidbody2D rigidbody;

    private void Awake()
    {
        if (!rigidbody) rigidbody = GetComponent<Rigidbody2D>();
    }

    public void Jump()
    {
        if (isGrounded)
        {
            rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
        }
    }

    public void Move(float value)
    {
        Vector3 movement = new Vector3(value, 0f, 0f);
        transform.position += movement * Time.deltaTime * moveSpeed;
    }
}

And this is the second script that mainly controls all the movement:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class ContinuesButton : MonoBehaviour, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
    [SerializeField] private Button button;

    [SerializeField] private UnityEvent whilePressed;

    private readonly bool isHover;

    private void Awake()
    {
        if (!button) button = GetComponent<Button>();
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        StartCoroutine(WhilePressed());
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        StopAllCoroutines();
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        StopAllCoroutines();
    }

    private IEnumerator WhilePressed()
    {
        while (true)
        {
            whilePressed?.Invoke();
            yield return null;
        }
    }
}

Any information or explanations is really appreciated as this part is very important for my game! :)


回答1:


Since your player has a rigidbody, you can move the player via the rigidbody's velocity rather than through it's transform.
(This makes it more consistent too, since your jump's implementation uses rigidbody)

Velocity is made out of Direction and Speed; Since speed is constant, You can make the button set the direction of the movement.
And since you would want the player to hold down the button in order to move, you can set the direction of the movement OnPointerDown, and reset it when OnPointerUp occurs, like so:

Move2D.cs

public class Move2D : MonoBehaviour {
    // ...

    [SerializeField]
    private float speed;

    private Rigidbody2D rigidBody;

    private Vector2 currentMoveDirection;

    private void Awake() {
        rigidBody = GetComponent<Rigidbody2D>();
        currentMoveDirection = Vector2.zero;
    }

    // ...

    private void FixedUpdate() {
        rigidBody.velocity = (currentMoveDirection + new Vector2(0f, rigidBody.velocity.y)).normalized * speed;
    }

    public void TriggerMoveLeft() {
        currentMoveDirection += Vector2.left;
    }

    public void StopMoveLeft() {
        currentMoveDirection -= Vector2.left;
    }

    public void TriggerMoveRight() {
        currentMoveDirection += Vector2.right;
    }

    public void StopMoveRight() {
        currentMoveDirection -= Vector2.right;
    }
}

PlayerMoveButton.cs

(Or your ContinuesButton.cs)

public class PlayerMoveButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler {
    [SerializeField]
    private Button targetButton;

    [SerializeField, Tooltip("The targeted player's movement component")]
    private Move2D playerMovement;

    [SerializeField, Tooltip("True if this button moves the player to the left")]
    private bool movesLeft;

    // ...

    public void OnPointerDown(PointerEventData eventData) {
        if (movesLeft) {
            playerMovement.TriggerMoveLeft();
        } else {
            playerMovement.TriggerMoveRight();
        }
    }

    public void OnPointerUp(PointerEventData eventData) {
        if (movesLeft) {
            playerMovement.StopMoveLeft();
        } else {
            playerMovement.StopMoveRight();
        }
    }
}

Example:

LeftButton is now clicked (OnPointerDown), currentMoveDirection is set to Left (-1, 0).
The moment the button is let go (OnPointerUp), the currentMoveDirection is reset to normal (0, 0)

The player constantly moves by setting it's velocity via currentMoveDirection * speed

Edit

And in order to preserve the jump motion, rather than simply do currentMoveDirection * speed, you would need to add the current upwards direction to it, like so:

private void FixedUpdate() {
    rigidBody.velocity = (currentMoveDirection + new Vector2(0f, rigidBody.velocity.y)).normalized * speed;
}


来源:https://stackoverflow.com/questions/57941225/continuously-run-code-while-ui-button-pressed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!