Compare commits

...

5 Commits
main ... code

@ -0,0 +1,247 @@
import pygame
from settings import *
from entity import Entity
from support import *
class Enemy(Entity):
def __init__(self,monster_name,pos,groups,obstacle_sprites,damage_player,trigger_death_particles,add_exp):
# general setup
# 调用父类的初始化方法,将实例添加到指定的分组中
super().__init__(groups)
# 设置角色的精灵类型为 'enemy'
self.sprite_type = 'enemy'
# graphics setup
# 导入指定怪物名称的图像资源
self.import_graphics(monster_name)
# 设置角色的状态为 'idle'(空闲状态)
self.status = 'idle'
# 获取角色当前状态的图像
self.image = self.animations[self.status][self.frame_index]
# movement
# 设置角色的位置
self.rect = self.image.get_rect(topleft = pos)
# 设置角色的碰撞框,稍微向上收缩一些
self.hitbox = self.rect.inflate(0,-10)
# 设置角色所在的障碍物精灵组
self.obstacle_sprites = obstacle_sprites
# stats 将怪物的各种值赋予
self.monster_name = monster_name
# 从怪物数据字典中获取指定怪物的信息
monster_info = monster_data[self.monster_name]
# 怪物的生命值
self.health = monster_info['health']
# 击败怪物后获得的经验值
self.exp = monster_info['exp']
# 怪物的移动速度
self.speed = monster_info['speed']
# 怪物的攻击伤害
self.attack_damage = monster_info['damage']
# 怪物的抵抗力
self.resistance = monster_info['resistance']
# 怪物的攻击范围
self.attack_radius = monster_info['attack_radius']
# 怪物的发现玩家范围
self.notice_radius = monster_info['notice_radius']
# 怪物的攻击类型
self.attack_type = monster_info['attack_type']
# player interaction 设置角色与玩家交互相关的属性和方法
# 角色是否能够进行攻击
self.can_attack = True
# 记录上次攻击的时间
self.attack_time = None
# 攻击的冷却时间(毫秒)
self.attack_cooldown = 400
# 对玩家造成伤害的方法
self.damage_player = damage_player
# 触发角色死亡特效的方法
self.trigger_death_particles = trigger_death_particles
# 增加玩家经验值的方法
self.add_exp = add_exp
# invincibility timer 设置角色的无敌时间相关属性
# 角色是否处于易受伤状态
self.vulnerable = True
# 记录角色受到攻击的时间点
self.hit_time = None
# 角色的无敌持续时间(毫秒)
self.invincibility_duration = 300
# sounds 设置角色相关的音效
# 死亡音效
self.death_sound = pygame.mixer.Sound('../audio/death.wav')
# 受伤音效
self.hit_sound = pygame.mixer.Sound('../audio/hit.wav')
# 攻击音效
self.attack_sound = pygame.mixer.Sound(monster_info['attack_sound'])
# 设置死亡音效的音量
self.death_sound.set_volume(0.6)
# 设置受伤音效的音量
self.hit_sound.set_volume(0.6)
# 设置攻击音效的音量
self.attack_sound.set_volume(0.6)
def import_graphics(self,name):
# 初始化动画字典包含三种动画状态idle空闲、move移动、attack攻击
self.animations = {'idle':[],'move':[],'attack':[]}
# 指定敌人角色图形资源的主路径,根据角色名称构建路径
main_path = f'../graphics/monsters/{name}/'
# 调用 import_folder 函数导入指定路径下的图像资源,并将结果存储到动画字典中对应状态的键中
for animation in self.animations.keys():
self.animations[animation] = import_folder(main_path + animation)
def get_player_distance_direction(self,player):
# 获取敌人角色和玩家角色的中心点坐标作为向量
enemy_vec = pygame.math.Vector2(self.rect.center)
player_vec = pygame.math.Vector2(player.rect.center)
# 计算敌人角色与玩家角色之间的距离
distance = (player_vec - enemy_vec).magnitude()
# 如果距离大于 0则计算方向向量
if distance > 0:
# 计算方向向量并归一化
direction = (player_vec - enemy_vec).normalize()
# 距离为 0 或负数时,方向向量为零向量
else:
direction = pygame.math.Vector2()
# 返回距离和方向向量的元组
return (distance,direction)
def get_status(self, player):
# 获取敌人角色与玩家角色的距离
distance = self.get_player_distance_direction(player)[0]
# 根据距离和设定的攻击范围、发现范围确定敌人角色的状态
if distance <= self.attack_radius and self.can_attack:
# 如果距离小于等于攻击范围并且可以进行攻击
if self.status != 'attack':
# 重置动画帧索引
self.frame_index = 0
# 设置状态为攻击
self.status = 'attack'
# 如果距离小于等于发现范围
elif distance <= self.notice_radius:
# 设置状态为移动
self.status = 'move'
# 距离大于发现范围
else:
# 设置状态为空闲(静止)
self.status = 'idle'
def actions(self,player):
# 如果状态为攻击
if self.status == 'attack':
# 记录攻击时间
self.attack_time = pygame.time.get_ticks()
# 对玩家造成伤害
self.damage_player(self.attack_damage,self.attack_type)
# 播放攻击音效
self.attack_sound.play()
# 如果状态为移动
elif self.status == 'move':
# 获取朝向玩家的方向向量
self.direction = self.get_player_distance_direction(player)[1]
# 其他情况(状态为空闲或其他)
else:
# 将方向向量设为零向量,即停止移动
self.direction = pygame.math.Vector2()
def animate(self):
# 获取当前状态对应的动画帧列表
animation = self.animations[self.status]
# 更新帧索引,控制动画播放速度
self.frame_index += self.animation_speed
# 如果帧索引超过动画帧列表的长度
if self.frame_index >= len(animation):
# 如果是攻击状态,设置为不可攻击状态
if self.status == 'attack':
self.can_attack = False
# 重置帧索引,从头开始播放动画
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)
# 如果角色不是易受伤状态,则设置完全不透明(透明度为 255
else:
self.image.set_alpha(255)
# 处理敌人角色的攻击冷却和无敌状态的持续时间。
def cooldowns(self):
# 获取当前时间(以毫秒为单位)
current_time = pygame.time.get_ticks()
# 处理攻击冷却时间
# 如果当前不能攻击(即处于攻击冷却中)
if not self.can_attack:
# 如果距离上次攻击时间已经超过攻击冷却时间
if current_time - self.attack_time >= self.attack_cooldown:
# 设置为可以再次攻击
self.can_attack = True
# 处理无敌状态持续时间
# 如果当前不可受伤(即处于无敌状态)
if not self.vulnerable:
# 如果距离上次受伤时间已经超过无敌状态持续时间
if current_time - self.hit_time >= self.invincibility_duration:
# 设置为可受伤状态(结束无敌状态)
self.vulnerable = True
# 处理敌人角色受到玩家攻击造成的伤害。
def get_damage(self,player,attack_type):
if self.vulnerable:
# 播放受击音效
self.hit_sound.play()
# 设置受击后的朝向玩家的方向向量
self.direction = self.get_player_distance_direction(player)[1]
# 根据攻击类型应用不同的伤害值
if attack_type == 'weapon':
# 玩家使用武器攻击造成伤害
self.health -= player.get_full_weapon_damage()
# 玩家使用魔法攻击造成伤害
else:
self.health -= player.get_full_magic_damage()
# 记录受击时间
self.hit_time = pygame.time.get_ticks()
# 设置为不可受伤状态,进入无敌状态
self.vulnerable = False
#检查角色是否死亡
def check_death(self):
# 如果敌人角色的生命值小于等于 0表示角色已经死亡
if self.health <= 0:
# 从精灵组中移除角色,通常用于删除角色或停止其更新和渲染
self.kill()
# 触发死亡粒子效果,通常用于播放死亡动画或粒子效果
self.trigger_death_particles(self.rect.center,self.monster_name)
# 增加经验值
self.add_exp(self.exp)
# 播放死亡音效,提供游戏中的音效反馈
self.death_sound.play()
#被攻击后的反应
def hit_reaction(self):
# 如果敌人角色不可受伤
if not self.vulnerable:
# 则将角色的移动方向向量乘以负阻力,模拟受击后的击退效果。
self.direction *= -self.resistance
#更新状态
def update(self):
# 处理受击反应
self.hit_reaction()
# 移动角色,传入速度参数
self.move(self.speed)
# 更新角色动画
self.animate()
# 处理攻击冷却和无敌状态持续时间
self.cooldowns()
# 检查角色是否死亡并执行死亡逻辑
self.check_death()
def enemy_update(self,player):
# 获取敌人角色的状态
self.get_status(player)
# 执行敌人角色的行为
self.actions(player)

