小众的Unity游戏框架
1. Entitas(ECS框架) ⭐⭐⭐⭐
小众但被多家大厂魔改使用
// Entitas - 轻量级ECS框架
// 被改造案例:网易、米哈游早期
// 1. 定义组件(纯数据)
public sealed class PositionComponent : IComponent {
public Vector3 value;
}
public sealed class VelocityComponent : IComponent {
public Vector3 value;
}
public sealed class HealthComponent : IComponent {
public int current;
public int max;
}
// 2. 自动生成的Context(代码生成器)
public sealed class GameContext : Context<GameEntity> {
public GameContext() : base(
ComponentsLookup.TotalComponents,0,
new ContextInfo("Game", ComponentsLookup.componentNames, ComponentsLookup.componentTypes),
(entity) => new GameEntity()
) { }
}
// 3. 系统(System)
public class MovementSystem : IExecuteSystem {
private readonly IGroup<GameEntity> _group;
public MovementSystem(Contexts contexts) {
// 只处理有Position和Velocity的实体
_group = contexts.game.GetGroup(GameMatcher.AllOf(
GameMatcher.Position,
GameMatcher.Velocity
));
}
public void Execute() {
foreach (var entity in _group.GetEntities()) {
var pos = entity.position.value;
var vel = entity.velocity.value;
pos += vel * Time.deltaTime;
entity.ReplacePosition(pos);
}
}
}
// 4. 响应式系统(Reactive System)
public class DeathSystem : ReactiveSystem<GameEntity> {
public DeathSystem(Contexts contexts) : base(contexts.game) { }
protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context) {
// 当Health组件变化时触发
return context.CreateCollector(GameMatcher.Health);
}
protected override bool Filter(GameEntity entity) {
return entity.health.current <= 0;
}
protected override void Execute(List<GameEntity> entities) {
foreach (var entity in entities) {
entity.isDead = true;
// 播放死亡动画
// 触发死亡事件
}
}
}
// 5. Feature(系统组)
public class GameSystems : Feature {
public GameSystems(Contexts contexts) {
// 输入系统
Add(new InputSystem(contexts));
// 游戏逻辑
Add(new MovementSystem(contexts));
Add(new CombatSystem(contexts));
Add(new AISystem(contexts));
// 响应式系统
Add(new DeathSystem(contexts));
Add(new ScoreSystem(contexts));
// 视图系统
Add(new RenderSystem(contexts));
Add(new AnimationSystem(contexts));
}
}
// 6. 游戏入口
public class GameController : MonoBehaviour {
private Systems _systems;
private Contexts _contexts;
void Start() {
_contexts = Contexts.sharedInstance;
_systems = new GameSystems(_contexts);
_systems.Initialize();
// 创建实体
CreatePlayer();
}
void Update() {
_systems.Execute();
_systems.Cleanup();
}
void CreatePlayer() {
var player = _contexts.game.CreateEntity();
player.AddPosition(Vector3.zero);
player.AddVelocity(Vector3.zero);
player.AddHealth(100, 100);
player.isPlayer = true;
}
}
// 🎮 大厂魔改方向:
// - 米哈游:改造成支持服务器+客户端双端
// - 网易:添加序列化、网络同步
// - 叠纸:增加帧同步支持
为什么大厂喜欢:
- 性能极高(缓存友好)
- 代码生成器减少重复代码
- 容易魔改
- 适合大规模实体
GitHub: https://github.com/sschmid/Entitas-CSharp
2. Zenject/VContainer(依赖注入) ⭐⭐⭐⭐
被大厂改造成内部DI框架
// Zenject(现改名为Extenject)
// 改造案例:Ubisoft、Supercell改成内部工具
// 1. 定义接口和实现
public interface IWeaponService {
void Fire();
}
public class GunService : IWeaponService {
private readonly IAmmoService _ammoService;
private readonly IAudioService _audioService;
// 构造函数注入
public GunService(IAmmoService ammoService, IAudioService audioService) {
_ammoService = ammoService;
_audioService = audioService;
}
public void Fire() {
if (_ammoService.HasAmmo()) {
_ammoService.ConsumeAmmo();
_audioService.PlaySound("gunshot");
}
}
}
// 2. Installer(注册依赖)
public class GameInstaller : MonoInstaller {
public override void InstallBindings() {
// 单例绑定
Container.Bind<IPlayerService>()
.To<PlayerService>()
.AsSingle();
// 工厂绑定
Container.Bind<IWeaponService>()
.To<GunService>()
.AsTransient();
// 从场景绑定
Container.Bind<PlayerController>()
.FromComponentInHierarchy()
.AsSingle();
// 从Resources绑定
Container.Bind<GameConfig>()
.FromScriptableObjectResource("Configs/GameConfig")
.AsSingle();
// 绑定实例
Container.BindInstance(new GameSettings {
Difficulty = 2
}).AsSingle();
// 工厂模式
Container.BindFactory<Enemy, Enemy.Factory>()
.FromComponentInNewPrefab(enemyPrefab);
}
[SerializeField] private GameObject enemyPrefab;
}
// 3. 使用注入
public class PlayerController : MonoBehaviour {
[Inject] private IWeaponService _weaponService;
[Inject] private IPlayerService _playerService;
[Inject] private SignalBus _signalBus; // 事件总线
void Start() {
// 注入已经完成,可以直接使用
_playerService.Initialize();
}
void Update() {
if (Input.GetKeyDown(KeyCode.Space)) {
_weaponService.Fire();
}
}
}
// 4. Signal(解耦事件系统)
public class PlayerDiedSignal {
public int PlayerId;
public Vector3 Position;
}
public class GameSignalInstaller : Installer<GameSignalInstaller> {
public override void InstallBindings() {
// 声明信号
Container.DeclareSignal<PlayerDiedSignal>();
// 绑定处理器
Container.BindSignal<PlayerDiedSignal>()
.ToMethod<UIManager>(x => x.OnPlayerDied)
.FromResolve();
}
}
// 发送信号
public class Player : MonoBehaviour {
[Inject] private SignalBus _signalBus;
void Die() {
_signalBus.Fire(new PlayerDiedSignal {
PlayerId = 1,
Position = transform.position
});
}
}
// 5. Memory Pool(对象池集成)
public class BulletPoolInstaller : MonoInstaller {
public override void InstallBindings() {
Container.BindMemoryPool<Bullet, Bullet.Pool>()
.WithInitialSize(50)
.FromComponentInNewPrefab(bulletPrefab)
.UnderTransformGroup("Bullets");
}
}
public class BulletSpawner : MonoBehaviour {
[Inject] private Bullet.Pool _bulletPool;
void Fire() {
var bullet = _bulletPool.Spawn();
bullet.transform.position = firePoint.position;
// 使用后回收
StartCoroutine(DespawnAfterDelay(bullet, 3f));
}
IEnumerator DespawnAfterDelay(Bullet bullet, float delay) {
yield return new WaitForSeconds(delay);
_bulletPool.Despawn(bullet);
}
}
// 🏢 魔改点:
// - Supercell:改造成支持热重载
// - Ubisoft:添加多场景管理
// - 某大厂:集成IL2CPP优化版本
VContainer(更轻量的替代)
// VContainer - 性能更好的DI框架
using VContainer;
using VContainer.Unity;
public class GameLifetimeScope : LifetimeScope {
protected override void Configure(IContainerBuilder builder) {
// 注册服务
builder.Register<IPlayerService, PlayerService>(Lifetime.Singleton);
builder.Register<IWeaponService, GunService>(Lifetime.Transient);
// 注册MonoBehaviour
builder.RegisterComponentInHierarchy<PlayerController>();
// 注册入口点
builder.RegisterEntryPoint<GameInitializer>();
}
}
// EntryPoint(替代MonoBehaviour.Start)
public class GameInitializer : IStartable {
private readonly IPlayerService _playerService;
public GameInitializer(IPlayerService playerService) {
_playerService = playerService;
}
public void Start() {
_playerService.Initialize();
}
}
3. Odin Inspector(编辑器增强) ⭐⭐⭐⭐⭐
using Sirenix.OdinInspector;
// 改造案例:很多大厂购买后改成内部工具链
public class WeaponData : ScriptableObject {
[BoxGroup("基础属性")]
[LabelText("武器名称")]
public string weaponName;
[BoxGroup("基础属性")]
[Range(1, 100)]
[LabelText("攻击力")]
public int damage;
[FoldoutGroup("高级设置")]
[ShowIf("@damage > 50")]
[LabelText("暴击率")]
public float criticalRate;
[FoldoutGroup("技能")]
[TableList(ShowIndexLabels = true)]
public List<Skill> skills;
[Button("生成配置文件", ButtonSizes.Large)]
[GUIColor(0.3f, 0.8f, 0.3f)]
private void GenerateConfig() {
// 一键生成配置
}
[PreviewField(100, ObjectFieldAlignment.Center)]
[BoxGroup("预览")]
public Sprite icon;
}
[System.Serializable]
public class Skill {
[HorizontalGroup("Split", 55)]
[PreviewField(50, ObjectFieldAlignment.Center)]
[HideLabel]
public Sprite icon;
[HorizontalGroup("Split")]
[VerticalGroup("Split/Right")]
public string skillName;
[VerticalGroup("Split/Right")]
[ProgressBar(0, 100)]
public float cooldown;
}
// 🎨 使用案例:
// - 改造成可视化关卡编辑器
// - 基于此做配置表编辑器
4. Behavior Designer(行为树) ⭐⭐⭐⭐
// 改造案例:腾讯、完美世界改成自己的AI系统
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
// 自定义行为节点
[TaskCategory("Custom/Combat")]
public class FindNearestEnemy : Action {
[RequiredField]
public SharedTransform targetEnemy;
public float searchRadius = 10f;
public override TaskStatus OnUpdate() {
Collider[] colliders = Physics.OverlapSphere(transform.position, searchRadius);
float nearestDistance = float.MaxValue;
Transform nearest = null;
foreach (var col in colliders) {
if (col.CompareTag("Enemy")) {
float distance = Vector3.Distance(transform.position, col.transform.position);
if (distance < nearestDistance) {
nearestDistance = distance;
nearest = col.transform;
}
}
}
if (nearest != null) {
targetEnemy.Value = nearest;
return TaskStatus.Success;
}
return TaskStatus.Failure;
}
}
// 条件节点
[TaskCategory("Custom/Combat")]
public class CanAttack : Conditional {
public SharedTransform target;
public float attackRange = 2f;
public override TaskStatus OnUpdate() {
if (target.Value == null) {
return TaskStatus.Failure;
}
float distance = Vector3.Distance(transform.position, target.Value.position);
return distance <= attackRange ? TaskStatus.Success : TaskStatus.Failure;
}
}
// 🧠 魔改方向:
// - 加入HTN(分层任务网络)
// - 集成GOAP规划
// - 添加多线程支持
// - 与动画系统深度集成
5. Mirror/FishNet(网络框架) ⭐⭐⭐⭐
开源网络框架,被改造成内部方案
// Mirror - Unity官方UNET的开源替代
// 改造案例:多家独立工作室
using Mirror;
// NetworkBehaviour
public class Player : NetworkBehaviour {
// [SyncVar] 自动同步
[SyncVar(hook = nameof(OnHealthChanged))]
public int health = 100;
[SyncVar]
public string playerName;
// Command: 客户端 → 服务器
[Command]
void CmdFire(Vector3 direction) {
// 在服务器上执行
GameObject bullet = Instantiate(bulletPrefab, transform.position, Quaternion.identity);
// 通知所有客户端
RpcShowFireEffect(direction);
}
// ClientRpc: 服务器 → 所有客户端
[ClientRpc]
void RpcShowFireEffect(Vector3 direction) {
// 在所有客户端播放特效
PlayMuzzleFlash();
}
// TargetRpc: 服务器 → 指定客户端
[TargetRpc]
void TargetShowMessage(NetworkConnection target, string message) {
// 只在目标客户端显示
UIManager.Instance.ShowMessage(message);
}
void OnHealthChanged(int oldValue, int newValue) {
// SyncVar变化时的回调
UpdateHealthUI(newValue);
}
void Update() {
// 只在本地玩家执行
if (!isLocalPlayer) return;
if (Input.GetKeyDown(KeyCode.Space)) {
CmdFire(transform.forward);
}
}
private GameObject bulletPrefab;
void PlayMuzzleFlash() { }
void UpdateHealthUI(int health) { }
}
// NetworkManager
public class GameNetworkManager : NetworkManager {
public override void OnServerAddPlayer(NetworkConnectionToClient conn) {
// 服务器添加玩家
GameObject player = Instantiate(playerPrefab);
NetworkServer.AddPlayerForConnection(conn, player);
}
public override void OnClientConnect() {
// 客户端连接成功
Debug.Log("已连接到服务器");
}
private GameObject playerPrefab;
}
// 🌐 魔改案例:
// - 某工作室:改成帧同步
// - 某团队:加入状态同步优化
// - 某公司:集成KCP传输协议
FishNet(更现代的替代)
using FishNet.Object;
using FishNet.Connection;
// FishNet - 性能更好
public class Player : NetworkBehaviour {
[SyncVar]
private int health;
[ServerRpc]
private void Attack(NetworkConnection conn = null) {
// 服务器RPC
}
[ObserversRpc]
private void ShowEffect() {
// 所有观察者
}
}
6. DOTween Pro(动画框架) ⭐⭐⭐⭐⭐
几乎所有Unity项目都在用
using DG.Tweening;
public class TweenExamples : MonoBehaviour {
void Start() {
// 基础动画
transform.DOMove(new Vector3(10, 0, 0), 2f);
// 链式调用
transform.DOScale(2f, 1f)
.SetEase(Ease.OutBounce)
.SetDelay(0.5f)
.OnComplete(() => Debug.Log("完成"));
// Sequence(序列动画)
Sequence seq = DOTween.Sequence();
seq.Append(transform.DOMove(Vector3.up * 5, 1f));
seq.Append(transform.DORotate(Vector3.up * 180, 0.5f));
seq.Join(transform.DOScale(2f, 0.5f)); // 同时执行
seq.AppendInterval(1f); // 等待
seq.Append(transform.DOMove(Vector3.zero, 1f));
// Path动画
Vector3[] path = new Vector3[] {
new Vector3(0, 0, 0),
new Vector3(5, 0, 0),
new Vector3(5, 5, 0),
new Vector3(10, 5, 0)
};
transform.DOPath(path, 3f, PathType.CatmullRom);
// Shake效果
Camera.main.DOShakePosition(0.5f, 0.3f);
// UI动画
image.DOFade(0, 1f);
text.DOText("Hello World", 2f);
}
}
// 🎬 用法:
// - 几乎所有项目的UI动画
// - 技能特效、相机震动
// - 过场动画
7. 小众但强大的框架
A. Stateless(状态机)
// 轻量级状态机,被多家公司集成
using Stateless;
public class EnemyAI : MonoBehaviour {
enum State { Idle, Patrol, Chase, Attack }
enum Trigger { SeePlayer, LosePlayer, InRange, OutOfRange }
StateMachine<State, Trigger> _machine;
void Start() {
_machine = new StateMachine<State, Trigger>(State.Idle);
_machine.Configure(State.Idle)
.Permit(Trigger.SeePlayer, State.Chase);
_machine.Configure(State.Chase)
.OnEntry(OnStartChase)
.Permit(Trigger.InRange, State.Attack)
.Permit(Trigger.LosePlayer, State.Patrol);
_machine.Configure(State.Attack)
.OnEntry(OnStartAttack)
.Permit(Trigger.OutOfRange, State.Chase);
}
void OnStartChase() { Debug.Log("开始追击"); }
void OnStartAttack() { Debug.Log("开始攻击"); }
}
B. MessagePack(序列化)
// 被大厂用于网络传输和存档
using MessagePack;
[MessagePackObject]
public class SaveData {
[Key(0)]
public int Level { get; set; }
[Key(1)]
public List<ItemData> Items { get; set; }
}
// 序列化(比JSON快5-10倍)
byte[] bytes = MessagePackSerializer.Serialize(saveData);
SaveData loaded = MessagePackSerializer.Deserialize<SaveData>(bytes);
💡 关键启示
大厂魔改小众框架关键点
开源 = 可控 - 可以完全掌控源码
轻量 = 易改 - 小框架容易理解和修改
专注 = 好用 - 专注解决一个问题
免费 = 省钱 - 开源框架降低成本
社区 = 参考 - 有社区反馈问题
✨随便写写
by ONE
798

被折叠的 条评论
为什么被折叠?



