我正在编写一个脚本,如果单击向右箭头,玩家就会以恒定的速度向屏幕右侧移动,然后在离开屏幕后停止。 (同样,如果点击向左箭头,玩家会以匀速向屏幕左侧移动,离开屏幕后停止。)
但是,当我添加代码后,我遇到了一个问题,玩家移动得很慢,一点一点。另外,我不确定我的代码是否简洁。
我使用了 while 循环将玩家移动到目标位置,但代码严重超载了计算机,迫使我关闭 Unity。我担心这会导致计算机出现问题。该代码造成了严重的滞后,我不知道是什么原因造成的。请帮助我...
这是我的代码:(逻辑包括使用方向键移动)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour
{
public float speed = 500f;
public float runSpeed = 200f;
public GameObject player;
public GameObject rightArrow;
public GameObject leftArrow;
private Vector2 movement;
private bool isRunning;
private Animator anim;
private Rigidbody2D rb;
private void Start()
{
anim = player.GetComponent<Animator>();
rb = player.GetComponent<Rigidbody2D>();
}
private void Update()
{
// Get input
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
isRunning = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
if (Input.GetMouseButtonDown(0))
{
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero);
if (hit.collider != null)
{
if (hit.collider.gameObject == rightArrow)
{
int clickX = 1;
ArrowClick(clickX);
}
else if (hit.collider.gameObject == leftArrow)
{
int clickX = -1;
ArrowClick(clickX);
}
}
}
}
public void ArrowClick(int _clickX)
{
Vector2 target = new Vector2(100 * _clickX, 0);
while (true)
{
player.transform.position
= Vector2.MoveTowards(player.transform.position, target, 10);
}
}
private void FixedUpdate()
{
// Move the character
float currentSpeed = isRunning ? speed * runSpeed : speed;
Vector2 velocity = movement.normalized * currentSpeed;
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
}
private void LateUpdate()
{
// Update animator
anim.SetFloat("DirX", movement.x);
anim.SetFloat("DirY", movement.y);
anim.SetBool("Idle", movement.magnitude == 0);
}
}
您创建了一个没有退出条件的无限循环(
while (true)
永远不会是false
...),因此当Unity看起来没有响应时,它仍在执行while (true)
内的代码。以及结束。以及结束。等等
其次,像这样的循环移动对象(或实际上做任何事情)将在单个帧内发生,这将导致您的对象传送到目的地。
您可以使用协程同时解决这两个问题,它是可以暂停和恢复执行的单段代码(函数):
public IEnumerator ArrowClick(int _clickX)
{
float speed = 10;
Vector2 target = new Vector2(100 * _clickX, 0);
// Changed "while true" to be "while far from the destination"
while (Vector2.Distance(player.transform.position, target) > 0.05f)
{
// Changed from hardcoded "10" to rather be based on the "Time.deltaTime": enables framerate independence (player will move the same amount in a second, regardless of FPS)
player.transform.position = Vector2.MoveTowards(player.transform.position, target, speed * Time.deltaTime);
// Tells the game to wait a frame before continuing execution
yield return null;
}
}
然后可以这样开始:
// This is a class variable, put it at the top
Coroutine playerMoveRoutine;
//Inside your click code
if (hit.collider.gameObject == rightArrow)
{
int clickX = 1;
// If we're already moving, cancel that coroutine so the two don't execute at the same time
if (playerMoveRoutine != null)
{
StopCoroutine(playerMoveRoutine);
}
playerMoveRoutine = StartCoroutine(ArrowClick(clickX));
}
else if (hit.collider.gameObject == leftArrow)
{
int clickX = -1;
// If we're already moving, cancel that coroutine so the two don't execute at the same time
if (playerMoveRoutine != null)
{
StopCoroutine(playerMoveRoutine);
}
playerMoveRoutine = StartCoroutine(ArrowClick(clickX));
}