@ -0,0 +1,67 @@
import pygame
from math import sin
class Entity(pygame.sprite.Sprite):
def __init__(self,groups):
# 初始化精灵对象,将其添加到指定的精灵组中
super().__init__(groups)
# 当前动画帧的索引,初始值为 0
self.frame_index = 0
# 动画播放速度,控制动画切换的速度
self.animation_speed = 0.15
# 实体对象的移动方向向量,初始为零向量
self.direction = pygame.math.Vector2()
def move(self,speed):
# 检查移动方向向量的大小是否不为零
if self.direction.magnitude() != 0:
# 将移动方向向量归一化单位化确保移动方向的长度为1用于保持移动速度的一致性和准确性
self.direction = self.direction.normalize()
# 更新碰撞箱hitbox的水平位置
self.hitbox.x += self.direction.x * speed
# 进行水平方向上的碰撞检测和处理
self.collision('horizontal')
# 更新碰撞箱hitbox的垂直位置
self.hitbox.y += self.direction.y * speed
# 进行垂直方向上的碰撞检测和处理
self.collision('vertical')
# 更新实体对象的外部矩形rect的中心位置确保渲染时显示在正确的位置
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

@ -0,0 +1,246 @@
import pygame
from settings import *
from tile import Tile
from player import Player
from support import *
from random import choice, randint
from weapon import Weapon
from ui import UI
from enemy import Enemy
from particles import AnimationPlayer
from magic import MagicPlayer
from upgrade import Upgrade
class Level:
def __init__(self):
# 获取游戏窗口的显示表面surface
self.display_surface = pygame.display.get_surface()
# 标记游戏是否处于暂停状态
self.game_paused = False
# 可见精灵组,用于管理在摄像机视野内可见的精灵
self.visible_sprites = YSortCameraGroup()
# 障碍物精灵组,用于管理所有的障碍物精灵
self.obstacle_sprites = pygame.sprite.Group()
# 当前攻击对象
self.current_attack = None
# 攻击精灵组,用于管理所有的攻击精灵
self.attack_sprites = pygame.sprite.Group()
# 可被攻击的精灵组,用于管理所有可以被攻击的精灵
self.attackable_sprites = pygame.sprite.Group()
# 创建地图
self.create_map()
# UI 对象,用于管理游戏界面的显示和交互
self.ui = UI()
# 升级对象,与玩家角色相关联,用于管理升级和技能
self.upgrade = Upgrade(self.player)
# 动画播放器对象,用于管理游戏中的动画效果
self.animation_player = AnimationPlayer()
# 魔法播放器对象,与动画播放器相关联,用于管理游戏中的魔法效果
self.magic_player = MagicPlayer(self.animation_player)
def create_map(self):
# 定义不同类型的地图布局和图形资源路径
layouts = {
'boundary': import_csv_layout('../map/map_FloorBlocks.csv'),
'grass': import_csv_layout('../map/map_Grass.csv'),
'object': import_csv_layout('../map/map_Objects.csv'),
'entities': import_csv_layout('../map/map_Entities.csv')
}
graphics = {
'grass': import_folder('../graphics/Grass'),
'objects': import_folder('../graphics/objects')
}
# 遍历不同的地图布局和样式
for style,layout in layouts.items():
# 遍历地图布局的每一行
for row_index,row in enumerate(layout):
# 遍历每行中的每个元素(列
for col_index, col in enumerate(row):
# 如果元素不为'-1',表示有地图元素需要创建
if col != '-1':
# 计算元素在屏幕上的位置(像素坐标)
x = col_index * TILESIZE
y = row_index * TILESIZE
# 边界类型的地图元素
if style == 'boundary':
# 创建障碍物精灵对象,设置为'invisible'类型(不可见)
Tile((x,y),[self.obstacle_sprites],'invisible')
# 草地类型的地图元素
if style == 'grass':
# 从草地图形资源中随机选择一个图像
random_grass_image = choice(graphics['grass'])
# 创建草地精灵对象,加入可见精灵组、障碍物精灵组和可攻击精灵组
Tile(
(x,y),
[self.visible_sprites,self.obstacle_sprites,self.attackable_sprites],
'grass',
random_grass_image)
# 物体类型的地图元素
if style == 'object':
# 根据列数获取物体图形资源,创建物体精灵对象
surf = graphics['objects'][int(col)]
Tile((x,y),[self.visible_sprites,self.obstacle_sprites],'object',surf)
# 实体类型的地图元素(角色和敌人)
if style == 'entities':
# 玩家角色
if col == '394':
# 创建玩家对象,并加入可见精灵组
self.player = Player(
(x,y),
[self.visible_sprites],
self.obstacle_sprites,
self.create_attack,
self.destroy_attack,
self.create_magic)
# 敌人角色
else:
# 根据不同的角色编号选择对应的怪物名称
if col == '390': monster_name = 'bamboo'
elif col == '391': monster_name = 'spirit'
elif col == '392': monster_name ='raccoon'
else: monster_name = 'squid'
# 创建敌人对象,并加入可见精灵组和可攻击精灵组
Enemy(
monster_name,
(x,y),
[self.visible_sprites,self.attackable_sprites],
self.obstacle_sprites,
self.damage_player,
self.trigger_death_particles,
self.add_exp)
# 创建武器对象,将其设为当前攻击对象
def create_attack(self):
# 该方法用于创建武器对象,并将其设为当前攻击对象。
self.current_attack = Weapon(self.player,[self.visible_sprites,self.attack_sprites])
def create_magic(self,style,strength,cost):
if style == 'heal':
# 创建治疗魔法效果
self.magic_player.heal(self.player,strength,cost,[self.visible_sprites])
if style == 'flame':
# 创建火焰魔法效果
self.magic_player.flame(self.player,cost,[self.visible_sprites,self.attack_sprites])
def destroy_attack(self):
# 检查当前是否存在攻击对象
if self.current_attack:
# 销毁当前攻击对象
self.current_attack.kill()
# 将当前攻击对象设置为 None
self.current_attack = None
def player_attack_logic(self):
# 检查是否存在攻击精灵
if self.attack_sprites:
# 遍历每个攻击精灵
for attack_sprite in self.attack_sprites:
# 检测当前攻击精灵与可攻击精灵组中的精灵是否发生碰撞
collision_sprites = pygame.sprite.spritecollide(attack_sprite,self.attackable_sprites,False)
# 如果发生碰撞,遍历碰撞到的每个精灵
if collision_sprites:
for target_sprite in collision_sprites:
# 如果碰撞到的是草地精灵
if target_sprite.sprite_type == 'grass':
# 获取草地精灵的中心位置和偏移量
pos = target_sprite.rect.center
offset = pygame.math.Vector2(0,75)
# 随机生成一定数量的草叶粒子效果
for leaf in range(randint(3,6)):
self.animation_player.create_grass_particles(pos - offset,[self.visible_sprites])
# 销毁草地精灵
target_sprite.kill()
# 如果碰撞到的是其他类型的精灵,执行造成伤害的操作
else:
target_sprite.get_damage(self.player,attack_sprite.sprite_type)
def damage_player(self,amount,attack_type):
# 如果玩家处于可受伤状态
if self.player.vulnerable:
# 减少玩家的健康值
self.player.health -= amount
# 设置玩家为无敌状态
self.player.vulnerable = False
# 记录玩家受伤的时间
self.player.hurt_time = pygame.time.get_ticks()
# 创建攻击类型的粒子效果
self.animation_player.create_particles(attack_type,self.player.rect.center,[self.visible_sprites])
def trigger_death_particles(self,pos,particle_type):
# 创建指定类型的死亡粒子效果
self.animation_player.create_particles(particle_type,pos,self.visible_sprites)
def add_exp(self,amount):
# 增加玩家的经验值
self.player.exp += amount
def toggle_menu(self):
# 切换游戏菜单状态(暂停或继续)
self.game_paused = not self.game_paused
def run(self):
# 绘制可见精灵和玩家
self.visible_sprites.custom_draw(self.player)
# 显示用户界面UI
self.ui.display(self.player)
# 如果游戏暂停,显示升级界面
if self.game_paused:
self.upgrade.display()
# 如果游戏未暂停,更新可见精灵组
else:
self.visible_sprites.update()
# 更新敌人精灵状态
self.visible_sprites.enemy_update(self.player)
# 处理玩家攻击逻辑
self.player_attack_logic()
class YSortCameraGroup(pygame.sprite.Group):
def __init__(self):
# 调用父类的初始化方法,初始化精灵组
super().__init__()
# 获取当前 Pygame 显示的表面(屏幕)
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
# 创建一个空的 Vector2 对象,用于表示摄像机的偏移量
self.offset = pygame.math.Vector2()
# 加载地板图像并转换为适合显示的格式
self.floor_surf = pygame.image.load('../graphics/tilemap/ground.png').convert()
# 获取地板图像的矩形区域(左上角位置为 (0, 0)
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)
# 按精灵的中心 Y 坐标排序并绘制精灵
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)

