【问题标题】:Player randomly changing position after implementing UI elements播放器在实现 UI 元素后随机改变位置
【发布时间】:2020-01-22 08:55:10
【问题描述】:

所以我一直在关注在 Unity 中制作 2D 游戏的教程(我是一个完全的新手,这是我第一次接触编程),我想为游戏添加一个功能(粗体)。 我添加的“心脏系统”正常工作(空心的数量等于玩家受到的伤害),但它导致我的玩家以一种奇怪的方式改变了他的位置。您可以看到,设置了边界(maxHeight =3,2,minHeight=-3,2),以及他的运动值(Yincrement = 3.2),然而,在按下向上或向下箭头键后,他似乎改变了Y 位置约 4.67。 这是播放器脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class Player : MonoBehaviour
{
    private Vector2 targetPos;
    public float Yincrement;

    public float speed;
    public float maxHeight;
    public float minHeigth;

    public int health = 3;
    public int numOfHearts;

    public Image[] hearts;
    public Sprite heartFull;
    public Sprite heartEmpty;

    public GameObject effect;

    public Image healthDisplay;

    private void Update()
    {
        for (int i = 0; i < hearts.Length; i++)
        {
            if (i < health)
            {
                hearts[i].sprite = heartFull;
            }
            else
            {
                hearts[i].sprite = heartEmpty;

                if (i < numOfHearts)
                {
                    hearts[i].enabled = true;
                }
                else
                {
                    hearts[i].enabled = false;
                }
            }

            if (health <= 0)
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
            }

            transform.position = Vector2.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);

            if (Input.GetKeyDown(KeyCode.UpArrow) && transform.position.y < maxHeight)
            {
                Instantiate(effect, transform.position, Quaternion.identity);
                targetPos = new Vector2(transform.position.x, transform.position.y + Yincrement);
            }
            else if (Input.GetKeyDown(KeyCode.DownArrow) && transform.position.y > minHeigth)
            {
                Instantiate(effect, transform.position, Quaternion.identity);

                targetPos = new Vector2(transform.position.x, transform.position.y - Yincrement);
            }
        }
    }
}

【问题讨论】:

  • 决定naming convention(我强烈推荐一个与Rider/Resharper相同或相似的),使您的代码至少有点人类可读(去掉块末端的那些空行),然后我们可以交谈。
  • 您的 for 循环应该只包含 UI 部分...您正在 for 循环内进行移动,因此它将被执行 hearts.Length 次。此外,您对该位置的夹紧也不安全......想象当前位置为3.1,即&lt; maxHeight,因此您添加一次增量,它会导致最大可能高度为6.3

标签: c# user-interface unity3d position


【解决方案1】:

主要问题

主要问题是您的for 循环。它应该只用于更新 UI - 多次调用您的移动和场景重新加载!您应该提前关闭 for 循环。

for (int i = 0; i < hearts.Length; i++)
{
    // you can also reduce these to single lines
    hearts[i].enabled = i < numOfHearts;

    if(i < numOfHearts) hearts[i].sprite = i < health ? heartFull : heartEmpty;    
} // <-- ALREADY CLOSE IT HERE

if(health <= 0) ...

...

定位夹紧

你的持仓非常不安全!想象一下当前位置是3.1,它仍然是&lt; maxHeight,所以你添加一次Yincrement,它会产生6.3的最大可能高度!这不是你想要的。

您应该直接夹住targetPosition,而不是当前的transform.position。例如,您可以使用Mathf.Clamp 确保targetPos.y 始终保持在给定范围内。

另外,由于这两种情况都做了非常相似的事情,我会使用简单的int 变量来设置方向,将其减少到只有一个动作:

...

transform.position = Vector2.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);

var move = 0;
var targetPosY = targePos.y;

if (Input.GetKeyDown(KeyCode.UpArrow) && targetPosY < maxHeight)
{
    move = 1;
}
else if (Input.GetKeyDown(KeyCode.DownArrow) && targetPosY > minHeigth)
{
    move = -1;
}

// Handle the movement according to the direction
// in one single code block for both directions
if(move != 0)
{
    Instantiate(effect, transform.position, Quaternion.identity);

    // increase/decrease the targetPosY according to the move direction
    targetPosY += move * Yincrement;
    // Now make sure it is within the range
    targetPosY = Mathf.Clamp(targetPosY, minHeight, maxHeight);

    // finally assign the new target position
    targetPos = new Vector2(transform.position.x, targetPosY);
}

