Unity中,当物体在屏幕外时,在屏幕边缘显示它的方位

2024-03-27  本文已影响0人  全新的饭

用法

需在游戏开始时创建PosCursorSys,游戏结束时销毁PosCursorSys。
通过CreatePosCursor为特定的target transform创建一个对应的posCursor
其中cursorGoTemplate是一个UIGo预制体,通常是一个图标。

通过上述方式创建PosCursor后,需在合适的时机(一般是销毁target transform时)调用DestroyPosCursor,传入前述返回值将相应PosCursor同步销毁。

具体代码

PosCursorSys.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PosCursorSysModel
{
    public Canvas Canvas;
    public float RefPosZ => Canvas.planeDistance;
    public Camera UICam => Canvas.worldCamera;
}
public class PosCursorSys
{
    private PosCursorSysModel _model;
    private List<PosCursor> _cursors;

    public PosCursorSys(PosCursorSysModel model)
    {
        _model = model;
        _cursors = new List<PosCursor>();
        MonoSys.Instance.AddLateUpdateEvent(LateUpate);
    }
    public void Destroy()
    {
        MonoSys.Instance.RemoveLateUpdateEvent(LateUpate);

        foreach (var cursor in _cursors)
        {
            cursor.Destroy();
        }
        _cursors.Clear();
        _cursors = null;

        _model = null;
    }

    private void LateUpate()
    {
        foreach (var cursor in _cursors)
        {
            cursor.UpdatePosAndActive();
        }
    }

    public PosCursor CreatePosCursor(Transform target, GameObject cursorGoTemplate, Vector2 cursorSize)
    {
        var model = new PosCursorModel()
        {
            WorldCam = Camera.main,
            UICam = _model.UICam,
            Target = target,
            CursorGoTemplate = cursorGoTemplate,
            CursorSize = cursorSize,
            RefPosZ = _model.RefPosZ,
            MinScreenPos = Vector2.zero,
            MaxScreenPos = new Vector2(Screen.width, Screen.height),
            CursorParent = _model.Canvas.transform
        };
        var cursor = new PosCursor(model);
        _cursors.Add(cursor);
        return cursor;
    }
    public void DestroyPosCursor(PosCursor posCursor)
    {
        posCursor?.Destroy();
        _cursors.Remove(posCursor);
    }
}

PosCursor.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PosCursorModel
{
    public Camera WorldCam;
    public Camera UICam;
    public Transform Target;
    public GameObject CursorGoTemplate;
    public Vector2 CursorSize;
    public float RefPosZ;
    public Vector2 MinScreenPos;
    public Vector2 MaxScreenPos;

    public Transform CursorParent;
}

public class PosCursor
{
    private PosCursorModel _model;
    private GameObject _cursorGo;
    public PosCursor(PosCursorModel model)
    {
        _model = model;

        _cursorGo = GOPool.Instance.GetInstance(_model.CursorGoTemplate);
        _cursorGo.transform.SetParent(_model.CursorParent);
        _cursorGo.transform.localPosition = Vector3.zero;
        _cursorGo.transform.localRotation = Quaternion.identity;
        _cursorGo.transform.localScale = Vector3.one;
    }
    public void Destroy()
    {
        GOPool.Instance.RecycleInstance(_model.CursorGoTemplate, _cursorGo);
        _cursorGo = null;
        _model = null;
    }

    public void UpdatePosAndActive()
    {
        var screenPos = _model.WorldCam.WorldToScreenPoint(_model.Target.transform.position);
        screenPos = LimitInScreen(screenPos, out bool isHorizontalInScreen, out bool isVerticalInScreen, out bool isInLeft, out bool isInDown);
        bool isInScreen = isHorizontalInScreen && isVerticalInScreen;
        if (!isInScreen)
        {
            screenPos.z = _model.RefPosZ;
            var uiPos = _model.UICam.ScreenToWorldPoint(screenPos);
            _cursorGo.transform.position = uiPos;

            _cursorGo.transform.localPosition += new Vector3(_model.CursorSize.x * 0.5f * (isHorizontalInScreen ? 0 : (isInLeft ? 1 : -1)),
                                                              _model.CursorSize.y * 0.5f * (isVerticalInScreen ? 0 : (isInDown ? 1 : -1)), 0);
        }
        _cursorGo.SetActive(!isInScreen);
    }

    private Vector3 LimitInScreen(Vector2 pos, out bool isHorizontalInScreen, out bool isVerticalInScreen, out bool isInLeft, out bool isInDown)
    {
        isHorizontalInScreen = true;
        isVerticalInScreen = true;
        isInLeft = false;
        isInDown = false;

        if (pos.x <= _model.MinScreenPos.x)
        {
            pos.x = _model.MinScreenPos.x;
            isInLeft = true;
            isHorizontalInScreen = false;
        }
        if (pos.x >= _model.MaxScreenPos.x)
        {
            pos.x = _model.MaxScreenPos.x;
            isInLeft = false;
            isHorizontalInScreen = false;
        }
        if (pos.y <= _model.MinScreenPos.y)
        {
            pos.y = _model.MinScreenPos.y;
            isInDown = true;
            isVerticalInScreen = false;
        }
        if (pos.y >= _model.MaxScreenPos.y)
        {
            pos.y = _model.MaxScreenPos.y;
            isInDown = false;
            isVerticalInScreen = false;
        }
        return pos;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读