Unity通用组件单例代码:
using UnityEngine;
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour {
private static T instance;
public static T Instance {
get => instance != null ? instance : InstanceInit();
set => instance = value;
}
protected static T InstanceInit() {
if (instance != null) return instance;
instance = GameObject.FindObjectOfType(typeof(T)) as T;
if (instance != null) return instance;
var obj = new GameObject(typeof(T).Name) {
//hideFlags = HideFlags.HideAndDontSave
};
DontDestroyOnLoad(obj);
instance = obj.AddComponent<T>();
return instance;
}
}
Unity通用对象池:
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using Object = UnityEngine.Object;
public class ObjectPoolManager : MonoBehaviour
{
private static ObjectPoolManager _instance;
public static ObjectPoolManager Instance {
get {
if (_instance) return _instance;
_instance = FindObjectOfType<ObjectPoolManager>();
if (_instance) return _instance;
var obj = new GameObject("ObjectPoolManager");
DontDestroyOnLoad(obj);
_instance = obj.AddComponent<ObjectPoolManager>();
return _instance;
}
}
private Dictionary<string, Queue<GameObject>> objectPoolDictionary = new ();
private void Awake() {
_instance = this;
}
public void Clear() {
foreach (var (objName, goList) in objectPoolDictionary) {
foreach (var obj in goList) {
Destroy(obj);
}
}
objectPoolDictionary.Clear();
}
/// <summary>
/// 创建对象池
/// </summary>
/// <param name="prefab"></param>
/// <param name="initialPoolSize"></param>
public void CreateObjectPool(GameObject prefab, int initialPoolSize) {
var prefabName = prefab.name;
if (!objectPoolDictionary.ContainsKey(prefabName))
{
Queue<GameObject> objectPoolQueue = new Queue<GameObject>();
for (int i = 0; i < initialPoolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
objectPoolQueue.Enqueue(obj);
}
objectPoolDictionary.Add(prefabName, objectPoolQueue);
}
}
/// <summary>
/// 获取对象
/// </summary>
/// <param name="prefab"></param>
/// <param name="parent"></param>
/// <param name="status"></param>
/// <returns></returns>
public GameObject GetObj(GameObject prefab, Transform parent = null, bool status = true) {
var prefabName = prefab.name;
//当前没有对象池,新创建并返回
GameObject obj;
if (!objectPoolDictionary.TryGetValue(prefabName, out var objectPoolQueue)) {
objectPoolQueue = new Queue<GameObject>();
objectPoolDictionary.Add(prefabName, objectPoolQueue);
obj = Instantiate(prefab, parent);
obj.name = prefab.name;
obj.SetActive(status);
return obj;
}
if (objectPoolQueue.TryDequeue(out obj)) {
if (obj) return obj;
objectPoolQueue.Clear();
obj = Instantiate(prefab, parent);
obj.name = prefab.name;
obj.SetActive(status);
return obj;
}
obj = Instantiate(prefab, parent);
obj.name = prefab.name;
obj.SetActive(status);
return obj;
}
/// <summary>
/// 放回对象池
/// </summary>
/// <param name="obj"></param>
public void ReturnObj(GameObject obj) {
var prefabName = obj.name;
if(!objectPoolDictionary.TryGetValue(prefabName, out var objectPoolQueue)) {
objectPoolQueue = new Queue<GameObject>();
objectPoolDictionary.Add(prefabName, objectPoolQueue);
}
try {obj.SetActive(false);} catch{}
if(objectPoolQueue.Contains(obj)) return;
objectPoolQueue.Enqueue(obj);
}
public readonly Dictionary<int, Transform> findTransforms = new();
}
public static class PoolManagerEx {
private static Dictionary<int, GameObject> _objCache = new Dictionary<int, GameObject>();
static PoolManagerEx() {
_objCache = new Dictionary<int, GameObject>();
Application.quitting += () => {
Debug.Log("ObjectCache clear!");
_objCache.Clear();
};
}
/// <summary>
/// 获取对象实例
/// </summary>
/// <param name="objName"></param>
/// <param name="getOrigin"></param>
/// <param name="parent"></param>
/// <param name="status"></param>
/// <returns></returns>
public static async UniTask<GameObject> GetInstance(this string objName, bool getOrigin = false, Transform parent = null, bool status = true) {
int idx = objName.GetHashCode();
if (_objCache.TryGetValue(idx, out var obj))
return getOrigin ? obj : ObjectPoolManager.Instance.GetObj(obj, parent, status);
obj = await objName.GetAssetAsync<GameObject>();
_objCache[idx] = obj;
return ObjectPoolManager.Instance.GetObj(obj, parent, status);
}
public static GameObject GetInstance(this GameObject gameObject, Transform parent = null, bool status = true) {
return ObjectPoolManager.Instance.GetObj(gameObject,parent, status);
}
public static void Recovery(this GameObject gameObject) {
ObjectPoolManager.Instance.ReturnObj(gameObject);
}
public static bool Find(this MonoBehaviour mono, string objName, out Transform target) {
target = null;
var objHash = objName.GetHashCode();
if (ObjectPoolManager.Instance.findTransforms.TryGetValue(objHash, out var transform)) {
if (transform != null) {
target = transform;
return true;
}
}
try {
var obj = GameObject.Find(objName);
if (obj == null) return false;
ObjectPoolManager.Instance.findTransforms[objHash] = obj.transform;
target = obj.transform;
return true;
}
catch {
Debug.LogWarning("Does not find Obj");
return false;
}
}
public static bool FindWithType<T>(this MonoBehaviour mono, out Transform target) where T : MonoBehaviour {
target = null;
var objName = typeof(T).Name.GetHashCode();
if (ObjectPoolManager.Instance.findTransforms.TryGetValue(objName, out var transform)) {
if (transform != null) {
target = transform;
return true;
}
}
try {
var obj = Object.FindObjectOfType<T>();
if (obj == null) return false;
ObjectPoolManager.Instance.findTransforms[objName] = obj.transform;
target = obj.transform;
return true;
}
catch {
Debug.LogWarning("Does not find Obj");
return false;
}
}
}
状态机:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace Module.StateMachine {
public class StateManager {
//当前状态ID
public int CurStateId { get; private set; }
//下一状态ID
public int NextStateId { get; private set; }
//当前状态委托
private StateAction _curStateAction;
//当前状态持续时间
public float CurStateDuration { get; private set; }
//状态映射表
private readonly Dictionary<int, StateAction> _stateMapping = new(5);
public bool displayDebugInfo;
#if UNITY_EDITOR
public Dictionary<int, string> _stateNameMapping = new(5);
#endif
public void OnUpdate() {
CurStateDuration += Time.deltaTime;
_curStateAction?.OnUpdate?.Invoke();
}
/// <summary>
/// 转换状态
/// </summary>
/// <param name="newState"></param>
/// <param name="forceSwitch"></param>
public void ChangeState(int newState, bool forceSwitch = true) {
//新状态不存在
if(!_stateMapping.TryGetValue(newState, out var newStateAction)) return;
NextStateId = newState;
if (_curStateAction == null) {
CurStateDuration = 0;
CurStateId = newState;
newStateAction.OnEnter?.Invoke();
_curStateAction = newStateAction;
return;
}
//当前状态无法转换
if(!forceSwitch && !_curStateAction.CanSwitchNext()) return;
#if UNITY_EDITOR
if(displayDebugInfo)
Debug.Log($"ChangeState: [{_stateNameMapping[CurStateId]}] ----> [{_stateNameMapping[newState]}]");
#endif
_curStateAction.OnExit?.Invoke();
_curStateAction = newStateAction;
CurStateDuration = 0;
CurStateId = newState;
newStateAction.OnEnter?.Invoke();
NextStateId = -1;
}
/// <summary>
/// 状态注册
/// </summary>
/// <param name="stateId"></param>
/// <param name="stateAction"></param>
public void StateRegister(int stateId, StateAction stateAction) {
_stateMapping[stateId] = stateAction;
}
/// <summary>
/// 使用枚举注册状态机
/// </summary>
/// <typeparam name="T"></typeparam>
public void StateRegister<T>(object obj) where T : Enum {
var methodInfos = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).ToList();
foreach (string stateName in Enum.GetNames(typeof(T))) {
var methodInfo = methodInfos.Find(item => item.Name.Equals(stateName));
if (methodInfo == null) continue;
Enum.TryParse(typeof(T), stateName, true, out object state);
#if UNITY_EDITOR
_stateNameMapping[(int)state] = stateName;
#endif
StateRegister((int)state, (StateAction)methodInfo.Invoke(obj, null));
}
}
/// <summary>
/// 移除状态
/// </summary>
/// <param name="stateId"></param>
public void RemoveState(int stateId) {
_stateMapping.Remove(stateId);
}
public void ChangeState(Enum enumType, bool forceSwitch = false) {
ChangeState(enumType.GetHashCode(),forceSwitch);
}
}
}
namespace Module.StateMachine {
public delegate bool StateDelegateBool();
public delegate void StateDelegate();
public class StateAction {
public StateDelegateBool CanSwitchNext = () => true;
public StateDelegate OnEnter = null;
public StateDelegate OnUpdate = null;
public StateDelegate OnExit = null;
}
}
AI控制器:
using Module.StateMachine;
using UnityEngine;
namespace Module.AIController {
public class AIBase : MonoBehaviour {
protected StateManager StateMachine;
protected Vector3 moveDir;
protected float moveSpeed = 1;
protected Transform _transform;
private void Awake() {
_transform = transform;
StateMachine = new StateManager();
OnInit();
}
private void Update() {
StateMachine.OnUpdate();
}
protected virtual void OnInit(){}
protected Vector3 Movement() {
var position = _transform.position;
position += moveSpeed * Time.deltaTime * moveDir;
_transform.position = position;
return position;
}
protected void ChangeDir() {
var localScale = _transform.localScale;
localScale.x = Mathf.Abs(localScale.x) * (moveDir.x > 0 ? 1 : -1);
_transform.localScale = localScale;
}
}
}
正交摄像机平滑移动:
public class LandCameraComponent
{
public Camera camera;
public Rect cameraMoveRange;
public Vector3 cameraPosition;
public Vector3 cameraMovePosition;
private static void InitCameraMoveRange(this LandCameraComponent self)
{
Rect moveRange = new()
{
xMin = 0,
xMax = (Vector3.right * 宽度).x,
yMin = 0,
yMax = (Vector3.up * 高度).y
};
Vector3 cameraViewCenter = self.GetInCameraWorldPosition(new Vector3(Screen.width / 2, Screen.height / 2));
Vector3 upperRight = self.GetInCameraWorldPosition(new Vector3(Screen.width, Screen.height));
Vector3 lowerLeft = self.GetInCameraWorldPosition(Vector3.zero);
//xMin
moveRange.xMin = cameraViewCenter.x - lowerLeft.x;
//yMin
moveRange.yMin = cameraViewCenter.y - lowerLeft.y;
//xMax
float value = upperRight.x - cameraViewCenter.x;
moveRange.xMax -= value;
//yMax
value = upperRight.y - cameraViewCenter.y;
moveRange.yMax -= value;
self.cameraMoveRange = moveRange;
}
private static void MoveCamera(this LandCameraComponent self)
{
if(Input.GetMouseButtonDown(0))
{
self.cameraPosition = Input.mousePosition;
}
if (Input.GetMouseButton(0))
{
if(self.cameraMovePosition != Input.mousePosition)
{
Vector3 cameraPosition = self.cameraMovePosition;
Vector3 newPosition = Input.mousePosition - cameraPosition;
newPosition.z = cameraPosition.z;
cameraPosition = self.camera.transform.position - 16 * Time.deltaTime * newPosition.normalized;
if(cameraPosition.x > self.cameraMoveRange.xMax)
cameraPosition.x = self.cameraMoveRange.xMax;
if (cameraPosition.x < self.cameraMoveRange.xMin)
cameraPosition.x = self.cameraMoveRange.xMin;
if(cameraPosition.y > self.cameraMoveRange.yMax)
cameraPosition.y = self.cameraMoveRange.yMax;
if(cameraPosition.y < self.cameraMoveRange.yMin)
cameraPosition.y = self.cameraMoveRange.yMin;
self.camera.transform.position = cameraPosition;
}
self.cameraMovePosition = Input.mousePosition;
}
if (Input.GetMouseButtonUp(0))
{
Vector3 moveDistances = Input.mousePosition - self.cameraPosition;
if(moveDistances.sqrMagnitude < 0.01f)
{
Log.Warning($"点击执行代码区域{self.GetInCameraWorldPosition(Input.mousePosition)}");
}
self.cameraPosition = Input.mousePosition;
}
}
}