You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

323 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import pygame
from settings import *
from support import import_folder
from entity import Entity
class Player(Entity):
def __init__(self,pos,groups,obstacle_sprites,create_attack,destroy_attack,create_magic):
# 调用父类的初始化方法
super().__init__(groups)
# 设置玩家图像和位置
self.image = pygame.image.load('../graphics/test/player.png').convert_alpha()
self.rect = self.image.get_rect(topleft = pos)
# 设置玩家的碰撞框
self.hitbox = self.rect.inflate(-6,HITBOX_OFFSET['player'])
# 图形设置
# 导入玩家的其他图形资源
self.import_player_assets()
# 状态设置
# 玩家初始状态朝向下
self.status = 'down'
# 移动和攻击相关设置
self.attacking = False
# 攻击冷却时间
self.attack_cooldown = 400
# 攻击时间
self.attack_time = None
# 障碍物精灵组
self.obstacle_sprites = obstacle_sprites
# 武器设置
self.create_attack = create_attack
self.destroy_attack = destroy_attack
self.weapon_index = 0
self.weapon = list(weapon_data.keys())[self.weapon_index]
# 初始武器
self.can_switch_weapon = True
self.weapon_switch_time = None
# 切换武器的冷却时间
self.switch_duration_cooldown = 200
# 魔法设置
self.create_magic = create_magic
self.magic_index = 0
self.magic = list(magic_data.keys())[self.magic_index]
# 初始魔法
self.can_switch_magic = True
self.magic_switch_time = None
# 玩家属性设置
# 初始属性
self.stats = {'health': 100,'energy':60,'attack': 10,'magic': 4,'speed': 5}
# 最大属性
self.max_stats = {'health': 300, 'energy': 140, 'attack': 20, 'magic' : 10, 'speed': 10}
# 升级消耗
self.upgrade_cost = {'health': 100, 'energy': 100, 'attack': 100, 'magic' : 100, 'speed': 100}
# 当前生命值
self.health = self.stats['health'] * 1.0
# 当前能量值
self.energy = self.stats['energy'] * 0.8
# 初始经验值
self.exp = 5000
# 移动速度
self.speed = self.stats['speed']
# 伤害计时器和无敌状态设置
# 是否可以受到伤害
self.vulnerable = True
# 受伤时间
self.hurt_time = None
# 无敌持续时间
self.invulnerability_duration = 500
# 导入武器攻击音效
self.weapon_attack_sound = pygame.mixer.Sound('../audio/sword.wav')
# 设置音量
self.weapon_attack_sound.set_volume(0.4)
def import_player_assets(self):
# 设置玩家动画资源的文件路径
character_path = '../graphics/player/'
# 初始化玩家动画字典,包含不同方向和状态的动画列表
self.animations = {'up': [],'down': [],'left': [],'right': [],
'right_idle':[],'left_idle':[],'up_idle':[],'down_idle':[],
'right_attack':[],'left_attack':[],'up_attack':[],'down_attack':[]}
# 遍历动画字典,加载对应路径下的动画帧
for animation in self.animations.keys():
full_path = character_path + animation
# 调用函数导入文件夹中的动画帧
self.animations[animation] = import_folder(full_path)
def input(self):
# 如果玩家当前未处于攻击状态
if not self.attacking:
# 获取当前按下的键
keys = pygame.key.get_pressed()
# 处理移动输入
# 按下向上键
if keys[pygame.K_UP]:
# 设置垂直方向向上移动
self.direction.y = -1
# 设置玩家状态为向上
self.status = 'up'
# 按下向下键
elif keys[pygame.K_DOWN]:
# 设置垂直方向向下移动
self.direction.y = 1
# 设置玩家状态为向下
self.status = 'down'
else:
# 停止垂直移动
self.direction.y = 0
# 按下向右键
if keys[pygame.K_RIGHT]:
# 设置水平方向向右移动
self.direction.x = 1
# 设置玩家状态为向右
self.status = 'right'
# 按下向左键
elif keys[pygame.K_LEFT]:
# 设置水平方向向左移动
self.direction.x = -1
# 设置玩家状态为向左
self.status = 'left'
else:
# 停止水平移动
self.direction.x = 0
# 处理攻击输入
# 按下空格键
if keys[pygame.K_SPACE]:
# 玩家开始攻击
self.attacking = True
# 记录攻击时间
self.attack_time = pygame.time.get_ticks()
# 创建攻击对象
self.create_attack()
# 播放武器攻击音效
self.weapon_attack_sound.play()
# 处理魔法输入
# 按下左Ctrl键
if keys[pygame.K_LCTRL]:
# 玩家开始攻击
self.attacking = True
# 记录攻击时间
self.attack_time = pygame.time.get_ticks()
# 获取当前魔法类型
style = list(magic_data.keys())[self.magic_index]
# 计算魔法强度
strength = list(magic_data.values())[self.magic_index]['strength'] + self.stats['magic']
# 获取魔法消耗
cost = list(magic_data.values())[self.magic_index]['cost']
# 创建魔法效果
self.create_magic(style,strength,cost)
# 处理切换武器输入
# 按下Q键且可以切换武器
if keys[pygame.K_q] and self.can_switch_weapon:
# 设置切换武器冷却状态为False
self.can_switch_weapon = False
# 记录切换武器时间
self.weapon_switch_time = pygame.time.get_ticks()
if self.weapon_index < len(list(weapon_data.keys())) - 1:
# 切换至下一个武器
self.weapon_index += 1
else:
# 回到第一个武器
self.weapon_index = 0
# 更新当前武器
self.weapon = list(weapon_data.keys())[self.weapon_index]
# 处理切换魔法输入
# 按下E键且可以切换魔法
if keys[pygame.K_e] and self.can_switch_magic:
# 设置切换魔法冷却状态为False
self.can_switch_magic = False
# 记录切换魔法时间
self.magic_switch_time = pygame.time.get_ticks()
if self.magic_index < len(list(magic_data.keys())) - 1:
# 切换至下一个魔法
self.magic_index += 1
else:
# 回到第一个魔法
self.magic_index = 0
# 更新当前魔法
self.magic = list(magic_data.keys())[self.magic_index]
def get_status(self):
# 空闲状态
# 如果角色没有移动且不在攻击状态下
if self.direction.x == 0 and self.direction.y == 0:
# 如果当前状态不包含 'idle' 和 'attack'
if not 'idle' in self.status and not 'attack' in self.status:
# 添加 '_idle' 到状态末尾,表示空闲状态
self.status = self.status + '_idle'
# 如果角色正在攻击
if self.attacking:
# 停止移动
self.direction.x = 0
self.direction.y = 0
# 如果当前状态不包含 'attack'
if not 'attack' in self.status:
# 如果当前状态包含 'idle'
if 'idle' in self.status:
# 将 'idle' 替换为 'attack'
self.status = self.status.replace('_idle','_attack')
else:
# 在当前状态末尾添加 '_attack'
self.status = self.status + '_attack'
# 如果角色不在攻击状态下
else:
# 如果当前状态包含 'attack'
if 'attack' in self.status:
# 移除 'attack',恢复到移动状态
self.status = self.status.replace('_attack','')
def cooldowns(self):
# 处理攻击冷却
current_time = pygame.time.get_ticks()
# 如果当前时间超过攻击冷却时间,则停止攻击
if self.attacking:
if current_time - self.attack_time >= self.attack_cooldown + weapon_data[self.weapon]['cooldown']:
self.attacking = False
self.destroy_attack()
# 处理武器切换冷却
if not self.can_switch_weapon:
# 如果当前时间超过武器切换冷却时间,则允许切换武器
if current_time - self.weapon_switch_time >= self.switch_duration_cooldown:
self.can_switch_weapon = True
# 处理魔法切换冷却
if not self.can_switch_magic:
# 如果当前时间超过魔法切换冷却时间,则允许切换魔法
if current_time - self.magic_switch_time >= self.switch_duration_cooldown:
self.can_switch_magic = True
# 处理受伤后的无敌时间
if not self.vulnerable:
# 如果当前时间超过无敌时间,则角色恢复可受伤状态
if current_time - self.hurt_time >= self.invulnerability_duration:
self.vulnerable = True
def animate(self):
# 获取当前状态对应的动画列表
animation = self.animations[self.status]
# 更新帧索引
self.frame_index += self.animation_speed
# 如果帧索引超过动画长度则重置为0实现循环播放
if self.frame_index >= len(animation):
self.frame_index = 0
# 根据帧索引设置当前图像
self.image = animation[int(self.frame_index)]
# 更新图像的位置
self.rect = self.image.get_rect(center = self.hitbox.center)
# 无敌状态下的闪烁效果
if not self.vulnerable:
# 使用波动值计算透明度
alpha = self.wave_value()
# 设置图像的透明度
self.image.set_alpha(alpha)
else:
# 恢复图像完全可见(不透明)
self.image.set_alpha(255)
def get_full_weapon_damage(self):
# 获取角色基础攻击力
base_damage = self.stats['attack']
# 获取当前武器的伤害值
weapon_damage = weapon_data[self.weapon]['damage']
# 返回角色使用当前武器的总伤害值
return base_damage + weapon_damage
def get_full_magic_damage(self):
# 获取角色基础魔法伤害
base_damage = self.stats['magic']
# 获取当前魔法的伤害值
spell_damage = magic_data[self.magic]['strength']
# 返回角色使用当前魔法的总伤害值
return base_damage + spell_damage
def get_value_by_index(self,index):
return list(self.stats.values())[index]
def get_cost_by_index(self,index):
return list(self.upgrade_cost.values())[index]
def energy_recovery(self):
if self.energy < self.stats['energy']:
# 根据魔法属性恢复能量
self.energy += 0.01 * self.stats['magic']
else:
# 能量恢复到最大值
self.energy = self.stats['energy']
def check_death(self):
# 如果敌人角色的生命值小于等于 0表示角色已经死亡
if self.health <= 0:
# 从精灵组中移除角色,通常用于删除角色或停止其更新和渲染
self.kill()
def update(self):
# 处理用户输入
self.input()
# 处理冷却时间
self.cooldowns()
# 更新角色状态
self.get_status()
# 更新角色动画
self.animate()
# 移动角色
self.move(self.stats['speed'])
# 恢复能量
self.energy_recovery()
#死亡判断
self.check_death()