# Python实战:用代码还原LOL英雄技能机制(艾瑞莉娅篇)
如果你既是一名《英雄联盟》的忠实玩家,又对Python编程充满兴趣,那么这篇文章就是为你准备的。我们不再满足于在召唤师峡谷中操作英雄,而是要深入代码层面,去理解那些令人着迷的技能机制是如何被设计和实现的。今天,我们将聚焦于一位极具操作美感的英雄——刀锋舞者 艾瑞莉娅。通过Python代码,我们将亲手“锻造”她的利刃,从被动的层数管理,到Q技能的刷新逻辑,再到W的减伤与蓄力,一步步拆解其核心玩法。这不仅仅是一次编程练习,更是一次从玩家视角到设计者思维的转变,让你在理解游戏底层逻辑的同时,掌握面向对象设计、状态管理等实用的编程技巧。无论你是想用代码复现心爱英雄的玩家,还是希望学习如何将复杂规则转化为清晰逻辑的开发者,这里都有你想要的。
## 1. 项目构思与核心机制解析
在动手敲代码之前,我们必须先吃透艾瑞莉娅的技能机制。她的魅力在于技能间的精妙联动,而非孤立的伤害数字。我们的目标不是简单地复制游戏数据,而是用代码构建一个可运行、可测试的技能系统原型。
艾瑞莉娅的核心玩法围绕“艾欧尼亚热诚”层数和“利刃冲击”的刷新机制展开。被动技能在命中技能后叠加层数,提供攻击速度,并在满层时附加魔法伤害。Q技能则是一个典型的状态依赖型技能:如果目标已被标记(例如被E或R命中)或被Q技能击杀,则冷却时间立即重置。这种“刷新”机制是她飘逸灵动、连续位移的关键。
为了实现这些,我们需要思考几个编程层面的核心问题:
* **状态管理**:如何优雅地管理被动层数及其持续时间?层数何时增加、何时刷新、何时消失?
* **事件驱动**:技能命中、普攻命中、目标死亡等事件如何触发被动的变化和Q技能的刷新?
* **伤害计算**:如何根据英雄等级、攻击力、法强等属性,动态计算不同技能的基础伤害、加成伤害和特效(如治疗)?
* **对象交互**:英雄、技能、目标(敌方英雄、小兵、野怪)之间如何传递信息?一个技能释放后,如何影响多个对象的状态?
我们将采用面向对象编程(OOP)的方式来构建这个世界。每个英雄、每个技能甚至每个效果都可以是一个对象,它们通过定义好的接口进行交互。这样做的好处是代码结构清晰,易于扩展和维护。例如,我们完全可以基于这套框架,后续轻松加入亚索、劫等其他英雄。
> 注意:本文的代码实现旨在揭示核心逻辑与编程思想,是一个简化版的模拟。真实的游戏客户端涉及复杂的网络同步、碰撞检测、动画和渲染,其复杂度远超此范畴。
## 2. 构建基础:英雄类与目标类
任何战斗都发生在主体(英雄)与客体(目标)之间。我们首先搭建这两个最基础的类,为后续的技能系统奠定地基。
### 2.1 目标类 (Target)
目标是技能释放的对象,它拥有一些最基本的属性,并能接收伤害。
```python
class Target:
"""模拟游戏中的一个可被攻击的目标(英雄、小兵、野怪)。"""
def __init__(self, name, max_health, armor=0, magic_resist=0, target_type="minion"):
"""
初始化一个目标。
:param name: 目标名称
:param max_health: 最大生命值
:param armor: 护甲值
:param magic_resist: 魔法抗性
:param target_type: 目标类型 ('champion', 'minion', 'large_monster')
"""
self.name = name
self.max_health = max_health
self.current_health = max_health
self.armor = armor
self.magic_resist = magic_resist
self.type = target_type # 用于区分技能触发逻辑
self.is_marked = False # 是否被艾瑞莉娅的E或R标记
self.mark_duration = 0 # 标记剩余时间
def is_alive(self):
"""判断目标是否存活。"""
return self.current_health > 0
def take_damage(self, damage, damage_type="physical"):
"""
承受伤害。
:param damage: 原始伤害值
:param damage_type: 伤害类型 ('physical', 'magic', 'true')
:return: 实际造成的伤害值
"""
if not self.is_alive():
return 0
if damage_type == "physical":
# 护甲减伤公式简化版:实际伤害 = 原始伤害 * (100 / (100 + 护甲))
actual_damage = damage * (100 / (100 + self.armor))
elif damage_type == "magic":
# 魔抗减伤公式
actual_damage = damage * (100 / (100 + self.magic_resist))
else: # 真实伤害
actual_damage = damage
actual_damage = round(actual_damage)
self.current_health -= actual_damage
print(f"{self.name} 受到 {actual_damage} 点{damage_type}伤害,剩余生命值:{max(self.current_health, 0)}")
return actual_damage
def apply_mark(self, duration):
"""被艾瑞莉娅的E或R技能标记。"""
self.is_marked = True
self.mark_duration = duration
print(f"{self.name} 被标记,持续 {duration} 秒。")
def update_status(self, delta_time):
"""更新状态,例如标记持续时间。"""
if self.is_marked:
self.mark_duration -= delta_time
if self.mark_duration <= 0:
self.is_marked = False
print(f"{self.name} 身上的标记已消失。")
```
这个`Target`类封装了目标的通用行为。`take_damage`方法处理了不同类型的伤害计算,这是MOBA游戏伤害系统的核心。`apply_mark`和`update_status`方法则为后续实现艾瑞莉娅的联动机制做好了准备。
### 2.2 英雄基类与艾瑞莉娅类 (Irelia)
接下来,我们创建英雄的基类,并由此派生出艾瑞莉娅类。英雄类需要管理自身属性、技能和状态。
```python
class Champion:
"""英雄基类,定义通用属性和方法。"""
def __init__(self, name, level=1, attack_damage=0, ability_power=0):
self.name = name
self.level = level
self.attack_damage = attack_damage # AD
self.ability_power = ability_power # AP
self.max_health = 0 # 由子类定义
self.current_health = 0
self.attack_speed = 0.0 # 基础攻速
# 技能实例将在子类中初始化
self.passive = None
self.q_skill = None
self.w_skill = None
self.e_skill = None
self.r_skill = None
def basic_attack(self, target):
"""执行一次普通攻击。"""
if not target.is_alive():
print(f"{target.name} 已死亡,无法攻击。")
return
damage_dealt = target.take_damage(self.attack_damage, "physical")
print(f"{self.name} 普通攻击了 {target.name}。")
# 触发与普攻相关的效果(例如被动层数刷新)
if self.passive:
self.passive.on_basic_attack(target)
return damage_dealt
class Irelia(Champion):
"""刀锋舞者 艾瑞莉娅"""
def __init__(self, level=1, attack_damage=70, ability_power=0):
super().__init__("艾瑞莉娅", level, attack_damage, ability_power)
self.max_health = 590 + (level - 1) * 95 # 简化成长公式
self.current_health = self.max_health
self.attack_speed = 0.625 # 基础攻速
# 初始化所有技能
self.passive = IonianFervor(self) # 被动
self.q_skill = Bladesurge(self) # Q
self.w_skill = DefiantDance(self) # W
self.e_skill = FlawlessDuet(self) # E
self.r_skill = VanguardEdge(self) # R
def cast_q(self, target):
"""玩家调用:释放Q技能。"""
return self.q_skill.cast(target)
def cast_w(self, charge_time):
"""玩家调用:释放W技能。"""
return self.w_skill.cast(charge_time)
def cast_e(self, first_pos, second_pos, enemy_list):
"""玩家调用:释放E技能。"""
return self.e_skill.cast(first_pos, second_pos, enemy_list)
def cast_r(self, direction_vector, enemy_list):
"""玩家调用:释放R技能。"""
return self.r_skill.cast(direction_vector, enemy_list)
def update(self, delta_time):
"""更新英雄和所有技能的内部状态(如冷却、标记持续时间)。"""
self.q_skill.cooldown_tick(delta_time)
self.w_skill.cooldown_tick(delta_time)
self.e_skill.cooldown_tick(delta_time)
self.r_skill.cooldown_tick(delta_time)
self.passive.update(delta_time)
# 更新E/R技能施加的标记
for skill in [self.e_skill, self.r_skill]:
skill.update_marks(delta_time)
```
在`Irelia`类中,我们将英雄属性(如根据等级成长的生命值)和四个技能实例进行了初始化。`update`方法模拟了游戏每帧(或每个时间片段)的逻辑更新,这是实现冷却缩减、状态持续等效果的关键。现在,舞台已经搭好,主角即将登场。
## 3. 核心机制实现:被动与Q技能
艾瑞莉娅的飘逸身法,根基在于被动“艾欧尼亚热诚”和Q技能“利刃冲击”的完美配合。我们用代码来诠释这种艺术。
### 3.1 被动技能:艾欧尼亚热诚 (IonianFervor)
被动的核心是层数管理。我们需要一个计数器,以及管理其增加、刷新和消失的逻辑。
```python
class IonianFervor:
"""被动技能:艾欧尼亚热诚"""
def __init__(self, irelia_instance):
self.irelia = irelia_instance # 持有英雄实例的引用,以便获取等级等属性
self.stacks = 0
self.max_stacks = 4
self.duration = 6.0 # 层数持续时间
self.time_since_last_stack = 0.0 # 距离上次获得层数的时间
def on_ability_hit(self, target_type):
"""
当技能命中敌人时调用。
:param target_type: 目标类型 ('champion', 'large_monster', 'minion')
"""
old_stacks = self.stacks
if target_type == 'champion' or target_type == 'large_monster':
# 命中英雄或大型野怪,获得1层并刷新所有层数持续时间
self.stacks = min(self.stacks + 1, self.max_stacks)
self.time_since_last_stack = 0.0
print(f"命中{target_type},被动层数:{old_stacks} -> {self.stacks},持续时间刷新。")
elif target_type == 'minion' and self.stacks == 0:
# 仅当层数为0时,命中小兵可获得1层
self.stacks = 1
self.time_since_last_stack = 0.0
print(f"命中小兵,获得第1层被动。")
# 命中小兵但已有层数时,不获得也不刷新
def on_basic_attack(self, target):
"""当普通攻击命中英雄或大型野怪时,刷新层数持续时间。"""
if target.type in ['champion', 'large_monster'] and self.stacks > 0:
self.time_since_last_stack = 0.0
# print(f"普攻命中{target.type},刷新被动持续时间。")
def update(self, delta_time):
"""更新层数状态。"""
if self.stacks > 0:
self.time_since_last_stack += delta_time
if self.time_since_last_stack >= self.duration:
self.stacks = 0
self.time_since_last_stack = 0.0
print("被动层数已消失。")
def get_attack_speed_bonus(self):
"""获取当前层数提供的攻击速度加成百分比。"""
# 攻击速度加成随等级变化:1-6级(7.5%),7-12级(13.75%),13-18级(20%)
level = self.irelia.level
if level <= 6:
bonus_per_stack = 0.075
elif level <= 12:
bonus_per_stack = 0.1375
else:
bonus_per_stack = 0.20
return self.stacks * bonus_per_stack
def get_on_hit_magic_damage(self):
"""获取满层时普攻附带的额外魔法伤害。"""
if self.stacks < self.max_stacks:
return 0
# 基础伤害:10 + (等级-1)*3
base_damage = 10 + (self.irelia.level - 1) * 3
# 附加20%额外攻击力的魔法伤害
bonus_damage = self.irelia.attack_damage * 0.20
return base_damage + bonus_damage
```
这个类清晰地定义了被动的所有规则:`on_ability_hit`处理技能命中逻辑,`on_basic_attack`处理普攻刷新,`update`负责倒计时和层数消失。`get_attack_speed_bonus`和`get_on_hit_magic_damage`则提供了属性查询接口。这种设计将数据(层数、时间)和行为(命中、刷新、查询)封装在一起,非常清晰。
### 3.2 Q技能:利刃冲击 (Bladesurge)
Q技能是艾瑞莉娅的灵魂,其刷新机制是代码实现的重点。
```python
class Bladesurge:
"""Q技能:利刃冲击"""
def __init__(self, irelia_instance):
self.irelia = irelia_instance
self.cooldown = 0.0
self.base_cooldown = 12.0 # 初始冷却
self.level = 1
self.damage_values = [55, 75, 95, 115, 135] # 1-5级基础伤害
self.heal_ratio = [0.09, 0.10, 0.11, 0.12, 0.13] # 1-5级攻击力治疗比例
def level_up(self):
"""升级Q技能。"""
if self.level < 5:
self.level += 1
print(f"Q技能升级至 {self.level} 级。")
def get_damage(self):
"""获取当前等级的技能基础伤害。"""
return self.damage_values[self.level - 1]
def get_heal_amount(self):
"""获取基于攻击力的治疗量。"""
return self.irelia.attack_damage * self.heal_ratio[self.level - 1]
def cast(self, target):
"""
释放Q技能。
:param target: Target对象
:return: 是否刷新了冷却
"""
if self.cooldown > 0:
print(f"Q技能冷却中,剩余 {self.cooldown:.1f} 秒。")
return False
if not target.is_alive():
print("目标已死亡,无法释放Q技能。")
return False
# 计算伤害并施加
damage = self.get_damage()
actual_damage = target.take_damage(damage, "physical")
print(f"{self.irelia.name} 对 {target.name} 使用了利刃冲击!")
# 计算治疗(实际应对英雄或大型野怪生效,此处简化)
if target.type in ['champion', 'large_monster']:
heal = self.get_heal_amount()
self.irelia.current_health = min(self.irelia.max_health, self.irelia.current_health + heal)
print(f" 治疗了 {heal:.1f} 点生命值。")
# 触发被动:技能命中
self.irelia.passive.on_ability_hit(target.type)
# 判断是否刷新冷却:目标被标记 或 被此技能击杀
refresh_cd = False
if target.is_marked or not target.is_alive():
self.cooldown = 0.0
refresh_cd = True
print(" Q技能冷却已刷新!")
else:
self.cooldown = self.base_cooldown # 进入完整冷却
# 如果击杀了目标,触发额外的被动层数逻辑(例如,击杀小兵刷新Q)
# 此处已通过 `not target.is_alive()` 条件处理
return refresh_cd
def cooldown_tick(self, delta_time):
"""减少冷却时间。"""
if self.cooldown > 0:
self.cooldown = max(0, self.cooldown - delta_time)
```
`cast`方法是核心。它按顺序处理了:冷却检查、伤害计算与施加、治疗生效、触发被动层数,最后是关键逻辑——**判断是否刷新冷却**。这个判断条件(`target.is_marked or not target.is_alive()`)完美还原了游戏内的机制。`cooldown_tick`方法则与英雄类的`update`方法联动,实现了冷却时间的自然流逝。
为了更直观地对比Q技能在不同条件下的行为,我们可以用下表总结:
| 释放条件 | 目标状态 | 冷却结果 | 说明 |
| :--- | :--- | :--- | :--- |
| 技能可用 | 存活,未被标记 | 进入完整冷却 | 常规情况,Q进入CD |
| 技能可用 | 存活,**已被标记** | **立即刷新** | 利用E/R先手标记,实现连续位移 |
| 技能可用 | **被此Q击杀** | **立即刷新** | 利用Q收掉残血小兵,实现“踏前斩” |
| 技能冷却中 | 任何状态 | 无法释放 | 需等待CD结束 |
## 4. 进阶技能实现:W、E与R技能
掌握了核心联动后,我们来实现艾瑞莉娅的另外三个技能。它们同样包含独特的机制,是检验我们代码设计灵活性的好机会。
### 4.1 W技能:距破之舞 (DefiantDance)
W技能是一个两段式技能:第一段蓄力减伤,第二段释放伤害。蓄力时间越长,伤害越高。
```python
class DefiantDance:
"""W技能:距破之舞"""
def __init__(self, irelia_instance):
self.irelia = irelia_instance
self.cooldown = 0.0
self.base_cooldown = 16.0
self.level = 1
self.is_charging = False
self.charge_start_time = 0.0
self.charge_duration = 0.0
# 技能数据
self.damage_reduction = 0.50 # 基础50%物理伤害减免
self.ap_scaling_reduction = 0.001 # 每100AP提供10%额外减伤 (0.1/100)
self.base_damage = [10, 25, 40, 55, 70]
self.ad_ratio = 0.5
self.ap_ratio = 0.4
def start_charge(self, current_time):
"""开始蓄力(第一段W)。"""
if self.cooldown > 0:
print("W技能冷却中。")
return False
self.is_charging = True
self.charge_start_time = current_time
print(f"{self.irelia.name} 开始为利刃蓄力,获得伤害减免。")
return True
def release(self, current_time):
"""
释放蓄力伤害(第二段W)。
:param current_time: 当前游戏时间
:return: 造成的伤害值
"""
if not self.is_charging:
print("错误:尚未开始蓄力。")
return 0
self.charge_duration = current_time - self.charge_start_time
self.is_charging = False
self.cooldown = self.base_cooldown
# 计算基础伤害
base_dmg = self.base_damage[self.level - 1]
total_damage = base_dmg + (self.irelia.attack_damage * self.ad_ratio) + (self.irelia.ability_power * self.ap_ratio)
# 计算蓄力加成:每0.075秒增加10%伤害,最高100%
charge_bonus_multiplier = min(self.charge_duration / 0.075 * 0.1, 1.0)
final_damage = total_damage * (1 + charge_bonus_multiplier)
print(f"释放蓄力攻击!蓄力时间:{self.charge_duration:.3f}秒")
print(f" 造成 {final_damage:.1f} 点物理伤害(基础:{total_damage:.1f},蓄力加成:{charge_bonus_multiplier*100:.0f}%)。")
return final_damage # 注意:实际需要将此伤害作用于一个目标
def get_damage_reduction(self):
"""获取当前的物理伤害减免百分比。"""
ap_bonus = (self.irelia.ability_power // 100) * 0.1
return min(self.damage_reduction + ap_bonus, 0.80) # 假设上限为80%
def cooldown_tick(self, delta_time):
if self.cooldown > 0:
self.cooldown = max(0, self.cooldown - delta_time)
```
W技能的实现引入了“时间”维度。`start_charge`和`release`方法模拟了玩家的操作序列。伤害计算中,`charge_bonus_multiplier`的算法是亮点,它用一行代码就表达了“线性增长,存在上限”的常见游戏数值设计。`get_damage_reduction`方法则展示了如何根据英雄属性(AP)动态计算技能效果。
### 4.2 E技能:比翼双刃 (FlawlessDuet) 与 R技能:先锋之刃 (Vanguard‘s Edge)
E和R技能都涉及范围效果和标记机制。它们的实现会共享一些逻辑,比如“标记”目标。我们先定义一个简单的标记管理器。
```python
class MarkManager:
"""简单的标记管理器,用于E和R技能。"""
def __init__(self):
self.marked_targets = {} # {target_id: remaining_time}
def apply_mark(self, target, duration):
"""标记一个目标。"""
# 假设target有一个唯一id属性,这里用名字简化
target.apply_mark(duration)
self.marked_targets[target.name] = duration
def update_marks(self, delta_time):
"""更新所有标记的剩余时间。"""
expired = []
for target_name, time_left in list(self.marked_targets.items()):
new_time = time_left - delta_time
if new_time <= 0:
expired.append(target_name)
del self.marked_targets[target_name]
else:
self.marked_targets[target_name] = new_time
return expired
```
接着,我们实现E技能。E技能需要放置两片刀刃,并在第二片放置时触发伤害和眩晕。
```python
class FlawlessDuet:
"""E技能:比翼双刃"""
def __init__(self, irelia_instance):
self.irelia = irelia_instance
self.cooldown = 0.0
self.base_cooldown = 14.0
self.level = 1
self.mark_manager = MarkManager()
self.first_blade_pos = None
self.second_blade_pos = None
self.base_damage = [80, 125, 170, 215, 260]
self.ap_ratio = 0.8
self.stun_duration = 0.75 # 眩晕时间
self.mark_duration = 5.0 # 标记持续时间
def place_first_blade(self, position):
"""放置第一片刀刃。"""
self.first_blade_pos = position
print(f"第一片刀刃放置在位置 {position}。")
def place_second_blade(self, position, enemy_targets):
"""
放置第二片刀刃并触发效果。
:param position: 第二片刀刃位置
:param enemy_targets: 可能被命中的敌人目标列表
:return: 被眩晕和标记的敌人列表
"""
if self.first_blade_pos is None:
print("错误:请先放置第一片刀刃。")
return []
self.second_blade_pos = position
print(f"第二片刀刃放置在位置 {position},触发比翼双刃!")
# 简化版碰撞检测:假设在两点连线附近的敌人都被命中
hit_enemies = []
for enemy in enemy_targets:
# 这里应包含复杂的几何碰撞判断,此处简化为所有传入的敌人
hit_enemies.append(enemy)
if hit_enemies:
damage = self.base_damage[self.level - 1] + (self.irelia.ability_power * self.ap_ratio)
print(f" 对 {len(hit_enemies)} 名敌人造成 {damage:.1f} 点魔法伤害,并眩晕 {self.stun_duration} 秒。")
for enemy in hit_enemies:
enemy.take_damage(damage, "magic")
# 对英雄和大型野怪施加标记
if enemy.type in ['champion', 'large_monster']:
self.mark_manager.apply_mark(enemy, self.mark_duration)
self.cooldown = self.base_cooldown
self.first_blade_pos = None # 重置
self.second_blade_pos = None
return hit_enemies
else:
print(" 没有命中任何敌人。")
self.first_blade_pos = None # 重置,允许重新放置
self.second_blade_pos = None
return []
def update_marks(self, delta_time):
"""更新E技能施加的标记。"""
self.mark_manager.update_marks(delta_time)
```
R技能的实现相对直接,它是一个非指向性的直线范围技能,命中英雄后会展开一道刃墙。
```python
class VanguardEdge:
"""R技能:先锋之刃"""
def __init__(self, irelia_instance):
self.irelia = irelia_instance
self.cooldown = 0.0
self.base_cooldown = 120.0 # 2分钟
self.level = 1
self.mark_manager = MarkManager()
self.base_damage = [125, 250, 375]
self.ap_ratio = 0.7
self.mark_duration = 5.0
self.wall_duration = 2.5
self.wall_slow = 0.90 # 90%减速
def cast(self, direction_vector, enemy_targets):
"""
释放R技能。
:param direction_vector: 释放方向(简化处理)
:param enemy_targets: 在技能路径上的敌人列表
:return: 被标记的敌人列表和创建的刃墙信息
"""
if self.cooldown > 0:
print(f"R技能冷却中,剩余 {self.cooldown:.1f} 秒。")
return [], None
hit_champions = [e for e in enemy_targets if e.type == 'champion']
if not hit_champions:
print("先锋之刃未命中任何敌方英雄,不会展开刃墙。")
self.cooldown = self.base_cooldown
return [], None
# 对路径上所有敌人造成伤害
damage = self.base_damage[self.level - 1] + (self.irelia.ability_power * self.ap_ratio)
print(f"{self.irelia.name} 释放了先锋之刃!")
for enemy in enemy_targets:
enemy.take_damage(damage, "magic")
# 对被命中的英雄施加标记
for champion in hit_champions:
self.mark_manager.apply_mark(champion, self.mark_duration)
# 创建刃墙(这里用一个字典模拟其属性)
wall = {
'duration': self.wall_duration,
'slow_percent': self.wall_slow,
'position': 'some_position' # 实际应为生成位置
}
print(f" 命中 {len(hit_champions)} 名英雄,并生成持续 {self.wall_duration} 秒的刃墙。")
self.cooldown = self.base_cooldown
return hit_champions, wall
def update_marks(self, delta_time):
self.mark_manager.update_marks(delta_time)
```
E和R技能都通过`MarkManager`来管理标记,这避免了代码重复。`FlawlessDuet.place_second_blade`方法中的“碰撞检测”部分是极大的简化,在真实项目中,这里需要实现线段与目标碰撞体的相交检测算法。
## 5. 实战模拟与系统整合
现在,让我们把所有的零件组装起来,进行一场小规模的实战模拟,看看艾瑞莉娅的技能连招在代码中如何流畅执行。
```python
def simulate_combo():
"""模拟一次艾瑞莉娅的经典连招:E标记 -> Q近身 -> 普攻 -> Q追击。"""
print("===== 艾瑞莉娅连招模拟开始 =====")
# 1. 创建英雄和目标
irelia = Irelia(level=9, attack_damage=100, ability_power=0)
enemy_champion = Target("敌方亚索", max_health=800, armor=30, magic_resist=30, target_type='champion')
low_hp_minion = Target("残血近战兵", max_health=80, armor=0, magic_resist=0, target_type='minion')
print(f"创建英雄: {irelia.name} (等级{irelia.level}, AD:{irelia.attack_damage})")
print(f"创建目标: {enemy_champion.name} (生命值:{enemy_champion.current_health})")
print(f"创建目标: {low_hp_minion.name} (生命值:{low_hp_minion.current_health})")
print("-" * 40)
# 2. 使用E技能标记敌方英雄
print("步骤1: 艾瑞莉娅使用比翼双刃 (E)。")
irelia.e_skill.place_first_blade((100, 200))
# 假设第二片刀刃命中敌方英雄
stunned_enemies = irelia.e_skill.place_second_blade((150, 250), [enemy_champion])
if enemy_champion in stunned_enemies:
print(f" {enemy_champion.name} 被眩晕并标记!")
print("-" * 40)
# 3. 使用Q技能冲向被标记的英雄(应刷新冷却)
print("步骤2: 艾瑞莉娅对标记目标使用利刃冲击 (Q)。")
q_refreshed = irelia.cast_q(enemy_champion)
print(f" Q技能是否刷新: {q_refreshed}")
print(f" 当前被动层数: {irelia.passive.stacks}")
print("-" * 40)
# 4. 普攻一下,刷新被动持续时间
print("步骤3: 艾瑞莉娅进行一次普通攻击。")
irelia.basic_attack(enemy_champion)
print(f" 当前被动层数: {irelia.passive.stacks}")
print("-" * 40)
# 5. 使用Q技能击杀残血小兵,再次刷新冷却
print("步骤4: 艾瑞莉娅使用Q技能击杀残血小兵。")
# 先将小兵打到残血
low_hp_minion.take_damage(70, "physical")
q_refreshed_again = irelia.cast_q(low_hp_minion)
print(f" Q技能是否刷新: {q_refreshed_again}")
print(f" 当前被动层数: {irelia.passive.stacks} (命中小兵时,非0层不叠加)")
print("-" * 40)
# 6. 模拟时间流逝,更新状态
print("步骤5: 模拟2秒后...")
irelia.update(2.0)
print(f" Q技能剩余冷却: {irelia.q_skill.cooldown:.1f}")
print(f" 被动层数剩余时间: {irelia.passive.duration - irelia.passive.time_since_last_stack:.1f}秒")
print("-" * 40)
# 7. 检查满层被动效果
print("步骤6: 检查满层被动效果。")
if irelia.passive.stacks == irelia.passive.max_stacks:
attack_speed_bonus = irelia.passive.get_attack_speed_bonus()
on_hit_damage = irelia.passive.get_on_hit_magic_damage()
print(f" 被动已满层 ({irelia.passive.stacks}层)!")
print(f" 获得 {attack_speed_bonus*100:.1f}% 攻击速度加成。")
print(f" 普攻附带 {on_hit_damage:.1f} 点额外魔法伤害。")
else:
print(f" 被动层数: {irelia.passive.stacks}/{irelia.passive.max_stacks}")
print("===== 模拟结束 =====")
if __name__ == "__main__":
simulate_combo()
```
运行这段模拟代码,你将在控制台看到一次完整的技能交互过程。从E技能起手眩晕标记,到Q技能近身刷新,再到普攻续被动,最后Q小兵刷新进行位移追击。整个过程清晰地展示了我们构建的代码系统如何协同工作,还原了游戏中的核心体验。
通过这个项目,我们不仅用Python实现了艾瑞莉娅的技能,更重要的是实践了如何将复杂的、有状态的游戏规则转化为结构清晰、可维护的面向对象代码。你可以在此基础上继续扩展,比如加入更精确的碰撞检测、实现其他英雄、甚至构建一个简单的回合制战斗模拟器。编程与游戏理解的结合,其乐趣正在于此。