Unity 2D - 将玩家对象保持在其父面板的边界内

问题描述

在 Unity 中,我有一个 UI 面板,其中有一个播放器对象(一个 UI 图像对象)。

我使用用户输入(键盘或触摸)将玩家对象移动到平面上

我无法将玩家对象保留在其父面板中,

请检查下图,我想将玩家留在红色面板内

这是我尝试过的代码

public Camera MainCamera; //be sure to assign this in the inspector to your main camera
private Vector2 screenBounds;
private float objectWidth;
private float objectHeight;
private RectTransform pnlBackgroundTransform;


private void Start()
{
    pnlBackgroundTransform = GameObject.Find("PnlBackground").GetComponent<RectTransform>();

    screenBounds = MainCamera.ScreenToWorldPoint(new Vector3(pnlBackgroundTransform.rect.width,pnlBackgroundTransform.rect.height,MainCamera.transform.position.z));

    objectWidth = transform.GetComponent<SpriteRenderer>().bounds.extents.x; //extents = size of width / 2
    objectHeight = transform.GetComponent<SpriteRenderer>().bounds.extents.y; //extents = size of height / 2
}

void LateUpdate()
{
    Vector3 viewPos = transform.position;
    viewPos.x = Mathf.Clamp(viewPos.x,screenBounds.x * -1 + objectWidth,screenBounds.x - objectWidth);
    viewPos.y = Mathf.Clamp(viewPos.y,screenBounds.y * -1 + objectHeight,screenBounds.y - objectHeight);
    Debug.Log(screenBounds);
    Debug.Log(viewPos);
    transform.position = viewPos;
}

enter image description here

解决方法

我认为将播放器实现为 UI 元素并不常见,您应该在 UI/Canvas 系统之外实现它。

UI/Canvas 系统使用一组放置和缩放规则来处理响应式设计。你至少有 4 个值(不包括旋转)来在屏幕上放置一些东西:anchorpivotpositionscale em>.

例如:如果您想创建一个正方形,您可以将其大小设置为绝对像素值或相对值(到父级)。如果您使用绝对值,则在 UI Scale Mode 对象上定义的 Canvas 应该会影响视觉效果。

UI absolute vs relative

这意味着 UI/Canvas 用于应适应屏幕的元素,例如按钮、对话框、标签等。利用设备参数来改善用户体验。

UI/Canvas 系统之外,事物直接基于线性代数:您有一个 3D 向量空间(一个“世界”),其中一切都以绝对大小和位置存在。然后,您的相机会拉伸和扭曲整个世界以匹配您当前的视角。这意味着无论屏幕大小如何,您的对象都将始终具有相同的大小。

Camera size

现在,假设您有一个非常具体的理由将您的游戏实现到 UI 中,那么您可以通过几种方法来实现。我假设您使用的是绝对值。请注意,这里使用的所有单位都是像素,对于具有不同分辨率且对 UI Scale Mode 参数敏感的设备,效果应该有所不同。另外,请注意我已将锚点 min 和 max 都设置为 (0,0),左下角(默认为屏幕中心,(0.5,0.5)),以避免出现负坐标。

以下脚本附加到播放器的 UI 图像中。

public class UIMovementController : MonoBehaviour
{
    public float speed = 5.0f;

    new private RectTransform transform;
    private Rect canvasRect;
    
    private void Start()
    {
        transform = GetComponent<RectTransform>();
        canvasRect = GetComponentInParent<Canvas>().pixelRect;
    }

    void Update()
    {
        // Keyboard Input (Arrows)

        Vector2 move = new Vector2(0,0);
        if (Input.GetKey(KeyCode.UpArrow)) { move.y += speed; }
        if (Input.GetKey(KeyCode.DownArrow)) { move.y -= speed; }
        if (Input.GetKey(KeyCode.LeftArrow)) { move.x -= speed; }
        if (Input.GetKey(KeyCode.RightArrow)) { move.x += speed; }
        transform.anchoredPosition += move;

        // Position clamping
        
        Vector2 clamped = transform.anchoredPosition;
        clamped.x = Mathf.Clamp(clamped.x,transform.rect.width / 2,canvasRect.width - transform.rect.width / 2);
        clamped.y = Mathf.Clamp(clamped.y,transform.rect.height / 2,canvasRect.height - transform.rect.height / 2);
        transform.anchoredPosition = clamped;
    }
}

UI Movement Clamping