前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PyZelda 源码解析(全)

PyZelda 源码解析(全)

作者头像
ApacheCN_飞龙
发布2024-02-17 09:58:41
800
发布2024-02-17 09:58:41
举报
文章被收录于专栏:信数据得永生信数据得永生

.\Zelda-with-Python\Code\Debug.py

代码语言:javascript
复制
# 导入pygame和os模块
import pygame
import os

# 设置当前工作目录为项目所在的目录,用于导入文件(特别是图片)
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 初始化pygame
pygame.init()

# 创建字体对象,用于在屏幕上显示调试信息
font = pygame.font.Font(None, 30)

# 定义一个函数用于在屏幕上显示调试信息
def debug(info, y = 10, x = 10):
    # 获取当前显示的表面
    display_surface = pygame.display.get_surface()
    # 创建一个包含调试信息的表面
    debug_surf = font.render(str(info), True, "White")
    # 获取调试信息表面的矩形
    debug_rect = debug_surf.get_rect(topleft = (x, y))
    # 在屏幕上绘制一个黑色矩形
    pygame.draw.rect(display_surface, "Black", debug_rect)
    # 在屏幕上显示调试信息
    display_surface.blit(debug_surf, debug_rect)

.\Zelda-with-Python\Code\Enemy.py

代码语言:javascript
复制
# 导入 pygame 模块
import pygame
# 从 Settings 模块中导入所有内容
from Settings import *
# 从 Entity 模块中导入 Entity 类
from Entity import Entity
# 从 Support 模块中导入所有内容
from Support import *
# 导入 os 模块
import os

# 将当前工作目录更改为 Main.py 文件所在的目录
os.chdir(os.path.dirname(os.path.abspath(__file__)))

.\Zelda-with-Python\Code\Entity.py

代码语言:javascript
复制
# 从 cmath 模块中导入 rect 函数
from cmath import rect
# 导入 pygame 模块
import pygame
# 从 math 模块中导入 sin 函数
from math import sin
# 导入 os 模块
import os

# 这是用于文件(特别是图片)导入的代码(这行代码将目录更改为项目保存的位置)
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 创建实体类,继承自 pygame.sprite.Sprite 类
class Entity(pygame.sprite.Sprite):
    # 初始化方法
    def __init__(self, groups):
        # 调用父类的初始化方法
        super().__init__(groups)
        # 设置帧索引初始值为 0
        self.frame_index = 0
        # 设置动画速度为 0.15
        self.animation_speed = 0.15
        # 创建一个方向向量
        self.direction = pygame.math.Vector2()
    
    # 移动方法
    def move(self, speed):
        # 如果方向向量的大小不为 0,则将其归一化
        if self.direction.magnitude() != 0:
            self.direction = self.direction.normalize()
        
        # 根据方向向量的值移动碰撞框
        self.hitbox.x += self.direction.x * speed
        self.collision("Horizontal")
        self.hitbox.y += self.direction.y * speed
        self.collision("Vertical")
        self.rect.center = self.hitbox.center

    # 碰撞检测方法
    def collision(self, direction):
        # 如果是水平方向的碰撞检测
        if direction == "Horizontal":
            # 遍历障碍物精灵组中的精灵
            for sprite in self.obstacle_sprites:
                # 如果碰撞框发生碰撞
                if sprite.hitbox.colliderect(self.hitbox):
                    # 根据移动方向调整碰撞框的位置
                    if self.direction.x > 0: # 向右移动
                        self.hitbox.right = sprite.hitbox.left
                    if self.direction.x < 0: # 向左移动
                        self.hitbox.left = sprite.hitbox.right
                        
        # 如果是垂直方向的碰撞检测
        if direction == "Vertical":
            # 遍历障碍物精灵组中的精灵
            for sprite in self.obstacle_sprites:
                # 如果碰撞框发生碰撞
                if sprite.hitbox.colliderect(self.hitbox):
                    # 根据移动方向调整碰撞框的位置
                    if self.direction.y > 0: # 向下移动
                        self.hitbox.bottom = sprite.hitbox.top
                    if self.direction.y < 0: # 向上移动
                        self.hitbox.top = sprite.hitbox.bottom

    # 返回正弦波值的方法
    def wave_value(self):
        # 获取当前时间的正弦值
        value = sin(pygame.time.get_ticks())
        # 如果值大于等于 0,则返回 255,否则返回 0
        if value >= 0:
            return 255
        else:
            return 0

.\Zelda-with-Python\Code\Level.py

