问题
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 toLeft (-1, 0)
.
The moment the button is let go (OnPointerUp
), thecurrentMoveDirection
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