一、ECCore
需要在Unity项目中使用插件:UniRx,通过UniRx代替Mono的Update,Mono下做轮询性能消耗会有点大。
EntityMono代码:
using System; using System.Collections.Generic; using EC; using UniRx; using UnityEngine;namespace ECCore {public abstract class EntityMono : MonoBehaviour{private readonly List<CapBase> caps = new();private IDisposable updateSubscription;public CapBase AddCap<T>() where T : CapBase, new(){// 检查是否已经添加了相同类型的 CapBase 实例if (caps.Exists(cap => cap is T)){Debug.LogWarning($"{typeof(T).Name} 已经添加了!");return null;}// 创建新的实例并添加到 caps 列表中var c = (T)System.Activator.CreateInstance(typeof(T));caps.Add(c);LogErrorByCap(c);return c;}public T GetCap<T>() where T : CapBase{return (T)caps.Find(cap => cap is T);}public void RemoveCap(CapBase cap){caps.Remove(cap);}private void Awake(){OnInit();updateSubscription?.Dispose();updateSubscription = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(0.01f)).Subscribe(_ => OnUpdate());}private void OnDestroy(){updateSubscription?.Dispose();OnClear();}// entity生命周期protected abstract void OnInit();protected abstract void OnUpdate();protected abstract void OnClear();void OnCollisionEnter(Collision collision){GetCap<OnColliderCapBase>()?.OnCollisionEnter(collision);}void OnCollisionStay(Collision collision){GetCap<OnColliderCapBase>()?.OnCollisionStay(collision);}void OnCollisionExit(Collision collision){GetCap<OnColliderCapBase>()?.OnCollisionExit(collision);}void OnTriggerEnter(Collider otherCollision){GetCap<OnTriggerCapBase>()?.OnTriggerEnter(otherCollision);}void OnTriggerStay(Collider otherCollision){GetCap<OnTriggerCapBase>()?.OnTriggerStay(otherCollision);}void OnTriggerExit(Collider otherCollision){GetCap<OnTriggerCapBase>()?.OnTriggerExit(otherCollision);}private void LogErrorByCap(CapBase cap){switch (cap){case OnColliderCapBase onColliderCapBase:if (GetComponent<Collider>() == null){Debug.LogError("碰撞能力实体没有添加Collider:"+ name);}break;case OnTriggerCapBase onTriggerCapBase:var colliderComponent = GetComponent<Collider>();if (colliderComponent == null)Debug.LogError("触发能力实体没有添加Collider:"+ name);else{if(!colliderComponent.isTrigger)Debug.LogError("触发能力实体没有勾选isTrigger:"+ name);}break;}}} }
CapBase代码:
namespace ECCore {public abstract class CapBase{public abstract void InitData(EntityMono initEntity);public abstract void OnClear();} }
二、OnColliderCapBase和OnTriggerCapBase 碰撞能力基类和触发能力基类
碰撞和触发需要依赖Mono下内部方法,所以给碰撞能力和触发能力抽象出基类方法。
OnColliderCapBase代码:
using ECCore; using UnityEngine;namespace EC {public abstract class OnColliderCapBase : CapBase{public abstract void OnCollisionEnter(Collision collision);public abstract void OnCollisionStay(Collision collision);public abstract void OnCollisionExit(Collision collision);} }
OnTriggerCapBase代码:
using ECCore; using UnityEngine;namespace EC {public abstract class OnTriggerCapBase : CapBase{public abstract void OnTriggerEnter(Collider otherCollision);public abstract void OnTriggerStay(Collider otherCollision);public abstract void OnTriggerExit(Collider otherCollision);} }
三、GameEC
PlayerEntity代码:
using ECCore; using UnityEngine;namespace EC {public class PlayerEntity : EntityMono{public float mouseSensitivity = 10.0f;protected override void OnInit(){// AddCap<InputCap>().InitData(this);AddCap<MoveCap>().InitData(this);AddCap<GravityCap>().InitData(this);GetCap<GravityCap>()?.SetGravity(10);AddCap<LookCap>().InitData(this);AddCap<PlayerOnColliderCap>().InitData(this);}protected override void OnUpdate(){// 输入先这么做 不知道要不要加Cap 思考中.....Vector3 movement = Vector3.zero;Vector2 look = Vector2.zero;movement.x = Input.GetAxis("Horizontal");movement.z = Input.GetAxis("Vertical");look.x = Input.GetAxis("Mouse X");look.y = Input.GetAxis("Mouse Y");GetCap<LookCap>()?.Look(look, mouseSensitivity);GetCap<MoveCap>()?.Move(movement);}protected override void OnClear(){}}}
MoveCap代码:
using UnityEngine; using ECCore;namespace EC {public class MoveCap : CapBase{private EntityMono entity;public override void InitData(EntityMono initEntity){entity = initEntity;}public void Move(Vector3 pos){pos = entity.transform.TransformDirection(pos);entity.transform.position += pos;}public override void OnClear(){entity = null;}} }