390 lines
8.6 KiB
Markdown
390 lines
8.6 KiB
Markdown
|
|
# 技能系统优化建议
|
||
|
|
|
||
|
|
## 1. 技能系统架构优化
|
||
|
|
|
||
|
|
### 1.1 当前问题
|
||
|
|
- 技能效果和表现耦合
|
||
|
|
- 技能配置管理复杂
|
||
|
|
- 技能判定性能问题
|
||
|
|
- 技能打断和状态管理
|
||
|
|
|
||
|
|
### 1.2 优化建议
|
||
|
|
|
||
|
|
1. 技能组件化系统:
|
||
|
|
```csharp
|
||
|
|
public abstract class SkillComponent
|
||
|
|
{
|
||
|
|
protected SkillData _skillData;
|
||
|
|
protected GameUnit _owner;
|
||
|
|
|
||
|
|
public virtual void Initialize(SkillData data, GameUnit owner)
|
||
|
|
{
|
||
|
|
_skillData = data;
|
||
|
|
_owner = owner;
|
||
|
|
}
|
||
|
|
|
||
|
|
public abstract UniTask Execute(SkillContext context);
|
||
|
|
}
|
||
|
|
|
||
|
|
public class SkillBuilder
|
||
|
|
{
|
||
|
|
private List<SkillComponent> _components = new();
|
||
|
|
private SkillData _skillData;
|
||
|
|
|
||
|
|
public SkillBuilder AddComponent<T>() where T : SkillComponent, new()
|
||
|
|
{
|
||
|
|
_components.Add(new T());
|
||
|
|
return this;
|
||
|
|
}
|
||
|
|
|
||
|
|
public Skill Build(GameUnit owner)
|
||
|
|
{
|
||
|
|
var skill = new Skill(_skillData);
|
||
|
|
foreach (var component in _components)
|
||
|
|
{
|
||
|
|
component.Initialize(_skillData, owner);
|
||
|
|
skill.AddComponent(component);
|
||
|
|
}
|
||
|
|
return skill;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
2. 技能效果分离:
|
||
|
|
```csharp
|
||
|
|
public class SkillEffect : SkillComponent
|
||
|
|
{
|
||
|
|
private List<IEffectModifier> _modifiers = new();
|
||
|
|
|
||
|
|
public override async UniTask Execute(SkillContext context)
|
||
|
|
{
|
||
|
|
var effect = CreateBaseEffect();
|
||
|
|
|
||
|
|
// 应用效果修饰器
|
||
|
|
foreach (var modifier in _modifiers)
|
||
|
|
{
|
||
|
|
effect = modifier.Modify(effect);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 应用效果
|
||
|
|
await ApplyEffect(effect, context);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public interface IEffectModifier
|
||
|
|
{
|
||
|
|
SkillEffectData Modify(SkillEffectData effect);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
3. 技能状态管理:
|
||
|
|
```csharp
|
||
|
|
public class SkillStateMachine
|
||
|
|
{
|
||
|
|
private Dictionary<Type, ISkillState> _states = new();
|
||
|
|
private ISkillState _currentState;
|
||
|
|
|
||
|
|
public async UniTask ChangeState<T>() where T : ISkillState
|
||
|
|
{
|
||
|
|
if (_currentState != null)
|
||
|
|
{
|
||
|
|
await _currentState.Exit();
|
||
|
|
}
|
||
|
|
|
||
|
|
_currentState = _states[typeof(T)];
|
||
|
|
await _currentState.Enter();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public interface ISkillState
|
||
|
|
{
|
||
|
|
UniTask Enter();
|
||
|
|
UniTask Update();
|
||
|
|
UniTask Exit();
|
||
|
|
bool CanInterrupt(SkillInterruptType type);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 2. 技能性能优化
|
||
|
|
|
||
|
|
### 2.1 区域判定优化:
|
||
|
|
```csharp
|
||
|
|
public class SkillAreaManager
|
||
|
|
{
|
||
|
|
private SpatialHashGrid _spatialHash;
|
||
|
|
|
||
|
|
public List<GameUnit> GetUnitsInSkillArea(SkillArea area)
|
||
|
|
{
|
||
|
|
var results = new List<GameUnit>();
|
||
|
|
|
||
|
|
// 使用空间哈希快速查找
|
||
|
|
var potentialUnits = _spatialHash.GetObjectsInArea(area.bounds);
|
||
|
|
|
||
|
|
// 精确判定
|
||
|
|
foreach (var unit in potentialUnits)
|
||
|
|
{
|
||
|
|
if (area.Contains(unit.position))
|
||
|
|
{
|
||
|
|
results.Add(unit);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return results;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public class SkillArea
|
||
|
|
{
|
||
|
|
public virtual bool Contains(Vector3 position)
|
||
|
|
{
|
||
|
|
// 基础形状判定
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public class CircleSkillArea : SkillArea
|
||
|
|
{
|
||
|
|
private float _radius;
|
||
|
|
private Vector3 _center;
|
||
|
|
|
||
|
|
public override bool Contains(Vector3 position)
|
||
|
|
{
|
||
|
|
return Vector3.Distance(_center, position) <= _radius;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.2 效果计算优化:
|
||
|
|
```csharp
|
||
|
|
public class SkillEffectCalculator
|
||
|
|
{
|
||
|
|
private struct EffectJob : IJobParallelFor
|
||
|
|
{
|
||
|
|
[ReadOnly] public NativeArray<float> baseValues;
|
||
|
|
[ReadOnly] public NativeArray<float> modifiers;
|
||
|
|
public NativeArray<float> results;
|
||
|
|
|
||
|
|
public void Execute(int index)
|
||
|
|
{
|
||
|
|
float value = baseValues[index];
|
||
|
|
float modifier = modifiers[index];
|
||
|
|
results[index] = CalculateEffect(value, modifier);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public async UniTask<NativeArray<float>> CalculateEffects(SkillEffect[] effects)
|
||
|
|
{
|
||
|
|
var job = new EffectJob
|
||
|
|
{
|
||
|
|
baseValues = new NativeArray<float>(effects.Length, Allocator.TempJob),
|
||
|
|
modifiers = new NativeArray<float>(effects.Length, Allocator.TempJob),
|
||
|
|
results = new NativeArray<float>(effects.Length, Allocator.TempJob)
|
||
|
|
};
|
||
|
|
|
||
|
|
var handle = job.Schedule(effects.Length, 64);
|
||
|
|
await handle.ToUniTask();
|
||
|
|
|
||
|
|
return job.results;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2.3 技能缓存系统:
|
||
|
|
```csharp
|
||
|
|
public class SkillCache
|
||
|
|
{
|
||
|
|
private Dictionary<int, SkillData> _skillDataCache = new();
|
||
|
|
private ObjectPool<SkillInstance> _skillInstancePool;
|
||
|
|
|
||
|
|
public SkillInstance GetSkillInstance(int skillId)
|
||
|
|
{
|
||
|
|
var instance = _skillInstancePool.Get();
|
||
|
|
var data = GetSkillData(skillId);
|
||
|
|
instance.Initialize(data);
|
||
|
|
return instance;
|
||
|
|
}
|
||
|
|
|
||
|
|
private SkillData GetSkillData(int skillId)
|
||
|
|
{
|
||
|
|
if (_skillDataCache.TryGetValue(skillId, out var data))
|
||
|
|
{
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
|
||
|
|
data = LoadSkillData(skillId);
|
||
|
|
_skillDataCache[skillId] = data;
|
||
|
|
return data;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 3. 技能表现优化
|
||
|
|
|
||
|
|
### 3.1 特效系统优化:
|
||
|
|
```csharp
|
||
|
|
public class SkillEffectManager
|
||
|
|
{
|
||
|
|
private Dictionary<string, Queue<ParticleSystem>> _effectPools = new();
|
||
|
|
|
||
|
|
public async UniTask<ParticleSystem> PlayEffect(string effectId, Vector3 position)
|
||
|
|
{
|
||
|
|
var effect = GetEffectFromPool(effectId);
|
||
|
|
effect.transform.position = position;
|
||
|
|
|
||
|
|
// 使用对象池管理特效
|
||
|
|
effect.Play();
|
||
|
|
|
||
|
|
// 等待特效完成
|
||
|
|
await UniTask.WaitUntil(() => !effect.isPlaying);
|
||
|
|
|
||
|
|
ReturnToPool(effectId, effect);
|
||
|
|
return effect;
|
||
|
|
}
|
||
|
|
|
||
|
|
private ParticleSystem GetEffectFromPool(string effectId)
|
||
|
|
{
|
||
|
|
if (!_effectPools.ContainsKey(effectId))
|
||
|
|
{
|
||
|
|
_effectPools[effectId] = new Queue<ParticleSystem>();
|
||
|
|
}
|
||
|
|
|
||
|
|
var pool = _effectPools[effectId];
|
||
|
|
if (pool.Count > 0)
|
||
|
|
{
|
||
|
|
return pool.Dequeue();
|
||
|
|
}
|
||
|
|
|
||
|
|
return CreateNewEffect(effectId);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 动画系统优化:
|
||
|
|
```csharp
|
||
|
|
public class SkillAnimationController
|
||
|
|
{
|
||
|
|
private AnimationEventReceiver _eventReceiver;
|
||
|
|
private Dictionary<string, AnimationClip> _clipCache = new();
|
||
|
|
|
||
|
|
public async UniTask PlaySkillAnimation(string animId, bool waitForComplete = true)
|
||
|
|
{
|
||
|
|
var clip = await LoadAnimationClip(animId);
|
||
|
|
|
||
|
|
// 使用动画事件优化同步点
|
||
|
|
var completion = new UniTaskCompletionSource();
|
||
|
|
_eventReceiver.OnAnimationComplete += () => completion.TrySetResult();
|
||
|
|
|
||
|
|
PlayAnimation(clip);
|
||
|
|
|
||
|
|
if (waitForComplete)
|
||
|
|
{
|
||
|
|
await completion.Task;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 4. 技能配置系统
|
||
|
|
|
||
|
|
### 4.1 配置数据结构:
|
||
|
|
```csharp
|
||
|
|
[CreateAssetMenu(fileName = "SkillConfig", menuName = "Game/Skill/Config")]
|
||
|
|
public class SkillConfigAsset : ScriptableObject
|
||
|
|
{
|
||
|
|
public List<SkillData> skills = new();
|
||
|
|
|
||
|
|
// 编辑器工具支持
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
public void ValidateConfig()
|
||
|
|
{
|
||
|
|
foreach (var skill in skills)
|
||
|
|
{
|
||
|
|
ValidateSkillData(skill);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
[System.Serializable]
|
||
|
|
public class SkillData
|
||
|
|
{
|
||
|
|
public int id;
|
||
|
|
public string name;
|
||
|
|
public List<SkillPhase> phases = new();
|
||
|
|
public List<SkillModifier> modifiers = new();
|
||
|
|
public SkillTargeting targeting;
|
||
|
|
public List<SkillEffect> effects = new();
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4.2 技能编辑工具:
|
||
|
|
```csharp
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
public class SkillEditorWindow : EditorWindow
|
||
|
|
{
|
||
|
|
private SkillConfigAsset _config;
|
||
|
|
private SerializedObject _serializedObject;
|
||
|
|
|
||
|
|
public static void ShowWindow()
|
||
|
|
{
|
||
|
|
GetWindow<SkillEditorWindow>("Skill Editor");
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnGUI()
|
||
|
|
{
|
||
|
|
if (_config == null)
|
||
|
|
{
|
||
|
|
DrawNullConfig();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
_serializedObject.Update();
|
||
|
|
DrawSkillList();
|
||
|
|
DrawSkillDetails();
|
||
|
|
_serializedObject.ApplyModifiedProperties();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
```
|
||
|
|
|
||
|
|
## 5. 建议改进方向
|
||
|
|
|
||
|
|
### 5.1 架构改进
|
||
|
|
1. 技能组件化
|
||
|
|
- 效果组件
|
||
|
|
- 条件组件
|
||
|
|
- 目标组件
|
||
|
|
|
||
|
|
2. 性能优化
|
||
|
|
- Job System优化判定
|
||
|
|
- 效果计算并行化
|
||
|
|
- 缓存系统优化
|
||
|
|
|
||
|
|
3. 工具链改进
|
||
|
|
- 可视化编辑器
|
||
|
|
- 技能预览工具
|
||
|
|
- 数值分析工具
|
||
|
|
|
||
|
|
### 5.2 功能扩展
|
||
|
|
1. 技能连击系统
|
||
|
|
2. 技能打断机制
|
||
|
|
3. 技能反馈系统
|
||
|
|
4. 技能成长系统
|
||
|
|
|
||
|
|
## 6. 注意事项
|
||
|
|
|
||
|
|
### 6.1 性能相关
|
||
|
|
- 控制技能特效数量
|
||
|
|
- 优化判定频率
|
||
|
|
- 合理使用对象池
|
||
|
|
|
||
|
|
### 6.2 gameplay相关
|
||
|
|
- 平衡技能效果
|
||
|
|
- 优化技能反馈
|
||
|
|
- 保证打击感
|
||
|
|
|
||
|
|
### 6.3 开发相关
|
||
|
|
- 完善技能编辑工具
|
||
|
|
- 规范配置流程
|
||
|
|
- 添加调试功能
|