✅ 项目说明

  • 引擎版本建议:Unity 2021.3 LTS 或 Unity 2022+
  • 适用于:Top-down RPG、模拟类、策略类等有“世界-角色-行为”结构的项目
  • 架构风格:面向接口、职责分离、可单元测试

📁 目录结构

Assets/
├── Scripts/
│   ├── Core/
│   │   ├── GameWorld.cs
│   │   └── GameWorldContext.cs
│   ├── Interfaces/
│   │   ├── IGameContext.cs
│   │   └── IEventDispatcher.cs
│   ├── Characters/
│   │   ├── NPC.cs
│   │   └── Player.cs
│   ├── Events/
│   │   └── DefaultEventDispatcher.cs
│   ├── Tests/
│   │   └── MockGameContext.cs
│   └── Entry/
│       └── GameStartup.cs
└── Scenes/
    └── SampleScene.unity

✏️ 脚本模板内容(部分示例)

IGameContext.cs

public interface IGameContext
{
    Player GetPlayer();
    Vector3 GetSpawnPoint();
    IEventDispatcher GetEventDispatcher();
}

IEventDispatcher.cs

public interface IEventDispatcher
{
    void Dispatch(string eventName, object data = null);
    void Subscribe(string eventName, Action<object> callback);
    void Unsubscribe(string eventName, Action<object> callback);
}

GameWorld.cs

using UnityEngine;

public class GameWorld : MonoBehaviour
{
    private GameWorldContext context;
    private Player player;
    private List<NPC> npcs = new();

    private void Awake()
    {
        context = new GameWorldContext(this);
        player = new GameObject("Player").AddComponent<Player>();
        player.Init(context);

        for (int i = 0; i < 3; i++)
        {
            var npcObj = new GameObject($"NPC_{i}");
            var npc = npcObj.AddComponent<NPC>();
            npc.Init(context);
            npcs.Add(npc);
        }
    }

    public Player GetPlayer() => player;
    public Vector3 GetSpawnPoint() => Vector3.zero;
}

GameWorldContext.cs

public class GameWorldContext : IGameContext
{
    private GameWorld world;
    private IEventDispatcher dispatcher;

    public GameWorldContext(GameWorld world)
    {
        this.world = world;
        this.dispatcher = new DefaultEventDispatcher();
    }

    public Player GetPlayer() => world.GetPlayer();
    public Vector3 GetSpawnPoint() => world.GetSpawnPoint();
    public IEventDispatcher GetEventDispatcher() => dispatcher;
}

NPC.cs

using UnityEngine;

public class NPC : MonoBehaviour
{
    private IGameContext context;

    public void Init(IGameContext context)
    {
        this.context = context;
    }

    public void Act()
    {
        context.GetEventDispatcher().Dispatch("NPC_Acted", this);
        Debug.Log("NPC acting...");
    }
}

Player.cs

using UnityEngine;

public class Player : MonoBehaviour
{
    private IGameContext context;

    public void Init(IGameContext context)
    {
        this.context = context;
    }

    public void Interact()
    {
        context.GetEventDispatcher().Dispatch("Player_Interacted", this);
    }
}

DefaultEventDispatcher.cs

using System;
using System.Collections.Generic;

public class DefaultEventDispatcher : IEventDispatcher
{
    private Dictionary<string, Action<object>> listeners = new();

    public void Dispatch(string eventName, object data = null)
    {
        if (listeners.TryGetValue(eventName, out var callback))
        {
            callback?.Invoke(data);
        }
    }

    public void Subscribe(string eventName, Action<object> callback)
    {
        if (listeners.ContainsKey(eventName))
            listeners[eventName] += callback;
        else
            listeners[eventName] = callback;
    }

    public void Unsubscribe(string eventName, Action<object> callback)
    {
        if (listeners.ContainsKey(eventName))
            listeners[eventName] -= callback;
    }
}

GameStartup.cs(用于启动游戏)

using UnityEngine;

public class GameStartup : MonoBehaviour
{
    private void Start()
    {
        var worldObj = new GameObject("GameWorld");
        worldObj.AddComponent<GameWorld>();
    }
}

MockGameContext.cs(测试用)

using UnityEngine;

public class MockGameContext : IGameContext
{
    public Player GetPlayer() => new GameObject("MockPlayer").AddComponent<Player>();
    public Vector3 GetSpawnPoint() => Vector3.zero;
    public IEventDispatcher GetEventDispatcher() => new DefaultEventDispatcher();
}

🔨 使用方法

  1. 新建 Unity 项目,导入上述目录结构和脚本。
  2. SampleScene 中放置一个空物体并挂载 GameStartup.cs
  3. 运行场景,将看到 Player 和多个 NPC 在控制台输出行为。