【讨论】:

  • 感谢您的回复。如果有帮助,我的游戏应该是一个简单的无尽奔跑,玩家必须通过移动到上、中或下三排之一来避开障碍物。当涉及到您更正的代码时,我有一个小问题。在 targetPosY = Mathf.Clamp(targetPos, minHeight, maxHeight); targetPos 无法转换为 float 并且作为初学者,我不知道如何解决这个问题:(
  • 抱歉,小错字!这里应该是targetPosY 而不是targetPos。我的大脑或智能手机自动更正一定吃掉了Y ;)
  • 非常感谢,它运行良好!这个项目对我来说真的很令人兴奋,让我想学习更多的编码!我现在对此知之甚少,但可能性似乎无穷无尽。
  • 很高兴为您提供帮助!请随时接受的答案:)
【解决方案2】:

您能否详细说明您的游戏是关于什么的,以及您在脚本的每个部分中尝试做什么。那我也许能帮你。此外,如果这是您第一次接触编程,这是一种进阶方式。从更简单的东西开始,在继续之前先了解编程的基本概念。这是一个很好的教程系列,可以为绝对初学者学习 c# 编程。

https://www.youtube.com/watch?v=pSiIHe2uZ2w

我不确定您要做什么,但为什么您的运动控制在您的 for 循环中。这可能就是你搞砸的原因。尝试从 for 循环中删除所有这些代码。

transform.position = Vector2.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);

if (Input.GetKeyDown(KeyCode.UpArrow) && transform.position.y < maxHeight)
{
    Instantiate(effect, transform.position, Quaternion.identity);
    targetPos = new Vector2(transform.position.x, transform.position.y + Yincrement);
}
else if (Input.GetKeyDown(KeyCode.DownArrow) && transform.position.y > minHeigth)
{
    Instantiate(effect, transform.position, Quaternion.identity);

    targetPos = new Vector2(transform.position.x, transform.position.y - Yincrement);
}

此外,此代码应在您检查玩家是否已移动之后。

transform.position = Vector2.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);

这里有一个让移动更轻松的提示。使用 transform.translate 而不是 Vector2.MoveTowards。 Transform.translate 接受 3 个浮点数,并通过表示为向量的三个浮点数来改变玩家的位置。

这是一个例子

transform.translate(0,2,0);

这会将玩家的 y 位置改变 2。我认为你的代码应该是这样的。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class Player : MonoBehaviour
{
    private Vector2 targetPos;
    public float Yincrement;

    public float speed;
    public float maxHeight;
    public float minHeigth;

    public int health = 3;
    public int numOfHearts;

    public Image[] hearts;
    public Sprite heartFull;
    public Sprite heartEmpty;

    public GameObject effect;

    public Image healthDisplay;

    private void Update()
    {
        for (int i = 0; i < hearts.Length; i++)
        {
            if (i < health)
            {
                hearts[i].sprite = heartFull;
            }
            else
            {
                hearts[i].sprite = heartEmpty;

                if (i < numOfHearts)
                {
                    hearts[i].enabled = true;
                }
                else
                {
                    hearts[i].enabled = false;
                }
            }
        }

        if (health <= 0)
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
        }

        if (Input.GetKeyDown(KeyCode.UpArrow) && transform.position.y < maxHeight)
        {
            transform.Translate(0,Yincrement,0)
        }
        else if (Input.GetKeyDown(KeyCode.DownArrow) && transform.position.y > minHeigth)
        {
            Instantiate(effect, transform.position, Quaternion.identity);

            transform.Translate(0,Yincrement,0);
        }
    }
}

收到您的回复后,我可能会提供帮助,但不能保证,因为我也只有大约一年的经验。

【讨论】:

  • 请注意,transform.Translate 以大写字母 T 开头。使用后你错过了;。同样,现在您对于 KeyCode.UpArrow 案例不使用 Instantiate
  • 您不想在这里使用Translate,因为它会使对象立即跳转到那个位置!而且位置的夹紧仍然非常不安全:想象当前位置是3.1,即&lt; maxHeight,所以你添加一次增量,它会导致最大可能高度为6.3
  • 哦,是的。傻我。他应该使用vector2.movetowards,但他仍然不应该在for循环中拥有所有这些。
猜你喜欢
  • 2011-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多