代码语言:javascript
复制
# 导入pygame模块
import pygame
# 从Settings模块中导入所有内容
from Settings import *
# 从Tile模块中导入Tile类
from Tile import Tile
# 从Player模块中导入Player类
from Player import Player
# 从Debug模块中导入debug函数
from Debug import debug
# 从Support模块中导入所有内容
from Support import *
# 从random模块中导入choice和randint函数
from random import choice, randint
# 从Weapon模块中导入Weapon类
from Weapon import Weapon
# 从UI模块中导入UI类
from UI import UI
# 从Enemy模块中导入Enemy类
from Enemy import Enemy
# 从Particles模块中导入AnimationPlayer类
from Particles import AnimationPlayer
# 从Magic模块中导入MagicPlayer类
from Magic import MagicPlayer
# 从Upgrade模块中导入Upgrade类
from Upgrade import Upgrade
# 导入os模块
import os

# 用于文件(特别是图片)导入的代码(这行代码将目录更改为项目保存的位置)
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 创建YSortCameraGroup类,继承自pygame.sprite.Group类
class YSortCameraGroup(pygame.sprite.Group):
    def __init__(self):
        # 通用设置
        super().__init__()
        self.display_surface = pygame.display.get_surface()
        self.half_width = self.display_surface.get_size()[0] // 2
        self.half_height = self.display_surface.get_size()[1] // 2
        self.offset = pygame.math.Vector2()

        # 创建地板
        self.floor_surf = pygame.image.load("../Graphics/Tilemap/Ground.png").convert()
        self.floor_rect = self.floor_surf.get_rect(topleft = (0, 0))

    # 自定义绘制方法
    def custom_draw(self, player):
        # 获取偏移量
        self.offset.x = player.rect.centerx - self.half_width
        self.offset.y = player.rect.centery - self.half_height

        # 绘制地板
        floor_offset_pos = self.floor_rect.topleft - self.offset
        self.display_surface.blit(self.floor_surf, floor_offset_pos)

        # 对精灵进行排序绘制
        for sprite in sorted(self.sprites(), key = lambda sprite: sprite.rect.centery):
            offset_pos = sprite.rect.topleft - self.offset
            self.display_surface.blit(sprite.image, offset_pos)

    # 更新敌人位置
    def enemy_update(self, player):
        enemy_sprites = [sprite for sprite in self.sprites() if hasattr(sprite, "sprite_type") and sprite.sprite_type == "enemy"]
        for enemy in enemy_sprites:
            enemy.enemy_update(player)

.\Zelda-with-Python\Code\Magic.py

代码语言:javascript
复制
# 导入pygame模块
import pygame
# 从Settings模块中导入所有内容
from Settings import *
# 从random模块中导入randint函数
from random import randint
# 导入os模块
import os