@ -0,0 +1,63 @@
import pygame
from settings import *
from random import randint
class MagicPlayer:
def __init__(self,animation_player):
# 初始化 MagicPlayer 类,传入 AnimationPlayer 实例作为参数
self.animation_player = animation_player
# 定义魔法音效字典
self.sounds = {
# 创建 'heal' 音效对象
'heal': pygame.mixer.Sound('../audio/heal.wav'),
# 创建 'flame' 音效对象
'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,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)
# 根据方向生成火焰粒子效果
# 创建 1 到 5 个火焰粒子
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)

@ -0,0 +1,57 @@
import pygame, sys
from settings import *
from level import Level
class Game:
def __init__(self):
# 初始化 Pygame 库
pygame.init()
# 设置游戏窗口尺寸
self.screen = pygame.display.set_mode((WIDTH,HEIGTH))
# 设置游戏窗口标题
pygame.display.set_caption('Zelda')
# 创建时钟对象,用于控制游戏帧率
self.clock = pygame.time.Clock()
# 创建游戏关卡对象
self.level = Level()
# 声音设置
# 加载背景音乐文件
main_sound = pygame.mixer.Sound('../audio/main.ogg')
# 设置背景音乐音量
main_sound.set_volume(0.5)
# 播放背景音乐循环播放loops=-1 表示无限循环)
main_sound.play(loops = -1)
def run(self):
# 进入游戏主循环,持续运行直到退出。
while True:
# 遍历所有的事件。
for event in pygame.event.get():
# 如果事件类型是退出事件,即关闭窗口。
if event.type == pygame.QUIT:
# 退出 Pygame 应用程序
pygame.quit()
# 退出 Python 解释器
sys.exit()
# 如果有键盘按下事件。
if event.type == pygame.KEYDOWN:
# 按下 'm' 键切换游戏菜单的显示
if event.key == pygame.K_m:
# 切换游戏菜单的显示状态。
self.level.toggle_menu()
# 用水的颜色填充游戏窗口背景
self.screen.fill(WATER_COLOR)
# 运行游戏关卡的主循环
self.level.run()
# 更新屏幕显示
pygame.display.update()
# 控制游戏帧率为 FPS
self.clock.tick(FPS)
if __name__ == '__main__':
# 创建 Game 类的实例 game
game = Game()
# 调用 game 对象的 run 方法,启动游戏主循环
game.run()
Loading…
Cancel
Save