671 lines
16 KiB
Markdown
671 lines
16 KiB
Markdown
# Cielonos 项目架构改进建议
|
||
|
||
## 一、整体架构评估
|
||
|
||
### 当前架构优势
|
||
1. **模块化设计**: Submodule/Subcontroller架构将逻辑和表现分离,提供了良好的可扩展性
|
||
2. **组件化思想**: 大量使用字典存储子模块,便于动态增删功能
|
||
3. **事件驱动**: 使用UniRx实现响应式事件系统,解耦了系统间的依赖
|
||
4. **系统完整性**: 战斗、Buff、状态、动画等核心系统已经具备完整的基础架构
|
||
|
||
### 当前架构不足
|
||
1. **职责边界模糊**: 部分类承担了过多职责
|
||
2. **代码组织混乱**: 部分脚本放置位置不合理
|
||
3. **抽象程度不足**: 部分核心逻辑缺少接口抽象
|
||
4. **文档注释缺失**: 代码缺少必要的注释和说明
|
||
5. **配置化程度低**: 硬编码问题较多
|
||
|
||
---
|
||
|
||
## 二、具体改进建议
|
||
|
||
### 1. 核心架构层
|
||
|
||
#### 1.1 建立核心接口层
|
||
**问题**: 当前系统之间直接依赖具体实现,缺乏抽象层
|
||
|
||
**建议**:
|
||
```
|
||
Core/Interfaces/
|
||
├── ICharacter.cs # 角色接口
|
||
├── IAttackable.cs # 可攻击对象接口
|
||
├── IBuffable.cs # 可附魔Buff对象接口
|
||
├── IItem.cs # 物品接口
|
||
├── IWeapon.cs # 武器接口
|
||
├── IDamageable.cs # 可受伤害对象接口
|
||
└── ITeamMember.cs # 阵营成员接口
|
||
```
|
||
|
||
**示例代码**:
|
||
```csharp
|
||
public interface ICharacter
|
||
{
|
||
Fraction Team { get; }
|
||
bool IsDead { get; }
|
||
float Health { get; }
|
||
float MaxHealth { get; }
|
||
|
||
void TakeDamage(DamageInfo damageInfo);
|
||
void ApplyBuff(IBuff buff);
|
||
void Heal(float amount);
|
||
}
|
||
|
||
public interface IDamageSource
|
||
{
|
||
DamageInfo CreateDamage();
|
||
AttackType DamageType { get; }
|
||
float DamageValue { get; }
|
||
}
|
||
```
|
||
|
||
#### 1.2 引入服务定位器模式
|
||
**问题**: Manager类直接持有引用,系统间耦合度高
|
||
|
||
**建议**:
|
||
```csharp
|
||
public static class GameServices
|
||
{
|
||
private static readonly Dictionary<Type, object> services = new Dictionary<Type, object>();
|
||
|
||
public static void Register<T>(T service) where T : class
|
||
{
|
||
services[typeof(T)] = service;
|
||
}
|
||
|
||
public static T Get<T>() where T : class
|
||
{
|
||
if (services.TryGetValue(typeof(T), out var service))
|
||
{
|
||
return service as T;
|
||
}
|
||
|
||
Debug.LogError($"Service {typeof(T)} not found!");
|
||
return null;
|
||
}
|
||
|
||
public static void Clear()
|
||
{
|
||
services.Clear();
|
||
}
|
||
}
|
||
|
||
// 使用示例
|
||
public class BattleManager : MonoBehaviour
|
||
{
|
||
public void Initialize()
|
||
{
|
||
GameServices.Register<IBattleService>(this);
|
||
GameServices.Register<ICharacterService>(new CharacterService());
|
||
GameServices.Register<IBuffService>(new BuffService());
|
||
}
|
||
}
|
||
|
||
// 在其他类中使用
|
||
var battleService = GameServices.Get<IBattleService>();
|
||
```
|
||
|
||
#### 1.3 建立消息总线系统
|
||
**问题**: 当前事件系统分散在各个类中,难以追踪和调试
|
||
|
||
**建议**:
|
||
```csharp
|
||
public enum GameEvent
|
||
{
|
||
// 角色事件
|
||
CharacterDied,
|
||
CharacterSpawned,
|
||
CharacterRevived,
|
||
|
||
// 战斗事件
|
||
DamageDealt,
|
||
DamageTaken,
|
||
AttackBlocked,
|
||
AttackDodged,
|
||
CriticalHit,
|
||
|
||
// 物品事件
|
||
ItemAcquired,
|
||
ItemUsed,
|
||
ItemDiscarded,
|
||
WeaponSwitched,
|
||
|
||
// Buff事件
|
||
BuffApplied,
|
||
BuffRemoved,
|
||
BuffExpired,
|
||
|
||
// 游戏状态事件
|
||
WaveStarted,
|
||
WaveCleared,
|
||
BossAppeared,
|
||
BossDefeated,
|
||
|
||
// 系统事件
|
||
GamePaused,
|
||
GameResumed,
|
||
CheckpointReached
|
||
}
|
||
|
||
public class GameEventBus
|
||
{
|
||
private static readonly Dictionary<GameEvent, Action<GameEventArgs>>
|
||
eventHandlers = new Dictionary<GameEvent, Action<GameEventArgs>>();
|
||
|
||
public static void Subscribe(GameEvent eventType, Action<GameEventArgs> handler)
|
||
{
|
||
if (!eventHandlers.ContainsKey(eventType))
|
||
{
|
||
eventHandlers[eventType] = handler;
|
||
}
|
||
else
|
||
{
|
||
eventHandlers[eventType] += handler;
|
||
}
|
||
}
|
||
|
||
public static void Unsubscribe(GameEvent eventType, Action<GameEventArgs> handler)
|
||
{
|
||
if (eventHandlers.ContainsKey(eventType))
|
||
{
|
||
eventHandlers[eventType] -= handler;
|
||
}
|
||
}
|
||
|
||
public static void Publish(GameEvent eventType, GameEventArgs args = null)
|
||
{
|
||
if (eventHandlers.TryGetValue(eventType, out var handler))
|
||
{
|
||
handler?.Invoke(args);
|
||
}
|
||
}
|
||
}
|
||
|
||
public class GameEventArgs
|
||
{
|
||
public object Sender { get; set; }
|
||
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
|
||
}
|
||
```
|
||
|
||
### 2. 角色系统改进
|
||
|
||
#### 2.1 拆分CharacterBase
|
||
**问题**: CharacterBase类过于庞大,承担了太多职责
|
||
|
||
**建议**: 将其拆分为多个专门类
|
||
```csharp
|
||
// 核心角色数据
|
||
public class CharacterData : ScriptableObject
|
||
{
|
||
public string characterId;
|
||
public string characterName;
|
||
public Fraction defaultFaction;
|
||
public AttributeData baseAttributes;
|
||
public VFXData vfxData;
|
||
public AudioContainer audioData;
|
||
public List<SerializableType> availableBuffs;
|
||
}
|
||
|
||
// 角色配置器
|
||
public class CharacterBuilder
|
||
{
|
||
private CharacterData data;
|
||
private List<ICharacterComponent> components = new List<ICharacterComponent>();
|
||
|
||
public CharacterBuilder SetData(CharacterData data) { ... }
|
||
public CharacterBuilder AddComponent<T>() where T : ICharacterComponent { ... }
|
||
public ICharacter Build() { ... }
|
||
}
|
||
|
||
// 组件接口
|
||
public interface ICharacterComponent
|
||
{
|
||
void Initialize(ICharacter character);
|
||
void Update(float deltaTime);
|
||
void Cleanup();
|
||
}
|
||
```
|
||
|
||
#### 2.2 改进属性系统
|
||
**问题**: 当前属性使用字符串字典,缺少类型安全和IDE支持
|
||
|
||
**建议**:
|
||
```csharp
|
||
// 属性ID枚举
|
||
public enum AttributeId
|
||
{
|
||
// 基础属性
|
||
MaxHealth,
|
||
CurrentHealth,
|
||
MaxEnergy,
|
||
CurrentEnergy,
|
||
MovementSpeed,
|
||
AttackSpeed,
|
||
|
||
// 战斗属性
|
||
PhysicalAttack,
|
||
PhysicalDefense,
|
||
EnergyAttack,
|
||
EnergyDefense,
|
||
CriticalRate,
|
||
CriticalDamage,
|
||
|
||
// 抗性
|
||
FireResistance,
|
||
IceResistance,
|
||
LightningResistance,
|
||
|
||
// 特殊属性
|
||
LifeSteal,
|
||
CooldownReduction,
|
||
}
|
||
|
||
// 属性修饰器
|
||
public interface IAttributeModifier
|
||
{
|
||
int Priority { get; }
|
||
AttributeId TargetAttribute { get; }
|
||
float Modify(float originalValue);
|
||
}
|
||
|
||
// 属性计算器
|
||
public class AttributeCalculator
|
||
{
|
||
private List<IAttributeModifier> modifiers = new List<IAttributeModifier>();
|
||
|
||
public float Calculate(AttributeId attributeId, float baseValue)
|
||
{
|
||
var applicableModifiers = modifiers
|
||
.Where(m => m.TargetAttribute == attributeId)
|
||
.OrderBy(m => m.Priority);
|
||
|
||
float result = baseValue;
|
||
foreach (var modifier in applicableModifiers)
|
||
{
|
||
result = modifier.Modify(result);
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 战斗系统改进
|
||
|
||
#### 3.1 建立战斗配置系统
|
||
**问题**: 战斗参数硬编码,难以平衡调整
|
||
|
||
**建议**:
|
||
```csharp
|
||
[CreateAssetMenu(fileName = "BattleConfig", menuName = "Cielonos/Config/BattleConfig")]
|
||
public class BattleConfig : ScriptableObject
|
||
{
|
||
[Header("Damage Calculation")]
|
||
public float baseCriticalMultiplier = 1.5f;
|
||
public float maxCriticalMultiplier = 3.0f;
|
||
public float levelDamageBonus = 0.1f;
|
||
|
||
[Header("Breakthrough Thresholds")]
|
||
public float weakBreakthroughThreshold = 0.5f;
|
||
public float mediumBreakthroughThreshold = 0.75f;
|
||
public float heavyBreakthroughThreshold = 1.0f;
|
||
|
||
[Header("Hit Detection")]
|
||
public float hitstopDuration = 0.05f;
|
||
public float screenShakeIntensity = 0.1f;
|
||
|
||
[Header("Damage Numbers")]
|
||
public float damageNumberScale = 1.0f;
|
||
public float criticalScale = 1.5f;
|
||
public float damageNumberLifetime = 1.0f;
|
||
}
|
||
|
||
public class BattleConfigProvider
|
||
{
|
||
public static BattleConfig Config =>
|
||
Resources.Load<BattleConfig>("Config/BattleConfig");
|
||
}
|
||
```
|
||
|
||
#### 3.2 改进攻击判定系统
|
||
**问题**: AttackArea承担了过多职责
|
||
|
||
**建议**:
|
||
```csharp
|
||
// 攻击配置
|
||
[CreateAssetMenu(fileName = "AttackConfig", menuName = "Cielonos/Attack/AttackConfig")]
|
||
public class AttackConfig : ScriptableObject
|
||
{
|
||
public LayerMask targetLayers;
|
||
public float hitboxActiveDuration;
|
||
public Vector3 hitboxSize;
|
||
public Vector3 hitboxOffset;
|
||
public bool useRaycast;
|
||
public float raycastDistance;
|
||
}
|
||
|
||
// 命中结果
|
||
public struct HitResult
|
||
{
|
||
public ICharacter Target;
|
||
public Vector3 HitPoint;
|
||
public Vector3 HitNormal;
|
||
public bool IsCritical;
|
||
public float FinalDamage;
|
||
public DamageType DamageType;
|
||
}
|
||
|
||
// 命中事件
|
||
public class HitEventArgs : GameEventArgs
|
||
{
|
||
public HitResult HitResult { get; set; }
|
||
public ICharacter Attacker { get; set; }
|
||
}
|
||
```
|
||
|
||
### 4. 物品系统改进
|
||
|
||
#### 4.1 建立物品数据库
|
||
**问题**: 物品管理分散在各处
|
||
|
||
**建议**:
|
||
```csharp
|
||
[CreateAssetMenu(fileName = "ItemDatabase", menuName = "Cielonos/Items/Database")]
|
||
public class ItemDatabase : ScriptableObject
|
||
{
|
||
[SerializeField] private List<WeaponData> weapons = new List<WeaponData>();
|
||
[SerializeField] private List<ArmorData> armors = new List<ArmorData>();
|
||
[SerializeField] private List<ConsumableData> consumables = new List<ConsumableData>>();
|
||
|
||
public WeaponData GetWeapon(string id) => weapons.FirstOrDefault(w => w.Id == id);
|
||
public T GetItem<T>(string id) where T : ItemData
|
||
{
|
||
var field = typeof(ItemDatabase).GetField(typeof(T).Name.ToLower() + "s",
|
||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||
var list = field?.GetValue(this) as IEnumerable<ItemData>;
|
||
return list?.FirstOrDefault(i => i.Id == id) as T;
|
||
}
|
||
}
|
||
|
||
// 物品生成器
|
||
public static class ItemFactory
|
||
{
|
||
public static IItem Create(ItemData data, int level = 1)
|
||
{
|
||
return data switch
|
||
{
|
||
WeaponData weaponData => CreateWeapon(weaponData, level),
|
||
ArmorData armorData => CreateArmor(armorData, level),
|
||
ConsumableData consumableData => CreateConsumable(consumableData),
|
||
_ => throw new ArgumentException($"Unknown item type: {data.GetType()}")
|
||
};
|
||
}
|
||
|
||
private static Weapon CreateWeapon(WeaponData data, int level)
|
||
{
|
||
var weapon = new Weapon();
|
||
weapon.Initialize(data, level);
|
||
return weapon;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. AI系统改进
|
||
|
||
#### 5.1 建立AI配置系统
|
||
**问题**: AI行为硬编码,缺乏配置化
|
||
|
||
**建议**:
|
||
```csharp
|
||
[CreateAssetMenu(fileName = "AIConfig", menuName = "Cielonos/AI/AIConfig")]
|
||
public class AIConfig : ScriptableObject
|
||
{
|
||
[Header("Detection")]
|
||
public float detectionRange = 10f;
|
||
public float attackRange = 2f;
|
||
public float loseInterestRange = 20f;
|
||
|
||
[Header("Movement")]
|
||
public float preferredDistance = 5f;
|
||
public float strafeSpeed = 2f;
|
||
|
||
[Header("Decision Making")]
|
||
public float decisionInterval = 0.5f;
|
||
public float healthThresholdForRetreat = 0.3f;
|
||
public float energyThresholdForSpecial = 0.7f;
|
||
|
||
[Header("Behavior Weights")]
|
||
public float attackWeight = 1.0f;
|
||
public float defendWeight = 0.5f;
|
||
public float retreatWeight = 0.3f;
|
||
public float supportWeight = 0.4f;
|
||
}
|
||
|
||
[Serializable]
|
||
public class BehaviorState
|
||
{
|
||
public string stateName;
|
||
public BehaviorTree tree;
|
||
public List<Transition> transitions = new List<Transition>();
|
||
public float enterDelay;
|
||
}
|
||
|
||
[Serializable]
|
||
public class Transition
|
||
{
|
||
public string targetState;
|
||
public List<Condition> conditions = new List<Condition>();
|
||
}
|
||
|
||
[Serializable]
|
||
public abstract class Condition
|
||
{
|
||
public abstract bool Evaluate(IAIController controller);
|
||
}
|
||
```
|
||
|
||
### 6. 数据持久化改进
|
||
|
||
#### 6.1 建立游戏存档系统
|
||
**问题**: 缺乏统一的存档管理
|
||
|
||
**建议**:
|
||
```csharp
|
||
[System.Serializable]
|
||
public class GameSaveData
|
||
{
|
||
public string saveId;
|
||
public DateTime saveTime;
|
||
public int playerLevel;
|
||
public Vector3 playerPosition;
|
||
public List<ItemSaveData> inventory;
|
||
public List<string> unlockedAbilities;
|
||
public int currentZoneIndex;
|
||
public int currentScore;
|
||
public List<AchievementSaveData> achievements;
|
||
}
|
||
|
||
public interface ISaveSystem
|
||
{
|
||
void Save(GameSaveData data);
|
||
GameSaveData Load(string saveId);
|
||
List<string> GetAllSaves();
|
||
void DeleteSave(string saveId);
|
||
}
|
||
|
||
public class EasySaveAdapter : ISaveSystem
|
||
{
|
||
public void Save(GameSaveData data)
|
||
{
|
||
ES3.Save("save_" + data.saveId, data);
|
||
}
|
||
|
||
public GameSaveData Load(string saveId)
|
||
{
|
||
return ES3.Load<GameSaveData>("save_" + saveId);
|
||
}
|
||
|
||
public List<string> GetAllSaves()
|
||
{
|
||
// 实现保存文件列表获取
|
||
}
|
||
|
||
public void DeleteSave(string saveId)
|
||
{
|
||
ES3.DeleteKey("save_" + saveId);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 7. UI系统改进
|
||
|
||
#### 7.1 建立UI框架
|
||
**问题**: UI组件耦合度高,难以复用
|
||
|
||
**建议**:
|
||
```csharp
|
||
public abstract class UIScreen : MonoBehaviour
|
||
{
|
||
protected bool isVisible;
|
||
|
||
public virtual void Show()
|
||
{
|
||
gameObject.SetActive(true);
|
||
OnShow();
|
||
isVisible = true;
|
||
}
|
||
|
||
public virtual void Hide()
|
||
{
|
||
OnHide();
|
||
gameObject.SetActive(false);
|
||
isVisible = false;
|
||
}
|
||
|
||
protected abstract void OnShow();
|
||
protected abstract void OnHide();
|
||
}
|
||
|
||
public class UIManager
|
||
{
|
||
private Stack<UIScreen> screenStack = new Stack<UIScreen>();
|
||
|
||
public void ShowScreen<T>() where T : UIScreen
|
||
{
|
||
var screen = GetScreen<T>();
|
||
if (screen != null)
|
||
{
|
||
screen.Show();
|
||
screenStack.Push(screen);
|
||
}
|
||
}
|
||
|
||
public void CloseCurrentScreen()
|
||
{
|
||
if (screenStack.Count > 0)
|
||
{
|
||
var screen = screenStack.Pop();
|
||
screen.Hide();
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8. 代码规范与工具
|
||
|
||
#### 8.1 增加代码注释
|
||
**建议**: 在关键类和方法添加XML文档注释
|
||
```csharp
|
||
/// <summary>
|
||
/// 伤害信息结构体,包含所有与伤害计算相关的参数
|
||
/// </summary>
|
||
public struct DamageInfo
|
||
{
|
||
/// <summary>
|
||
/// 伤害来源
|
||
/// </summary>
|
||
public IDamageSource Source;
|
||
|
||
/// <summary>
|
||
/// 伤害值基数
|
||
/// </summary>
|
||
public float BaseDamage;
|
||
|
||
/// <summary>
|
||
/// 伤害类型
|
||
/// </summary>
|
||
public DamageType Type;
|
||
}
|
||
```
|
||
|
||
#### 8.2 建立自定义编辑器工具
|
||
**建议**: 为复杂系统创建编辑器窗口
|
||
```csharp
|
||
#if UNITY_EDITOR
|
||
public class CharacterEditorWindow : EditorWindow
|
||
{
|
||
[MenuItem("Cielonos/Character Editor")]
|
||
public static void OpenWindow()
|
||
{
|
||
GetWindow<CharacterEditorWindow>("Character Editor");
|
||
}
|
||
|
||
private void OnGUI()
|
||
{
|
||
// 创建角色编辑器UI
|
||
}
|
||
}
|
||
|
||
public class BuffEditorWindow : EditorWindow
|
||
{
|
||
[MenuItem("Cielonos/Buff Editor")]
|
||
public static void OpenWindow()
|
||
{
|
||
GetWindow<BuffEditorWindow>("Buff Editor");
|
||
}
|
||
}
|
||
#endif
|
||
```
|
||
|
||
---
|
||
|
||
## 三、改进优先级
|
||
|
||
### P0 - 必须改进(阻塞性问题)
|
||
1. 建立核心接口层
|
||
2. 改进属性系统类型安全
|
||
3. 建立消息总线
|
||
|
||
### P1 - 重要改进(核心功能)
|
||
1. 拆分CharacterBase
|
||
2. 建立战斗配置系统
|
||
3. 建立物品数据库
|
||
4. 建立AI配置系统
|
||
|
||
### P2 - 优化改进(提升开发效率)
|
||
1. 建立存档系统
|
||
2. 建立UI框架
|
||
3. 增加代码注释
|
||
4. 创建编辑器工具
|
||
|
||
### P3 - 长期改进(架构优化)
|
||
1. 服务定位器模式
|
||
2. 组件化重构
|
||
3. 配置化完善
|
||
|
||
---
|
||
|
||
## 四、总结
|
||
|
||
当前项目在架构上已经奠定了良好的基础,核心系统基本完备。要构建完善的Roguelike ARPG框架,重点需要:
|
||
|
||
1. **抽象接口层**: 建立清晰的接口边界,提高系统可测试性和可替换性
|
||
2. **配置驱动**: 将硬编码转为配置化,提高设计迭代效率
|
||
3. **数据管理**: 建立统一的数据管理系统,包括物品、敌人、AI等
|
||
4. **代码规范**: 增加注释和文档,提高代码可维护性
|
||
5. **工具支持**: 开发自定义编辑器工具,提高开发效率
|
||
|
||
---
|
||
|
||
*文档生成日期: 2026-04-17*
|
||
*生成者: Game Designer Agent*
|