将UI RectTransform 移动到世界坐标位置

5

我有一个名为Player的游戏物体和一个画布(Canvas)。 HealthBar游戏物体是Canvas的子级(Canvas>HealthBar)。我使用脚本让血条跟随角色移动。它应该固定在角色上方的位置,以便在精灵的顶部附近。以下是HP Follow脚本中的“跟随”部分。

        void Update () 
{
    Vector3 currentPos = transform.position;
    Vector3 playerPos = Camera.main.WorldToViewportPoint (Player.transform.position);
    transform.position = playerPos;

问题在于血条跟随着角色移动,但是移动的速度只有玩家移动速度的一小部分。比如,如果玩家移动了一个单位,血条只会移动0.1个单位。
错误视频:https://streamable.com/vaz7h

上面的脚本附加在HP条上。我希望它跟随Player变量,该变量引用Player游戏对象。我确保Canvas不是任何对象的子级。 - David Rios
我将画布从玩家中移出。现在它是独立的了,不再是任何对象的子级。 - David Rios
它是一个GameObject,但附加了一个UI.Image组件。 - David Rios
没问题。https://streamable.com/vaz7h - David Rios
3个回答

13

您希望将一个UI对象(Image)跟随一个GameObject,该GameObject可以是SpriteRenderer或MeshRenderer。

换句话说,这可以描述为将世界坐标转换为UI坐标。

下面这个简单的函数将世界坐标转换为UI空间。它需要一个UI的Canvas作为参数,然后是您想要转换为UI位置的位置,这在您的情况下是Player.transform.position变量。

移动UI对象的关键是RectTransformUtility.ScreenPointToLocalPointInRectangle函数,它将屏幕点转换为UI矩形局部点。

public Vector3 worldToUISpace(Canvas parentCanvas, Vector3 worldPos)
{
    //Convert the world for screen point so that it can be used with ScreenPointToLocalPointInRectangle function
    Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
    Vector2 movePos;

    //Convert the screenpoint to ui rectangle local point
    RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvas.transform as RectTransform, screenPos, parentCanvas.worldCamera, out movePos);
    //Convert the local point to world point
    return parentCanvas.transform.TransformPoint(movePos);
}

使用方法:

public GameObject Player;
public Canvas canvas;
void Update()
{
    //Convert the player's position to the UI space then apply the offset
    transform.position = worldToUISpace(canvas, Player.transform.position);
}

现在假设你已经将UI放置到了正确的位置,现在你想让它跟随另一个对象(玩家),你需要使用上面的代码实现一个简单的偏移。这很容易。下面展示了代码应该是什么样子:

public GameObject Player;
public Canvas canvas;


Vector3 Offset = Vector3.zero;

void Start()
{
    Offset = transform.position - worldToUISpace(canvas, Player.transform.position);
}

void Update()
{
    //Convert the player's position to the UI space then apply the offset
    transform.position = worldToUISpace(canvas, Player.transform.position) + Offset;
}

public Vector3 worldToUISpace(Canvas parentCanvas, Vector3 worldPos)
{
    //Convert the world for screen point so that it can be used with ScreenPointToLocalPointInRectangle function
    Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
    Vector2 movePos;

    //Convert the screenpoint to ui rectangle local point
    RectTransformUtility.ScreenPointToLocalPointInRectangle(parentCanvas.transform as RectTransform, screenPos, parentCanvas.worldCamera, out movePos);
    //Convert the local point to world point
    return parentCanvas.transform.TransformPoint(movePos);
}

1
非常感谢!它完美地工作了 :) 我非常感激你的帮助。 - David Rios
1
谢谢!如果将“UI 比例模式”设置为“像素固定大小”,它可以很好地工作。你有什么想法,如何使其在“UI 比例模式”设置为“与屏幕尺寸缩放”时也能正常工作吗? - SePröbläm

1
如果画布是屏幕空间(ScreenSpace),您可以使用以下代码:

healthbarTransform.position = camera.WorldToScreenPoint(playerTransform.position);

(if it is screen space, it can be child of player or whatever as long as you set the position every frame)
关于您的问题,有一些因素可以解决这个问题: 您正在update功能中设置血条位置,为了让Unity知道在玩家移动后执行此代码,您需要将HPFollow脚本添加到脚本执行顺序下方的默认时间(如果要使用Update)。 或者您可以使用lateUpdate来设置UI位置。我强烈推荐这种方法。
如果您的问题只是UI闪烁,那么应该与UI矩形变换比例有关...

我认为解决这个问题的好方法是将HP条作为玩家的子对象,但需要使用画布来显示图像组件,以填充/取消填充条形图,因为这些解决方案都无法正常工作,所以我一直遇到同样的问题。 - David Rios
将血条放在玩家下方除了与您在代码中所做的相同之外,没有解决任何问题。我相信这只是一个执行顺序的问题... - 31thUser
我将HPController脚本的执行顺序更改为-100,但没有影响任何内容。 - David Rios
看了你的视频之后,我发现我的答案并不是你的解决方案。我完全误解了你的意思... - 31thUser
无论如何,还是谢谢你的帮助 :) - David Rios
显示剩余2条评论

-2

这是解决方案:

void Start () {
    Canvas.willRenderCanvases += canvasUpdate;
}

void canvasUpdate () {
    var screenPoint = RectTransformUtility.WorldToScreenPoint( canvas.worldCamera, worldPoint );
    Vector2 localPoint;
    RectTransformUtility.ScreenPointToLocalPointInRectangle( canvas.GetComponent<RectTransform>(), screenPoint, canvas.worldCamera, out localPoint );
    transform.localPosition = localPoint;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接