# 这是用于文件(特别是图像)导入的(这一行将目录更改为项目保存的位置)
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 创建魔法玩家类
class MagicPlayer:
    def __init__(self, animation_player):
        # 初始化动画播放器
        self.animation_player = animation_player
        # 初始化声音字典
        self.sounds = {
            "heal": pygame.mixer.Sound("../Audio/Heal.wav"), 
            "flame": pygame.mixer.Sound("../Audio/Fire.wav")
        }

    # 治愈方法
    def heal(self, player, strength, cost, groups):
        # 如果玩家能量大于等于治愈消耗
        if player.energy >= cost:
            # 播放治愈声音
            self.sounds["heal"].play()
            # 增加玩家生命值
            player.health += strength
            # 减少玩家能量
            player.energy -= cost
            # 如果玩家生命值大于等于最大生命值
            if player.health >= player.stats["health"]:
                player.health = player.stats["health"]
            # 创建光环粒子效果
            self.animation_player.create_particles("aura", player.rect.center, groups)
            # 创建治愈粒子效果
            self.animation_player.create_particles("heal", player.rect.center + pygame.math.Vector2(0, -60), groups)

    # 火焰方法
    def flame(self, player, cost, groups):
        # 如果玩家能量大于等于火焰消耗
        if player.energy >= cost:
            # 减少玩家能量
            player.energy -= cost
            # 播放火焰声音
            self.sounds["flame"].play()

            # 根据玩家状态确定火焰方向
            if player.status.split("_")[0] == "right": direction = pygame.math.Vector2(1, 0)
            elif player.status.split("_")[0] == "left": direction = pygame.math.Vector2(-1, 0)
            elif player.status.split("_")[0] == "up": direction = pygame.math.Vector2(0, -1)
            else: direction = pygame.math.Vector2(0, 1)

            # 创建火焰粒子效果
            for i in range(1, 6):
                if direction.x: # 水平
                    offset_x = (direction.x * i) * TILESIZE
                    x = player.rect.centerx + offset_x + randint(-TILESIZE // 3, TILESIZE // 3)
                    y = player.rect.centery + randint(-TILESIZE // 3, TILESIZE // 3)
                    self.animation_player.create_particles("flame", (x, y), groups)
                else: # 垂直
                    offset_y = (direction.y * i) * TILESIZE
                    x = player.rect.centerx + randint(-TILESIZE // 3, TILESIZE // 3)
                    y = player.rect.centery + offset_y + randint(-TILESIZE // 3, TILESIZE // 3)
                    self.animation_player.create_particles("flame", (x, y), groups)

.\Zelda-with-Python\Code\Main.py

代码语言:javascript
复制
# 导入pygame和sys模块
import pygame, sys
# 从Settings模块中导入所有内容
from Settings import *
# 从Level模块中导入Level类
from Level import Level
# 导入os模块
import os

# 更改工作目录到项目所在的目录
os.chdir(os.path.dirname(os.path.abspath(__file__))

# 创建游戏屏幕并调用一些类
class Game:
    def __init__(self):
        # 初始化pygame
        pygame.init()
        # 创建屏幕并设置宽度和高度
        self.screen = pygame.display.set_mode((WIDTH, HEIGTH))
        # 设置窗口标题
        pygame.display.set_caption("Zelda with Python")
        # 加载游戏图标
        pygame_icon = pygame.image.load("../Graphics/Test/Player.png")
        pygame.display.set_icon(pygame_icon)
        # 创建时钟对象
        self.clock = pygame.time.Clock()

        # 创建Level对象
        self.level = Level()

        # 加载音乐
        main_sound = pygame.mixer.Sound("../Audio/Main.ogg")
        main_sound.set_volume(0.5)
        main_sound.play(loops = -1)

    # 游戏运行循环
    def run(self):
        while True:
            # 处理事件
            for event in pygame.event.get():
                # 如果事件类型为退出,则退出游戏
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                # 如果按下键盘上的m键,则切换菜单状态
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_m:
                        self.level.toggle_menu()
            
            # 填充屏幕颜色
            self.screen.fill(WATER_COLOR)
            # 运行关卡
            self.level.run()
            # 更新屏幕
            pygame.display.update()
            # 控制帧率
            self.clock.tick(FPS)

# 如果该文件被直接运行,则创建Game对象并运行游戏
if __name__ == "__main__":
    game = Game()
    game.run()

.\Zelda-with-Python\Code\Particles.py

代码语言:javascript
复制
# 导入pygame模块
import pygame
# 从Support模块中导入import_folder函数
from Support import import_folder
# 从random模块中导入choice函数
from random import choice
# 导入os模块
import os

# 改变当前工作目录到脚本所在目录
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 定义动画播放器类
class AnimationPlayer:
    def __init__(self):
        # 定义frames属性,包含不同动画类型的帧
        self.frames = {
            # Magic
            "flame": import_folder("../Graphics/Particles/Flame/Frames"),
            "aura": import_folder("../Graphics/Particles/Aura"),
            "heal": import_folder("../Graphics/Particles/Heal/Frames"),
            # Attacks 
            "claw": import_folder("../Graphics/Particles/Claw"),
            "slash": import_folder("../Graphics/Particles/Slash"),
            "sparkle": import_folder("../Graphics/Particles/Sparkle"),
            "leaf_attack": import_folder("../Graphics/Particles/leaf_attack"),
            "thunder": import_folder("../Graphics/Particles/Thunder"),
            # Monster Deaths
            "squid": import_folder("../Graphics/Particles/smoke_orange"),
            "raccoon": import_folder("../Graphics/Particles/Raccoon"),
            "spirit": import_folder("../Graphics/Particles/Nova"),
            "bamboo": import_folder("../Graphics/Particles/Bamboo"),
            # Leafs
            "leaf":(
                import_folder("../Graphics/Particles/Leaf1"),
                import_folder("../Graphics/Particles/Leaf2"),
                import_folder("../Graphics/Particles/Leaf3"),
                import_folder("../Graphics/Particles/Leaf4"),
                import_folder("../Graphics/Particles/Leaf5"),
                import_folder("../Graphics/Particles/Leaf6"),
                self.reflect_images(import_folder("../Graphics/Particles/Leaf1")),
                self.reflect_images(import_folder("../Graphics/Particles/Leaf2")),
                self.reflect_images(import_folder("../Graphics/Particles/Leaf3")),
                self.reflect_images(import_folder("../Graphics/Particles/Leaf4")),
                self.reflect_images(import_folder("../Graphics/Particles/Leaf5")),
                self.reflect_images(import_folder("../Graphics/Particles/Leaf6"))
                )
            }

    # 反转图像
    def reflect_images(self, frames):
        new_frames = []
        for frame in frames:
            flipped_frame = pygame.transform.flip(frame, True, False)
            new_frames.append(flipped_frame)
        return new_frames

    # 创建草粒子效果
    def create_grass_particles(self, pos, groups):
        animation_frames = choice(self.frames["leaf"])
        ParticleEffect(pos, animation_frames, groups)

    # 创建粒子效果
    def create_particles(self, animation_type, pos, groups):
        animation_frames = self.frames[animation_type]
        ParticleEffect(pos, animation_frames, groups)

# 粒子效果类
class ParticleEffect(pygame.sprite.Sprite):
    def __init__(self, pos, animation_frames, groups):
        super().__init__(groups)
        self.sprite_type = "magic"
        self.frame_index = 0
        self.animation_speed = 0.15
        self.frames = animation_frames
        self.image = self.frames[self.frame_index]
        self.rect = self.image.get_rect(center = pos)

    # 动画
    def animate(self):
        self.frame_index += self.animation_speed
        if self.frame_index >= len(self.frames):
            self.kill()
        else:
            self.image = self.frames[int(self.frame_index)]

    # 更新
    def update(self):
        self.animate()

.\Zelda-with-Python\Code\Player.py

代码语言:javascript
复制
# 导入 pygame 模块
import pygame
# 从 Support 模块中导入 import_folder 函数
from Support import import_folder
# 从 Settings 模块中导入所有内容
from Settings import *
# 从 Entity 模块中导入 Entity 类
from Entity import Entity
# 导入 os 和 sys 模块
import os, sys

# 将当前工作目录更改为 Main.py 文件所在的目录
# 这是为了在 Main.py 中进行文件导入时的路径设置
os.chdir(os.path.dirname(os.path.abspath(__file__)))

.\Zelda-with-Python\Code\Settings.py

代码语言:javascript
复制
# 导入 os 模块
import os

# 更改当前工作目录为当前文件所在目录
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 游戏设置
WIDTH = 1280  # 游戏窗口宽度
HEIGTH = 720  # 游戏窗口高度
FPS = 60  # 游戏帧率
TILESIZE = 64  # 地图瓦片大小
HITBOX_OFFSET = {  # 不同对象的碰撞框偏移量
	"player": -26,
	"object": -40,
	"grass": -10,
	"invisible": 0
	}

# 用户界面设置
BAR_HEIGHT = 20  # 柱状图高度
HEALTH_BAR_WIDTH = 200  # 生命值柱状图宽度
ENERGY_BAR_WIDTH = 140  # 能量值柱状图宽度
ITEM_BOX_SIZE = 80  # 物品框大小
UI_FONT = "../Graphics/Font/Joystix.ttf"  # 用户界面字体
UI_FONT_SIZE = 18  # 用户界面字体大小

# 通用颜色
WATER_COLOR = "#71ddee"  # 水的颜色
UI_BG_COLOR = "#222222"  # 用户界面背景颜色
UI_BORDER_COLOR = "#111111"  # 用户界面边框颜色
TEXT_COLOR = "#EEEEEE"  # 文本颜色

# 用户界面颜色
HEALTH_COLOR = "Red"  # 生命值颜色
ENERGY_COLOR = "Blue"  # 能量值颜色
UI_BORDER_COLOR_ACTIVE = "Gold"  # 用户界面激活时的边框颜色

# 升级菜单
TEXT_COLOR_SELECTED = "#111111"  # 选中文本颜色
BAR_COLOR = "#EEEEEE"  # 柱状图颜色
BAR_COLOR_SELECTED = "#111111"  # 选中柱状图颜色
UPGRADE_BG_COLOR_SELECTED = "#EEEEEE"  # 选中升级菜单背景颜色

# 武器
weapon_data = {
	"sword": {"cooldown": 100, "damage": 15, "graphic": "../Graphics/Weapons/Sword/Full.png"},  # 剑的冷却时间、伤害和图像路径
	"lance": {"cooldown": 400, "damage": 30, "graphic": "../Graphics/Weapons/Lance/Full.png"},  # 枪的冷却时间、伤害和图像路径
	"axe": {"cooldown": 300, "damage": 20, "graphic": "../Graphics/Weapons/Axe/Full.png"},  # 斧头的冷却时间、伤害和图像路径
	"rapier": {"cooldown": 50, "damage": 8, "graphic": "../Graphics/Weapons/Rapier/Full.png"},  # 细剑的冷却时间、伤害和图像路径
	"sai": {"cooldown": 80, "damage": 10, "graphic": "../Graphics/Weapons/Sai/Full.png"}  # 菜刀的冷却时间、伤害和图像路径
    }

# 魔法
magic_data = {
	"flame": {"strength": 5, "cost": 20, "graphic": "../Graphics/Particles/Flame/Fire.png"},  # 火焰的强度、消耗和图像路径
	"heal": {"strength": 20, "cost": 10, "graphic": "../Graphics/Particles/Heal/Heal.png"}  # 治疗的强度、消耗和图像路径
	}

# 敌人
monster_data = {
	"squid": {"health": 100, "exp": 180, "damage": 20, "attack_type": "slash", "attack_sound": "../Audio/Attack/Slash.wav", "speed": 3, "resistance": 3, "attack_radius": 80, "notice_radius": 360},  # 鱿鱼的生命值、经验值、伤害等信息
	"raccoon": {"health": 300, "exp": 300, "damage": 40, "attack_type": "claw", "attack_sound": "../Audio/Attack/Claw.wav", "speed": 2, "resistance": 3, "attack_radius": 120, "notice_radius": 400},  # 浣熊的生命值、经验值、伤害等信息
	"spirit": {"health": 100, "exp": 200, "damage": 8, "attack_type": "thunder", "attack_sound": "../Audio/Attack/Fireball.wav", "speed": 4, "resistance": 3, "attack_radius": 60, "notice_radius": 350},  # 精灵的生命值、经验值、伤害等信息
	"bamboo": {"health": 70, "exp": 150, "damage": 6, "attack_type": "leaf_attack", "attack_sound": "../Audio/Attack/Slash.wav", "speed": 3, "resistance": 3, "attack_radius": 50, "notice_radius": 300}  # 竹子的生命值、经验值、伤害等信息
	}

.\Zelda-with-Python\Code\Support.py

代码语言:javascript
复制
# 从csv模块中导入reader函数
from csv import reader
# 导入os模块
import os
# 从os模块中导入walk函数
from os import walk
# 导入pygame模块

# 用于将CSV文件导入Python以及其他相关操作

# 这是用于文件(特别是图片)导入的代码(这行将目录更改为项目保存的位置)
os.chdir(os.path.dirname(os.path.abspath(__file__)))


def import_csv_layout(path): 
    # 创建一个空的地形地图列表
    terrain_map = []

    # 打开指定路径的文件
    with open(path) as level_map:
        # 使用CSV reader函数读取文件,以逗号为分隔符
        layout = reader(level_map, delimiter = ",")

        # 遍历CSV文件的每一行
        for row in layout:
            # 将每一行转换为列表,并添加到地形地图列表中
            terrain_map.append(list(row))
        
        # 返回地形地图列表
        return terrain_map


def import_folder(path):
    # 创建一个空的表面列表
    surface_list = []
    
    # 遍历指定路径下的所有文件和子目录
    for _, __, img_files in walk(path):
        # 遍历每个图片文件
        for image in img_files:
            # 拼接完整的文件路径
            full_path = path + "/" + image
            # 加载图片并转换为alpha通道
            image_surf = pygame.image.load(full_path).convert_alpha()
            # 将图片表面添加到表面列表中
            surface_list.append(image_surf)
    # 返回表面列表
    return surface_list

.\Zelda-with-Python\Code\Tile.py

代码语言:javascript
复制
# 导入pygame模块
import pygame
# 从Settings模块中导入所有内容
from Settings import *
# 导入os模块
import os

# 将当前工作目录更改为Main.py所在的目录
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 创建Tile类,继承自pygame.sprite.Sprite类
class Tile(pygame.sprite.Sprite):
    # 初始化方法,接受位置、组、精灵类型和表面作为参数
    def __init__(self, pos, groups, sprite_type, surface = pygame.Surface((TILESIZE, TILESIZE))):
        # 调用父类的初始化方法
        super().__init__(groups)

        # 设置精灵类型
        self.sprite_type = sprite_type
        # 根据精灵类型获取y轴偏移量
        y_offset = HITBOX_OFFSET[sprite_type]
        # 设置精灵的图像
        self.image = surface
        
        # 根据精灵类型设置精灵的矩形位置
        if sprite_type == "object":
            self.rect = self.image.get_rect(topleft = (pos[0], pos[1] - TILESIZE))
        else:
            self.rect = self.image.get_rect(topleft = pos)
        # 设置精灵的碰撞框
        self.hitbox = self.rect.inflate(0, y_offset)

.\Zelda-with-Python\Code\UI.py

代码语言:javascript
复制
# 导入pygame模块
import pygame
# 从Settings模块中导入所有内容
from Settings import *
# 导入os模块
import os

# 改变当前工作目录到项目所在的目录
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 创建UI类
class UI:
    def __init__(self):
        
        # General
        # 获取显示表面
        self.display_surface = pygame.display.get_surface()
        # 创建字体对象
        self.font = pygame.font.Font(UI_FONT, UI_FONT_SIZE)

        # Bar Setup
        # 创建血条矩形对象
        self.health_bar_rect = pygame.Rect(10, 10, HEALTH_BAR_WIDTH, BAR_HEIGHT)
        # 创建能量条矩形对象
        self.energy_bar_rect = pygame.Rect(10, 34, ENERGY_BAR_WIDTH, BAR_HEIGHT)

        # Convert Weapon Dictionary
        # 将武器字典中的图像转换为pygame图像对象
        self.weapon_graphics = []
        for weapon in weapon_data.values():
            path = weapon["graphic"]
            weapon = pygame.image.load(path).convert_alpha()
            self.weapon_graphics.append(weapon)

        # Convert Magic Dictionary
        # 将魔法字典中的图像转换为pygame图像对象
        self.magic_graphics = []
        for magic in magic_data.values():
            magic = pygame.image.load(magic["graphic"]).convert_alpha()
            self.magic_graphics.append(magic)

    # 显示条形图
    def show_bar(self, current, max_amount, bg_rect, color):
        # 绘制背景
        pygame.draw.rect(self.display_surface, UI_BG_COLOR, bg_rect)

        # 将状态转换为像素
        ratio = current / max_amount
        current_width = bg_rect.width * ratio
        current_rect = bg_rect.copy()
        current_rect.width = current_width

        # 绘制条形图
        pygame.draw.rect(self.display_surface, color, current_rect)
        pygame.draw.rect(self.display_surface, UI_BORDER_COLOR, bg_rect, 3)

    # 显示经验值
    def show_exp(self, exp):
        text_surf = self.font.render(str(int(exp)), False, TEXT_COLOR)
        x = self.display_surface.get_size()[0] - 20
        y = self.display_surface.get_size()[1] - 20
        text_rect = text_surf.get_rect(bottomright = (x, y))

        pygame.draw.rect(self.display_surface, UI_BG_COLOR, text_rect.inflate(20, 20))
        self.display_surface.blit(text_surf, text_rect)
        pygame.draw.rect(self.display_surface, UI_BORDER_COLOR, text_rect.inflate(20, 20), 3)

    # 选择框
    def selection_box(self, left, top, has_switched):
        bg_rect = pygame.Rect(left, top, ITEM_BOX_SIZE, ITEM_BOX_SIZE)
        pygame.draw.rect(self.display_surface, UI_BG_COLOR, bg_rect)
        if has_switched:
            pygame.draw.rect(self.display_surface, UI_BORDER_COLOR_ACTIVE, bg_rect, 3)
        else:
            pygame.draw.rect(self.display_surface, UI_BORDER_COLOR, bg_rect, 3)
        return bg_rect

    # 武器叠加
    def weapon_overlay(self, weapon_index, has_switched):
        bg_rect = self.selection_box(10, 630, has_switched) # 武器框
        weapon_surf = self.weapon_graphics[weapon_index]
        weapon_rect = weapon_surf.get_rect(center = bg_rect.center)

        self.display_surface.blit(weapon_surf, weapon_rect)

    # 魔法叠加
    def magic_overlay(self, magic_index, has_switched):
        bg_rect = self.selection_box(100, 630, has_switched) # 魔法框
        magic_surf = self.magic_graphics[magic_index]
        magic_rect = magic_surf.get_rect(center = bg_rect.center)

        self.display_surface.blit(magic_surf, magic_rect)

    # 显示
    def display(self, player):
        self.show_bar(player.health, player.stats["health"], self.health_bar_rect, HEALTH_COLOR)
        self.show_bar(player.energy, player.stats["energy"], self.energy_bar_rect, ENERGY_COLOR)

        self.show_exp(player.exp)

        self.weapon_overlay(player.weapon_index, not player.can_switch_weapon)
        self.magic_overlay(player.magic_index, not player.can_switch_magic)

.\Zelda-with-Python\Code\Upgrade.py

代码语言:javascript
复制
# 导入必要的模块
import imp  # 引入模块
from traceback import print_tb  # 从模块中引入特定函数
import pygame  # 导入pygame模块
from Settings import *  # 从Settings模块中导入所有内容
import os  # 导入os模块

# 更改工作目录到项目所在的目录
os.chdir(os.path.dirname(os.path.abspath(__file__))

# 定义Upgrade类
class Upgrade:
    def __init__(self, player):
        # 通用设置
        self.display_surface = pygame.display.get_surface()  # 获取显示表面
        self.player = player  # 设置玩家对象
        self.attribute_nr = len(player.stats)  # 获取玩家属性数量
        self.attribute_names = list(player.stats.keys())  # 获取玩家属性名称列表
        self.max_values = list(player.max_stats.values())  # 获取玩家最大属性值列表
        self.font = pygame.font.Font(UI_FONT, UI_FONT_SIZE)  # 设置字体

        # 创建物品
        self.height = self.display_surface.get_size()[1] * 0.8  # 设置高度
        self.width = self.display_surface.get_size()[0] // 6  # 设置宽度
        self.create_items()  # 创建物品

        # 选择系统
        self.selection_index = 0  # 初始化选择索引
        self.selection_time = None  # 初始化选择时间
        self.can_move = True  # 初始化可移动状态

    # 输入处理
    def input(self):
        keys = pygame.key.get_pressed()  # 获取按键状态

        if self.can_move:
            if keys[pygame.K_RIGHT] and self.selection_index < self.attribute_nr - 1:  # 如果按下右键且选择索引小于属性数量减1
                self.selection_index += 1  # 选择索引加1
                self.can_move = False  # 设置为不可移动
                self.selection_time = pygame.time.get_ticks()  # 获取当前时间
            elif keys[pygame.K_LEFT] and self.selection_index >= 1:  # 如果按下左键且选择索引大于等于1
                self.selection_index -= 1  # 选择索引减1
                self.can_move = False  # 设置为不可移动
                self.selection_time = pygame.time.get_ticks()  # 获取当前时间

            if keys[pygame.K_SPACE]:  # 如果按下空格键
                self.can_move = False  # 设置为不可移动
                self.selection_time = pygame.time.get_ticks()  # 获取当前时间
                self.item_list[self.selection_index].trigger(self.player)  # 触发物品效果

    # 选择冷却
    def selection_cooldown(self):
        if not self.can_move:  # 如果可以移动
            current_time = pygame.time.get_ticks()  # 获取当前时间
            if current_time - self.selection_time >= 300:  # 如果当前时间减去选择时间大于等于300
                self.can_move = True  # 设置为可移动

    # 创建物品
    def create_items(self):
        self.item_list = []  # 初始化物品列表

        for item, index in enumerate(range(self.attribute_nr)):  # 遍历属性数量
            # 水平位置
            full_width = self.display_surface.get_size()[0]  # 获取显示表面宽度
            increment = full_width // self.attribute_nr  # 计算增量
            left = (item * increment) + (increment - self.width) // 2  # 计算左边距

            # 垂直位置
            top = self.display_surface.get_size()[1] * 0.1  # 计算顶部距离

            # 创建对象
            item = Item(left, top, self.width, self.height, index, self.font)  # 创建物品对象
            self.item_list.append(item)  # 将物品对象添加到列表中

    # 显示
    def display(self):
        self.input()  # 处理输入
        self.selection_cooldown()  # 处理选择冷却

        for index, item in enumerate(self.item_list):  # 遍历物品列表
            # 获取属性
            name = self.attribute_names[index]  # 获取属性名称
            value = self.player.get_value_by_index(index)  # 获取属性值
            max_value = self.max_values[index]  # 获取最大属性值
            cost = self.player.get_cost_by_index(index)  # 获取花费
            item.display(self.display_surface, self.selection_index, name, value, max_value, cost)  # 显示物品


# 物品类
class Item:
    def __init__(self, l, t, w, h, index, font):
        self.rect = pygame.Rect(l, t, w, h)  # 设置矩形
        self.index = index  # 设置索引
        self.font = font  # 设置字体

    # 显示名称
    def display_names(self, surface, name, cost, selected):
        color = TEXT_COLOR_SELECTED if selected else TEXT_COLOR  # 根据选择状态设置颜色

        # 标题
        title_surf = self.font.render(name, False, color)  # 渲染标题
        title_rect = title_surf.get_rect(midtop=self.rect.midtop + pygame.math.Vector2(0, 20))  # 设置标题位置

        # 花费
        cost_surf = self.font.render(f"{int(cost)}", False, color)  # 渲染花费
        cost_rect = cost_surf.get_rect(midbottom=self.rect.midbottom - pygame.math.Vector2(0, 20))  # 设置花费位置

        # 绘制
        surface.blit(title_surf, title_rect)  # 绘制标题
        surface.blit(cost_surf, cost_rect)  # 绘制花费

    # 显示进度条
    def display_bar(self, surface, value, max_value, selected):
        # 绘制设置
        top = self.rect.midtop + pygame.math.Vector2(0, 60)  # 设置顶部位置
        bottom = self.rect.midbottom - pygame.math.Vector2(0, 60)  # 设置底部位置
        color = BAR_COLOR_SELECTED if selected else BAR_COLOR  # 根据选择状态设置颜色

        # 进度条设置
        full_height = bottom[1] - top[1]  # 计算总高度
        relative_number = (value / max_value) * full_height  # 计算相对数值
        value_rect = pygame.Rect(top[0] - 15, bottom[1] - relative_number, 30, 10)  # 设置数值矩形

        # 绘制元素
        pygame.draw.line(surface, color, top, bottom, 5)  # 绘制线条
        pygame.draw.rect(surface, color, value_rect)  # 绘制矩形

    # 触发效果
    def trigger(self, player):
        upgrade_attribute = list(player.stats.keys())[self.index]  # 获取升级属性

        if player.exp >= player.upgrade_cost[upgrade_attribute] and player.stats[upgrade_attribute] < player.max_stats[upgrade_attribute]:  # 如果玩家经验大于等于升级花费且属性小于最大属性
            player.exp -= player.upgrade_cost[upgrade_attribute]  # 减去升级花费
            player.stats[upgrade_attribute] *= 1.2  # 属性增加20%
            player.upgrade_cost[upgrade_attribute] *= 1.4  # 升级花费增加40%

        if player.stats[upgrade_attribute] > player.max_stats[upgrade_attribute]:  # 如果属性大于最大属性
            player.stats[upgrade_attribute] = player.max_stats[upgrade_attribute]  # 将属性设置为最大属性

    # 显示
    def display(self, surface, selection_num, name, value, max_value, cost):
        if self.index == selection_num:  # 如果索引等于选择索引
            pygame.draw.rect(surface, UPGRADE_BG_COLOR_SELECTED, self.rect)  # 绘制选中背景
            pygame.draw.rect(surface, UI_BORDER_COLOR, self.rect, 4)  # 绘制边框
        else:
            pygame.draw.rect(surface, UI_BG_COLOR, self.rect)  # 绘制背景
            pygame.draw.rect(surface, UI_BORDER_COLOR, self.rect, 4)  # 绘制边框

        self.display_names(surface, name, cost, self.index == selection_num)  # 显示名称
        self.display_bar(surface, value, max_value, self.index == selection_num)  # 显示进度条

.\Zelda-with-Python\Code\Weapon.py

代码语言:javascript
复制
# 导入必要的模块
import os
import pygame

# 这是用于导入文件(特别是图片)的部分(这一行将目录更改为项目保存的位置)
os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 创建武器类,继承自 pygame.sprite.Sprite 类
class Weapon(pygame.sprite.Sprite):
    def __init__(self, player, groups):
        super().__init__(groups)
        self.sprite_type = "weapon"
        # 获取玩家的状态(方向)
        direction = player.status.split("_")[0]

        # 图形
        full_path = f"../Graphics/Weapons/{player.weapon}/{direction}.png"
        # 加载武器图片并转换为透明度格式
        self.image = pygame.image.load(full_path).convert_alpha()

        # 放置
        if direction == "right":
            # 如果方向向右,则将武器放置在玩家矩形的右侧中间位置
            self.rect = self.image.get_rect(midleft = player.rect.midright + pygame.math.Vector2(0, 16))
        elif direction == "left":
            # 如果方向向左,则将武器放置在玩家矩形的左侧中间位置
            self.rect = self.image.get_rect(midright = player.rect.midleft + pygame.math.Vector2(0, 16))
        elif direction == "down":
            # 如果方向向下,则将武器放置在玩家矩形的底部中间位置
            self.rect = self.image.get_rect(midtop = player.rect.midbottom + pygame.math.Vector2(-10, 0))
        else:
            # 如果方向向上,则将武器放置在玩家矩形的顶部中间位置
            self.rect = self.image.get_rect(midbottom = player.rect.midtop + pygame.math.Vector2(-10, 0))
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-02-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • .\Zelda-with-Python\Code\Debug.py
  • .\Zelda-with-Python\Code\Enemy.py
  • .\Zelda-with-Python\Code\Entity.py
  • .\Zelda-with-Python\Code\Level.py
  • .\Zelda-with-Python\Code\Magic.py
  • .\Zelda-with-Python\Code\Main.py
  • .\Zelda-with-Python\Code\Particles.py
  • .\Zelda-with-Python\Code\Player.py
  • .\Zelda-with-Python\Code\Settings.py
  • .\Zelda-with-Python\Code\Support.py
  • .\Zelda-with-Python\Code\Tile.py
  • .\Zelda-with-Python\Code\UI.py
  • .\Zelda-with-Python\Code\Upgrade.py
  • .\Zelda-with-Python\Code\Weapon.py
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档