长安区网站建设,wordpress模板是否死循环,新浪微博关联wordpress,怎么分析网站建设的优缺点Python制作流浪气球游戏#xff08;导弹射击类#xff09;教学课程代码#xff08;分步教学版#xff09;1、构建全局通用代码结构2、构建气球精灵类3、构建导弹精灵类4、碰撞检测5、构建游戏信息类 #xff08;最终完整代码#xff09;教学课程代码#xff08;分步教学…
Python制作流浪气球游戏导弹射击类教学课程代码分步教学版1、构建全局通用代码结构2、构建气球精灵类3、构建导弹精灵类4、碰撞检测5、构建游戏信息类 最终完整代码教学课程代码分步教学版
实时同步文件Python制作流浪气球游戏射击类 B站视频教学地址浪淘三千 代码和素材是完整的对应视频也已更新完毕 以下是静态样式展示
1、构建全局通用代码结构 本游戏制作了导弹拦截流浪气球的基本代码 有 音效、音乐、精灵、碰撞、轨迹计算 等知识的应用
当基础功能学会以后可以教大家平面地图文件的绘制和使用 制作更丰富精彩的游戏场景
视频教学地址会陆续更新 https://space.bilibili.com/455954948
欢迎积极交流更好的改进建议一起升级游戏 代码已同步 链接见视频评论区import arcade# 常量 窗口大小和标题
SCREEN_WIDTH 1200
SCREEN_HEIGHT 600
SCREEN_TITLE Arcade 游戏教学 流浪气球# arcade_game_202302 流浪气球Ⅰ 教学版
class LiuLangQiQiu(arcade.View): 视图程序用于在窗体内展示. def __init__(self):# 初始化父类的属性super().__init__()self.background_image None# 鼠标的图片self.couser_pic None# 游戏背景音乐self.background_sound arcade.load_sound(../声音文件/忍者神龟背景音乐.mp3)# 在初始化时调用的一些准备工作代码self.set_up()def set_up(self): 进行一些游戏准备工作让游戏主逻辑从这开始以便于在有需要时重开游戏. # 背景图片 当作精灵加载进来self.background_image arcade.Sprite(../图片文件/世界卫星地图.png)# 播放并记录游戏背景音乐self.current_play self.background_sound.play(volume0.4, loopTrue)# 设置精灵素材中心点的位置self.background_image.center_x self.window.width // 3self.background_image.center_y self.window.height // 2# 鼠标图片加载self.couser_pic arcade.Sprite(../图片文件/瞄准.png, scale0.2)# 画面渲染绘制def on_draw(self): 负责渲染画面 速率 60帧/秒. # 清除上一帧绘制的画面self.clear()# 绘制背景图片self.background_image.draw()# 绘制鼠标self.couser_pic.draw()# 控制每次刷新时的变化def on_update(self, delta_time: float): 负责逻辑变化 速率 60帧/秒. passdef on_mouse_press(self, x, y, button, modifiers): 监听鼠标点击事件. mouse_buttons {1: 左键, 2: 中键, 4: 右键}print(f当前点击的坐标是{x,y})def on_mouse_release(self, x: float, y: float, button: int, modifiers: int): 监听鼠标释放事件. passdef on_mouse_motion(self, x: float, y: float, dx: float, dy: float): 监听鼠标移动事件 self.couser_pic.center_x xself.couser_pic.center_y ydef on_key_press(self,key, modifiers):监听键盘按键点击事件modifiers:None 16,shift 117 ctrl 218 alt 420 print(---键盘按键按下了--,key,--修饰键编号的和是---, modifiers)def on_key_release(self, key, modifiers):print(---键盘按键抬起了--,key,--剩余修饰键编号的和是---, modifiers)def on_resize(self, width: int, height: int):# 重新设置精灵素材中心点的位置self.background_image.center_x self.window.width // 2self.background_image.center_y self.window.height // 2# 重新设置精灵素材宽度和高度self.background_image.width self.window.widthself.background_image.height self.window.heightdef main():# 设置窗体的宽、高、名字、是否支持缩放window arcade.Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizableTrue)# 设置窗体的 logo 图标import pygletwindow.set_icon(pyglet.image.load(../图片文件/浪淘三千.png))# 设置鼠标形状cursor window.get_system_mouse_cursor(window.CURSOR_HAND)window.set_mouse_cursor(cursor)# 实例化定义的某个窗体start_view LiuLangQiQiu()# 设置当前应该显示哪个窗体window.show_view(start_view)# 保持程序持续运行arcade.run()if __name__ __main__:main()
2、构建气球精灵类 本游戏制作了导弹拦截流浪气球的基本代码 有 音效、音乐、精灵、碰撞、轨迹计算 等知识的应用
当基础功能学会以后可以教大家平面地图文件的绘制和使用 制作更丰富精彩的游戏场景
视频教学地址会陆续更新 https://space.bilibili.com/455954948
欢迎积极交流更好的改进建议一起升级游戏 代码已同步 链接见视频评论区import arcade
import os,random# 常量 窗口大小和标题
SCREEN_WIDTH 1200
SCREEN_HEIGHT 600
SCREEN_TITLE Arcade 游戏教学 流浪气球class QiQiu(arcade.Sprite):def __init__(self, filename, change_x, change_y, init_x, init_y):super(QiQiu, self).__init__(filename,hit_box_algorithm Simple)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 记录气球单次持续垂直移动的距离self.total_change_y 0# 是否被追踪 一旦被追踪则不再被别的导弹追踪self.is_tracked False# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转if self.center_x 0:self.append_texture((arcade.load_texture(filename, mirroredTrue)))# texture_right_forward arcade.load_texture(filename, mirroredTrue)self.set_texture(1)def update(self, window_height800):self.total_change_y self.change_y# 当单次垂直移动距离超过50就重新随机选择方向 这个数字通过自己测试调整得到if abs(self.total_change_y) 50:# 随机改变气球纵向移动方向self.change_y * random.choice([-1, 1])# 再次重新计算持续垂直移动的距离self.total_change_y 0if self.center_y window_height- self.height or self.center_y self.height:self.change_y 0self.total_change_y 0self.center_x self.change_xself.center_y self.change_y# arcade_game_202302 流浪气球Ⅰ教学版
class LiuLangQiQiu(arcade.View): 视图程序用于在窗体内展示. def __init__(self):# 初始化父类的属性super().__init__()self.background_image None# 气球类self.qi_qiu Noneself.qi_qiu_list None# 所有气球文件self.all_qi_qiu None# 游戏背景音乐self.background_sound arcade.load_sound(../声音文件/忍者神龟背景音乐.mp3)# 鼠标的图片self.couser_pic None# 在初始化时调用的一些准备工作代码self.set_up()def set_up(self,init_qi_qiu_num3): 进行一些游戏准备工作让游戏主逻辑从这开始以便于在有需要时重开游戏. # 背景图片 当作精灵加载进来self.background_image arcade.Sprite(../图片文件/世界卫星地图.png)# 播放并记录游戏背景音乐self.current_play self.background_sound.play(volume0.4, loopTrue)# 气球精灵列表self.qi_qiu_list arcade.SpriteList()# 获取文件夹中所有的飞艇图片self.all_qi_qiu os.listdir(../图片文件/气球飞艇)print(self.all_qi_qiu)# 设置精灵素材中心点的位置self.background_image.center_x self.window.width // 3self.background_image.center_y self.window.height // 2# 初始状态时创建自定义个气球(默认3个)self.creat_qi_qiu(init_qi_qiu_num)self.couser_pic arcade.Sprite(../图片文件/瞄准.png, scale0.2)def creat_qi_qiu(self, num):创建气球for i in range(1, num1):self.qi_qiu QiQiu(filenamef../图片文件/气球飞艇/{random.choice(self.all_qi_qiu)},change_xrandom.choice([0.5,0.5,1,2,2]), change_yrandom.choice([1,2]),init_xrandom.choice([-80, self.window.width 200]),init_yrandom.randint(200, self.window.height - num*50))self.qi_qiu.width 60self.qi_qiu.height 40# self.qi_qiu.scale 0.5if self.qi_qiu.center_x self.window.width//2:self.qi_qiu.change_x -self.qi_qiu.change_xself.qi_qiu_list.append(self.qi_qiu)# 画面渲染绘制def on_draw(self): 负责渲染画面 速率 60帧/秒. # 清除上一帧绘制的画面self.clear()# 绘制背景图片self.background_image.draw()# 绘制气球精灵组self.qi_qiu_list.draw()# 绘制鼠标self.couser_pic.draw()# 控制每次刷新时的变化def on_update(self, delta_time: float): 负责逻辑变化 速率 60帧/秒. for qi_qiu_id, qi_qiu in enumerate(self.qi_qiu_list):# 气球移动qi_qiu.update(self.window.height)if qi_qiu.center_x not in range(-230, self.window.width230):# 气球飞出屏幕一定距离后 则消失qi_qiu.remove_from_sprite_lists()# 再次创建气球self.creat_qi_qiu(1)def on_mouse_press(self, x, y, button, modifiers): 监听鼠标点击事件. mouse_buttons {1: 左键, 2: 中键, 4: 右键}print(f当前点击的坐标是{x,y})def on_mouse_release(self, x: float, y: float, button: int, modifiers: int): 监听鼠标释放事件. passdef on_mouse_motion(self, x: float, y: float, dx: float, dy: float): 监听鼠标移动事件 self.couser_pic.center_x xself.couser_pic.center_y ydef on_key_press(self,key, modifiers):监听键盘按键点击事件modifiers:None 16,shift 117 ctrl 218 alt 420 print(---键盘按键按下了--,key,--修饰键编号的和是---, modifiers)def on_key_release(self, key, modifiers):print(---键盘按键抬起了--,key,--剩余修饰键编号的和是---, modifiers)def on_resize(self, width: int, height: int):# 重新设置精灵素材中心点的位置self.background_image.center_x self.window.width // 2self.background_image.center_y self.window.height // 2# 重新设置精灵素材宽度和高度self.background_image.width self.window.widthself.background_image.height self.window.heightdef main():# 设置窗体的宽、高、名字、是否支持缩放window arcade.Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizableTrue)# 设置窗体的 logo 图标import pygletwindow.set_icon(pyglet.image.load(../图片文件/浪淘三千.png))# 设置鼠标形状cursor window.get_system_mouse_cursor(window.CURSOR_HAND)window.set_mouse_cursor(cursor)# 实例化定义的某个窗体start_view LiuLangQiQiu()# 设置当前应该显示哪个窗体window.show_view(start_view)# 保持程序持续运行arcade.run()if __name__ __main__:main()
3、构建导弹精灵类 本游戏制作了导弹拦截流浪气球的基本代码 有 音效、音乐、精灵、碰撞、轨迹计算 等知识的应用
当基础功能学会以后可以教大家平面地图文件的绘制和使用 制作更丰富精彩的游戏场景
视频教学地址会陆续更新 https://space.bilibili.com/455954948
欢迎积极交流更好的改进建议一起升级游戏 代码已同步 链接见视频评论区import arcade
import os,random,math# 常量 窗口大小和标题
SCREEN_WIDTH 1200
SCREEN_HEIGHT 600
SCREEN_TITLE Arcade 游戏教学 流浪气球class QiQiu(arcade.Sprite):def __init__(self, filename, change_x, change_y, init_x, init_y):super(QiQiu, self).__init__(filename,hit_box_algorithm Simple)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 记录气球单次持续垂直移动的距离self.total_change_y 0# 是否被追踪 一旦被追踪则不再被别的导弹追踪self.is_tracked False# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转if self.center_x 0:self.append_texture((arcade.load_texture(filename, mirroredTrue)))# texture_right_forward arcade.load_texture(filename, mirroredTrue)self.set_texture(1)def update(self, window_height800):self.total_change_y self.change_y# 当单次垂直移动距离超过50就重新随机选择方向 这个数字通过自己测试调整得到if abs(self.total_change_y) 50:# 随机改变气球纵向移动方向self.change_y * random.choice([-1, 1])# 再次重新计算持续垂直移动的距离self.total_change_y 0if self.center_y window_height- self.height or self.center_y self.height:self.change_y 0self.total_change_y 0self.center_x self.change_xself.center_y self.change_yclass DaoDan(arcade.Sprite):目前是设计成了自动搜寻目标 然后攻击的模式def __init__(self, filename, change_x, change_y, init_x, init_y, target_xNone, target_yNone):super(DaoDan, self).__init__(filename,hit_box_algorithm Simple)# self.load_animated_gif(filename)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_yself.change_y_init change_y# 记录导弹精灵的初始点self.init_x init_xself.init_y init_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 要追踪的目标self.target_x target_xself.target_y target_y# 导弹是否还在地面上没有发射self.is_on_ground True# 是否正在追踪 初始是未开始追踪self.is_tracking False# 导弹点火发射音效self.fire_sound arcade.load_sound(../声音文件/火焰推进器.mp3)# 导弹爆炸音效self.explode_sound arcade.load_sound(../声音文件/中距离爆炸.mp3)def track_target(self, target_x, target_y, change_angle0.1):# 当被调用的时候开始追踪目标气球# 计算导弹和气球飞艇之间的弧度值 Π 3.14弧度 180°角度 向左转角度要加 向右转角度要减target_radians_angle math.atan2(target_y-self.center_y,target_x-self.center_x)# 将上一步计算出的弧度转换为角度值# 都要减去90 因为导弹的初始方向是向上的所以有一个默认的90°角减去后恢复到 0°再计算。target_degree_angle math.degrees(target_radians_angle)-90# print(f角度是{target_degree_angle})self.center_x self.change_x if self.center_x target_x else -self.change_xself.center_y self.change_y if self.center_y target_y else -self.change_yself.change_y 0 if abs(self.center_y - target_y) 5 else self.change_y_init# print(2222, self.center_y, target_y, self.change_y)if abs(target_degree_angle) in range(0,8):self.angle 0elif abs(target_degree_angle) in range(172,188):self.angle 180else:self.angle target_degree_angle# 定义一个弹道导弹类 继承导弹基类 因为追踪逻辑不一样所以需要重写其追踪方法
class DanDaoDaoDan(DaoDan):# def __init__(self):# super().__init__()def track_target(self):开始计算固定飞行轨迹 y a(x-h)²k h 和 k 为抛物线的顶点横纵坐标将鼠标点击的self.target_x,self.target_y点作为顶点则有【抛物线函数 y a(x-self.target_x)²self.target_y 】将导弹的起点坐标带入上述方程 可以求出 a 值 于是就可以求出抛物线的函数式【抛物线函数 init_y a(init_x-self.target_x)²self.target_y 】a (init_y - self.target_y)/(init_x-self.target_x)²# 如果开口向下,a小于0;开口向上,a大于0.a (self.init_y - self.target_y)/(self.init_x-self.target_x)**2# print(fa的值是{a})self.center_x self.change_x# 将横坐标带入方程求纵坐标self.center_y a*(int(self.center_x - self.target_x)**2)self.target_y# print(f{self.center_y} {a}*({int(self.center_x - self.target_x)})**2{self.target_y})# 计算导弹和气球飞艇之间的弧度值 Π 3.14弧度 180°角度target_radians_angle math.atan2(self.target_y-self.center_y,self.target_x-self.center_x)# 将上一步计算出的弧度转换为角度值# 都要减去90 因为导弹的初始方向是向上的所以有一个默认的90°角减去后恢复到 0°再计算。target_degree_angle math.degrees(target_radians_angle)-90if (self.target_x-self.init_x)*(self.target_x-self.center_x) 0:# 值小于0 的时候说明导弹飞行中已经超过了设定好的最高点target_degree_angle target_degree_angle 180# print(f角度是{target_degree_angle})if abs(target_degree_angle) in range(0,8):self.angle 0elif abs(target_degree_angle) in range(172,188):self.angle 180else:self.angle target_degree_angleclass BaoZhaYanWu(arcade.Sprite):def __init__(self):super(BaoZhaYanWu, self).__init__()# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转all_explore_pic os.listdir(../图片文件/images11)for pic_name in all_explore_pic:self.append_texture((arcade.load_texture(f../图片文件/images11/{pic_name})))# 记下一共有多少纹理图self.textures_num_len len(all_explore_pic)self.texture_index_now 0def update(self, texture_index: int None):# 如果状态是 True 则开始计算绘制位置if self.texture_index_now self.textures_num_len:self.set_texture(self.texture_index_now)self.texture_index_now 1return Falseelse:# 收到为True的返回值时 销毁烟雾精灵return True# arcade_game_202302 流浪气球Ⅰ教学版
class LiuLangQiQiu(arcade.View): 视图程序用于在窗体内展示. def __init__(self):# 初始化父类的属性super().__init__()self.background_image Noneself.dao_dan None# 气球类self.qi_qiu Noneself.qi_qiu_list None# 导弹类self.dao_dan Noneself.dao_dan_list None# 弹道导弹类self.dan_dao_dao_dan Noneself.dan_dao_dao_dan_list None# 所有气球文件self.all_qi_qiu None# 游戏背景音乐self.background_sound arcade.load_sound(../声音文件/忍者神龟背景音乐.mp3)# 导弹发射车self.dao_dan_che_image None# 爆炸烟雾self.explode_smoke Noneself.explode_smoke_list None# 鼠标的图片self.couser_pic None# 在初始化时调用的一些准备工作代码self.set_up()def set_up(self,init_qi_qiu_num3): 进行一些游戏准备工作让游戏主逻辑从这开始以便于在有需要时重开游戏. # 背景图片 当作精灵加载进来self.background_image arcade.Sprite(../图片文件/世界卫星地图.png)# 游戏背景音乐self.current_play self.background_sound.play(volume0.4, loopTrue)# 气球精灵列表self.qi_qiu_list arcade.SpriteList()# 导弹精灵列表self.dao_dan_list arcade.SpriteList()# 弹道导弹精灵列表self.dan_dao_dao_dan_list arcade.SpriteList()# 爆炸烟雾精灵self.explode_smoke_list arcade.SpriteList()# 获取文件夹中所有的飞艇图片self.all_qi_qiu os.listdir(../图片文件/气球飞艇)print(self.all_qi_qiu)# 设置精灵素材中心点的位置self.background_image.center_x self.window.width // 3self.background_image.center_y self.window.height // 2# 导弹发射车 在on_resize()里设置绘制位置self.dao_dan_che_image arcade.Sprite(../图片文件/东风41.png)self.dao_dan_che_image.width 70self.dao_dan_che_image.height 70# 初始状态时创建自定义个气球(默认3个)self.creat_qi_qiu(init_qi_qiu_num)self.couser_pic arcade.Sprite(../图片文件/瞄准.png, scale0.2)def creat_qi_qiu(self, num):创建气球for i in range(1, num1):self.qi_qiu QiQiu(filenamef../图片文件/气球飞艇/{random.choice(self.all_qi_qiu)},change_xrandom.choice([0.5,0.5,1,2,2]), change_yrandom.choice([1,2]),init_xrandom.choice([-80, self.window.width 200]),init_yrandom.randint(200, self.window.height - num*50))self.qi_qiu.width 60self.qi_qiu.height 40# self.qi_qiu.scale 0.5if self.qi_qiu.center_x self.window.width//2:self.qi_qiu.change_x -self.qi_qiu.change_xself.qi_qiu_list.append(self.qi_qiu)def creat_zhui_zong_dao_dan(self):dao_dan DaoDan(../图片文件/导弹.gif, change_x4, change_y3,init_xself.window.width // 3, init_yself.window.height // 2)self.dao_dan_list.append(dao_dan)dao_dan.fire_sound.play()def creat_dan_dao_dao_dan(self,x,y):# 弹道导弹 如果剩余的弹道弹数量大于0 就接受命令进行创建init_x self.window.width // 3init_y self.window.height // 2speed 1 if abs(x - init_x) 200 else 3# 如果目标点在右侧 则导弹向右飞行 横坐标变化为正数 否则为负数change_x speed if x self.window.width // 3 else - speeddan_dao_dao_dan DanDaoDaoDan(../图片文件/弹道导弹.png, change_xchange_x, change_y3,init_xinit_x, init_yinit_y,target_xx, target_yy)dan_dao_dao_dan.scale 0.7self.dan_dao_dao_dan_list.append(dan_dao_dao_dan)dan_dao_dao_dan.fire_sound.play()def creat_yan_wu(self,center_x, center_y):yan_wu BaoZhaYanWu()yan_wu.center_x center_xyan_wu.center_y center_yself.explode_smoke_list.append(yan_wu)# 画面渲染绘制def on_draw(self): 负责渲染画面 速率 60帧/秒. # 清除上一帧绘制的画面self.clear()# 绘制背景图片self.background_image.draw()# 导弹发射车self.dao_dan_che_image.draw()# 绘制气球精灵组self.qi_qiu_list.draw()# 绘制导弹精灵组self.dao_dan_list.draw()# 绘制弹道导弹精灵组self.dan_dao_dao_dan_list.draw()# 绘制爆炸烟雾self.explode_smoke_list.draw()# 绘制鼠标self.couser_pic.draw()# 控制每次刷新时的变化def on_update(self, delta_time: float): 负责逻辑变化 速率 60帧/秒. for qi_qiu_id, qi_qiu in enumerate(self.qi_qiu_list):# 处理气球和自动追踪导弹的移动qi_qiu.update(self.window.height)if qi_qiu_id len(self.dao_dan_list)-1:dao_dan self.dao_dan_list[qi_qiu_id]dao_dan.track_target(qi_qiu.center_x, qi_qiu.center_y, change_angle-0.5)# else:# print(请尽快发射导弹)if qi_qiu.center_x not in range(-230, self.window.width230):# 气球飞出屏幕一定距离后 则消失qi_qiu.remove_from_sprite_lists()# 再次创建气球self.creat_qi_qiu(1)# 处理按下鼠标发射的弹道导弹for dan_dao_dao_dan in self.dan_dao_dao_dan_list:# 处理气球和弹道导弹的移动dan_dao_dao_dan.track_target()# 如果导弹飞出了屏幕 则销毁if dan_dao_dao_dan.center_x not in range(-230, self.window.width230):dan_dao_dao_dan.remove_from_sprite_lists()def on_mouse_press(self, x, y, button, modifiers): 监听鼠标点击事件. mouse_buttons {1: 左键, 2: 中键, 4: 右键}# print(f当前点击的坐标是{x,y})# 创建弹道导弹self.creat_dan_dao_dao_dan(x,y)def on_mouse_release(self, x: float, y: float, button: int, modifiers: int): 监听鼠标释放事件. passdef on_mouse_motion(self, x: float, y: float, dx: float, dy: float): 监听鼠标移动事件 self.couser_pic.center_x xself.couser_pic.center_y ydef on_key_press(self,key, modifiers):监听键盘按键点击事件modifiers:None 16,shift 117 ctrl 218 alt 420 print(---键盘按键按下了--,key,--修饰键编号的和是---, modifiers)if key arcade.key.SPACE:self.creat_zhui_zong_dao_dan()def on_key_release(self, key, modifiers):print(---键盘按键抬起了--,key,--剩余修饰键编号的和是---, modifiers)def on_resize(self, width: int, height: int):# 重新设置精灵素材中心点的位置self.background_image.center_x self.window.width // 2self.background_image.center_y self.window.height // 2# 重新设置精灵素材宽度和高度self.background_image.width self.window.widthself.background_image.height self.window.height# 设置导弹车精灵素材中心点的位置self.dao_dan_che_image.center_x self.window.width // 3 - 30self.dao_dan_che_image.center_y self.window.height // 2def main():# 设置窗体的宽、高、名字、是否支持缩放window arcade.Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizableTrue)# 设置窗体的 logo 图标import pygletwindow.set_icon(pyglet.image.load(../图片文件/浪淘三千.png))# 设置鼠标形状cursor window.get_system_mouse_cursor(window.CURSOR_HAND)window.set_mouse_cursor(cursor)# 实例化定义的某个窗体start_view LiuLangQiQiu()# 设置当前应该显示哪个窗体window.show_view(start_view)# 保持程序持续运行arcade.run()if __name__ __main__:main()
4、碰撞检测 本游戏制作了导弹拦截流浪气球的基本代码 有 音效、音乐、精灵、碰撞、轨迹计算 等知识的应用
当基础功能学会以后可以教大家平面地图文件的绘制和使用 制作更丰富精彩的游戏场景
视频教学地址会陆续更新 https://space.bilibili.com/455954948
欢迎积极交流更好的改进建议一起升级游戏 代码已同步 链接见视频评论区import arcade
import os,random,math# 常量 窗口大小和标题
SCREEN_WIDTH 1200
SCREEN_HEIGHT 600
SCREEN_TITLE Arcade 游戏教学 流浪气球class QiQiu(arcade.Sprite):def __init__(self, filename, change_x, change_y, init_x, init_y):super(QiQiu, self).__init__(filename,hit_box_algorithm Simple)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 记录气球单次持续垂直移动的距离self.total_change_y 0# 是否被追踪 一旦被追踪则不再被别的导弹追踪self.is_tracked False# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转if self.center_x 0:self.append_texture((arcade.load_texture(filename, mirroredTrue)))# texture_right_forward arcade.load_texture(filename, mirroredTrue)self.set_texture(1)def update(self, window_height800):self.total_change_y self.change_y# 当单次垂直移动距离超过50就重新随机选择方向 这个数字通过自己测试调整得到if abs(self.total_change_y) 50:# 随机改变气球纵向移动方向self.change_y * random.choice([-1, 1])# 再次重新计算持续垂直移动的距离self.total_change_y 0if self.center_y window_height- self.height or self.center_y self.height:self.change_y 0self.total_change_y 0self.center_x self.change_xself.center_y self.change_yclass DaoDan(arcade.Sprite):目前是设计成了自动搜寻目标 然后攻击的模式def __init__(self, filename, change_x, change_y, init_x, init_y, target_xNone, target_yNone):super(DaoDan, self).__init__(filename,hit_box_algorithm Simple)# self.load_animated_gif(filename)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_yself.change_y_init change_y# 记录导弹精灵的初始点self.init_x init_xself.init_y init_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 要追踪的目标self.target_x target_xself.target_y target_y# 导弹是否还在地面上没有发射self.is_on_ground True# 是否正在追踪 初始是未开始追踪self.is_tracking False# 导弹点火发射音效self.fire_sound arcade.load_sound(../声音文件/火焰推进器.mp3)# 导弹爆炸音效self.explode_sound arcade.load_sound(../声音文件/中距离爆炸.mp3)def track_target(self, target_x, target_y, change_angle0.1):# 当被调用的时候开始追踪目标气球# 计算导弹和气球飞艇之间的弧度值 Π 3.14弧度 180°角度 向左转角度要加 向右转角度要减target_radians_angle math.atan2(target_y-self.center_y,target_x-self.center_x)# 将上一步计算出的弧度转换为角度值# 都要减去90 因为导弹的初始方向是向上的所以有一个默认的90°角减去后恢复到 0°再计算。target_degree_angle math.degrees(target_radians_angle)-90# print(f角度是{target_degree_angle})self.center_x self.change_x if self.center_x target_x else -self.change_xself.center_y self.change_y if self.center_y target_y else -self.change_yself.change_y 0 if abs(self.center_y - target_y) 5 else self.change_y_init# print(2222, self.center_y, target_y, self.change_y)if abs(target_degree_angle) in range(0,8):self.angle 0elif abs(target_degree_angle) in range(172,188):self.angle 180else:self.angle target_degree_angle# 定义一个弹道导弹类 继承导弹基类 因为追踪逻辑不一样所以需要重写其追踪方法
class DanDaoDaoDan(DaoDan):# def __init__(self):# super().__init__()def track_target(self):开始计算固定飞行轨迹 y a(x-h)²k h 和 k 为抛物线的顶点横纵坐标将鼠标点击的self.target_x,self.target_y点作为顶点则有【抛物线函数 y a(x-self.target_x)²self.target_y 】将导弹的起点坐标带入上述方程 可以求出 a 值 于是就可以求出抛物线的函数式【抛物线函数 init_y a(init_x-self.target_x)²self.target_y 】a (init_y - self.target_y)/(init_x-self.target_x)²# 如果开口向下,a小于0;开口向上,a大于0.a (self.init_y - self.target_y)/(self.init_x-self.target_x)**2# print(fa的值是{a})self.center_x self.change_x# 将横坐标带入方程求纵坐标self.center_y a*(int(self.center_x - self.target_x)**2)self.target_y# print(f{self.center_y} {a}*({int(self.center_x - self.target_x)})**2{self.target_y})# 计算导弹和气球飞艇之间的弧度值 Π 3.14弧度 180°角度target_radians_angle math.atan2(self.target_y-self.center_y,self.target_x-self.center_x)# 将上一步计算出的弧度转换为角度值# 都要减去90 因为导弹的初始方向是向上的所以有一个默认的90°角减去后恢复到 0°再计算。target_degree_angle math.degrees(target_radians_angle)-90if (self.target_x-self.init_x)*(self.target_x-self.center_x) 0:# 值小于0 的时候说明导弹飞行中已经超过了设定好的最高点target_degree_angle target_degree_angle 180# print(f角度是{target_degree_angle})if abs(target_degree_angle) in range(0,8):self.angle 0elif abs(target_degree_angle) in range(172,188):self.angle 180else:self.angle target_degree_angleclass BaoZhaYanWu(arcade.Sprite):def __init__(self):super(BaoZhaYanWu, self).__init__()# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转all_explore_pic os.listdir(../图片文件/images11)for pic_name in all_explore_pic:self.append_texture((arcade.load_texture(f../图片文件/images11/{pic_name})))# 记下一共有多少纹理图self.textures_num_len len(all_explore_pic)self.texture_index_now 0def update(self, texture_index: int None):# 如果状态是 True 则开始计算绘制位置if self.texture_index_now self.textures_num_len:self.set_texture(self.texture_index_now)self.texture_index_now 1return Falseelse:# 收到为True的返回值时 销毁烟雾精灵return True# arcade_game_202302 流浪气球Ⅰ教学版
class LiuLangQiQiu(arcade.View): 视图程序用于在窗体内展示. def __init__(self):# 初始化父类的属性super().__init__()self.background_image Noneself.dao_dan None# 气球类self.qi_qiu Noneself.qi_qiu_list None# 导弹类self.dao_dan Noneself.dao_dan_list None# 弹道导弹类self.dan_dao_dao_dan Noneself.dan_dao_dao_dan_list None# 所有气球文件self.all_qi_qiu None# 游戏背景音乐self.background_sound arcade.load_sound(../声音文件/忍者神龟背景音乐.mp3)# 导弹发射车self.dao_dan_che_image None# 爆炸烟雾self.explode_smoke Noneself.explode_smoke_list None# 为了有节奏的控制游戏刷新时个别元素的刷新速度 设置一个记录时间间隔变量self.interval_time 0# 鼠标的图片self.couser_pic None# 在初始化时调用的一些准备工作代码self.set_up()def set_up(self,init_qi_qiu_num3): 进行一些游戏准备工作让游戏主逻辑从这开始以便于在有需要时重开游戏. # 背景图片 当作精灵加载进来self.background_image arcade.Sprite(../图片文件/世界卫星地图.png)# 游戏背景音乐self.current_play self.background_sound.play(volume0.4, loopTrue)# 气球精灵列表self.qi_qiu_list arcade.SpriteList()# 导弹精灵列表self.dao_dan_list arcade.SpriteList()# 弹道导弹精灵列表self.dan_dao_dao_dan_list arcade.SpriteList()# 爆炸烟雾精灵self.explode_smoke_list arcade.SpriteList()# 获取文件夹中所有的飞艇图片self.all_qi_qiu os.listdir(../图片文件/气球飞艇)print(self.all_qi_qiu)# 设置精灵素材中心点的位置self.background_image.center_x self.window.width // 3self.background_image.center_y self.window.height // 2# 导弹发射车 在on_resize()里设置绘制位置self.dao_dan_che_image arcade.Sprite(../图片文件/东风41.png)self.dao_dan_che_image.width 70self.dao_dan_che_image.height 70# 初始状态时创建自定义个气球(默认3个)self.creat_qi_qiu(init_qi_qiu_num)self.couser_pic arcade.Sprite(../图片文件/瞄准.png, scale0.2)def creat_qi_qiu(self, num):创建气球for i in range(1, num1):self.qi_qiu QiQiu(filenamef../图片文件/气球飞艇/{random.choice(self.all_qi_qiu)},change_xrandom.choice([0.5,0.5,1,2,2]), change_yrandom.choice([1,2]),init_xrandom.choice([-80, self.window.width 200]),init_yrandom.randint(200, self.window.height - num*50))self.qi_qiu.width 60self.qi_qiu.height 40# self.qi_qiu.scale 0.5if self.qi_qiu.center_x self.window.width//2:self.qi_qiu.change_x -self.qi_qiu.change_xself.qi_qiu_list.append(self.qi_qiu)def creat_zhui_zong_dao_dan(self):dao_dan DaoDan(../图片文件/导弹.gif, change_x4, change_y3,init_xself.window.width // 3, init_yself.window.height // 2)self.dao_dan_list.append(dao_dan)dao_dan.fire_sound.play()def creat_dan_dao_dao_dan(self,x,y):# 弹道导弹 如果剩余的弹道弹数量大于0 就接受命令进行创建init_x self.window.width // 3init_y self.window.height // 2speed 1 if abs(x - init_x) 200 else 3# 如果目标点在右侧 则导弹向右飞行 横坐标变化为正数 否则为负数change_x speed if x self.window.width // 3 else - speeddan_dao_dao_dan DanDaoDaoDan(../图片文件/弹道导弹.png, change_xchange_x, change_y3,init_xinit_x, init_yinit_y,target_xx, target_yy)dan_dao_dao_dan.scale 0.7self.dan_dao_dao_dan_list.append(dan_dao_dao_dan)dan_dao_dao_dan.fire_sound.play()def creat_yan_wu(self,center_x, center_y):yan_wu BaoZhaYanWu()yan_wu.center_x center_xyan_wu.center_y center_yself.explode_smoke_list.append(yan_wu)# 画面渲染绘制def on_draw(self): 负责渲染画面 速率 60帧/秒. # 清除上一帧绘制的画面self.clear()# 绘制背景图片self.background_image.draw()# 导弹发射车self.dao_dan_che_image.draw()# 绘制气球精灵组self.qi_qiu_list.draw()# 绘制导弹精灵组self.dao_dan_list.draw()# 绘制弹道导弹精灵组self.dan_dao_dao_dan_list.draw()# 绘制爆炸烟雾self.explode_smoke_list.draw()# 绘制鼠标self.couser_pic.draw()# 控制每次刷新时的变化def on_update(self, delta_time: float): 负责逻辑变化 速率 60帧/秒. for qi_qiu_id, qi_qiu in enumerate(self.qi_qiu_list):# 处理气球和自动追踪导弹的碰撞及逻辑qi_qiu.update(self.window.height)if qi_qiu_id len(self.dao_dan_list)-1:dao_dan self.dao_dan_list[qi_qiu_id]dao_dan.track_target(qi_qiu.center_x, qi_qiu.center_y, change_angle-0.5)# else:# print(请尽快发射导弹)collision arcade.check_for_collision_with_list(qi_qiu, self.dao_dan_list)if len(collision) 0:print(f发生碰撞了,相撞的{qi_qiu_id}号导弹和气球都被移除)# 移除碰到的气球qi_qiu.remove_from_sprite_lists()# 创建气球self.creat_qi_qiu(1)# 移除碰到的追踪导弹for collision_obj in collision:collision_obj.remove_from_sprite_lists()collision_obj.explode_sound.play()# 创建烟雾 坐标为所碰撞气球的坐标self.creat_yan_wu(qi_qiu.center_x,qi_qiu.center_y)if qi_qiu.center_x not in range(-230, self.window.width230):# 气球飞出屏幕一定距离后 则消失qi_qiu.remove_from_sprite_lists()# 再次创建气球self.creat_qi_qiu(1)# 处理按下鼠标发射的弹道导弹for dan_dao_dao_dan in self.dan_dao_dao_dan_list:# 处理气球和弹道导弹的碰撞及逻辑dan_dao_dao_dan.track_target()collision2 arcade.check_for_collision_with_list(dan_dao_dao_dan, self.qi_qiu_list)for collision_obj2 in collision2:collision_obj2.remove_from_sprite_lists()dan_dao_dao_dan.remove_from_sprite_lists()dan_dao_dao_dan.explode_sound.play()# 创建气球self.creat_qi_qiu(1)# 创建烟雾self.creat_yan_wu(collision_obj2.center_x, collision_obj2.center_y)# 如果导弹飞出了屏幕 则销毁if dan_dao_dao_dan.center_x not in range(-230, self.window.width230):dan_dao_dao_dan.remove_from_sprite_lists()# 烟雾的绘制for smoke in self.explode_smoke_list:self.interval_time delta_timeif self.interval_time 0.08:res smoke.update()self.interval_time 0if res:smoke.remove_from_sprite_lists()def on_mouse_press(self, x, y, button, modifiers): 监听鼠标点击事件. mouse_buttons {1: 左键, 2: 中键, 4: 右键}# print(f当前点击的坐标是{x,y})# 创建弹道导弹self.creat_dan_dao_dao_dan(x,y)def on_mouse_release(self, x: float, y: float, button: int, modifiers: int): 监听鼠标释放事件. passdef on_mouse_motion(self, x: float, y: float, dx: float, dy: float): 监听鼠标移动事件 self.couser_pic.center_x xself.couser_pic.center_y ydef on_key_press(self,key, modifiers):监听键盘按键点击事件modifiers:None 16,shift 117 ctrl 218 alt 420 print(---键盘按键按下了--,key,--修饰键编号的和是---, modifiers)if key arcade.key.SPACE:self.creat_zhui_zong_dao_dan()def on_key_release(self, key, modifiers):print(---键盘按键抬起了--,key,--剩余修饰键编号的和是---, modifiers)def on_resize(self, width: int, height: int):# 重新设置精灵素材中心点的位置self.background_image.center_x self.window.width // 2self.background_image.center_y self.window.height // 2# 重新设置精灵素材宽度和高度self.background_image.width self.window.widthself.background_image.height self.window.height# 设置导弹车精灵素材中心点的位置self.dao_dan_che_image.center_x self.window.width // 3 - 30self.dao_dan_che_image.center_y self.window.height // 2def main():# 设置窗体的宽、高、名字、是否支持缩放window arcade.Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizableTrue)# 设置窗体的 logo 图标import pygletwindow.set_icon(pyglet.image.load(../图片文件/浪淘三千.png))# 设置鼠标形状cursor window.get_system_mouse_cursor(window.CURSOR_HAND)window.set_mouse_cursor(cursor)# 实例化定义的某个窗体start_view LiuLangQiQiu()# 设置当前应该显示哪个窗体window.show_view(start_view)# 保持程序持续运行arcade.run()if __name__ __main__:main()
5、构建游戏信息类 最终完整代码 本游戏制作了导弹拦截流浪气球的基本代码 有 音效、音乐、精灵、碰撞、轨迹计算 等知识的应用
当基础功能学会以后可以教大家平面地图文件的绘制和使用 制作更丰富精彩的游戏场景
视频教学地址会陆续更新 https://space.bilibili.com/455954948
欢迎积极交流更好的改进建议一起升级游戏 代码已同步 链接见视频评论区import arcade
import os,random,math# 常量 窗口大小和标题
SCREEN_WIDTH 1200
SCREEN_HEIGHT 600
SCREEN_TITLE Arcade 游戏教学 流浪气球class QiQiu(arcade.Sprite):def __init__(self, filename, change_x, change_y, init_x, init_y):super(QiQiu, self).__init__(filename,hit_box_algorithm Simple)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 记录气球单次持续垂直移动的距离self.total_change_y 0# 是否被追踪 一旦被追踪则不再被别的导弹追踪self.is_tracked False# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转if self.center_x 0:self.append_texture((arcade.load_texture(filename, mirroredTrue)))# texture_right_forward arcade.load_texture(filename, mirroredTrue)self.set_texture(1)def update(self, window_height800):self.total_change_y self.change_y# 当单次垂直移动距离超过50就重新随机选择方向 这个数字通过自己测试调整得到if abs(self.total_change_y) 50:# 随机改变气球纵向移动方向self.change_y * random.choice([-1, 1])# 再次重新计算持续垂直移动的距离self.total_change_y 0if self.center_y window_height- self.height or self.center_y self.height:self.change_y 0self.total_change_y 0self.center_x self.change_xself.center_y self.change_yclass DaoDan(arcade.Sprite):目前是设计成了自动搜寻目标 然后攻击的模式def __init__(self, filename, change_x, change_y, init_x, init_y, target_xNone, target_yNone):super(DaoDan, self).__init__(filename,hit_box_algorithm Simple)# self.load_animated_gif(filename)# 导弹精灵的飞行变化速度self.change_x change_xself.change_y change_yself.change_y_init change_y# 记录导弹精灵的初始点self.init_x init_xself.init_y init_y# 导弹精灵的初始中心点init_x,init_yself.center_x init_xself.center_y init_y# 要追踪的目标self.target_x target_xself.target_y target_y# 导弹是否还在地面上没有发射self.is_on_ground True# 是否正在追踪 初始是未开始追踪self.is_tracking False# 导弹点火发射音效self.fire_sound arcade.load_sound(../声音文件/火焰推进器.mp3)# 导弹爆炸音效self.explode_sound arcade.load_sound(../声音文件/中距离爆炸.mp3)def track_target(self, target_x, target_y, change_angle0.1):# 当被调用的时候开始追踪目标气球# 计算导弹和气球飞艇之间的弧度值 Π 3.14弧度 180°角度 向左转角度要加 向右转角度要减target_radians_angle math.atan2(target_y-self.center_y,target_x-self.center_x)# 将上一步计算出的弧度转换为角度值# 都要减去90 因为导弹的初始方向是向上的所以有一个默认的90°角减去后恢复到 0°再计算。target_degree_angle math.degrees(target_radians_angle)-90# print(f角度是{target_degree_angle})self.center_x self.change_x if self.center_x target_x else -self.change_xself.center_y self.change_y if self.center_y target_y else -self.change_yself.change_y 0 if abs(self.center_y - target_y) 5 else self.change_y_init# print(2222, self.center_y, target_y, self.change_y)if abs(target_degree_angle) in range(0,8):self.angle 0elif abs(target_degree_angle) in range(172,188):self.angle 180else:self.angle target_degree_angle# 定义一个弹道导弹类 继承导弹基类 因为追踪逻辑不一样所以需要重写其追踪方法
class DanDaoDaoDan(DaoDan):# def __init__(self):# super().__init__()def track_target(self):开始计算固定飞行轨迹 y a(x-h)²k h 和 k 为抛物线的顶点横纵坐标将鼠标点击的self.target_x,self.target_y点作为顶点则有【抛物线函数 y a(x-self.target_x)²self.target_y 】将导弹的起点坐标带入上述方程 可以求出 a 值 于是就可以求出抛物线的函数式【抛物线函数 init_y a(init_x-self.target_x)²self.target_y 】a (init_y - self.target_y)/(init_x-self.target_x)²# 如果开口向下,a小于0;开口向上,a大于0.a (self.init_y - self.target_y)/(self.init_x-self.target_x)**2# print(fa的值是{a})self.center_x self.change_x# 将横坐标带入方程求纵坐标self.center_y a*(int(self.center_x - self.target_x)**2)self.target_y# print(f{self.center_y} {a}*({int(self.center_x - self.target_x)})**2{self.target_y})# 计算导弹和气球飞艇之间的弧度值 Π 3.14弧度 180°角度target_radians_angle math.atan2(self.target_y-self.center_y,self.target_x-self.center_x)# 将上一步计算出的弧度转换为角度值# 都要减去90 因为导弹的初始方向是向上的所以有一个默认的90°角减去后恢复到 0°再计算。target_degree_angle math.degrees(target_radians_angle)-90if (self.target_x-self.init_x)*(self.target_x-self.center_x) 0:# 值小于0 的时候说明导弹飞行中已经超过了设定好的最高点target_degree_angle target_degree_angle 180# print(f角度是{target_degree_angle})if abs(target_degree_angle) in range(0,8):self.angle 0elif abs(target_degree_angle) in range(172,188):self.angle 180else:self.angle target_degree_angleclass BaoZhaYanWu(arcade.Sprite):def __init__(self):super(BaoZhaYanWu, self).__init__()# 初始中心点不在界面左侧则是从右向左飞行的因为原始图片都朝向右侧向左飞行的要水平翻转all_explore_pic os.listdir(../图片文件/images11)for pic_name in all_explore_pic:self.append_texture((arcade.load_texture(f../图片文件/images11/{pic_name})))# 记下一共有多少纹理图self.textures_num_len len(all_explore_pic)self.texture_index_now 0def update(self, texture_index: int None):# 如果状态是 True 则开始计算绘制位置if self.texture_index_now self.textures_num_len:self.set_texture(self.texture_index_now)self.texture_index_now 1return Falseelse:# 收到为True的返回值时 销毁烟雾精灵return Trueclass InfoPanel:信息板 以后可以优化为游戏公共信息类def __init__(self):super(InfoPanel, self).__init__()self.game_info {}self.set_up()def set_up(self,init_qi_qiu_num0,game_limit_time10,zhui_zong_dao_dan_num10,dan_dao_dao_dan_num20,difficulty_level2):self.game_info.clear()self.game_info[game_status] True # 游戏状态(能玩和不能玩)self.game_info[game_pause] False # 游戏暂停状态self.game_info[player_score] 0 # 玩家分数self.game_info[player_use_time] 0 # 玩家用时self.game_info[game_limit_time] game_limit_time # 游戏限时 单位秒self.game_info[difficulty_level] difficulty_level # 游戏难度平均几个弹道导弹 VS 一个气球self.game_info[surplus_dan_dao_dao_dan_num] dan_dao_dao_dan_num # surplus剩余 弹道导弹数量self.game_info[surplus_zhui_zong_dao_dan_num] zhui_zong_dao_dan_num # 剩余追踪弹的数量# 得分要求为 追踪导弹的数量个数 加上 弹道导弹数量个数的一半self.game_info[player_target_score] zhui_zong_dao_dan_num dan_dao_dao_dan_num//max(1,difficulty_level) # 玩家目标分数self.game_info[init_qi_qiu_num] init_qi_qiu_num # 初始气球数量设置为self.game_info[surplus_qi_qiu_num] 0 # 剩余气球数量self.game_info[all_qi_qiu_num] 0 # 全部出现过的气球数量self.game_info[zhui_zong_dao_dan_pic] arcade.Sprite(../图片文件/导弹.gif)self.game_info[dan_dao_dao_dan_pic] arcade.Sprite(../图片文件/弹道导弹.png)# 游戏胜利图片self.game_info[game_win_pic] arcade.Sprite(../图片文件/win.png)# 游戏失败图片self.game_info[game_over_pic] arcade.Sprite(../图片文件/game_over.png)# 游戏暂停图片self.game_info[game_pause_pic] arcade.Sprite(../图片文件/游戏暂停.png)# 游戏胜利音乐self.game_info[game_win_sound] arcade.sound.load_sound(../声音文件/成功.mp3)# 游戏失败音乐self.game_info[game_over_sound_1] arcade.sound.load_sound(../声音文件/马里奥游戏结束.mp3)# 游戏失败嘲讽self.game_info[game_over_sound_2] arcade.sound.load_sound(../声音文件/马里奥哈哈嘲讽.mp3)# 游戏暂停音效self.game_info[game_pause_sound] arcade.sound.load_sound(../声音文件/暂停.mp3)# # 游戏暂停后重新开始音效# self.game_info[game_continue_sound] arcade.sound.load_sound(../声音文件/暂停后开始.mp3)def draw_game_info(self,x,y):# x: 屏幕宽度 y:屏幕高度font_size 20# 第一行# 描述游戏信息的字符串self.game_info[game_info_txt] f难度{self.game_info[difficulty_level]} vs 1 \f 得分{self.game_info[player_score]} /{self.game_info[player_target_score]}\f 命中率{self.game_info[player_score]}/{self.game_info[all_qi_qiu_num]}\f 计时{self.game_info[player_use_time]}/{self.game_info[game_limit_time]}arcade.Text(self.game_info[game_info_txt], 10, y - font_size*2,colorarcade.color.SAE, font_sizefont_size, widthx, font_name站酷快乐体2016修订版,boldTrue, alignleft, anchor_xleft, multilineFalse).draw()# 第二行# 绘制追踪导弹信息self.game_info[zhui_zong_dao_dan_pic].width font_size*2self.game_info[zhui_zong_dao_dan_pic].height font_size*2self.game_info[zhui_zong_dao_dan_pic].center_x 10 font_size // 2self.game_info[zhui_zong_dao_dan_pic].center_y y - font_size * 3.5self.game_info[zhui_zong_dao_dan_pic].draw()arcade.Text(fX {self.game_info[surplus_zhui_zong_dao_dan_num]}, 10 font_size*2 , y - font_size *4,colorarcade.color.SAE, font_sizefont_size, widthx, font_name站酷快乐体2016修订版,boldTrue, alignleft, anchor_xleft, multilineTrue).draw()# 绘制弹道导弹信息 (第二行 追踪导弹后面的内容)self.game_info[dan_dao_dao_dan_pic].width font_size*2self.game_info[dan_dao_dao_dan_pic].height font_size*2self.game_info[dan_dao_dao_dan_pic].center_x 10 font_size * 2 5*font_sizeself.game_info[dan_dao_dao_dan_pic].center_y y - font_size * 3.5self.game_info[dan_dao_dao_dan_pic].draw()arcade.Text(fX {self.game_info[surplus_dan_dao_dao_dan_num]}, 10 font_size * 2 6*font_size, y - font_size *4,colorarcade.color.SAE, font_sizefont_size, widthx, font_name站酷快乐体2016修订版,boldTrue, alignleft, anchor_xleft, multilineTrue).draw()# 游戏失败时持续执行if not self.game_info[game_status] and self.game_info[player_use_time] self.game_info[game_limit_time]:self.game_info[game_over_pic].center_x x // 2self.game_info[game_over_pic].center_y y // 2self.game_info[game_over_pic].draw()arcade.Text(f~~按右侧 SHIFT 键重新开始~~, x//2,y//2 - 200,colorarcade.color.WHITE, font_sizefont_size*2, widthx, font_name站酷快乐体2016修订版,boldTrue, alignleft, anchor_xcenter, multilineFalse).draw()# 游戏胜利时持续执行if not self.game_info[game_status] and (self.game_info[player_score] self.game_info[player_target_score]):self.game_info[game_win_pic].center_x x // 2self.game_info[game_win_pic].center_y y // 2self.game_info[game_win_pic].draw()# 触发游戏暂停时持续执行if self.game_info[game_status] and self.game_info[game_pause]:self.game_info[game_pause_pic].center_x x // 2self.game_info[game_pause_pic].center_y y // 2self.game_info[game_pause_pic].draw()arcade.Text(f~~按 Enter 键继续~~, x // 2, y // 2 - 200,colorarcade.color.WHITE, font_sizefont_size*2, widthx, font_name站酷快乐体2016修订版,boldTrue, alignleft, anchor_xcenter, multilineFalse).draw()def check_game_status(self, bgm):# 游戏失败时执行if self.game_info[game_status] and self.game_info[player_use_time] self.game_info[game_limit_time]:self.game_info[game_status] Falsearcade.stop_sound(bgm)self.game_info[game_over_sound_1].play()self.game_info[game_over_sound_2].play()# 游戏胜利时执行if self.game_info[game_status] and (self.game_info[player_score] self.game_info[player_target_score]):self.game_info[game_status] Falsearcade.stop_sound(bgm)self.game_info[game_win_sound].play()# 游戏暂停时执行if self.game_info[game_pause]:return Falsereturn self.game_info[game_status]# arcade_game_202302 流浪气球Ⅰ
class LiuLangQiQiu(arcade.View): 视图程序用于在窗体内展示. def __init__(self):# 初始化父类的属性super().__init__()self.background_image Noneself.dao_dan None# 气球类self.qi_qiu Noneself.qi_qiu_list None# 导弹类self.dao_dan Noneself.dao_dan_list None# 弹道导弹类self.dan_dao_dao_dan Noneself.dan_dao_dao_dan_list None# 所有气球文件self.all_qi_qiu None# 游戏背景音乐self.background_sound arcade.load_sound(../声音文件/忍者神龟背景音乐.mp3)# 导弹发射车self.dao_dan_che_image None# 爆炸烟雾self.explode_smoke Noneself.explode_smoke_list None# 为了有节奏的控制游戏刷新时个别元素的刷新速度 设置一个记录时间间隔变量self.interval_time 0# 游戏信息面板self.info_panel None# 鼠标的图片self.couser_pic None# 在初始化时调用的一些准备工作代码self.set_up()# 有规律的调用time_clock函数每次调用间隔设置为1秒arcade.schedule(self.time_clock, 1)def set_up(self,init_qi_qiu_num 5,zhui_zong_dao_dan_num 20,dan_dao_dao_dan_num30,difficulty_level3):difficulty_level难度等级 代表平均至少用几个弹道导弹就击中一个气球 会以此来计算玩家的目标分数 数字越大越简单 最小是1 进行一些游戏准备工作让游戏主逻辑从这开始以便于在有需要时重开游戏. # 实例化游戏信息类self.info_panel InfoPanel()self.info_panel.set_up(init_qi_qiu_numinit_qi_qiu_num,game_limit_timezhui_zong_dao_dan_num * 1 dan_dao_dao_dan_num*2,zhui_zong_dao_dan_numzhui_zong_dao_dan_num, dan_dao_dao_dan_numdan_dao_dao_dan_num,difficulty_leveldifficulty_level)# 游戏背景音乐self.current_play self.background_sound.play(volume0.4, loopTrue)# 气球精灵列表self.qi_qiu_list arcade.SpriteList()# 导弹精灵列表self.dao_dan_list arcade.SpriteList()# 弹道导弹精灵列表self.dan_dao_dao_dan_list arcade.SpriteList()# 爆炸烟雾精灵self.explode_smoke_list arcade.SpriteList()# 获取文件夹中所有的飞艇图片self.all_qi_qiu os.listdir(../图片文件/气球飞艇)print(self.all_qi_qiu)# 背景图片 当作精灵加载进来self.background_image arcade.Sprite(../图片文件/世界卫星地图.png)# 设置精灵素材中心点的位置self.background_image.center_x self.window.width // 3self.background_image.center_y self.window.height // 2# 导弹发射车 在on_resize()里设置绘制位置self.dao_dan_che_image arcade.Sprite(../图片文件/东风41.png)self.dao_dan_che_image.width 70self.dao_dan_che_image.height 70# 初始状态时创建自定义个气球(默认3个)self.creat_qi_qiu(init_qi_qiu_num)self.couser_pic arcade.Sprite(../图片文件/瞄准.png, scale0.2)# 括号里的这个参数必须写他是一个时间间隔代表上次调用 到本次调用之间的时间差 不严格等于我们设置的1秒def time_clock(self, delta_time):# print(delta_time)# 因为我们要更改TIME_CLOCK的值所以使用global 让函数可以改变这个全局变量if self.info_panel.game_info[game_status] and not self.info_panel.game_info[game_pause]:self.info_panel.game_info[player_use_time] 1def creat_qi_qiu(self, num):创建气球for i in range(1, num1):self.qi_qiu QiQiu(filenamef../图片文件/气球飞艇/{random.choice(self.all_qi_qiu)},change_xrandom.choice([0.5,0.5,1,2,2]), change_yrandom.choice([1,2]),init_xrandom.choice([-80, self.window.width 200]),init_yrandom.randint(200, self.window.height - num*50))self.qi_qiu.width 60self.qi_qiu.height 40# self.qi_qiu.scale 0.5if self.qi_qiu.center_x self.window.width//2:self.qi_qiu.change_x -self.qi_qiu.change_xself.qi_qiu_list.append(self.qi_qiu)# 每次创建过气球后 都将统计到游戏信息面板中self.info_panel.game_info[all_qi_qiu_num] numdef creat_zhui_zong_dao_dan(self):# 追踪导弹 如果剩余的追踪弹数量大于0 就接受命令进行创建if self.info_panel.game_info[surplus_zhui_zong_dao_dan_num] 0:dao_dan DaoDan(../图片文件/导弹.gif, change_x4, change_y3,init_xself.window.width // 3, init_yself.window.height // 2)self.dao_dan_list.append(dao_dan)dao_dan.fire_sound.play()self.info_panel.game_info[surplus_zhui_zong_dao_dan_num] - 1def creat_dan_dao_dao_dan(self,x,y):# 弹道导弹 如果剩余的弹道弹数量大于0 就接受命令进行创建if self.info_panel.game_info[surplus_dan_dao_dao_dan_num] 0:init_x self.window.width // 3init_y self.window.height // 2speed 1 if abs(x - init_x) 200 else 3# 如果目标点在右侧 则导弹向右飞行 横坐标变化为正数 否则为负数change_x speed if x self.window.width // 3 else - speeddan_dao_dao_dan DanDaoDaoDan(../图片文件/弹道导弹.png, change_xchange_x, change_y3,init_xinit_x, init_yinit_y,target_xx, target_yy)dan_dao_dao_dan.scale 0.7self.dan_dao_dao_dan_list.append(dan_dao_dao_dan)dan_dao_dao_dan.fire_sound.play()# 创建完毕后 剩余弹道导弹数量 -1self.info_panel.game_info[surplus_dan_dao_dao_dan_num] - 1def creat_yan_wu(self,center_x, center_y):yan_wu BaoZhaYanWu()yan_wu.center_x center_xyan_wu.center_y center_yself.explode_smoke_list.append(yan_wu)# 画面渲染绘制def on_draw(self): 负责渲染画面 速率 60帧/秒. # 清除上一帧绘制的画面self.clear()# 绘制背景图片self.background_image.draw()# 导弹发射车self.dao_dan_che_image.draw()# 绘制气球精灵组self.qi_qiu_list.draw()# 绘制导弹精灵组self.dao_dan_list.draw()# 绘制弹道导弹精灵组self.dan_dao_dao_dan_list.draw()# 绘制爆炸烟雾self.explode_smoke_list.draw()# 绘制游戏信息self.info_panel.draw_game_info(self.window.width, self.window.height)# 绘制鼠标self.couser_pic.draw()# 控制每次刷新时的变化def on_update(self, delta_time: float): 负责逻辑变化 速率 60帧/秒. if self.info_panel.check_game_status(self.current_play):# 如果检测游戏的状态为True 则继续刷新 否则不再执行后续逻辑for qi_qiu_id, qi_qiu in enumerate(self.qi_qiu_list):# 处理气球和自动追踪导弹的碰撞及逻辑qi_qiu.update(self.window.height)if qi_qiu_id len(self.dao_dan_list)-1:dao_dan self.dao_dan_list[qi_qiu_id]dao_dan.track_target(qi_qiu.center_x, qi_qiu.center_y, change_angle-0.5)# else:# print(请尽快发射导弹)collision arcade.check_for_collision_with_list(qi_qiu, self.dao_dan_list)if len(collision) 0:print(f发生碰撞了,相撞的{qi_qiu_id}号导弹和气球都被移除)# 移除碰到的气球qi_qiu.remove_from_sprite_lists()# 剩余气球数量 -1self.info_panel.game_info[surplus_qi_qiu_num] - 1# 玩家分数 1self.info_panel.game_info[player_score] 1# 创建气球self.creat_qi_qiu(1)# 移除碰到的追踪导弹for collision_obj in collision:collision_obj.remove_from_sprite_lists()collision_obj.explode_sound.play()# 追踪导弹数量-1 因为在创建时候就减去了1 所以这里不再减# self.info_panel.game_info[surplus_zhui_zong_dao_dan_num] - 1# 创建烟雾 坐标为所碰撞气球的坐标self.creat_yan_wu(qi_qiu.center_x,qi_qiu.center_y)if qi_qiu.center_x not in range(-230, self.window.width230):# 气球飞出屏幕一定距离后 则消失qi_qiu.remove_from_sprite_lists()# 剩余气球数量 -1self.info_panel.game_info[surplus_qi_qiu_num] - 1# 再次创建气球self.creat_qi_qiu(1)# 处理按下鼠标发射的弹道导弹for dan_dao_dao_dan in self.dan_dao_dao_dan_list:# 处理气球和弹道导弹的碰撞及逻辑dan_dao_dao_dan.track_target()collision2 arcade.check_for_collision_with_list(dan_dao_dao_dan, self.qi_qiu_list)for collision_obj2 in collision2:collision_obj2.remove_from_sprite_lists()dan_dao_dao_dan.remove_from_sprite_lists()dan_dao_dao_dan.explode_sound.play()# 剩余气球数量 -1self.info_panel.game_info[surplus_qi_qiu_num] - 1# 玩家分数 1self.info_panel.game_info[player_score] 1# 创建气球self.creat_qi_qiu(1)# 创建烟雾self.creat_yan_wu(collision_obj2.center_x, collision_obj2.center_y)# 如果导弹飞出了屏幕 则销毁if dan_dao_dao_dan.center_x not in range(-230, self.window.width230):dan_dao_dao_dan.remove_from_sprite_lists()# 将原来创建气球的时机改为每当有一个气球消失 就创建一个 下面代码不再使用# if len(self.qi_qiu_list) 3:# self.creat_qi_qiu(3)for smoke in self.explode_smoke_list:self.interval_time delta_timeif self.interval_time 0.08:res smoke.update()self.interval_time 0if res:smoke.remove_from_sprite_lists()def on_mouse_press(self, x, y, button, modifiers): 监听鼠标点击事件. mouse_buttons {1: 左键, 2: 中键, 4: 右键}# print(f当前点击的坐标是{x,y})if self.info_panel.game_info[game_status] and not self.info_panel.game_info[game_pause]:# 创建弹道导弹self.creat_dan_dao_dao_dan(x,y)def on_mouse_release(self, x: float, y: float, button: int, modifiers: int): 监听鼠标释放事件. passdef on_mouse_motion(self, x: float, y: float, dx: float, dy: float): 监听鼠标移动事件 self.couser_pic.center_x xself.couser_pic.center_y ydef on_key_press(self,key, modifiers):监听键盘按键点击事件modifiers:None 16,shift 117 ctrl 218 alt 420 print(---键盘按键按下了--,key,--修饰键编号的和是---, modifiers)if key arcade.key.SPACE and self.info_panel.game_info[game_status] \and not self.info_panel.game_info[game_pause]:self.creat_zhui_zong_dao_dan()if key arcade.key.RSHIFT and not self.info_panel.game_info[game_status]:# 让游戏重新开始 并且重置屏幕大小为上一次的大小self.set_up()self.on_resize(self.window.width,self.window.height)def on_key_release(self, key, modifiers):print(---键盘按键抬起了--,key,--剩余修饰键编号的和是---, modifiers)print(---键盘按下之前--,self.info_panel.game_info[game_pause])if key arcade.key.ENTER and self.info_panel.game_info[game_status]:self.info_panel.game_info[game_pause] not self.info_panel.game_info[game_pause]self.info_panel.game_info[game_pause_sound].play()print(---键盘按下之后--, self.info_panel.game_info[game_pause])def on_resize(self, width: int, height: int):# 重新设置精灵素材中心点的位置self.background_image.center_x self.window.width // 2self.background_image.center_y self.window.height // 2# 重新设置精灵素材宽度和高度self.background_image.width self.window.widthself.background_image.height self.window.height# 设置导弹车精灵素材中心点的位置self.dao_dan_che_image.center_x self.window.width // 3 - 30self.dao_dan_che_image.center_y self.window.height // 2for jing_ling in (self.dan_dao_dao_dan_list,self.dao_dan_list,self.qi_qiu_list):# 界面在玩耍时侯如果缩放会使导弹和气球位置发生相对于地图的偏移passdef main():# 设置窗体的宽、高、名字、是否支持缩放window arcade.Window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE, resizableTrue)# 设置窗体的 logo 图标import pygletwindow.set_icon(pyglet.image.load(../图片文件/浪淘三千.png))# 设置鼠标形状cursor window.get_system_mouse_cursor(window.CURSOR_HAND)window.set_mouse_cursor(cursor)# 实例化定义的某个窗体start_view LiuLangQiQiu()# 设置当前应该显示哪个窗体window.show_view(start_view)# 保持程序持续运行arcade.run()if __name__ __main__:main()