271 lines
11 KiB
Python
271 lines
11 KiB
Python
import pygame
|
||
import json
|
||
import os
|
||
from boss_fight import boss_fight
|
||
|
||
class BossFightUI:
|
||
def __init__(self, font=None):
|
||
# 初始化字体
|
||
font_path = os.path.join(os.path.dirname(__file__), "syht.otf")
|
||
|
||
if os.path.exists(font_path):
|
||
self.font = pygame.font.Font(font_path, 32)
|
||
self.small_font = pygame.font.Font(font_path, 24)
|
||
else:
|
||
# 备用字体
|
||
self.font = font if font else pygame.font.Font(None, 32)
|
||
self.small_font = pygame.font.Font(None, 24)
|
||
self.is_showing = False
|
||
self.boss_data = None
|
||
self.player_skills = None
|
||
self.fight_sequences = None
|
||
self.current_boss_index = 0
|
||
self.current_action_index = 0
|
||
self.animation_timer = 0
|
||
self.animation_speed = 60 # 每秒1步
|
||
self.auto_play = False
|
||
self.cooldowns = [] # 当前技能冷却状态
|
||
self.boss_hp = 0 # 当前boss剩余血量
|
||
self.round_count = 0 # 当前回合数
|
||
|
||
# UI位置和尺寸
|
||
self.window_rect = pygame.Rect(50, 50, 700, 500)
|
||
self.close_button_rect = pygame.Rect(self.window_rect.right - 30, self.window_rect.top + 5, 25, 25)
|
||
self.auto_button_rect = pygame.Rect(self.window_rect.left + 10, self.window_rect.bottom - 40, 80, 30)
|
||
self.next_button_rect = pygame.Rect(self.window_rect.left + 100, self.window_rect.bottom - 40, 80, 30)
|
||
self.reset_button_rect = pygame.Rect(self.window_rect.left + 190, self.window_rect.bottom - 40, 80, 30)
|
||
|
||
# 颜色定义
|
||
self.bg_color = (240, 240, 240)
|
||
self.border_color = (100, 100, 100)
|
||
self.button_color = (200, 200, 200)
|
||
self.button_hover_color = (180, 180, 180)
|
||
self.skill_colors = [(255, 100, 100), (100, 255, 100), (100, 100, 255), (255, 255, 100)]
|
||
self.cooldown_color = (150, 150, 150)
|
||
|
||
def show_boss_fight(self, boss_data, player_skills):
|
||
"""显示boss战斗界面"""
|
||
self.boss_data = boss_data
|
||
self.player_skills = player_skills
|
||
self.is_showing = True
|
||
|
||
# 计算战斗策略
|
||
self.fight_sequences = boss_fight(boss_data, player_skills)
|
||
|
||
if self.fight_sequences:
|
||
self.reset_fight_state()
|
||
else:
|
||
print("无法计算boss战斗策略")
|
||
|
||
def reset_fight_state(self):
|
||
"""重置战斗状态"""
|
||
self.current_boss_index = 0
|
||
self.current_action_index = 0
|
||
self.cooldowns = [0] * len(self.player_skills)
|
||
self.boss_hp = self.boss_data[0] if self.boss_data else 0
|
||
self.round_count = 0
|
||
self.animation_timer = 0
|
||
|
||
def handle_event(self, event):
|
||
"""处理事件"""
|
||
if not self.is_showing:
|
||
return False
|
||
|
||
if event.type == pygame.MOUSEBUTTONDOWN:
|
||
if self.close_button_rect.collidepoint(event.pos):
|
||
self.is_showing = False
|
||
return True
|
||
elif self.auto_button_rect.collidepoint(event.pos):
|
||
self.auto_play = not self.auto_play
|
||
return True
|
||
elif self.next_button_rect.collidepoint(event.pos):
|
||
self.next_action()
|
||
return True
|
||
elif self.reset_button_rect.collidepoint(event.pos):
|
||
self.reset_fight_state()
|
||
return True
|
||
|
||
elif event.type == pygame.KEYDOWN:
|
||
if event.key == pygame.K_ESCAPE:
|
||
self.is_showing = False
|
||
return True
|
||
elif event.key == pygame.K_SPACE:
|
||
self.next_action()
|
||
return True
|
||
elif event.key == pygame.K_r:
|
||
self.reset_fight_state()
|
||
return True
|
||
elif event.key == pygame.K_a:
|
||
self.auto_play = not self.auto_play
|
||
return True
|
||
|
||
return False
|
||
|
||
def update(self):
|
||
"""更新动画状态"""
|
||
if not self.is_showing or not self.auto_play:
|
||
return
|
||
|
||
self.animation_timer += 1
|
||
if self.animation_timer >= self.animation_speed:
|
||
self.next_action()
|
||
self.animation_timer = 0
|
||
|
||
def next_action(self):
|
||
"""执行下一个动作"""
|
||
if not self.fight_sequences or self.current_boss_index >= len(self.fight_sequences):
|
||
return
|
||
|
||
current_sequence = self.fight_sequences[self.current_boss_index]
|
||
|
||
if self.current_action_index >= len(current_sequence):
|
||
# 当前boss已击败,切换到下一个boss
|
||
self.current_boss_index += 1
|
||
if self.current_boss_index < len(self.boss_data):
|
||
self.current_action_index = 0
|
||
self.boss_hp = self.boss_data[self.current_boss_index]
|
||
# 冷却时间递减但不重置
|
||
self.cooldowns = [max(0, cd - 1) for cd in self.cooldowns]
|
||
self.round_count += 1
|
||
else:
|
||
# 所有boss都被击败
|
||
self.auto_play = False
|
||
return
|
||
|
||
# 执行当前动作
|
||
action = current_sequence[self.current_action_index]
|
||
|
||
# 先减少所有技能的冷却时间
|
||
self.cooldowns = [max(0, cd - 1) for cd in self.cooldowns]
|
||
|
||
if action == -1:
|
||
# 等待动作
|
||
pass
|
||
else:
|
||
# 使用技能
|
||
if action < len(self.player_skills):
|
||
damage, cooldown = self.player_skills[action]
|
||
self.boss_hp -= damage
|
||
self.cooldowns[action] = cooldown
|
||
|
||
# 检查boss是否被击败
|
||
if self.boss_hp <= 0:
|
||
self.boss_hp = 0
|
||
|
||
self.current_action_index += 1
|
||
self.round_count += 1
|
||
|
||
def draw(self, screen):
|
||
"""绘制boss战斗界面"""
|
||
if not self.is_showing:
|
||
return
|
||
|
||
# 绘制背景窗口
|
||
pygame.draw.rect(screen, self.bg_color, self.window_rect)
|
||
pygame.draw.rect(screen, self.border_color, self.window_rect, 3)
|
||
|
||
# 绘制标题
|
||
title_text = self.font.render("Boss战斗策略", True, (0, 0, 0))
|
||
screen.blit(title_text, (self.window_rect.left + 10, self.window_rect.top + 10))
|
||
|
||
# 绘制关闭按钮
|
||
pygame.draw.rect(screen, (255, 100, 100), self.close_button_rect)
|
||
close_text = self.small_font.render("X", True, (255, 255, 255))
|
||
close_rect = close_text.get_rect(center=self.close_button_rect.center)
|
||
screen.blit(close_text, close_rect)
|
||
|
||
if not self.fight_sequences:
|
||
# 无解情况
|
||
no_solution_text = self.font.render("无法击败所有Boss!", True, (255, 0, 0))
|
||
screen.blit(no_solution_text, (self.window_rect.left + 50, self.window_rect.top + 100))
|
||
return
|
||
|
||
# 绘制boss信息
|
||
y_offset = 50
|
||
for i, boss_hp in enumerate(self.boss_data):
|
||
color = (0, 255, 0) if i < self.current_boss_index else (255, 0, 0) if i == self.current_boss_index else (100, 100, 100)
|
||
if i == self.current_boss_index:
|
||
boss_text = f"Boss {i+1}: {self.boss_hp}/{boss_hp} HP"
|
||
else:
|
||
boss_text = f"Boss {i+1}: {boss_hp} HP"
|
||
text = self.small_font.render(boss_text, True, color)
|
||
screen.blit(text, (self.window_rect.left + 10, self.window_rect.top + y_offset))
|
||
y_offset += 25
|
||
|
||
# 绘制技能信息
|
||
y_offset += 20
|
||
skills_title = self.font.render("技能信息:", True, (0, 0, 0))
|
||
screen.blit(skills_title, (self.window_rect.left + 10, self.window_rect.top + y_offset))
|
||
y_offset += 30
|
||
|
||
for i, (damage, cooldown_time) in enumerate(self.player_skills):
|
||
current_cooldown = self.cooldowns[i] if i < len(self.cooldowns) else 0
|
||
color = self.skill_colors[i % len(self.skill_colors)] if current_cooldown == 0 else self.cooldown_color
|
||
|
||
skill_text = f"技能{i}: 伤害{damage}, 冷却{cooldown_time}"
|
||
if current_cooldown > 0:
|
||
skill_text += f" (冷却中: {current_cooldown})"
|
||
|
||
text = self.small_font.render(skill_text, True, color)
|
||
screen.blit(text, (self.window_rect.left + 10, self.window_rect.top + y_offset))
|
||
y_offset += 25
|
||
|
||
# 绘制当前战斗状态
|
||
y_offset += 20
|
||
if self.current_boss_index < len(self.fight_sequences):
|
||
current_sequence = self.fight_sequences[self.current_boss_index]
|
||
status_text = f"当前Boss {self.current_boss_index + 1}, 回合 {self.round_count}"
|
||
text = self.small_font.render(status_text, True, (0, 0, 0))
|
||
screen.blit(text, (self.window_rect.left + 10, self.window_rect.top + y_offset))
|
||
y_offset += 25
|
||
|
||
# 绘制当前boss的战斗序列
|
||
sequence_text = "战斗序列: "
|
||
for j, action in enumerate(current_sequence):
|
||
if j == self.current_action_index:
|
||
sequence_text += f"[{action}] "
|
||
elif j < self.current_action_index:
|
||
sequence_text += f"{action} "
|
||
else:
|
||
sequence_text += f"({action}) "
|
||
|
||
text = self.small_font.render(sequence_text, True, (0, 0, 0))
|
||
screen.blit(text, (self.window_rect.left + 10, self.window_rect.top + y_offset))
|
||
y_offset += 25
|
||
|
||
# 说明当前动作
|
||
if self.current_action_index < len(current_sequence):
|
||
action = current_sequence[self.current_action_index]
|
||
if action == -1:
|
||
action_text = "下一个动作: 等待"
|
||
else:
|
||
damage, cooldown = self.player_skills[action]
|
||
action_text = f"下一个动作: 使用技能{action} (伤害{damage})"
|
||
text = self.small_font.render(action_text, True, (0, 100, 0))
|
||
screen.blit(text, (self.window_rect.left + 10, self.window_rect.top + y_offset))
|
||
|
||
# 绘制控制按钮
|
||
# 自动播放按钮
|
||
auto_color = (100, 255, 100) if self.auto_play else self.button_color
|
||
pygame.draw.rect(screen, auto_color, self.auto_button_rect)
|
||
auto_text = self.small_font.render("自动" if not self.auto_play else "停止", True, (0, 0, 0))
|
||
auto_rect = auto_text.get_rect(center=self.auto_button_rect.center)
|
||
screen.blit(auto_text, auto_rect)
|
||
|
||
# 下一步按钮
|
||
pygame.draw.rect(screen, self.button_color, self.next_button_rect)
|
||
next_text = self.small_font.render("下一步", True, (0, 0, 0))
|
||
next_rect = next_text.get_rect(center=self.next_button_rect.center)
|
||
screen.blit(next_text, next_rect)
|
||
|
||
# 重置按钮
|
||
pygame.draw.rect(screen, self.button_color, self.reset_button_rect)
|
||
reset_text = self.small_font.render("重置", True, (0, 0, 0))
|
||
reset_rect = reset_text.get_rect(center=self.reset_button_rect.center)
|
||
screen.blit(reset_text, reset_rect)
|
||
|
||
# 绘制操作提示
|
||
hint_text = "ESC: 关闭 | 空格: 下一步 | A: 自动播放 | R: 重置"
|
||
hint = self.small_font.render(hint_text, True, (100, 100, 100))
|
||
screen.blit(hint, (self.window_rect.left + 10, self.window_rect.bottom - 60))
|