import pygame import sys import time import random import math # 配置 SCREEN_WIDTH, SCREEN_HEIGHT = 900, 600 BOSS_IMG = 'boss.png' # 替换为你的boss图片路径 SKILL_IMG = 'skill.png' # 替换为你的技能图片路径 FPS = 60 HIT_SOUND = 'hit.wav' # 技能击中boss CAST_SOUND = 'cast.wav' # 技能释放 WIN_SOUND = 'win.wav' # 胜利 GROAN_SOUND = 'groan.wav' # 怪物呻吟 # 技能颜色和名称 SKILL_COLORS = [(255, 80, 80), (80, 180, 255), (120, 255, 120), (255, 220, 80), (180, 80, 255)] SKILL_NAMES = ["火球", "冰锥", "风刃", "雷击", "暗影"] class Particle: def __init__(self, x, y, color, shadow=False, glow=False): self.x = x + random.randint(-10, 10) self.y = y + random.randint(-10, 10) self.radius = random.randint(2, 5) self.color = color self.life = random.randint(15, 30) self.vx = random.uniform(-1.2, 1.2) self.vy = random.uniform(-1.2, 1.2) self.shadow = shadow self.glow = glow def update(self): self.x += self.vx self.y += self.vy self.life -= 1 self.radius = max(0, self.radius - 0.08) def draw(self, screen): if self.life > 0 and self.radius > 0: if self.shadow: s = pygame.Surface((int(self.radius*4), int(self.radius*2)), pygame.SRCALPHA) pygame.draw.ellipse(s, (30,30,30,80), (0,0,int(self.radius*4),int(self.radius*2))) screen.blit(s, (int(self.x-self.radius*2), int(self.y+self.radius))) if self.glow: s = pygame.Surface((int(self.radius*4), int(self.radius*4)), pygame.SRCALPHA) pygame.draw.circle(s, (*self.color, 60), (int(self.radius*2), int(self.radius*2)), int(self.radius*2)) screen.blit(s, (int(self.x-self.radius), int(self.y-self.radius))) pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), int(self.radius)) def draw_gradient_bg(screen): for i in range(SCREEN_HEIGHT): color = ( 220 - i // 8, 220 - i // 16, 255 - i // 12 ) pygame.draw.line(screen, color, (0, i), (SCREEN_WIDTH, i)) def shake_pos(x, y, frame): if frame % 2 == 0: return x + 8, y + random.randint(-3, 3) else: return x - 8, y + random.randint(-3, 3) def draw_health_bar(screen, x, y, w, h, hp, max_hp): pygame.draw.rect(screen, (180, 0, 0), (x, y, w, h), border_radius=8) pygame.draw.rect(screen, (0, 220, 0), (x, y, int(w * hp / max_hp), h), border_radius=8) pygame.draw.rect(screen, (0, 0, 0), (x, y, w, h), 2, border_radius=8) def draw_skill_cooldown(screen, x, y, w, h, cooldown, max_cd): pygame.draw.rect(screen, (80, 80, 80), (x, y, w, h), border_radius=6) if cooldown > 0: pygame.draw.rect(screen, (120, 120, 255), (x, y, int(w * cooldown / max_cd), h), border_radius=6) class Skill: def __init__(self, idx, dmg, img): self.idx = idx self.dmg = dmg self.img = img self.x = 60 self.y = SCREEN_HEIGHT // 2 + random.randint(-60, 60) self.active = True self.color = SKILL_COLORS[idx % len(SKILL_COLORS)] self.angle = random.uniform(-0.2, 0.2) self.trail = [] self.shadow = True self.glow = True self.speed = 7 + self.idx * 0.7 # 更慢 self.cast_sound_played = False def update(self): self.trail.append((self.x, self.y)) if len(self.trail) > 12: self.trail.pop(0) self.x += self.speed self.y += math.sin(self.x / 40) * 3 + self.angle * 8 if self.x > SCREEN_WIDTH: self.active = False def draw(self, screen): # 阴影 s = pygame.Surface((self.img.get_width(), self.img.get_height()), pygame.SRCALPHA) pygame.draw.ellipse(s, (30,30,30,80), (0, self.img.get_height()//2, self.img.get_width(), self.img.get_height()//2)) screen.blit(s, (self.x, self.y+self.img.get_height()//2)) # 光晕 s2 = pygame.Surface((self.img.get_width()*2, self.img.get_height()*2), pygame.SRCALPHA) pygame.draw.circle(s2, (*self.color, 60), (self.img.get_width(), self.img.get_height()), self.img.get_width()) screen.blit(s2, (self.x-self.img.get_width()//2, self.y-self.img.get_height()//2)) # 轨迹 for i, (tx, ty) in enumerate(self.trail): alpha = int(255 * (i + 1) / len(self.trail)) s = pygame.Surface((self.img.get_width(), self.img.get_height()), pygame.SRCALPHA) s.fill((*self.color, alpha // 2)) screen.blit(s, (tx, ty)) screen.blit(self.img, (self.x, self.y)) class Boss: def __init__(self, img, hp, groan_sound=None): self.img = img self.hp = hp self.max_hp = hp self.x = SCREEN_WIDTH - img.get_width() - 80 self.y = SCREEN_HEIGHT // 2 - img.get_height() // 2 self.shake_frame = 0 self.shake = False self.dead = False self.death_anim = 0 self.particles = [] self.groan_sound = groan_sound self.groan_cooldown = 0 def hit(self, dmg): if self.hp > 0: self.hp = max(0, self.hp - dmg) self.shake = True self.shake_frame = 12 # 受击粒子 for _ in range(16): self.particles.append(Particle(self.x + self.img.get_width() // 2, self.y + self.img.get_height() // 2, (255, 80, 80), shadow=True, glow=True)) if self.groan_sound and self.groan_cooldown == 0: self.groan_sound.play() self.groan_cooldown = 30 if self.hp == 0: self.dead = True self.death_anim = 60 def update(self): if self.shake: self.shake_frame -= 1 if self.shake_frame <= 0: self.shake = False if self.groan_cooldown > 0: self.groan_cooldown -= 1 # 死亡动画 if self.dead and self.death_anim > 0: self.death_anim -= 1 for _ in range(8): self.particles.append(Particle(self.x + self.img.get_width() // 2, self.y + self.img.get_height() // 2, (80, 80, 80), shadow=True, glow=True)) # 更新粒子 for p in self.particles: p.update() self.particles = [p for p in self.particles if p.life > 0] def draw(self, screen): # 投影 s = pygame.Surface((self.img.get_width()*2, self.img.get_height()), pygame.SRCALPHA) pygame.draw.ellipse(s, (30,30,30,90), (0, self.img.get_height()//2, self.img.get_width()*2, self.img.get_height()//2)) screen.blit(s, (self.x-self.img.get_width()//2, self.y+self.img.get_height()-10)) # 光晕 s2 = pygame.Surface((self.img.get_width()*2, self.img.get_height()*2), pygame.SRCALPHA) pygame.draw.circle(s2, (200,200,255,60), (self.img.get_width(), self.img.get_height()), self.img.get_width()) screen.blit(s2, (self.x-self.img.get_width()//2, self.y-self.img.get_height()//2)) if self.shake: x, y = shake_pos(self.x, self.y, self.shake_frame) else: x, y = self.x, self.y if not self.dead or self.death_anim > 0: screen.blit(self.img, (x, y)) draw_health_bar(screen, x, y - 40, 240, 24, self.hp, self.max_hp) for p in self.particles: p.draw(screen) def main(boss_hp, skill_seq): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('自动打Boss - 3D炫酷升级版') clock = pygame.time.Clock() boss_img = pygame.image.load(BOSS_IMG).convert_alpha() skill_img = pygame.image.load(SKILL_IMG).convert_alpha() # 音效 try: hit_sound = pygame.mixer.Sound(HIT_SOUND) cast_sound = pygame.mixer.Sound(CAST_SOUND) win_sound = pygame.mixer.Sound(WIN_SOUND) groan_sound = pygame.mixer.Sound(GROAN_SOUND) except Exception: hit_sound = cast_sound = win_sound = groan_sound = None boss = Boss(boss_img, boss_hp, groan_sound=groan_sound) skills = [] skill_idx = 0 running = True skill_cooldown = 0 max_cd = 40 # 冷却更长 font = pygame.font.SysFont('SimHei', 36) big_font = pygame.font.SysFont('SimHei', 60) particles = [] while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False draw_gradient_bg(screen) # 随机背景粒子 if random.random() < 0.18: particles.append(Particle(random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT), (200, 200, 255), shadow=True, glow=True)) for p in particles: p.update() p.draw(screen) particles = [p for p in particles if p.life > 0] boss.update() boss.draw(screen) # 技能释放 if skill_idx < len(skill_seq) and skill_cooldown == 0 and not boss.dead: s = skill_seq[skill_idx] skills.append(Skill(s['first'], s['second'], skill_img)) if cast_sound: cast_sound.play() skill_cooldown = max_cd skill_idx += 1 if skill_cooldown > 0: skill_cooldown -= 1 # 技能动画 for skill in skills: if skill.active: skill.update() skill.draw(screen) # 判断是否击中boss if skill.x + skill.img.get_width() > boss.x and boss.hp > 0 and not boss.dead: boss.hit(skill.dmg) # 爆炸粒子 for _ in range(24): particles.append(Particle(boss.x+boss.img.get_width()//2, boss.y+boss.img.get_height()//2, random.choice(SKILL_COLORS), shadow=True, glow=True)) if hit_sound: hit_sound.play() skill.active = False # 移除无效技能 skills = [s for s in skills if s.active] # 技能冷却条和技能名 if skill_idx < len(skill_seq): s = skill_seq[skill_idx] skill_name = SKILL_NAMES[s['first'] % len(SKILL_NAMES)] name_text = font.render(f"下一个技能:{skill_name}", True, SKILL_COLORS[s['first'] % len(SKILL_COLORS)]) screen.blit(name_text, (60, SCREEN_HEIGHT - 80)) draw_skill_cooldown(screen, 60, SCREEN_HEIGHT - 40, 200, 18, skill_cooldown, max_cd) # 显示血量数字 hp_text = font.render(f'Boss HP: {boss.hp}/{boss.max_hp}', True, (0,0,0)) screen.blit(hp_text, (60, 30)) # Boss死亡动画 if boss.dead and boss.death_anim == 0: win_text = big_font.render("胜利!", True, (255, 120, 80)) screen.blit(win_text, (SCREEN_WIDTH // 2 - 80, SCREEN_HEIGHT // 2 - 60)) if win_sound: win_sound.play() pygame.display.flip() clock.tick(FPS) if boss.hp <= 0 and not skills and boss.death_anim == 0: time.sleep(1.5) running = False pygame.quit() if __name__ == "__main__": # 示例参数:boss血量1000,技能序列 boss_hp = 1000 skill_seq = [ {'first': 0, 'second': 120}, {'first': 1, 'second': 200}, {'first': 2, 'second': 150}, {'first': 3, 'second': 300}, {'first': 4, 'second': 250}, ] main(boss_hp, skill_seq)