c# - Unity 问题:如何使用 GetAxis 从一个预制件切换到另一个预制件?
问题描述
我想绑定向上和向下箭头键,以便在按下时循环显示不同的精灵。如果到达一端,它将循环回到第一个精灵。我尝试使用以下代码:
public class PhaseChanger : MonoBehaviour
{
// saved for efficiency
[SerializeField]
public GameObject prefabMoon0;
[SerializeField]
public GameObject prefabMoon1;
[SerializeField]
public GameObject prefabMoon2;
[SerializeField]
public GameObject prefabMoon3;
[SerializeField]
public GameObject prefabMoon4;
// needed for new phase
GameObject currentPhase;
bool previousFramePhaseChangeInput = false;
/// <summary>
/// Start is called before the first frame update
/// </summary>
void Start()
{
currentPhase = Instantiate<GameObject>(prefabMoon0);
}
/// <summary>
/// Update is called once per frame
/// </summary>
void Update()
{
// change phase on up arrow or down arrow
if (Input.GetAxis("ChangePhase") > 0)
{
// only change phase on first input frame
if (!previousFramePhaseChangeInput)
{
previousFramePhaseChangeInput = true;
// Save current position and destroy current phase
Destroy(currentPhase);
// instantiate next phase
if (currentPhase = prefabMoon0)
{
currentPhase = Instantiate(prefabMoon1);
}
else if (currentPhase = prefabMoon1)
{
currentPhase = Instantiate(prefabMoon2);
}
else if (currentPhase = prefabMoon2)
{
currentPhase = Instantiate(prefabMoon3);
}
else if (currentPhase = prefabMoon3)
{
currentPhase = Instantiate(prefabMoon4);
else
{
// no phase change input
previousFramePhaseChangeInput = false;
}
}
}
}
当我将脚本附加到我的主相机并运行它时,我可以使用向上箭头进行一次更改,然后在后续按下时不会发生任何其他事情。
我觉得我真的很接近完成这项工作,但我也可能在做整个事情时效率低下。帮助将不胜感激,谢谢!
另外:我知道我在帖子中说过精灵,并且正在共享一个调用预制件的脚本。我不知道如何只使用精灵而不为每个精灵制作预制件来解决这个问题。是否可以在没有为每个精灵单独的预制件的情况下做到这一点?
解决方案
问题
首先,您正在使用作业
currentPhase = XY
你应该在哪里使用
currentPhase == XY
它仍然编译的原因是
UnityEngine.Object
->bool
的隐式转换运算符。基本上你的分配等于写作currentPhase = XY; if(currentPhase)
无论哪种方式,它都不会像这样工作,因为您正在使用
Instantiate
创建一个预制件的新克隆,该预制件当然具有与克隆它的原始预制件不同的引用。所以即使你的支票看起来像
if(currentPhase == XY)
他们将永远是
true
。
解决方案
我宁愿将所有预制件/实例存储在一个数组中,而不是检查引用相等性
public GameObject[] phases;
然后简单地为这个数组设置一个int
索引,这样你就可以通过增加索引来简单地移动到数组中的下一个元素。
private int currentPhase;
你可以增加它并使用例如
currentPhase = (currentPhase + 1) % phases.Length;
所以它总是会从上到下成长0
,phases.Length - 1
然后从头再来0
。
然后我不知道您的用例的确切要求,但我建议不要一直使用Instantiate
,Destroy
而是已经将所有对象作为您的对象下的实例,然后(取消)激活它们!
你可以这样做,例如
public GameObject[] phases;
private int currentPhase;
private void Awake ()
{
Init();
}
private void Update ()
{
if (Input.GetAxis("ChangePhase") > 0)
{
if (!previousFramePhaseChangeInput)
{
previousFramePhaseChangeInput = true;
NextPhase();
}
}
else
{
previousFramePhaseChangeInput = false;
}
}
// Disables all phases except the first one and sets the current index to 0
private void Init()
{
for(var i = 1; i < phases.Length; i++)
{
phases[i].SetActive(false);
}
phases[0].SetActive(true);
currentPhase = 0;
}
// Disables the current phase and enables the next one
// wraps around at the end of the array
public void NextPhase()
{
phases[currentPhase].SetActive(false);
// increase the counter and wrap around at the end of the array
currentPhase = (currentPhase + 1) % phases.Length;
phases[currentPhase].SetActive(true);
}
如果您仍然想要Instantiate
这些对象,因为它们已经在场景中是没有选择的(无论出于何种原因),您可以在调用之前立即执行此操作,Init
例如
public GameObject[] phasePrefabs;
private GameObject[] phases;
private void Awake ()
{
var amount = phasePrefabs.Length;
phases = new GameObject [amount];
for(var i = 0; i < amount; i++)
{
phases[i] = Instantiate(phasePrefabs[i]);
}
Init();
}
虽然如前所述,我更愿意立即拥有它们,因为这样更不容易出错;)
推荐阅读
- android - 无法解析“:app@debug/compileClasspath”的依赖关系:无法转换工件“lifecycle-viewmodel.aar”
- python - 如何将这些数据与正则表达式匹配?
- linux - 麻烦将 grep 流水线化为排序
- python - 两个相互作用粒子之间的距离小于截止距离
- css - 在 css 计数器中使用第三章,而不是第三章
- json - 在 Json 模式中按名称封装 Root 对象以供重用?
- mysql - 我如何将数据从 reactjs 表单发布到 mysql 数据库
- r - 在r中删除多个带有条件的后续行
- java - 如何在java中刷新蓝牙设备列表
- ansible - 如果我想在同一个盒子上部署 gitlab + ansible,我需要“shell”运行器吗?