如何解决接收连续输入呼叫的最佳方式?
我是 Unity 的初级编码员,虽然我没有太多编码经验,但我知道我的代码一团糟。
所以,事情是这样的:我插入了一个特定的功能,当我单击鼠标 (0) 时,允许玩家从其位置 Lerp 到“Object1”。单击时,时间计数器启动,并且在 2 秒内,如果我再次单击鼠标(0),它将第二次将玩家拉到“对象 2”上。如果每个输入都在 5 秒以内,我以某种方式应用了这个逻辑,允许用户将玩家 Lerp 4 次到 4 个不同的位置。
我费了很大的力气,找到了让它工作的方法,它很实用,但代价是使用了许多布尔值和 ifs 语句,这是一个完整而糟糕的意大利面。所以我对你们的问题是,我怎样才能让这整个烂摊子更干净、更高效?在这种情况下我可以使用什么代码结构来使整个事情更具可读性,并切断大量的布尔值和条件?先谢谢大家!
代码如下:
[Serializefield] private Transform cube1;
[Serializefield] private Transform cube2;
[Serializefield] private Transform cube3;
[Serializefield] private Transform cube4;
private float timer;
private bool canCount;
private bool click1;
private bool click2;
private bool click3;
private bool click4;
private bool lerp1;
private bool lerp2;
private bool lerp3;
private bool lerp4;
private void CountDown()
{
if (canCount)
{
timer += Time.deltaTime;
if (timer >= 2)
{
canCount = false;
Debug.Log("Timer End");
}
}
}
private void Lerp()
{
if (lerp1)
{
transform.position = Vector3.Lerp(transform.position,cube1.position,Time.deltaTime * 10);
}
if (lerp2)
{
transform.position = Vector3.Lerp(transform.position,cube2.position,Time.deltaTime * 10);
}
if (lerp3)
{
transform.position = Vector3.Lerp(transform.position,cube3.position,Time.deltaTime * 10);
}
if (lerp4)
{
transform.position = Vector3.Lerp(transform.position,cube4.position,Time.deltaTime * 10);
}
}
private void Update()
{
CountDown();
Lerp();
if (Input.GetMouseButtonDown(0))
{
if (!canCount)
{
click1 = true;
click2 = false;
click3 = false;
click4 = false;
lerp2 = false;
lerp3 = false;
lerp4 = false;
if (click1)
{
click1 = false;
click2 = true;
lerp4 = false;
lerp1 = true;
timer = 0;
canCount = true;
}
else if (click2 && canCount)
{
click2 = false;
click3 = true;
lerp1 = false;
lerp2 = true;
timer = 0;
}
else if (click3 && canCount)
{
click3 = false;
click4 = true;
lerp2 = false;
lerp3 = true;
timer = 0;
}
else if (click4 && canCount)
{
click4 = false;
click1 = true;
lerp3 = false;
lerp4 = true;
timer = 0;
}
}
else
{
if (click1)
{
click1 = false;
click2 = true;
lerp4 = false;
lerp1 = true;
timer = 0;
canCount = true;
}
else if (click2)
{
click2 = false;
click3 = true;
lerp1 = false;
lerp2 = true;
timer = 0;
}
else if (click3)
{
click3 = false;
click4 = true;
lerp2 = false;
lerp3 = true;
timer = 0;
}
else if (click4)
{
click4 = false;
click1 = true;
lerp3 = false;
lerp4 = true;
timer = 0;
}
}
}
解决方法
下面的代码应该允许您按顺序设置无限数量的对象移动到每个对象的唯一等待时间,直到玩家可以再次单击以移动到下一个对象。如果用户在给定时间内没有点击,下一次点击将再次移动到第一个对象。
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
/// <summary>
/// Holds data to a goal target and how long the player has to click to move towards it
/// </summary>
[System.Serializable]
public class CountdownLerpData
{
public float timeToWaitForClick = 0.0f;
public Transform destination = null;
}
public class YourScript : MonoBehaviour
{
[SerializeField] private List<CountdownLerpData> LerpDestinations = new List<CountdownLerpData>();
private Coroutine ExtraMouseClicks = null;
private Coroutine MoveToDestination = null;
// distance until our object has reached our goal point
private const float DISTANCE_EPSILON = 0.001f;
// the speed at which our object moves to a goal position
private float moveSpeed = 10f;
private void Update()
{
// just use update for your first click input,any successive clicks are handled by the Coroutine
if (Input.GetMouseButtonDown(0) && ExtraMouseClicks == null)
ExtraMouseClicks = StartCoroutine(MoveAndDetectMouseClicks(0));
}
/// <summary>
/// Will start a movement coroutine and wait until the time to click is exceeded or
/// when the player clicks,it will start a new coroutine
/// </summary>
/// <param name="idx"></param>
/// <returns></returns>
private IEnumerator MoveAndDetectMouseClicks(int idx)
{
// we wait for the next frame to assure we do NOT use the same mouse click event
yield return null;
// we exceeded our container,so exit the coroutine and set it to null
if (idx >= LerpDestinations.Count)
{
ExtraMouseClicks = null;
yield break;
}
float currentTimer = 0.0f; // the time to wait for our next click
bool hasMouseClick = false; // flag to determine if the user clicked
// start a new Coroutine for the motion - stop it if it is ongoing
if (MoveToDestination != null)
StopCoroutine(MoveToDestination);
// start it with our current index
MoveToDestination = StartCoroutine(MoveTowardsDestination(LerpDestinations[idx].destination.position));
// now wait our time to determine if another mouse click occurs,if it does,then increment our counter
while (currentTimer <= LerpDestinations[idx].timeToWaitForClick && !hasMouseClick)
{
// if we have a mouse click,then
if (Input.GetMouseButtonDown(0) && !hasMouseClick)
{
// the user clicked,so set our flag to true
hasMouseClick = true;
// assign the coroutine
ExtraMouseClicks = StartCoroutine(MoveAndDetectMouseClicks(idx + 1));
}
// increase our time since the last frame
currentTimer += Time.deltaTime;
yield return null;
}
// the user missed the window to click again,so set the reference back to null
if (!hasMouseClick)
ExtraMouseClicks = null;
}
/// <summary>
/// Moves your object to a goal location by moveSpeed speed
/// </summary>
/// <param name="goalPosition"></param>
/// <returns></returns>
private IEnumerator MoveTowardsDestination(Vector3 goalPosition)
{
// now lerp until we reach our destination
while (Vector3.Distance(transform.position,goalPosition) > DISTANCE_EPSILON)
{
transform.position = Vector3.MoveTowards(transform.position,goalPosition,moveSpeed * Time.deltaTime);
yield return null;
}
}
}
我的方法将删除单独跟踪这些数据,而不是存储多次点击和 lerps,这很令人头疼。相反,您将拥有一个 List
的名为 CountdownLerpData
的对象,其中包含两个字段。第一个字段是 timeToWaitForClick
,这是程序在点击发生后等待的时间,以决定点击是移到列表中的下一个对象,还是移回第一个对象。第二个字段是 destination
,它是您此时要移动到的对象的 Transform
。
当用户首先点击时,它会通过您的对象数据的 List
启动一个看似合理的反应链。初始点击将启动所谓的 Coroutine
,它可以简单地定义为一种特殊功能,允许在多个帧内完成较大任务的一小部分。
一旦您开始倒计时 Coroutine
,它将开始 MoveTowardsDestination
Coroutine
,它只会将您的对象移动到倒计时 Coroutine
所在的索引的目标对象.如果用户碰巧在所需的时间间隔内点击,它将再次调用相同的 Coroutine
,但现在索引增加 1 以移动到我们列表中的下一个对象。如果它碰巧达到或超过 List
,它将退出 Coroutine
。
让我知道这对您有什么影响,或者这是否不是您想要的。如果我的实现不是你想要的,我可以调整答案。如果您对它的工作方式或原因有任何疑问,也可以发表评论。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。