美文网首页
Unity中,当物体在屏幕外时,在屏幕边缘显示它的方位

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

作者: 全新的饭 | 来源:发表于2024-03-27 18:17 被阅读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;
    }
}

相关文章

  • Unity3d:在屏幕边缘显示其他玩家/敌人/物体的方位

    系列传送门 IOS:IOS:使用shell命令打包并上传ItunesUnity3d:Unity3d:Canvas适...

  • Unity判断物体是否在屏幕中

    注意:要设置主相机的tag标签是MainCamera,不然会报空指针错误。

  • 解决ImageView超出父控件(或屏幕边界)时,图片挤压问题

    一、需求 在屏幕边缘显示一张图片,超出屏幕宽度时,只显示图片的左边部分,并且不被挤压,其余部分剪切。但我在实际开发...

  • 记录一些好的网站

    在Unity中实现屏幕空间阴影(1)在Unity中实现屏幕空间阴影(2)游戏里的动态阴影-ShadowMap实现原...

  • PxCook 窗口显示在屏幕外

    PxCook 窗口显示在屏幕外 解决方案: 1.找到layout.dat 的文件路径: ~/Library/App...

  • SnapHelper实现RecyclerView滑动对齐效果

    简介 在列表滑动浏览,有时希望当滑动停止某个 ItemView 时可以停留在屏幕中央吸引用户的焦点,或者在边缘显示...

  • 图层性能

    1. 离屏渲染 当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并...

  • iOS-对离屏渲染的理解

    什么是离屏渲染 当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并...

  • 离屏渲染

    当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并不意味着软件绘制...

  • 离屏渲染

    当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并不意味着软件绘制...

网友评论

      本文标题:Unity中,当物体在屏幕外时,在屏幕边缘显示它的方位

      本文链接:https://www.haomeiwen.com/subject/nopytjtx.html