
1) 【一句话结论】:在《三国杀》卡牌战斗系统中,通过组件化设计(角色拆分为技能、状态、生命等自定义组件)与**状态机(状态模式)**结合,实现了技能冲突的动态处理,核心是解耦状态逻辑与行为逻辑,提升系统可维护性与扩展性。
2) 【原理/概念讲解】:老师口吻解释关键概念:
MonoBehaviour组件构成,如SkillComponent(处理技能触发逻辑)、StateComponent(管理当前战斗状态,如“准备阶段”“出牌阶段”)、HealthComponent(维护生命值)。类比:组件像乐高积木,可独立组装、替换,降低代码耦合,比如新增技能只需添加SkillComponent,无需修改其他组件。3) 【对比与适用场景】:
| 状态管理方式 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 手动状态管理 | 直接在脚本中处理状态切换(如if判断) | 代码耦合度高,状态逻辑分散 | 状态简单、交互少(如单状态游戏) | 状态复杂易出错,维护成本高 |
| 状态机(状态模式) | 封装状态行为,通过状态转换管理 | 解耦状态逻辑,可维护性强 | 状态复杂、交互频繁(如回合制战斗) | 需额外状态机类,初始化成本略高 |
4) 【示例】(伪代码展示组件与状态机协作,包含状态依赖和优先级调整):
// 状态机基类
public abstract class State
{
public abstract void Enter(Character character);
public abstract void Update(Character character);
public abstract void Exit(Character character);
}
// 技能组件
public class SkillComponent
{
public void TriggerSkill(Character character, Skill skill)
{
// 触发技能时,状态机切换到对应状态
character.StateMachine.ChangeState(new SkillExecutingState(skill));
}
}
// 状态机实现
public class CharacterStateMachine
{
private State currentState;
public void ChangeState(State newState)
{
if (currentState != null) currentState.Exit(character);
currentState = newState;
currentState.Enter(character);
}
public void Update() => currentState.Update(character);
}
// 技能执行状态(依赖状态转换条件)
public class SkillExecutingState : State
{
private Skill skill;
public SkillExecutingState(Skill skill) => this.skill = skill;
public override void Enter(Character character) => Debug.Log($"开始执行技能 {skill.Name}");
public override void Update(Character character)
{
skill.Execute(character);
CheckSkillConflict(character);
}
public override void Exit(Character character) => Debug.Log($"技能执行结束");
}
// 状态转换条件示例:技能执行状态不能直接切换到移动状态
public class MoveState : State
{
public override void Enter(Character character) => Debug.Log("进入移动状态");
public override void Update(Character character) => Debug.Log("移动中");
public override void Exit(Character character) => Debug.Log("移动结束");
}
// 技能冲突检查(动态优先级调整)
private void CheckSkillConflict(Character character)
{
var activeSkills = character.SkillComponent.GetActiveSkills();
foreach (var skill in activeSkills)
{
foreach (var otherSkill in activeSkills)
{
if (skill != otherSkill && skill.IsConflictingWith(otherSkill))
{
ResolveConflict(character, skill, otherSkill);
}
}
}
}
// 解决冲突(动态优先级:基础优先级 + 角色等级加成)
private void ResolveConflict(Character character, Skill skill1, Skill skill2)
{
int priority1 = skill1.BasePriority + character.Level * 2;
int priority2 = skill2.BasePriority + character.Level * 2;
if (priority1 > priority2)
{
skill2.Cancel();
Debug.Log($"技能 {skill2.Name} 因冲突被取消(优先级 {priority2} < {priority1})");
}
else
{
skill1.Cancel();
Debug.Log($"技能 {skill1.Name} 因冲突被取消(优先级 {priority1} < {priority2})");
}
}
5) 【面试口播版答案】:各位面试官好,我之前在《三国杀》项目中负责卡牌战斗系统开发。核心是通过组件化设计(角色由技能、状态、生命等组件构成)和状态机(状态模式)管理战斗流程。比如,每个角色有SkillComponent(处理技能触发)、StateComponent(管理当前状态,如“准备阶段”“出牌阶段”),状态机通过状态转换(如“准备阶段→出牌阶段”切换)控制流程。遇到的最大挑战是技能冲突处理,比如两个技能同时触发可能互相抵消。解决方案是设计冲突检测机制,通过技能的优先级(结合角色等级动态调整)判断,优先执行高优先级技能,低优先级技能被取消。比如,当“火攻”和“闪”同时触发,“火攻”优先级高,则“闪”被取消。整个设计解耦了状态逻辑与行为逻辑,方便后续扩展新技能或状态。
6) 【追问清单】:
SkillComponent和对应状态,状态机通过事件驱动,无需修改现有代码,维护成本低。7) 【常见坑/雷区】: