Unity3D ACT手游战斗系统深度设计与C#实现
基于ECS架构实现高性能碰撞检测使用动画事件驱动的精确战斗节奏控制模块化的技能取消和连击系统设计多层次的打击反馈体系(动画/物理/镜头/音效)引入机器学习实现智能敌人AI实现基于物理的布料和毛发模拟开发可视化连招编辑工具添加网络同步的预测回滚机制集成基于Wwise的3D空间音效系统建议开发者根据具体项目需求,结合DOTS技术栈优化大规模战斗场景,通过Shader Graph实现高级视觉效果,最终打
·
Unity3D ACT手游战斗系统深度设计与C#实现
一、ACT战斗系统核心特性
- 实时精确的碰撞检测(HitBox/HurtBox)
- 多段连击与技能取消机制
- 硬直/浮空/受击反馈状态系统
- 动态镜头震动与打击特效
- 帧精确的动画状态控制
二、战斗系统架构设计
1. 基于ECS的实体组件架构
// 实体组件定义
public struct HitBoxComponent : IComponentData {
public float3 Center;
public float Radius;
public Entity Owner;
public int DamageValue;
}
public struct HurtBoxComponent : IComponentData {
public float3 Center;
public float Radius;
public Entity Owner;
}
// 碰撞检测系统
public class HitDetectionSystem : SystemBase {
protected override void OnUpdate() {
Entities.WithAll<HitBoxComponent>().ForEach((Entity hitEntity, ref HitBoxComponent hitBox) => {
Entities.WithAll<HurtBoxComponent>().ForEach((Entity hurtEntity, ref HurtBoxComponent hurtBox) => {
if (hitBox.Owner != hurtBox.Owner &&
math.distance(hitBox.Center, hurtBox.Center) < hitBox.Radius + hurtBox.Radius) {
var damageEvent = new DamageEvent {
Attacker = hitBox.Owner,
Target = hurtBox.Owner,
Damage = hitBox.DamageValue
};
EntityManager.AddComponentData(hurtEntity, damageEvent);
}
}).Run();
}).Run();
}
}
2. 动态骨骼动画控制
public class WeaponTrailController : MonoBehaviour {
private List<Vector3> _trailPoints = new List<Vector3>();
private LineRenderer _lineRenderer;
private Transform[] _boneChain;
void Update() {
RecordTrailPoints();
UpdateTrailRenderer();
}
private void RecordTrailPoints() {
if (_boneChain == null) return;
_trailPoints.Clear();
foreach (var bone in _boneChain) {
_trailPoints.Add(bone.position);
}
}
private void UpdateTrailRenderer() {
_lineRenderer.positionCount = _trailPoints.Count;
_lineRenderer.SetPositions(_trailPoints.ToArray());
}
public void Initialize(Transform rootBone, int chainLength) {
_boneChain = new Transform[chainLength];
Transform current = rootBone;
for (int i = 0; i < chainLength; i++) {
_boneChain[i] = current;
current = current.parent;
}
}
}
三、连击系统实现
1. 连击状态机
public class ComboSystem : MonoBehaviour {
private int _currentComboStep;
private float _comboResetTimer;
private bool _canAcceptNextInput;
[System.Serializable]
public class ComboSequence {
public string AnimationState;
public float InputWindowStart;
public float InputWindowDuration;
public AttackType[] CancelableAttacks;
}
public ComboSequence[] comboSequence;
void Update() {
if (_currentComboStep > 0) {
_comboResetTimer -= Time.deltaTime;
if (_comboResetTimer <= 0) {
ResetCombo();
}
}
}
public void TryNextAttack(AttackType inputType) {
if (!_canAcceptNextInput) return;
var currentStep = comboSequence[_currentComboStep];
if (Array.Exists(currentStep.CancelableAttacks, t => t == inputType)) {
ExecuteAttack(inputType);
}
}
private void ExecuteAttack(AttackType type) {
_currentComboStep = (_currentComboStep + 1) % comboSequence.Length;
_comboResetTimer = comboSequence[_currentComboStep].InputWindowDuration;
_canAcceptNextInput = false;
StartCoroutine(OpenInputWindow(
comboSequence[_currentComboStep].InputWindowStart,
comboSequence[_currentComboStep].InputWindowDuration
));
}
private IEnumerator OpenInputWindow(float startTime, float duration) {
yield return new WaitForSeconds(startTime);
_canAcceptNextInput = true;
yield return new WaitForSeconds(duration);
_canAcceptNextInput = false;
}
}
2. 技能取消机制
public class AttackCancelController : MonoBehaviour {
private Dictionary<AttackState, AttackCancelRule> _cancelRules =
new Dictionary<AttackState, AttackCancelRule>();
public void RegisterCancelRule(AttackState fromState,
AttackType cancelType, AttackState toState) {
if (!_cancelRules.ContainsKey(fromState)) {
_cancelRules[fromState] = new AttackCancelRule();
}
_cancelRules[fromState].AddCancelOption(cancelType, toState);
}
public bool TryGetCancelState(AttackState currentState,
AttackType inputType, out AttackState nextState) {
if (_cancelRules.TryGetValue(currentState, out var rule)) {
return rule.TryGetCancelState(inputType, out nextState);
}
nextState = AttackState.None;
return false;
}
}
public class AttackCancelRule {
private Dictionary<AttackType, AttackState> _cancelMap =
new Dictionary<AttackType, AttackState>();
public void AddCancelOption(AttackType type, AttackState state) {
_cancelMap[type] = state;
}
public bool TryGetCancelState(AttackType type, out AttackState state) {
return _cancelMap.TryGetValue(type, out state);
}
}
四、打击反馈系统
1. 受击反应控制器
public class HitReactionController : MonoBehaviour {
private Animator _animator;
private Rigidbody _rigidbody;
private Coroutine _currentReaction;
[Header("Hit Reactions")]
public float hitStunDuration = 0.3f;
public float launchForce = 5f;
public AnimationCurve hitSlowCurve;
public void ProcessHit(HitDirection direction, HitIntensity intensity) {
if (_currentReaction != null) {
StopCoroutine(_currentReaction);
}
_currentReaction = StartCoroutine(HitReactionRoutine(direction, intensity));
}
private IEnumerator HitReactionRoutine(HitDirection dir, HitIntensity intensity) {
// 动画触发
_animator.SetTrigger(GetHitTriggerName(dir, intensity));
// 物理反馈
Vector3 force = GetForceDirection(dir) * intensity.Power;
_rigidbody.AddForce(force, ForceMode.VelocityChange);
// 时间扭曲
Time.timeScale = 0.2f;
yield return new WaitForSecondsRealtime(0.1f);
float timer = 0f;
while (timer < hitStunDuration) {
Time.timeScale = Mathf.Lerp(0.2f, 1f, hitSlowCurve.Evaluate(timer / hitStunDuration));
timer += Time.unscaledDeltaTime;
yield return null;
}
Time.timeScale = 1f;
}
private string GetHitTriggerName(HitDirection dir, HitIntensity intensity) {
return $"Hit_{dir.ToString()}_{intensity.ToString()}";
}
}
2. 动态镜头控制
public class CombatCameraController : MonoBehaviour {
private CinemachineVirtualCamera _virtualCam;
private CinemachineBasicMultiChannelPerlin _noiseModule;
private Coroutine _currentShake;
void Awake() {
_virtualCam = GetComponent<CinemachineVirtualCamera>();
_noiseModule = _virtualCam.GetCinemachineComponent<CinemachineBasicMultiChannelPerlin>();
}
public void TriggerCameraShake(ShakePreset preset) {
if (_currentShake != null) StopCoroutine(_currentShake);
_currentShake = StartCoroutine(ShakeRoutine(preset));
}
private IEnumerator ShakeRoutine(ShakePreset preset) {
_noiseModule.m_AmplitudeGain = preset.amplitude;
_noiseModule.m_FrequencyGain = preset.frequency;
float decayRate = preset.amplitude / preset.duration;
float remaining = preset.duration;
while (remaining > 0) {
_noiseModule.m_AmplitudeGain = Mathf.Lerp(0, preset.amplitude, remaining / preset.duration);
remaining -= Time.deltaTime;
yield return null;
}
_noiseModule.m_AmplitudeGain = 0;
_noiseModule.m_FrequencyGain = 0;
}
}
五、性能优化策略
1. 基于Job System的碰撞检测
[BurstCompile]
public struct HitDetectionJob : IJobParallelFor {
[ReadOnly] public NativeArray<HitBoxData> hitBoxes;
[ReadOnly] public NativeArray<HurtBoxData> hurtBoxes;
public NativeQueue<DamageEvent>.ParallelWriter damageEvents;
public void Execute(int index) {
var hitBox = hitBoxes[index];
foreach (var hurtBox in hurtBoxes) {
if (hitBox.owner != hurtBox.owner &&
math.distance(hitBox.position, hurtBox.position) < hitBox.radius + hurtBox.radius) {
damageEvents.Enqueue(new DamageEvent {
attacker = hitBox.owner,
target = hurtBox.owner,
damage = hitBox.damage
});
}
}
}
}
2. 动画事件优化
public class AnimationEventOptimizer : MonoBehaviour {
private Dictionary<string, AnimationEvent[]> _cachedEvents =
new Dictionary<string, AnimationEvent[]>();
public void PrecacheAnimationEvents(Animator animator) {
foreach (var clip in animator.runtimeAnimatorController.animationClips) {
_cachedEvents[clip.name] = clip.events;
clip.events = OptimizeEvents(clip.events);
}
}
private AnimationEvent[] OptimizeEvents(AnimationEvent[] original) {
List<AnimationEvent> optimized = new List<AnimationEvent>();
foreach (var evt in original) {
if (evt.functionName.StartsWith("Combat/")) {
optimized.Add(evt);
}
}
return optimized.ToArray();
}
public void DispatchAnimationEvent(string eventPath) {
var parts = eventPath.Split('/');
string systemName = parts[1];
string methodName = parts[2];
switch (systemName) {
case "HitBox":
CombatSystem.Instance.HitBoxSystem.Invoke(methodName, 0);
break;
case "Camera":
CameraSystem.Instance.Invoke(methodName, 0);
break;
}
}
}
六、进阶扩展方向
- 精确的输入缓冲系统:
public class InputBufferSystem : MonoBehaviour {
private Queue<BufferedInput> _inputQueue = new Queue<BufferedInput>();
private float _bufferWindow = 0.15f;
void Update() {
ProcessExpiredInputs();
}
public void BufferInput(InputType type) {
_inputQueue.Enqueue(new BufferedInput {
type = type,
expireTime = Time.time + _bufferWindow
});
}
public bool TryConsumeInput(InputType type) {
foreach (var input in _inputQueue) {
if (input.type == type && Time.time <= input.expireTime) {
_inputQueue.Clear();
return true;
}
}
return false;
}
private void ProcessExpiredInputs() {
while (_inputQueue.Count > 0 &&
_inputQueue.Peek().expireTime < Time.time) {
_inputQueue.Dequeue();
}
}
}
- 动态物理材质控制:
public class PhysicsMaterialController : MonoBehaviour {
private Dictionary<Collider, PhysicMaterial> _originalMaterials =
new Dictionary<Collider, PhysicMaterial>();
public void ApplyTemporaryMaterial(Collider collider,
PhysicMaterial material, float duration) {
StartCoroutine(MaterialRoutine(collider, material, duration));
}
private IEnumerator MaterialRoutine(Collider collider,
PhysicMaterial material, float duration) {
if (!_originalMaterials.ContainsKey(collider)) {
_originalMaterials[collider] = collider.material;
}
collider.material = material;
yield return new WaitForSeconds(duration);
collider.material = _originalMaterials[collider];
}
}
七、总结与展望
本战斗系统实现方案具有以下核心优势:
- 基于ECS架构实现高性能碰撞检测
- 使用动画事件驱动的精确战斗节奏控制
- 模块化的技能取消和连击系统设计
- 多层次的打击反馈体系(动画/物理/镜头/音效)
未来优化方向:
- 引入机器学习实现智能敌人AI
- 实现基于物理的布料和毛发模拟
- 开发可视化连招编辑工具
- 添加网络同步的预测回滚机制
- 集成基于Wwise的3D空间音效系统
建议开发者根据具体项目需求,结合DOTS技术栈优化大规模战斗场景,通过Shader Graph实现高级视觉效果,最终打造出具备主机级品质的移动端ACT战斗体验。
更多推荐




所有评论(0)