首页 > 解决方案 > 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;
}

在此处输入图像描述

标签: unity3dboundary

解决方案


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

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

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

UI 绝对 vs 相对

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

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

相机尺寸

现在,假设您有一个非常具体的原因将您的游戏实现到 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 运动夹紧


推荐阅读