为回合制RPG中的攻击添加冷却(Cooldown)功能
解决回合制RPG攻击冷却问题
你的思路方向是对的,但直接把攻击从敌人的攻击列表里移除会导致失去对这个攻击的引用,自然没法在冷却结束后加回去。更好的做法是让每个敌人独立跟踪自己的冷却中的攻击,而不是修改共享的Attack实例或者直接移除攻击列表项。下面是具体的修改方案:
核心思路调整
- 不要从
enemy.attacklist里移除攻击,而是给Enemy类增加一个冷却跟踪机制,记录哪些攻击正在冷却以及剩余回合数。 - 每个回合开始时,先更新所有冷却中的攻击的剩余时间,把冷却结束的攻击标记为可用。
- 敌人选择攻击时,只从当前可用的攻击(不在冷却中的)里挑选。
修改后的完整代码
import random class Class: def __init__(self, name, health, attacklist): self.name = name self.health = health self.attacklist = attacklist class Enemy: def __init__(self, name, health, attacklist): self.name = name self.health = health self.base_attacklist = attacklist # 保存原始攻击列表,用于冷却结束后恢复 self.cooldowns = {} # 格式:{Attack实例: 剩余冷却回合数} @property def available_attacks(self): # 返回当前可用的攻击(不在冷却中的) return [atk for atk in self.base_attacklist if atk not in self.cooldowns] class Attack: def __init__(self, name, base_damage, max_damage, healing, stun, chance, reduce_chance, cooldown): # 移除on_cooldown属性,因为冷却是敌人的状态,不是攻击本身的 self.name = name self.base_damage = base_damage self.max_damage = max_damage self.healing = healing self.stun = stun self.chance = chance self.reduce_chance = reduce_chance self.cooldown = cooldown # 初始化攻击 Punch = Attack("Punch", 50, 100, 0, "no_stun", 80, 0, 0) Stunner = Attack("Stunner", 20, 30, 0, "stun", 70, 0, 0) Bite = Attack("Bite", 30, 40, 0, "no_stun", 60, 0, 0) Scratch = Attack("Scratch", 20, 30, 0, "no_stun", 70, 0, 0) garbage_fling = Attack("Garbage Fling", 5, 10, 0, 0, 80, 20, 2) # 初始化职业和敌人 fighter_attacklist = [Punch, Stunner] vermen_dreg_attacklist = [Bite, Scratch] vermen_scrounger_attacklist = [garbage_fling, Bite] Fighter = Class("Fighter", 500, fighter_attacklist) vermen_dreg = Enemy("Vermen Dreg", 100, vermen_dreg_attacklist) vermen_scrounger = Enemy("Vermen Scrounger", 100, vermen_scrounger_attacklist) enemy_list = [vermen_scrounger] stun_cooldown = 0 while True: print("Choose your class: Fighter (1)") choice = input() if choice == "1": player_class = Fighter print("You have chosen:", player_class.name) enemy = random.choice(enemy_list) print("Your enemy is:", enemy.name) else: print("Error, invalid input!") continue while True: # 先处理敌人的冷却更新:每个回合开始时减少冷却时间,移除冷却结束的攻击 to_remove = [] for atk, remaining in enemy.cooldowns.items(): enemy.cooldowns[atk] = remaining - 1 if enemy.cooldowns[atk] <= 0: to_remove.append(atk) for atk in to_remove: del enemy.cooldowns[atk] print(f"{enemy.name}'s {atk.name} is ready to use again!") enemy_stunned = False print("Your health:", player_class.health) print("Enemy health:", enemy.health) # 玩家选择攻击 print("Attacks:", player_class.attacklist[0].name, "(1)", player_class.attacklist[1].name, "(2)") choice = input() if choice == "1": player_attack = player_class.attacklist[0] elif choice == "2": player_attack = player_class.attacklist[1] else: print("Please enter a valid number!") continue # 玩家攻击逻辑 diceroll = random.randint(1, 100) if diceroll <= player_attack.chance: player_damage = random.randint(player_attack.base_damage, player_attack.max_damage) if player_damage > 0: enemy.health -= player_damage print("You hit", enemy.name, "for", player_damage) if player_attack.stun == "stun": if stun_cooldown > 0: print("The enemy resisted your stun attempt!") else: print("You stunned the enemy.") enemy_stunned = True stun_cooldown = 3 player_healing = player_attack.healing player_class.health += player_healing if player_healing > 0: print("You healed for", player_healing) else: print("You missed!") # 检查敌人是否死亡 if enemy.health <= 0: print(f"You defeated {enemy.name}!") break # 敌人回合 if not enemy_stunned: # 从可用攻击中选择 if not enemy.available_attacks: print(f"{enemy.name} has no attacks available!") else: enemy_move = random.choice(enemy.available_attacks) diceroll = random.randint(1, 100) if diceroll <= enemy_move.chance: enemy_damage = random.randint(enemy_move.base_damage, enemy_move.max_damage) if enemy_damage > 0: player_class.health -= enemy_damage print(enemy.name, "hit you with", enemy_move.name, "for", enemy_damage) # 处理攻击的减益效果 reduce_chance = enemy_move.reduce_chance if reduce_chance > 0: for atk in player_class.attacklist: atk.chance = max(50, atk.chance - reduce_chance) print("Your attack chance was reduced by", reduce_chance) # 如果攻击有冷却,加入冷却字典 if enemy_move.cooldown > 0: enemy.cooldowns[enemy_move] = enemy_move.cooldown print(f"{enemy.name}'s {enemy_move.name} is now on cooldown for {enemy_move.cooldown} rounds!") else: print("The enemy attack missed!") else: print("The enemy was stunned and could not attack.") stun_cooldown -= 1 if stun_cooldown < 0: stun_cooldown = 0 # 检查玩家是否死亡 if player_class.health <= 0: print("You have been defeated!") break
关键修改点解释
Enemy类的改进:
- 添加了
base_attacklist保存原始攻击列表,避免丢失引用。 - 新增
cooldowns字典,跟踪每个正在冷却的攻击和剩余回合数。 - 用
available_attacks属性动态返回当前可用的攻击,不用修改原始列表。
- 添加了
Attack类的简化:移除了
on_cooldown属性,因为冷却属于敌人使用攻击后的状态,不是攻击本身的固有属性(多个敌人使用同一个攻击时,冷却应该各自独立)。冷却更新逻辑:每个回合开始时,遍历冷却字典减少剩余时间,把冷却结束的攻击从字典中移除,自动恢复可用状态。
敌人攻击选择:现在敌人只会从
available_attacks里选攻击,确保不会用到冷却中的技能。
这样修改后,Garbage Fling攻击在使用后会进入2回合冷却,冷却结束后会自动恢复可用,完美解决你的问题!
内容的提问来源于stack exchange,提问作者angryshibe13




