用法
需在游戏开始时创建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;
}
}
网友评论