refactor(fight): 重构战斗系统并添加技能限制效果

- 重构了战斗单位、技能、Effect等基础数据结构
- 新增技能类型和技能限制Effect
- 优化了战斗流程和状态机逻辑
- 调整了伤害计算方式和Buff处理机制
This commit is contained in:
2025-08-11 23:53:07 +08:00
parent b6ef625524
commit d89769731c

View File

@@ -7,19 +7,18 @@ import (
"time" "time"
) )
// ===== 战斗单位 ===== // ==== 基础数据结构 ====
type BattleUnit struct {
Name string
Level int
Atk int
Def int
MaxHP int
HP int
Buffs map[string]Effect
IsCritical bool
// 阻止增益buff标记 type BattleUnit struct {
PreventBuff bool Name string
Level int
Atk int
Def int
MaxHP int
HP int
Buffs map[string]Effect
IsCritical bool
} }
func NewBattleUnit(name string, level, atk, def, maxHP int) *BattleUnit { func NewBattleUnit(name string, level, atk, def, maxHP int) *BattleUnit {
@@ -34,158 +33,46 @@ func NewBattleUnit(name string, level, atk, def, maxHP int) *BattleUnit {
} }
} }
// ===== 事件接口及类型 ===== // ==== 技能类型 ====
type BattleEvent interface { const (
Type() string SkillTypePhysical SkillType = iota + 1
} SkillTypeSpecial
SkillTypeGrass
SkillTypeWater
SkillTypeFire
)
type SkillUseEvent struct { // ==== 战斗上下文 ====
Source *BattleUnit
Target *BattleUnit
IsAttack bool // 是否攻击技能
}
func (e SkillUseEvent) Type() string { return "SkillUse" }
// ===== 战斗上下文 =====
type BattleContext struct { type BattleContext struct {
Rand *rand.Rand Rand *rand.Rand
Events []BattleEvent
} }
// ===== Effect 接口 ===== // ==== 技能 ====
type Skill struct {
Name string
Type SkillType
Power int
IsAttack bool
Attacker *BattleUnit
Defender *BattleUnit
Effects []Effect
}
// ==== Effect接口 ====
type Effect interface { type Effect interface {
ID() string ID() string
Apply(attacker, defender *BattleUnit, ctx *BattleContext)
BeforeApplyBuff(attacker, defender *BattleUnit, skill *Skill, damageBuff *int, ctx *BattleContext)
AfterApplyBuff(skill *Skill, owner, target *BattleUnit, ownerDamage *int, targetDamage *int) error
Apply(owner, target *BattleUnit, ctx *BattleContext)
Next() bool Next() bool
} }
// ===== Effect实现 ===== // ==== 伤害计算 ====
// 1. n回合内每回合恢复自身已损失体力的50%
type RecoverLostHPEffect struct {
id string
Duration int
}
func (e *RecoverLostHPEffect) ID() string { return e.id }
func (e *RecoverLostHPEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) {
if e.Duration <= 0 {
return
}
lost := attacker.MaxHP - attacker.HP
heal := lost / 2
if heal < 1 {
heal = 1
}
attacker.HP += heal
if attacker.HP > attacker.MaxHP {
attacker.HP = attacker.MaxHP
}
fmt.Printf("[%s] 回合回复 %d 点已损失体力 (HP=%d)\n", attacker.Name, heal, attacker.HP)
}
func (e *RecoverLostHPEffect) Next() bool {
e.Duration--
return e.Duration > 0
}
// 2. 自身不处于能力强化状态时则YY能力变化示例攻击力+50
type ConditionalBuffEffect struct {
id string
Duration int
BuffState string // 需要检测的强化状态ID
Applied bool
ChangeFunc func(unit *BattleUnit)
UndoFunc func(unit *BattleUnit)
}
func (e *ConditionalBuffEffect) ID() string { return e.id }
func (e *ConditionalBuffEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) {
hasBuff := false
if _, ok := attacker.Buffs[e.BuffState]; ok {
hasBuff = true
}
if !hasBuff && !e.Applied {
if e.ChangeFunc != nil {
e.ChangeFunc(attacker)
}
e.Applied = true
fmt.Printf("[%s] 未处于强化状态,触发能力变化\n", attacker.Name)
} else if hasBuff && e.Applied {
if e.UndoFunc != nil {
e.UndoFunc(attacker)
}
e.Applied = false
fmt.Printf("[%s] 处于强化状态,撤销能力变化\n", attacker.Name)
}
}
func (e *ConditionalBuffEffect) Next() bool {
e.Duration--
if e.Duration <= 0 && e.Applied && e.UndoFunc != nil {
e.UndoFunc(nil) // 这里传nil简化逻辑正常应传unit
}
return e.Duration > 0
}
// 3. n回合内若对手使用攻击技能降低对手最大体力的1/m
type ReduceMaxHPOnAttackEffect struct {
id string
Duration int
M int
}
func (e *ReduceMaxHPOnAttackEffect) ID() string { return e.id }
func (e *ReduceMaxHPOnAttackEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) {
if e.Duration <= 0 {
return
}
for _, ev := range ctx.Events {
if ev.Type() == "SkillUse" {
su := ev.(SkillUseEvent)
if su.Source == defender && su.IsAttack {
reduce := defender.MaxHP / e.M
defender.MaxHP -= reduce
if defender.HP > defender.MaxHP {
defender.HP = defender.MaxHP
}
fmt.Printf("[%s] 使用攻击技能,被降低最大体力 %d (MaxHP=%d)\n", defender.Name, reduce, defender.MaxHP)
break
}
}
}
}
func (e *ReduceMaxHPOnAttackEffect) Next() bool {
e.Duration--
return e.Duration > 0
}
// 4. n回合对手无法使自身能力出现提升状态
type PreventEnemyBuffEffect struct {
id string
Duration int
}
func (e *PreventEnemyBuffEffect) ID() string { return e.id }
func (e *PreventEnemyBuffEffect) Apply(attacker, defender *BattleUnit, ctx *BattleContext) {
// 标记对手PreventBuff
defender.PreventBuff = true
fmt.Printf("[%s] 使对手 [%s] 无法获得能力提升状态\n", attacker.Name, defender.Name)
}
func (e *PreventEnemyBuffEffect) Next() bool {
e.Duration--
return e.Duration > 0
}
// ===== 伤害计算函数 =====
func CalculateDamage(attacker, defender *BattleUnit, power int, isCritical bool, r *rand.Rand) int { func CalculateDamage(attacker, defender *BattleUnit, power int, isCritical bool, r *rand.Rand) int {
randomFactor := float64(r.Intn(39)+217) / 255.0 randomFactor := float64(r.Intn(39)+217) / 255.0
@@ -204,33 +91,143 @@ func CalculateDamage(attacker, defender *BattleUnit, power int, isCritical bool,
return damage return damage
} }
// ===== 技能 ===== // ==== 具体 Effect 实现 ====
type Skill struct { // 1. 普通伤害Effect一次性或持续
Name string
Effects []Effect type DamageEffect struct {
IsAttack bool // 标记是否攻击技能 id string
power int
duration int
} }
func (s *Skill) Cast(attacker, defender *BattleUnit, ctx *BattleContext) { func (d *DamageEffect) ID() string { return d.id }
fmt.Printf("\n>>> %s 使用技能 [%s] <<<\n", attacker.Name, s.Name)
// 记录技能使用事件供Effect消费 func (d *DamageEffect) BeforeApplyBuff(attacker, defender *BattleUnit, skill *Skill, damageBuff *int, ctx *BattleContext) {
ctx.Events = append(ctx.Events, SkillUseEvent{ // 不做修改,示例留空
Source: attacker, }
Target: defender,
IsAttack: s.IsAttack,
})
for _, effect := range s.Effects { func (d *DamageEffect) AfterApplyBuff(skill *Skill, owner, target *BattleUnit, ownerDamage *int, targetDamage *int) error {
effect.Apply(attacker, defender, ctx) // 持续回合伤害:每回合额外加伤害
if defender.HP <= 0 { if d.duration > 0 {
break *targetDamage += d.power
}
return nil
}
func (d *DamageEffect) Apply(owner, target *BattleUnit, ctx *BattleContext) {
if d.duration > 0 {
target.HP -= d.power
if target.HP < 0 {
target.HP = 0
}
fmt.Printf("[%s] 持续伤害 %d 点,目标 %s 剩余HP %d\n", owner.Name, d.power, target.Name, target.HP)
}
}
func (d *DamageEffect) Next() bool {
d.duration--
return d.duration > 0
}
// 2. Boss限制技能类型Effect (参考Map60Boss0)
type SkillLimitEffect struct {
id string
duration int
allowedSkillType SkillType
}
func NewSkillLimitEffect(duration int) *SkillLimitEffect {
return &SkillLimitEffect{
id: "SkillLimitEffect",
duration: duration,
allowedSkillType: SkillTypeGrass, // 从草技能开始循环
}
}
func (s *SkillLimitEffect) ID() string { return s.id }
func (s *SkillLimitEffect) BeforeApplyBuff(attacker, defender *BattleUnit, skill *Skill, damageBuff *int, ctx *BattleContext) {
// 不处理
}
func (s *SkillLimitEffect) AfterApplyBuff(skill *Skill, owner, target *BattleUnit, ownerDamage *int, targetDamage *int) error {
if !skill.IsAttack {
return nil
}
if skill.Type != s.allowedSkillType {
*targetDamage = 0
fmt.Printf("[SkillLimitEffect] 技能类型不符,伤害清零。允许类型: %d本次类型: %d\n", s.allowedSkillType, skill.Type)
} else {
// 循环切换允许技能类型
s.allowedSkillType++
if s.allowedSkillType > SkillTypeFire {
s.allowedSkillType = SkillTypeGrass
}
fmt.Printf("[SkillLimitEffect] 技能类型符合,允许类型切换为 %d\n", s.allowedSkillType)
}
return nil
}
func (s *SkillLimitEffect) Apply(owner, target *BattleUnit, ctx *BattleContext) {
// 可做每回合特效,示例空实现
}
func (s *SkillLimitEffect) Next() bool {
s.duration--
return s.duration > 0
}
// ==== Buff管理器 ====
func ProcessBuffs(unit *BattleUnit, target *BattleUnit, ctx *BattleContext) {
for id, buff := range unit.Buffs {
buff.Apply(unit, target, ctx)
if !buff.Next() {
fmt.Printf("[%s] 的 Buff [%s] 已结束\n", unit.Name, id)
delete(unit.Buffs, id)
} }
} }
} }
// ===== 战斗状态机 ===== // ==== 技能释放 ====
func (s *Skill) Cast(ctx *BattleContext) {
fmt.Printf("\n%s 使用技能 [%s]\n", s.Attacker.Name, s.Name)
ownerDamage := CalculateDamage(s.Attacker, s.Defender, s.Power, s.Attacker.IsCritical, ctx.Rand)
targetDamage := ownerDamage
// 技能中各效果触发BeforeApplyBuff影响伤害前
for _, e := range s.Effects {
e.BeforeApplyBuff(s.Attacker, s.Defender, s, &ownerDamage, ctx)
}
// Buff触发AfterApplyBuff允许调整伤害
for _, buff := range s.Defender.Buffs {
buff.AfterApplyBuff(s, s.Defender, s.Attacker, &targetDamage, &targetDamage)
}
// 应用伤害
if targetDamage > 0 {
s.Defender.HP -= targetDamage
if s.Defender.HP < 0 {
s.Defender.HP = 0
}
fmt.Printf("%s 对 %s 造成 %d 伤害剩余HP %d\n", s.Attacker.Name, s.Defender.Name, targetDamage, s.Defender.HP)
} else {
fmt.Printf("%s 的攻击被完全抵消!\n", s.Attacker.Name)
}
// 技能自身Effects持续效果Apply
for _, e := range s.Effects {
e.Apply(s.Attacker, s.Defender, ctx)
}
}
// ==== 战斗状态机 ====
type BattleState int type BattleState int
@@ -256,113 +253,98 @@ func (fsm *BattleStateMachine) Next() {
} }
} }
// ===== Buff处理 ===== // ==== 战斗主流程示例 ====
func AddBuff(unit *BattleUnit, buff Effect) { func Test_main(t *testing.T) {
// 检查PreventBuff标志阻止增益buff
if unit.PreventBuff {
fmt.Printf("[%s] 被阻止获得buff [%s]\n", unit.Name, buff.ID())
return
}
unit.Buffs[buff.ID()] = buff
fmt.Printf("[%s] 获得buff [%s]\n", unit.Name, buff.ID())
}
func ProcessBuffs(unit *BattleUnit, target *BattleUnit, ctx *BattleContext) {
for id, buff := range unit.Buffs {
buff.Apply(unit, target, ctx)
if !buff.Next() {
fmt.Printf("[%s] 的buff [%s] 结束\n", unit.Name, id)
delete(unit.Buffs, id)
}
}
// 重置阻止buff标记每回合重新计算
unit.PreventBuff = false
}
// ===== 测试战斗流程 =====
func TestBattleSystem(t *testing.T) {
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
player := NewBattleUnit("雷伊", 100, 300, 200, 300) player := NewBattleUnit("雷伊", 100, 300, 200, 5000)
enemy := NewBattleUnit("盖亚", 100, 280, 220, 300) enemy := NewBattleUnit("Map60Boss", 100, 280, 220, 4800)
ctx := &BattleContext{Rand: r} ctx := &BattleContext{Rand: r}
return
// 玩家技能:普通攻击 + 附加恢复buff持续3回合) // 给Boss添加技能限制buff持续5回合)
playerSkill := &Skill{ enemy.Buffs["SkillLimit"] = NewSkillLimitEffect(5)
Name: "雷光闪",
Effects: []Effect{ // 定义技能
&RecoverLostHPEffect{id: "recover1", Duration: 3}, grassSkill := &Skill{
}, Name: "草之击",
Type: SkillTypeGrass,
Power: 100,
IsAttack: true, IsAttack: true,
} Attacker: player,
Defender: enemy,
// 敌人技能攻击并附加降低最大HP效果(持续2回合)
enemySkill := &Skill{
Name: "岩石猛击",
Effects: []Effect{ Effects: []Effect{
&ReduceMaxHPOnAttackEffect{id: "reduce_maxhp1", Duration: 2, M: 5}, &DamageEffect{id: "damage1", power: 200, duration: 0},
}, },
}
waterSkill := &Skill{
Name: "水之击",
Type: SkillTypeWater,
Power: 120,
IsAttack: true, IsAttack: true,
} Attacker: player,
Defender: enemy,
// 玩家添加阻止敌人增益buffbuff(持续2回合) Effects: []Effect{
preventBuff := &PreventEnemyBuffEffect{id: "prevent_buff1", Duration: 2} &DamageEffect{id: "damage2", power: 100, duration: 0},
AddBuff(player, preventBuff)
// 玩家添加条件能力变化buff (攻击力+50),不处于强化状态时生效
condBuff := &ConditionalBuffEffect{
id: "cond_buff1",
Duration: 5,
BuffState: "attack_up",
ChangeFunc: func(unit *BattleUnit) {
if unit != nil {
unit.Atk += 50
}
},
UndoFunc: func(unit *BattleUnit) {
if unit != nil {
unit.Atk -= 50
}
}, },
} }
AddBuff(player, condBuff)
fsm := &BattleStateMachine{State: StateStart} fsm := &BattleStateMachine{State: StateStart}
round := 1 round := 1
for player.HP > 0 && enemy.HP > 0 { for player.HP > 0 && enemy.HP > 0 && round <= 10 {
fmt.Printf("\n===== 回合 %d =====\n", round) fmt.Printf("\n===== 回合 %d =====\n", round)
ctx.Events = nil // 清空事件队列,准备本回合事件
switch fsm.State { switch fsm.State {
case StateStart: case StateStart:
fmt.Println("战斗开始!") fmt.Println("战斗开始!")
fsm.Next() fsm.Next()
case StatePlayerTurn: case StatePlayerTurn:
playerSkill.Cast(player, enemy, ctx) // 玩家随机选择草或水技能攻击Boss
if round%2 == 1 {
grassSkill.Attacker = player
grassSkill.Defender = enemy
grassSkill.Cast(ctx)
} else {
waterSkill.Attacker = player
waterSkill.Defender = enemy
waterSkill.Cast(ctx)
}
ProcessBuffs(player, enemy, ctx) ProcessBuffs(player, enemy, ctx)
ProcessBuffs(enemy, player, ctx) ProcessBuffs(enemy, player, ctx)
fsm.Next() fsm.Next()
case StateEnemyTurn: case StateEnemyTurn:
enemySkill.Cast(enemy, player, ctx) // Boss普通攻击玩家
bossSkill := &Skill{
Name: "Boss普通攻击",
Type: SkillTypePhysical,
Power: 90,
IsAttack: true,
Attacker: enemy,
Defender: player,
Effects: []Effect{&DamageEffect{id: "bossHit", power: 150, duration: 0}},
}
bossSkill.Cast(ctx)
ProcessBuffs(player, enemy, ctx) ProcessBuffs(player, enemy, ctx)
ProcessBuffs(enemy, player, ctx) ProcessBuffs(enemy, player, ctx)
fsm.Next() fsm.Next()
} }
if player.HP <= 0 || enemy.HP <= 0 { if player.HP == 0 {
fmt.Println("Boss胜利")
break
} else if enemy.HP == 0 {
fmt.Println("玩家胜利!")
break break
} }
round++ round++
} }
fmt.Println("\n=== 战斗结束 ===")
if player.HP > 0 {
fmt.Println("玩家胜利!")
} else {
fmt.Println("敌人胜利!")
}
} }