python之星河战争游戏
效果图:
开始界面:
游戏中:
gameover!
文件结构:
- game_file:所有游戏逻辑相关的源码;
- rec:游戏相关的图片、音乐资源;
- main.py: 游戏的启动文件;
所用到的图片:
源码和文件我会放到文末,感兴趣的自取。
源码及注释:
game_windows.py 游戏运行的主函数模块,所有的顶层函数
1 # coding=utf-8 2 3 import time 4 import math 5 import sys 6 7 import pygame 8 from pygame.locals import * 9 10 from .resource_game import * 11 from . import setting as st 12 13 # 创建一个敌机机型的字典 14 dict_enemy = {'0': st.ENEMY_1, '1': st.ENEMY_2, '2': st.ENEMY_3} 15 fps1 = 0 # 开始按钮计数器 16 fps2 = 0 17 fps6 = 0 18 ran3 = 0 19 num = 0 # 减慢移动的计数器 20 num_shower = 0 # 创建流星雨的帧数计数器和循环次数的计数器 21 22 23 def main(): # 定义一个游戏运行的主函数 24 fps = 0 # 创建帧数计数器 25 fps4 = 0 26 fps5 = 0 27 f = 0 28 time1 = time.time() 29 buttons = () # 登陆界面按钮的元组 30 buttons1 = () # 用来放结束界面的按钮 31 32 pygame.init() # 系统初始化 33 # 创建一个全屏的屏幕对象 34 screen = pygame.display.set_mode((st.SCREEN_WIDTH, st.SCREEN_HIGHT), 0, 32) 35 pygame.display.set_caption("星河战争-天宇之游") 36 screen.get_rect() # 获取屏幕矩形 37 # 创建一个敌机生成器 38 EnemyCreate = enemy_create(screen) 39 # 创建一个文字显示效果生成器 40 Chars = chars(screen) 41 game_before(screen) # 加入游戏界面元素 42 st.GAME_BEFORE = True # 打开游戏前言开关 43 44 while True: # 开始游戏主循环 45 mouse_x, mouse_y = pygame.mouse.get_pos() # 获取光标的位置 46 if st.GAME_BEFORE: # 游戏进入前言 47 key_quit() # 检测退出按键 48 if fps % st.FRAMES == 0: # 每过帧数显示一个字 49 try: 50 next(Chars) 51 except StopIteration: 52 pass 53 fps += 1 54 if fps == st.WIN_OVER_FRAMES: 55 fps = 0 # 计数器还原 56 cls() # 清空子弹、删除、界面元素列表 57 buttons = game_load(screen) # 加入登陆界面元素,返回三个按钮的元组 58 bc(k2=True) # 打开游戏界面控制开关 59 60 elif st.SCREEN_CHANGE: # 游戏界面控制开关 61 # 界面按钮遍历检测 62 mc(buttons, mouse_x, mouse_y) 63 key_load(screen, mouse_x, mouse_y) # 按键的控制函数 64 65 elif st.GAME_SAY: # 游戏前言 66 key_quit() # 检测窗口退出按键 67 fps5 += 1 68 if fps5 == st.WIN_FONT_FRAMES: 69 bc(k4=True) # 打开战斗界面控制开关 70 fps5 = 0 # 计数器还原 71 cls() # 清空子弹、删除、界面元素列表 72 beijing_1, hero_me = game_fight(screen) # 加入游戏元素 73 74 elif st.GAME_FIGHT: # 进入战斗界面 75 # 创建一个开关字典用来指示上下左右方向 76 dict_key = {st.KEY_UP: 'up', 77 st.KEY_DOWN: 'down', 78 st.KEY_LEFT: 'left', 79 st.KEY_RIGHT: 'right' 80 } 81 buttons = key_fight(screen, hero_me) # 战斗界面的控制函数 82 # 创建敌机随机生成器 83 fps += 1 84 if st.GAME_MOSHI: # 判断目前的游戏模式 85 ps = st.ENEMY_CREATE1 86 else: 87 ps = st.ENEMY_CREATE2 88 if fps % ps == 0: # 每循环ps次执行 89 enemy_make(screen, EnemyCreate) # 敌机的生产控制 90 boss_make(screen) # boss飞机的产生 91 buff_make() # buff有效时间控制 92 move_make(dict_key, hero_me) # 通过开关字典控制飞机的移动 93 if st.ENEMY_START: # 在boss飞机出现后才检测 94 if boss_die(): # boss是否死光 95 buttons1 = go_game_end(screen) # 加载结束界面得到按钮 96 97 elif st.GAME_END: # 进入结束界面 98 # 界面按钮遍历检测 99 mc(buttons1, mouse_x, mouse_y) 100 # 按钮控制 101 buttons = key_end(screen, mouse_x, mouse_y) 102 # 计算帧数的速度 103 time2 = time.time() 104 fps4 += 1 105 if time2 - time1 >= 1: 106 time1 = time2 107 print(fps4 - f) 108 f = fps4 109 110 loop() # 元素循环显示和清空 111 pygame.display.update() # 更新屏幕 112 time.sleep(0.01) # 休眠0.01秒 113 114 115 def buttons_control(k1=False, k2=False, 116 k3=False, k4=False, k5=False): 117 """所有相关界面的开关管理,全部默认关闭""" 118 st.GAME_BEFORE = k1 # 游戏进入前的界面控制开关 119 st.SCREEN_CHANGE = k2 # 登陆界面开关 120 st.GAME_SAY = k3 # 游戏历史背景开关 121 st.GAME_FIGHT = k4 # 战斗界面控制开关 122 st.GAME_END = k5 # 游戏结束界面控制开关 123 bc = buttons_control 124 125 126 def mouse_control(buttons, mouse_x, mouse_y): 127 """界面按钮的检测函数""" 128 try: 129 for button in buttons: # 将光标的坐标传入对象检测开关是否应该打开 130 button.mouse_make(mouse_x, mouse_y) 131 except Exception as re: 132 print(re) 133 mc = mouse_control 134 135 136 def key_quit(): 137 """检测是否按了退出键""" 138 for event in pygame.event.get(): # 键盘和鼠标事件的监听 139 if event.type == pygame.QUIT: # 检测是否按了窗口的退出按键 140 sys.exit() 141 142 143 def key_end(screen, mouse_x, mouse_y): 144 """游戏结束后统计界面的按键控制函数""" 145 for event in pygame.event.get(): # 键盘和鼠标事件的监听 146 # 检测是否按了窗口的退出按键 147 if event.type == pygame.QUIT: 148 sys.exit() 149 # 判断是否按下了鼠标并且光标在按钮范围内 150 elif event.type == pygame.MOUSEBUTTONDOWN: 151 if 20 <= mouse_x <= 620: 152 print(mouse_x) 153 print(mouse_y) 154 if 200 <= mouse_y <= 285: # 按下了下一关按钮 155 # st.GAME_MOSHI = True 156 pass 157 elif 350 <= mouse_y <= 435: # 按下了重新开始按钮 158 bc(k2=True) # 打开登陆界面开关 159 cls() # 清空子弹、删除、界面元素列表 160 # 将敌机死亡的数量重新设置为0 161 EnemyPlane.set_enemy_die(True) 162 buttons = game_load(screen) # 加载登陆界面元素 163 164 return buttons 165 elif 500 <= mouse_y <= 585: # 按下了退出按钮 166 exit() 167 168 169 def key_load(screen, mouse_x, mouse_y): 170 """游戏开始前的设置界面的按键控制函数""" 171 for event in pygame.event.get(): # 键盘和鼠标事件的监听 172 # 检测是否按了窗口的退出按键 173 if event.type == pygame.QUIT: 174 sys.exit() 175 # 判断是否按下了鼠标并且光标在按钮范围内 176 elif event.type == pygame.MOUSEBUTTONDOWN: 177 if 220 <= mouse_x <= 420: 178 print(mouse_x) 179 print(mouse_y) 180 if 300 <= mouse_y <= 340: # 按下了标准模式按钮 181 st.GAME_MOSHI = True 182 elif 400 <= mouse_y <= 440: # 按下了困难模式按钮 183 st.GAME_MOSHI = False 184 elif 200 <= mouse_y <= 240: # 按下了退出按钮 185 exit() 186 187 # 按下了进入游戏按钮 188 if 230 <= mouse_x <= 412 and 500 <= mouse_y <= 695: 189 print("执行成功") 190 cls() # 清空子弹、删除、界面元素列表 191 game_say(screen) # 加入历史背景界面 192 bc(k3=True) # 游戏历史背景开关打开 193 st.ENEMY_MAKE = True # 重新打开敌机生成器的开关 194 195 196 def key_fight(screen, hero_me): 197 """一个战斗界面的按键检测控制函数 """ 198 for event in pygame.event.get(): # 键盘和鼠标事件的监听 199 if event.type == pygame.QUIT: # 检测是否按了窗口的退出按键 200 sys.exit() 201 elif event.type == pygame.KEYDOWN: # 判断是否按下了键盘 202 # 是否按下W键或up键 203 if event.key == pygame.K_w or event.key == pygame.K_UP: 204 st.KEY_UP = True # 打开开关 205 # 是否按下s or down 206 elif event.key == pygame.K_s or event.key == pygame.K_DOWN: 207 # 打开向下移动的开关 208 st.KEY_DOWN = True 209 # 是否按下a or left 210 elif event.key == pygame.K_a or event.key == pygame.K_LEFT: 211 # 打开向左移动的开关 212 st.KEY_LEFT = True 213 # 是否按下d or right 214 elif event.key == pygame.K_d or event.key == pygame.K_RIGHT: 215 # 打开向右移动的开关 216 st.KEY_RIGHT = True 217 # 判断是否按下了Q键 218 elif event.key == pygame.K_q: 219 bc(k2=True) # 打开登陆界面开关 220 cls() # 清空子弹、删除、界面元素列表 221 # 将敌机死亡的数量重新设置为0 222 EnemyPlane.set_enemy_die(True) 223 buttons = game_load(screen) # 加载登陆界面元素 224 return buttons 225 226 elif event.type == pygame.KEYUP: # 是否放开了键盘 227 if event.key == pygame.K_w or event.key == pygame.K_UP: 228 # 关闭开关 229 st.KEY_UP = False 230 elif event.key == pygame.K_s or event.key == pygame.K_DOWN: 231 # 关闭向下移动的开关 232 st.KEY_DOWN = False 233 elif event.key == pygame.K_a or event.key == pygame.K_LEFT: 234 # 关闭向左移动的开关 235 st.KEY_LEFT = False 236 elif event.key == pygame.K_d or event.key == pygame.K_RIGHT: 237 # 关闭向右移动的开关 238 st.KEY_RIGHT = False 239 240 if event.type == pygame.MOUSEBUTTONDOWN: # 判断是否按下了鼠标 241 if hero_me.get_fire(): # 如果发射子弹的开关是打开的 242 hero_me.fire() # 将子弹列表的元素加入显示列表 243 244 245 def go_game_end(screen): 246 """游戏结束的界面控制""" 247 global fps6 248 if st.ENEMY_START and st.BOSS_DIE: # 如果boss产生了但又死光 249 fps6 += 1 # 计数器启动 250 if fps6 == 300: 251 cls() # 清空子弹、删除、界面元素列表 252 buttons = game_end(screen) # 加载结束界面 253 bc(k5=True) # 打开结束界面开关 254 st.ENEMY_START = False # 关闭boss检测开关 255 st.BOSS_DIE = False # 关闭boss死光开关 256 return buttons 257 258 259 def game_end(screen): 260 """对方大boss死亡后出现结束界面""" 261 # 创建背景图片 262 Factory.beijing_act(0, 0, screen, st.MY_TEXT) 263 # 创建退出游戏按钮 264 button_4 = Factory.button1_act(20, 500, screen, st.BUTTON_D) 265 # 创建重新开始按钮 266 button_5 = Factory.button1_act(20, 350, screen, st.BUTTON_E) 267 # 创建下一关按钮 268 button_6 = Factory.button1_act(20, 200, screen, st.BUTTON_F) 269 # 创建积分界面画布 270 Factory.beijing_act(640, 0, screen, st.IMAGE_BJ) 271 integ(screen) # 创建统计信息标签 272 return button_4, button_5, button_6 273 274 275 def game_say(screen): 276 """显示一段文字""" 277 # 创建一个星空背景 278 Factory.beijing_act(0, 0, screen, st.MY_TEXT) 279 text = "公元2300年,外星人入侵,这是人类的最后时刻!" 280 Factory.script_act(20, 300, screen, text, 30, num=3, 281 filename=st.SCRIPT, bg_script=(255, 255, 255)) 282 283 284 def enemy_make(screen, EnemyCreate): 285 """敌机生成控制函数""" 286 if st.ENEMY_MAKE: # 生成器开关默认是打开的 287 enemy_plane = None 288 stony = None 289 try: 290 # 若未达到敌机死亡的上限 291 if EnemyPlane.get_enemy_die() < st.ENEMY_NUM: 292 enemy_plane = next(EnemyCreate) # 敌机生成 293 stony = stony_creat(screen) # 陨石生成 294 else: 295 st.BOSS_CREAT = True 296 st.ENEMY_MAKE = False # 关闭生成器的开关 297 except StopIteration: 298 enemy_plane = None 299 stony = None 300 301 try: 302 if enemy_plane: # 如果不为空 303 screen_list.append(enemy_plane) # 加入显示列表 304 305 if stony: # 如果不为空 306 screen_list.append(stony) 307 except Exception as re: 308 print(re) 309 310 311 def boss_make(screen): 312 """敌机boss的生成控制""" 313 global fps2 314 if st.BOSS_CREAT: # 创建boss 315 fps2 += 1 316 # print(fps2) 317 if fps2 == 100: 318 for i in range(st.BOSS_NUM): 319 Factory.enemy_act(300, -200, screen, dict_enemy['2']) 320 fps2 = 0 321 st.BOSS_CREAT = False # 关闭创建boss的开关 322 st.ENEMY_START = True # 打开检测boss飞机的开关 323 324 325 def boss_die(): 326 """所有的boss是否死亡检测""" 327 boss_button = True # 开始默认打开的 328 for ele in screen_list: # 如果遍历一次后发现还存在boss飞机,则关闭 329 if isinstance(ele, BossEnemy): 330 boss_button = False 331 if boss_button: # 如果没有boss飞机了 332 st.BOSS_DIE = True 333 return st.BOSS_DIE 334 335 336 def buff_make(): 337 """各种buff子弹有效时间计数函数""" 338 if st.GOD_BUFF: # 金币子弹buff出现,大于500帧数后消失 339 st.BUFF_TIME += 1 340 if st.BUFF_TIME >= 500: 341 st.GOD_BUFF = False 342 343 if st.LASER_BUFF: # 激光子弹buff出现,大于500帧数后消失 344 st.LASER_TIME += 1 345 if st.LASER_TIME >= 500: 346 st.LASER_BUFF = False 347 348 if st.RAN_BUFF: # 随机子弹buff出现 349 st.RAN_TIME += 1 350 if st.RAN_TIME >= 500: 351 st.RAN_BUFF = False 352 353 354 def move_make(dict_key, hero_me): 355 """控制飞机移动的方法""" 356 global num 357 for item in dict_key.items(): # 通过开关控制我方飞机移动 358 if item[0]: 359 # print(item[0]) 360 num += 1 361 if num > 2: 362 hero_me.hreo_move(item[1]) 363 num = 0 364 365 366 def clear_list(): 367 """清除相关列表中的元素函数""" 368 bullet_list.clear() # 清除发射出的列表 369 bullet_del.clear() # 清空该删除的列表 370 screen_list.clear() # 清空界面元素 371 372 373 cls = clear_list 374 375 376 def loop(): 377 """抽取主函数中循环的代码""" 378 screen_list.extend(bullet_list) # 将敌机产生的子弹加入显示列表 379 # print(len(bullet_list)) 380 bullet_list.clear() # 清除列表 381 382 for bu in bullet_del: # 从显示列表中删除应该消失的子弹 383 if bu in screen_list: 384 screen_list.remove(bu) 385 bullet_del.clear() # 清空列表 386 387 for element in screen_list: # 循环显示所有对象,默认多态 388 element.draw() 389 # print(len(screen_list)) 390 # print(screen_list) 391 392 393 def game_load(screen): 394 """创建游戏登陆界面需要的图像""" 395 # 创建开始界面背景 396 Factory.beijing_act(0, 0, screen, st.BEIJING_2) 397 # 创建积分界面 398 Factory.beijing_act(640, 0, screen, st.IMAGE_BJ) 399 # 创建游戏操作说明 400 Factory.beijing_act(120, 50, screen, st.FUNCTION_1) 401 # 创建标准模式按钮 402 button1 = Factory.button1_act(220, 300, screen, st.BUTTON_A) 403 # 困难模式按钮 404 button2 = Factory.button1_act(220, 400, screen, st.BUTTON_B) 405 # 退出按钮 406 button3 = Factory.button1_act(220, 200, screen, st.BUTTON_C) 407 # 生产一个开始按钮并加入显示列表 408 Factory.button_act(230, 500, screen, st.BUTTON_START) 409 410 integ(screen) # 创建统计信息标签 411 Factory.music_act(st.START_MUSIC) # 游戏的开始音乐 412 # print(len(screen_list)) 413 # print(len(list_game)) 414 return button1, button2, button3 415 416 417 def integ(screen): 418 """创建游戏统计信息的显示文字""" 419 # 取得一个随机数 420 ran = random.randint(0, 4) 421 # 创建角色头像标签 422 Factory.beijing_act(640, 0, screen, st.BOY_IMAGE[ran]) 423 # 创建分数标签 424 Factory.script_act(655, 325, screen, "分数", 50, 425 filename=st.SCRIPT, bg_script=(0, 255, 255)) 426 # 创建角色标签 427 Factory.script_act(655, 150, screen, "角色", 50, 428 filename=st.SCRIPT, bg_script=(0, 255, 255)) 429 # 创建排名标签 430 Factory.script_act(655, 500, screen, "排名", 50, 431 filename=st.SCRIPT, bg_script=(0, 255, 255)) 432 433 434 def game_before(screen): 435 """创建游戏之前的界面图像""" 436 # 有主背景图片、飞机大战题目图片、游戏发言图片、作者图片、积分界面图片 437 beijing_before = [[0, 0, st.MY_XING], 438 [100, 200, st.MY_READ], 439 [450, 380, st.MY_SELF], 440 [640, 0, st.IMAGE_BJ] 441 ] 442 # "保护地球人人有责"的坐标列表 443 script_before = ["保", "护", "地", "球", "人", "人", "有", "责"] 444 for i, bj in enumerate(beijing_before): 445 # 创建所有界面元素并添加 446 Factory.beijing_act(bj[0], bj[1], screen, bj[2]) 447 for j, sb in enumerate(script_before): 448 # 创建文字对象 449 Factory.script_act(660, 10 + j * 83, screen, sb, 80, filename=st.SCRIPT1) 450 451 Factory.music_act(st.START_MUSIC) # 创建并播放音乐 452 453 454 def chars(screen): 455 """显示“星河战争“四个字的动态效果生成器""" 456 list_char = [(120, "星"), (220, "河"), (320, "战"), (420, "争")] 457 458 for tp in list_char: 459 # 创建一个文字 460 script = Factory.script_act(tp[0], 100, screen, tp[1], 120, num=1, color=(0, 0, 255)) 461 # 创建一个爆炸 462 Factory.any_blast(script, "big", 2) 463 yield script 464 465 466 def game_fight(screen): 467 """创建游戏战斗需要的图像并加载""" 468 # 创建一个战斗界面背景 469 beijing_1 = Factory.beijing_act(0, 0, screen, st.BEIJING_1) 470 # 创建积分界面 471 Factory.beijing_act(640, 0, screen, st.IMAGE_BJ) 472 integ(screen) # 创建统计信息标签 473 # 创建我方飞机并设置初始位置 474 hero_me = Factory.hreo_act(270, 600, screen, st.HREO_1) 475 hero_me.button_fire = True # 将我方飞机的开火开关打开 476 return beijing_1, hero_me 477 478 479 def enemy_create(screen): 480 """敌机的生成器,使用了迭代器的方式""" 481 i = 0 482 while i < 500: 483 ran1 = random.randint(0, 2) # 生成敌机的 出生位置 484 ranx = random.randint(0, 20) # 调整敌机生成的概率 485 if ranx <= 14: 486 ran2 = 0 487 else: 488 ran2 = 1 489 # 创建敌方飞机 490 enemy_plane = EnemyPlane(100 + ran1 * 200, -100, screen, dict_enemy[str(ran2)]) 491 yield enemy_plane 492 i += 1 493 # st.BOSS_CREAT = True 494 495 496 def stony_creat(screen): 497 """陨石生成器""" 498 ran1 = random.randint(0, 2) # 生成出生位置 499 ran2 = random.randint(0, 10) # 设置出生概率 500 if ran2 <= 2: # 20%的出生概率 501 stony_one = Stony(250 + ran1 * 100, -100, screen, st.STONY_BUFF) 502 return stony_one 503 else: 504 return False 505 506 507 def delay_time(delay, time0=time.time()): 508 """一个延时函数""" 509 time1 = time.time() 510 if time1 - time0 >= delay: 511 return True 512 else: 513 return False 514 515 516 if __name__ == '__main__': 517 pass
resource_game.py 所有的元素类和功能类模块
1 import random 2 import pygame 3 from . import setting as st 4 from game_file.tool import * 5 6 7 screen_list = [] # 创建一个显示列表全局 8 bullet_list = [] # 创建一个显示子弹的全局列表 9 bullet_del = [] # 创建一个该删除的元素列表 10 num1 = 0 # 创建一个爆炸效果的计数器 11 12 13 class Obj(object): 14 """创建一个父类1""" 15 # 构造位置属性 16 def __init__(self, x, y, screen, filename): 17 self.x = x 18 self.y = y 19 self.screen = screen 20 self.name = filename 21 self.image_1 = pygame.image.load_extended(self.name) # 加载背景图片 22 self.rect = self.image_1.get_rect() # 获取图片的外接矩形 23 24 def draw(self): # 设置绘制的功能 25 pass 26 27 28 class ScriptBase(Obj): 29 """创建一个文字基类""" 30 31 def __init__(self, x, y, screen, script, size, 32 filename=st.SCRIPT, color=(255, 255, 255), 33 bool_sc=True, bg_script=None): 34 """ 35 构造函数,初始化文字的位置x,y,显示的窗口screen,文字script, 36 字体大小size,字体的TTF文件filename,字体的颜色color,默认开启抗锯齿True, 37 不定长参数为是否设置字的背景bg_script 38 """ 39 self.x = x 40 self.y = y 41 self.screen = screen 42 self.script = script 43 self.size = size 44 self.name = filename 45 self.color = color 46 self.bool_sc = bool_sc 47 self.bg_script = bg_script 48 49 def sc_act(self): 50 """创建文字的函数""" 51 # 创建一个文字对象 52 my_font = pygame.font.Font(self.name, self.size) 53 # 文件对象的显示参数 54 text_surface = my_font.render(self.script, self.bool_sc, 55 self.color, self.bg_script) 56 return text_surface 57 58 def draw(self): 59 text = self.sc_act() 60 # 显示创建的文字对象 61 self.screen.blit(text, (self.x, self.y)) 62 63 def change_size(self): 64 """文字的效果,如大小闪烁,移动变化等""" 65 pass 66 67 def change_color(self): 68 pass 69 70 71 class ScriptNew(ScriptBase): 72 """创建基本的文字""" 73 def __init__(self, x, y, screen, script, size, *args): 74 super().__init__(x, y, screen, script, size, *args) 75 # 创建一个文字对象 76 self.my_font = pygame.font.Font(self.name, self.size) 77 # 文件对象的显示参数 78 self.text_surface = self.my_font.render(self.script, self.bool_sc, 79 self.color, self.bg_script) 80 81 def draw(self): 82 # 显示创建的文字对象 83 self.screen.blit(self.text_surface, (self.x, self.y)) 84 85 86 class ScriptLong(ScriptBase): 87 """创建大段依次显示的文字""" 88 def __init__(self, x, y, screen, script, size, *args): 89 super().__init__(x, y, screen, script, size, *args) 90 # 创建一个文字对象 91 self.my_font = pygame.font.Font(self.name, self.size) 92 self.fps = 0 93 # 单个文字对象 94 self.t = None 95 # 创建一个文字图像列表 96 self.text = [] 97 for x in range(len(self.script)): # 创建单个的文字图像 98 t = self.my_font.render(self.script[:x+1], self.bool_sc, 99 self.color, self.bg_script) 100 self.text.append(t) 101 self.it = iter(self.text) # 获得迭代器 102 103 def draw(self): 104 self.fps += 1 105 if self.fps % 20 == 0: # 每隔5帧数显示一个文字 106 try: 107 self.t = next(self.it) 108 except StopIteration: 109 pass 110 if self.t: # 如果对象不为空 111 self.screen.blit(self.t, (self.x, self.y)) 112 113 114 class ScriptMove(ScriptBase): 115 """创建一个的大小变化和闪烁效果""" 116 def __init__(self, x, y, screen, script, size, *args): 117 super().__init__(x, y, screen, script, size, *args) 118 # 创建一个闪烁速度的计数器 119 self.fps = 0 120 # 字体尺寸最小 121 self.least = 80 122 # 字体最大 123 self.max = size 124 # 设置变化的颜色 125 self.list_color = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] 126 127 def draw(self): 128 self.fps += 1 129 super().draw() 130 if self.fps >= 20: # 20帧数后开始变化 131 self.change_size() # 改变文字大小 132 self.change_color() # 改变文字颜色 133 134 def change_size(self): 135 """重写父类的方法""" 136 # print("change执行了") 137 if self.fps % 2 == 0 and self.size > self.least: # 每过5帧数执行一次 138 self.size -= 2 139 self.x += 1 140 self.y += 1 141 # if self.size <= self.least: # 达到最小时还原大小 142 # self.size = self.max 143 144 def change_color(self): 145 """文字颜色红绿蓝三色变化""" 146 if self.fps % 5 == 0: 147 ran = random.randint(0, 2) 148 self.color = self.list_color[ran] 149 150 151 class ScriptEnd(ScriptBase): 152 """创建一个文字由小到大的效果""" 153 def __init__(self, x, y, screen, script, size, *args): 154 super().__init__(x, y, screen, script, size, *args) 155 # 创建一个闪烁速度的计数器 156 self.fps = 0 157 158 def change_size(self): 159 if self.fps % 2 == 0 and self.size < 180: # 每过5帧数执行一次 160 self.size += 3 161 self.x -= 1 162 self.y -= 1 163 164 def draw(self): 165 self.fps += 1 166 super().draw() 167 self.change_size() 168 169 170 class ButtonGame(Obj): 171 """创建一个游戏开始按钮""" 172 173 def __init__(self, x, y, screen, list_image): 174 self.x = x 175 self.y = y 176 self.screen = screen 177 self.images = [] # 按钮的图片群 178 self.fps = 0 # 按钮显示的计数器 179 self.ran = 0 # 图片下标 180 for image in list_image: # 所有图片全部加载 181 self.images.append(pygame.image.load_extended(image)) 182 183 def draw(self): 184 self.fps += 1 185 if self.fps % 10 == 0: # 每过15帧显示一张按钮图片 186 self.ran += 1 187 if self.ran > 3: 188 self.ran = 0 189 self.screen.blit(self.images[self.ran], (self.x, self.y)) # 循环显示背景图片 190 191 192 class ModeButton(ButtonGame): 193 """创建各种功能按钮""" 194 195 def __init__(self, x, y, screen, list_image): 196 super().__init__(x, y, screen, list_image) 197 self.image_size = [] 198 self.button_make = False # 创建一个按钮图片替换的开关 199 for image1 in self.images: 200 self.image_size.append(image1.get_rect()) # 获取图片的外接矩形 201 202 def mouse_make(self, mouse_x, mouse_y): 203 """根据光标位置控制显示的方法""" 204 # 如果光标的坐标在图片按钮的范围之内 205 if self.x <= mouse_x <= self.x + self.image_size[0].w \ 206 and self.y <= mouse_y <= self.y + self.image_size[0].h: 207 self.button_make = True # 显示黄色的图片 208 else: 209 self.button_make = False # 显示绿色的图片 210 211 def draw(self): # 重写显示方法 212 try: 213 if not self.button_make: # 如果替换开关是关闭的 214 self.screen.blit(self.images[0], (self.x, self.y)) # 显示绿色的图片 215 216 else: 217 self.screen.blit(self.images[1], (self.x, self.y)) # 显示黄色的图片 218 219 except Exception as re: 220 print(re) 221 222 223 class Beijing(Obj): 224 """创建一个背景类""" 225 def __init__(self, x, y, screen, filename): 226 super().__init__(x, y, screen, filename) 227 self.num = -2000 # 设置图片最初位置 228 229 def draw(self): # 重写父类的方法 230 if self.name == st.BEIJING_1: # 如果是游戏战斗背景图 231 self.y = self.num 232 self.num += st.BEIJING_SPEED # 使得背景图移动 233 if self.num > -10: 234 self.num = -2000 235 self.screen.blit(self.image_1, (self.x, self.y)) # 循环显示背景图片 236 237 238 class Factory(object): 239 """"创建一个万能的工厂,能够生产并自动将其添加到显示列表""" 240 @staticmethod 241 def beijing_act(x, y, screen, filename): 242 """创造并显示静态的图片""" 243 beijing = Beijing(x, y, screen, filename) 244 screen_list.append(beijing) # 将背景添加到显示列表 245 return beijing 246 247 @staticmethod 248 def script_act(x, y, screen, script, size, 249 filename=st.SCRIPT2, num=0, color=(255, 0, 0), 250 bool_sc=True, bg_script=None): 251 """创建一个柔性化制造各种效果文字的工厂""" 252 ls = [x, y, screen, script, size, 253 filename, color, bool_sc, bg_script 254 ] 255 if num == 0: # 如果选择为0则创建基本的文字 256 script = ScriptNew(*ls) 257 258 elif num == 1: # 如果选择为1则创建大小变化的文字 259 script = ScriptMove(*ls) 260 elif num == 2: 261 script = ScriptEnd(*ls) # 创建小变大的文字 262 elif num == 3: 263 script = ScriptLong(*ls) # 创建长文字 264 screen_list.append(script) # 添加文字到显示列表 265 return script 266 267 @staticmethod 268 def button1_act(x, y, screen, list_image): 269 """创建普通按钮""" 270 button = ModeButton(x, y, screen, list_image) 271 screen_list.append(button) 272 return button 273 274 @staticmethod 275 def button_act(x, y, screen, list_image): 276 """按钮生成器""" 277 button = ButtonGame(x, y, screen, list_image) 278 screen_list.append(button) 279 280 @staticmethod 281 def star_act(x, y, screen, filename): 282 """流星雨生成器""" 283 show = Star(x, y, screen, filename) 284 screen_list.append(show) 285 286 @staticmethod 287 def hreo_act(x, y, screen, filename): 288 """生产我方的飞机""" 289 my_plane = Hreo(x, y, screen, filename) 290 screen_list.append(my_plane) 291 return my_plane 292 293 @staticmethod 294 def any_blast(target1, blast_name, btitem=1): 295 """爆炸的公共方法""" 296 if btitem == 1: # 如果选择短爆炸 297 bst = SmallBlast(target1, blast_name) # 创建一个爆炸的对象 298 else: # 长爆炸 299 bst = LongBlast(target1, blast_name) # 创建一个爆炸的对象 300 screen_list.append(bst) # 将爆炸效果添加到显示列表 301 302 @staticmethod 303 def boss_blast(element): 304 """boss飞机爆炸的公共方法""" 305 for i in range(0, 4): 306 ran = random.randint(0, 4) # 随机生成位置 307 bst = LongBlast(element, 'big', -16 + 40*ran, -150 + i*40) 308 screen_list.append(bst) 309 310 @staticmethod 311 def buff_act(ele, prob): 312 """buff生成方法""" 313 ran = random.randint(0, 10) # 有一定概率出现buff 314 if ran < prob: # 调整概率 315 buff = BuffBullet1(ele.x, ele.y, ele.screen, random.choice(st.LIST_BUFF)) 316 screen_list.append(buff) # 添加到显示列表 317 318 @staticmethod 319 def music_act(name): 320 """音乐播放方法""" 321 music1 = MusicThis(name) 322 music1.play_music() 323 del music1 324 325 @staticmethod 326 def enemy_act(x, y, screen, filename): 327 """创建一个敌方飞机的生产线""" 328 if filename == st.ENEMY_3: # 如果生产的是敌方boss飞机 329 enemy = BossEnemy(x, y, screen, filename) 330 else: # 如果是其他的飞机 331 enemy = EnemyPlane(x, y, screen, filename) 332 screen_list.append(enemy) # 添加到显示列表 333 return enemy 334 335 @staticmethod 336 def bullet_act(element): 337 bullets = [] # 子弹初始值为空 338 """生产子弹""" 339 if isinstance(element, Hreo): # 如果发射子弹的是我方 340 if st.GOD_BUFF: # 如果金币buff开关打开 341 bullet = GodBullet(element, 0, 0) 342 bullets.append(bullet) 343 elif st.LASER_BUFF: # 如果是激光子弹开关打开 344 for i in range(-1, 2): # 创建3颗子弹 345 bullet = LaserBullet(element, i*40, 0) 346 bullets.append(bullet) 347 elif st.RAN_BUFF: # 如果是随机运动的子弹 348 for i in range(0, 2): 349 bullet = RanBullet(element, -32 + i*64, 0) 350 bullets.append(bullet) 351 else: # 螺旋子弹 352 bullet = LuoXBullet(element) 353 bullets.append(bullet) 354 355 elif isinstance(element, EnemyPlane): # 若果放射子弹的是敌方 356 if isinstance(element, BossEnemy): # 如果是boss飞机 357 for i in range(-1, 2): # 创建3颗子弹 358 bullet = EneBullet(element, i*32, 0) 359 bullets.append(bullet) 360 else: # 如果是普通飞机 361 bullet = EneBullet(element, 0, 0) 362 bullets.append(bullet) 363 364 else: 365 bullet = EneBullet(element, 0, 0) 366 bullets.append(bullet) 367 if bullets: # 如果不为空 368 bullet_list.extend(bullets) 369 370 371 class Hreo(Obj): 372 """创建一个我方飞机类""" 373 374 def __init__(self, x, y, screen, filename): 375 super().__init__(x, y, screen, filename) 376 self.speed = st.HERO_SPEED # 飞机的速度 377 self.__blood = st.HERO_BLOOD # 设置血量 378 self.button_fire = False # 一个控制开火的开关 379 380 @property 381 def blood(self): 382 """创建血量访问方法""" 383 return self.__blood 384 385 @blood.setter 386 def blood(self, new_blood): 387 """血量设置方法""" 388 self.__blood = new_blood 389 390 def __del__(self): 391 self.button_fire = False # 关闭开火 392 print("hero删除执行了") 393 394 def get_fire(self): # 设置类方法访问和修改类属性 395 return self.button_fire 396 397 def set_fire(self, bools): 398 self.button_fire = bools 399 400 def fire(self): 401 """发射子弹""" 402 Factory.music_act(st.FIRE_MUSIC) # 播放音乐 403 Factory.bullet_act(self) # 调用工厂产生子弹并发射出去 404 405 def hreo_move(self, strx): 406 """飞机移动的方法""" 407 if strx == 'up': # 向上移动 408 self.y -= self.speed 409 elif strx == 'down': # 向下移动 410 self.y += self.speed 411 elif strx == 'left': # 向左移动 412 self.x -= self.speed 413 elif strx == 'right': # 向右移动 414 self.x += self.speed 415 else: 416 pass 417 418 def ishit(self, ele): 419 """飞机的碰撞检测执行函数""" 420 # 忽略所有子弹、背景、爆炸图、本身、文字 421 if isinstance(ele, (Beijing, Blast, Hreo, Bullet, ScriptBase)): 422 # print("这是背景或本身") 423 return False 424 425 result = any_hit(self, ele) # 调用公共方法检测碰撞 426 427 if result: 428 if isinstance(ele, EnemyPlane): # 如果碰到敌方飞机 429 # print("撞上了!") 430 if ele.name == st.ENEMY_1: 431 self.__bloods(ele, 50, "big") 432 elif ele.name == st.ENEMY_2: 433 self.__bloods(ele, 100, "big", btm=2) 434 elif ele.name == st.ENEMY_3: 435 self.blood -= 5 # 自身血量减少 436 ele.blood -= 5 # boss血量减少5 437 438 if isinstance(ele, BuffBullet1): # 如果碰到的是buff 439 bullet_del.append(ele) # buff1消失 440 ele.buff_creat() # 调用方法产生效果 441 442 if isinstance(ele, Stony): # 如果碰到的是陨石 443 self.__bloods(ele, 500, "big", 2) 444 445 def __bloods(self, ele, blood_r, name, btm=1): 446 """检测血量""" 447 self.__blood -= blood_r # 自身血量减少 448 Factory.any_blast(ele, name, btm) # 敌方飞机爆炸并删除 449 bullet_del.append(ele) # 删除敌方飞机 450 451 def draw(self): # 重写父类的方法 452 self.screen.blit(self.image_1, (self.x, self.y)) # 显示我方飞机 453 for ele in screen_list: # 遍历显示列表检测碰撞 454 # print(ele) 455 self.ishit(ele) 456 457 self.serc() # 越界和血量检测 458 459 def serc(self): 460 """血量和越界检测""" 461 if self.__blood <= 0: # 如果血量少于0删除自己 462 Factory.any_blast(self, 'big', 2) # 产生爆炸 463 self.button_fire = False # 关闭开火开关 464 # 创建“你输了”文字 465 Factory.script_act(70, 250, self.screen, "你输了", 100, num=2) 466 bullet_del.append(self) 467 468 # 越界检测 469 if self.x <= 0: 470 self.x = 0 471 elif self.x >= 540: 472 self.x = 540 473 if self.y <= 0: 474 self.y = 0 475 elif self.y >= 600: 476 self.y = 600 477 478 479 class Bullet(Obj): 480 """创建子弹类""" 481 def __init__(self, element): 482 self.screen = element.screen 483 self.ele = element 484 self.name = None 485 self.image_bullet = None 486 self.bullet_speed = None 487 self.__blood = 50 # 设置血量 488 489 def bullet_init(self, x1, y1, speed): 490 """不同子弹初始化参数的函数""" 491 self.x = self.ele.x + x1 492 self.y = self.ele.y + y1 493 self.image_bullet = pygame.image.load_extended(self.name) # 加载背景图片 494 self.rect = self.image_bullet.get_rect() # 获得图片的尺寸 495 self.bullet_speed = speed # 设置子弹的速度 496 497 @property 498 def blood(self): 499 """创建血量访问方法""" 500 return self.__blood 501 502 @blood.setter 503 def blood(self, new_blood): 504 """血量设置方法""" 505 self.__blood = new_blood 506 507 def draw(self): 508 """ 509 修改数字,不要使用计数器来降低子弹的速度,因为计数器作为一个公共变量, 510 不同的子弹数据会造成干扰,导致子弹移动出现问题 511 """ 512 self.screen.blit(self.image_bullet, (self.x, self.y)) # 绘制子弹 513 for ele in screen_list: # 遍历显示列表检测碰撞 514 # print(ele) 515 self.ishit(ele) 516 self.bullet_move() # 子弹的移动 517 518 def bullet_move(self): 519 """子弹移动的函数""" 520 if isinstance(self.ele, Hreo): # 判断是那种飞机的子弹 521 self.y -= self.bullet_speed 522 else: 523 self.y += self.bullet_speed 524 self.bullet_out() # 子弹越界检测 525 526 def bullet_out(self): 527 """判断子弹越界""" 528 if self.y < -30 or self.y > 704: # 判断子弹是否越界 529 bullet_del.append(self) 530 531 def ishit(self, ele): 532 """子弹的碰撞检测函数""" 533 # 忽略掉子弹本身、背景、爆炸、buff子弹 534 if ele is self or isinstance(ele, (Beijing, Blast, BuffBullet1, ScriptBase)): 535 # print("这是背景或本身") 536 return False 537 538 # 若果是我方飞机产生的子弹或流星雨产生的子弹 539 if isinstance(self.ele, (Hreo, Star)): 540 result = any_hit(self, ele) 541 # 忽略本类对象 542 if isinstance(ele, Bullet) and isinstance(ele.ele, (Hreo, Star)): 543 return False 544 else: 545 if result: # 发生了碰撞 546 # print("撞上了") 547 # 如果碰撞到敌方子弹 548 if isinstance(ele, Bullet) and isinstance(ele.ele, EnemyPlane): 549 self.hit_result(ele, "xiao") # 调用效果函数 550 # 如果碰到的是敌方小飞机 551 elif ele.name == st.ENEMY_1 and isinstance(ele, EnemyPlane): 552 self.hit_result(ele) # 调用效果函数 553 # 如果碰到的是敌方大飞机 554 elif ele.name == st.ENEMY_2 and isinstance(ele, EnemyPlane): 555 self.hit_result(ele, "big", 2) 556 # 如果是boss飞机 557 elif ele.name == st.ENEMY_3 and isinstance(ele, EnemyPlane): 558 self.hit_result(ele, 'big', 2) 559 # 如果碰到的是陨石 560 elif isinstance(ele, Stony): 561 self.hit_result(ele, "big", 2) 562 Factory.buff_act(ele, 1) # 每次碰撞爆buff概率为10% 563 564 else: # 如果是敌方飞机产生的子弹 565 result = any_hit(self, ele) 566 if not isinstance(ele, Hreo): # 忽略除了英雄飞机外的所有对象 567 return False 568 else: 569 if result: # 发生了碰撞 570 # print("撞上了") 571 self.hit_result(ele, "big", 2) # 调用效果函数 572 573 def hit_result(self, ele, blast_name="big", btm=1): 574 """碰撞后产生的效果函数""" 575 if self.__blood >= ele.blood: # 如果子弹血量大于对方血量 576 self.__blood -= ele.blood 577 ele.blood = -1 578 else: 579 ele.blood -= self.blood 580 self.__blood = 0 581 bullet_del.append(self) 582 583 if ele.blood > 0: # 若果对方血量还大于0,产生小爆炸 584 Factory.any_blast(ele, 'xiao') # 产生一个小短爆炸效果 585 else: # 如果对方血量小于0,产生大爆炸,同时删除对方飞机 586 if isinstance(ele, BossEnemy): # 如果对方是boss飞机 587 # 创建“你赢了”文字 588 Factory.script_act(70, 250, self.screen, "你赢了", 100, num=2) 589 else: 590 Factory.any_blast(ele, blast_name, btm) 591 bullet_del.append(ele) # 将对方添加到删除列表 592 593 if isinstance(ele, EnemyPlane): # 如果是敌机被打爆,则敌机死亡计数器加1 594 ele.set_enemy_die() 595 596 if not isinstance(ele, Bullet): # 如果对方不是子弹才能产生buff 597 if isinstance(ele, Stony): # 对方陨石爆炸 598 Factory.buff_act(ele, 5) # 爆buff概率为30% 599 else: # 其他的爆炸 600 Factory.buff_act(ele, 3) # 爆buff概率为20% 601 602 603 class RanBullet(Bullet): 604 """创建随机跳弹""" 605 def __init__(self, element, x1, y1): 606 super().__init__(element) 607 self.name = st.RAN_BULLET # 得到子弹的图片作为名字 608 self.__blood = 50 # 设置血量 609 self.fps = 0 # 子弹移动换方向的时间 610 self.ran = 0 # 子弹左右的方向 611 if isinstance(self.ele, Hreo): # 我方飞机 612 self.bullet_init(48 + x1, -64 + y1, st.BULLET_SPEED+2) 613 614 def bullet_move(self): 615 """重写子弹移动的函数""" 616 if isinstance(self.ele, Hreo): # 判断是那种飞机的子弹 617 self.y -= self.bullet_speed # 向上运动 618 self.fps += 1 619 if self.fps % 10 == 0: # 每10帧数改变方向 620 self.ran = random.randint(0, 1) 621 if self.ran == 0: 622 self.x -= self.bullet_speed - 5 623 else: 624 self.x += self.bullet_speed - 5 625 626 self.bullet_out() # 子弹越界检测 627 628 629 class GodBullet(Bullet): 630 """创建一个金币子弹类""" 631 def __init__(self, element, x1, y1): 632 super().__init__(element) 633 self.name = st.GOD_BULLET # 得到子弹的图片作为名字 634 self.__blood = 200 # 设置血量 635 if isinstance(self.ele, Hreo): # 我方飞机 636 self.bullet_init(25 + x1, -30 + y1, st.BULLET_SPEED+2) 637 638 639 class LaserBullet(Bullet): 640 """创建激光子弹""" 641 def __init__(self, element, x1, y1): 642 super().__init__(element) 643 self.name = st.LASER_BULLET # 得到子弹的图片作为名字 644 self.__blood = 100 # 设置血量 645 if isinstance(self.ele, Hreo): # 我方飞机 646 self.bullet_init(40 + x1, -90 + y1, st.BULLET_SPEED) 647 648 649 class LuoXBullet(Bullet): 650 """创建螺旋子弹""" 651 def __init__(self, element): 652 super().__init__(element) 653 self.name = st.LUOXUAN_BULLET # 得到子弹的图片作为名字 654 self.__blood = 50 # 设置血量 655 if isinstance(self.ele, Hreo): # 我方飞机 656 self.bullet_init(42, -20, st.BULLET_SPEED) 657 658 659 class EneBullet(Bullet): 660 """创建普通子弹""" 661 def __init__(self, element, x1, y1): 662 super().__init__(element) 663 self.name = st.MY_BULLET # 得到子弹的图片作为名字 664 self.__blood = 50 # 设置血量 665 666 if isinstance(self.ele, EnemyPlane): # 如果是敌机 667 if self.ele.name == st.ENEMY_1: # 敌方小飞机 668 self.bullet_init(16 + x1, 32 + y1, st.BULLET_SPEED - 3) 669 elif self.ele.name == st.ENEMY_2: # 敌方中型飞机 670 self.bullet_init(24 + x1, 64 + y1, st.BULLET_SPEED - 3) 671 elif self.ele.name == st.ENEMY_3: # 敌方boss飞机 672 self.bullet_init(72 + x1, 220 + y1, st.BULLET_SPEED) 673 674 if isinstance(self.ele, Star): # 如果是流星雨 675 self.bullet_init(x1, y1, st.BULLET_SPEED) 676 677 678 class Star(Obj): 679 """一个下流星雨的类""" 680 __button1 = None # 创建控制单例模式开关 681 __button2 = True 682 683 def __init__(self, x, y, screen, filename): 684 if self.__button2: 685 super().__init__(x, y, screen, filename) 686 self.fps = 0 # 创建时间计数 687 self.num_shower = 0 # 创建流星雨下的次数计数 688 # self.button_star = False # 下雨的开关 689 self.__button2 = False # 保证只有一次初始化 690 691 def __new__(cls, *args, **kwargs): 692 if not cls.__button1: 693 cls.__button1 = Obj.__new__(cls) 694 return cls.__button1 695 696 def draw(self): 697 if st.SHOWER_BUFF: 698 self.fps += 1 699 if self.fps % 60 == 0: 700 self.num_shower += 1 701 for i in range(10): 702 bullet_new = EneBullet(self, i * 64, -32) 703 screen_list.append(bullet_new) # 添加到显示列表 704 # 五次后关闭流星雨 705 if self.num_shower > 3: 706 self.fps = 0 707 self.num_shower = 0 708 st.SHOWER_BUFF = False 709 710 711 class Blast(Obj): 712 """创建一个爆炸效果类""" 713 def __init__(self, ele, name): 714 self.num1 = 0 715 self.screen = ele.screen 716 self.name = name 717 self.image_blast = [] 718 719 # 如果是敌机的子弹爆炸 720 if isinstance(ele, Bullet) and not isinstance(ele.ele, Hreo): 721 self.x = ele.x - 56 722 self.y = ele.y - 32 723 # 如果是敌方的小飞机爆炸 724 elif ele.name == st.ENEMY_1 and isinstance(ele, EnemyPlane): 725 self.x = ele.x - 40 726 self.y = ele.y - 40 727 # 如果是敌方的中型飞机爆炸 728 elif ele.name == st.ENEMY_2 and isinstance(ele, EnemyPlane): 729 self.x = ele.x - 32 730 self.y = ele.y - 32 731 # 如果是敌方的boss飞机爆炸 732 elif ele.name == st.ENEMY_3 and isinstance(ele, BossEnemy): 733 self.x = ele.x + 16 734 self.y = ele.y + 150 735 # 如果是我方飞机爆炸 736 elif ele.name == st.HREO_1 and isinstance(ele, Hreo): 737 self.x = ele.x - 14 738 self.y = ele.y 739 # 如果是文字 740 elif isinstance(ele, ScriptBase): 741 self.x = ele.x 742 self.y = ele.y 743 else: 744 self.x = ele.x - 32 745 self.y = ele.y - 32 746 747 Factory.music_act(st.BLAST_MUSIC) # 播放音乐 748 749 def draw(self): 750 pass 751 752 def numx(self, n): 753 """改变爆炸的大小""" 754 if self.num1 > n: 755 self.num1 = 0 756 bullet_del.append(self) # 爆炸完成后删除本身 757 758 759 class SmallBlast(Blast): 760 """创建短爆炸""" 761 762 def __init__(self, ele, name): 763 super().__init__(ele, name) 764 for image in st.LIST_BLAST: # 加载爆炸图片资源 765 self.image_blast.append(pygame.image.load_extended(image)) 766 767 def draw(self): # 重写爆炸绘制方法 768 self.screen.blit(self.image_blast[self.num1], (self.x, self.y)) 769 self.num1 += 1 770 if self.name == "xiao": 771 self.numx(3) 772 elif self.name == "big": 773 self.numx(7) 774 775 776 class LongBlast(Blast): 777 """创建长爆炸""" 778 def __init__(self, ele, name, x=0, y=0): 779 super().__init__(ele, name) 780 self.x += x 781 self.y += y 782 for image in st.LIST_BLAST_BIG: # 加载爆炸图片资源 783 self.image_blast.append(pygame.image.load_extended(image)) 784 785 def draw(self): 786 """绘制长爆炸""" 787 self.screen.blit(self.image_blast[self.num1], (self.x, self.y)) 788 self.num1 += 1 789 if self.name == 'xiao': 790 self.numx(7) 791 elif self.name == 'big': 792 self.numx(13) 793 794 795 class EnemyPlane(Obj): 796 """创建一个敌方的飞机类1""" 797 __enemy_die = 0 # 创建一个类属性记录杀死的敌机数量 798 799 @classmethod 800 def get_enemy_die(cls): # 访问类属性方法 801 return cls.__enemy_die 802 803 @classmethod 804 def set_enemy_die(cls, num=False): # 设置类属性方法 805 if num: 806 cls.__enemy_die = 0 # 重新设置为0 807 else: 808 cls.__enemy_die += 1 809 810 def __init__(self, x, y, screen, filename): 811 super().__init__(x, y, screen, filename) 812 self.button_fire = True # 设置一个是否可以开火的开关 813 self.derc = None # 初始方向为向右 814 self.time2 = time.time() # 时间变量 815 if self.name == st.ENEMY_1: # 如果是敌方小飞机 816 self.__blood = st.Small_Blood 817 self.enemy_speed1 = st.ENEMY_DOWN_SPEED # 小飞机设置成快速 818 elif self.name == st.ENEMY_2: 819 self.__blood = st.Middle_Blood 820 self.enemy_speed1 = st.ENEMY_DOWN_SPEED1 # 中型飞机设置成中速 821 elif self.name == st.ENEMY_3: 822 self.__blood = st.Boss_Blood 823 self.enemy_speed1 = st.ENEMY_DOWN_SPEED # boss飞机设置成慢速 824 825 @property 826 def blood(self): 827 """创建血量访问方法""" 828 return self.__blood 829 830 @blood.setter 831 def blood(self, new_blood): 832 """血量设置方法""" 833 self.__blood = new_blood 834 835 def __del__(self): 836 self.button_fire = False # 关闭开火的开关 837 # print("敌机删除执行!") 838 839 def enemy_shoot(self): # 敌机发射子弹的方法 840 ran = random.randint(0, 100) # 敌机随机发射子弹 841 if ran == 80: 842 Factory.bullet_act(self) # 调用工厂生产和装填子弹 843 844 def draw(self): 845 # 绘制敌机 846 self.screen.blit(self.image_1, (self.x, self.y)) 847 self.enemy_move() # 敌机移动 848 if self.button_fire: # 如果开火的开关是打开的 849 self.enemy_shoot() # 敌机发射子弹 850 if self.__blood <= 0: # 小于0删除自身 851 bullet_del.append(self) 852 853 def enemy_move(self): # 使得敌方飞机移动 854 """敌机移动的方法""" 855 time1 = time.time() # 敌机每隔1.5秒改变方向 856 # print(timex) 857 # print(time1 - timex) 858 if time1 - self.time2 > 1.5: 859 self.time2 = time1 860 self.derc = random.randint(0, 3) # 获取敌机移动的方向 861 862 self.y += self.enemy_speed1 # 使得敌机保持向下,左右随机移动 863 if self.derc == 0: 864 self.x += st.ENEMY_LR_SPEED 865 elif self.derc == 1: 866 self.x -= st.ENEMY_LR_SPEED 867 self.out_screen() # 防止敌机左右出界 868 self.go_screen() # 防止敌机下出界 869 870 def out_screen(self): 871 """防止敌机左右出界""" 872 if self.x <= 0: 873 self.x = 0 874 elif self.name == st.ENEMY_1 and self.x >= 592: # 小飞机 875 self.x = 592 876 elif self.name == st.ENEMY_2 and self.x >= 576: # 中飞机 877 self.x = 576 878 elif self.name == st.ENEMY_3 and self.x >= 480: # boss飞机 879 self.x = 480 880 881 def go_screen(self): 882 """敌机下出界删除""" 883 if self.y > 710: 884 bullet_del.append(self) 885 886 887 class BossEnemy(EnemyPlane): 888 """创建敌方boss飞机类""" 889 890 def __init__(self, x, y, screen, filename): 891 super().__init__(x, y, screen, filename) 892 self.time3 = time.time() # 用来记录换方向的初始时间 893 self.button_fire = False # 开火的开关初始状态设为关闭 894 895 def enemy_shoot(self): 896 """重写父类发射子弹的方法""" 897 ran = random.randint(0, 100) # 敌机随机发射子弹 898 if ran <= 10: # 10%的时间发射子弹 899 Factory.bullet_act(self) # 调用工厂生产和装填子弹 900 901 def enemy_move(self): 902 """boss移动""" 903 time1 = time.time() # 记录boss移动的时间 904 time3 = time.time() # boss左右换方向的时间 905 # print(timex) 906 # print(time1 - timex) 907 if time1 - self.time2 < 6: # 如果小于六秒就一直向下移动 908 self.y += self.enemy_speed1 909 else: # 大于6秒开始左右移动 910 self.button_fire = True # 打开开火的开关 911 if time3 - self.time3 >= 2: 912 self.time3 = time3 913 while True: 914 derc = random.randint(0, 6) # 获取敌机移动的方向 915 if self.derc != derc: 916 self.derc = derc 917 break 918 919 if self.derc == 0: # 向右边移动 920 self.x += st.ENEMY_LR_SPEED + 3 921 elif self.derc == 1: # 向左移动 922 self.x -= st.ENEMY_LR_SPEED + 3 923 elif self.derc == 2: # 向右弧形移动 924 self.x += st.ENEMY_LR_SPEED + 3 925 self.y += st.ENEMY_LR_SPEED + 3 926 elif self.derc == 3: # 向右边移动 927 self.x += st.ENEMY_LR_SPEED + 3 928 self.y -= st.ENEMY_LR_SPEED + 3 929 elif self.derc == 4: # 向左边移动 930 self.x -= st.ENEMY_LR_SPEED + 3 931 self.y += st.ENEMY_LR_SPEED + 3 932 elif self.derc == 5: # 向左上移动 933 self.x -= st.ENEMY_LR_SPEED + 3 934 self.y -= st.ENEMY_LR_SPEED + 3 935 self.go_screen1() # 防止上出界 936 self.out_screen() # 防止敌机左右出界 937 self.go_screen() # 防止敌机下出界 938 939 def go_screen1(self): 940 """防止敌机上出界""" 941 if self.y <= 0: 942 self.y = 0 943 944 def go_screen(self): 945 """防止敌机下出界""" 946 if self.y >= 448: 947 self.y = 448 948 949 def draw(self): 950 super().draw() 951 if self.blood <= 0: 952 Factory.boss_blast(self) # 创建超极爆炸 953 bullet_del.append(self) 954 955 956 class MusicThis(object): 957 """创建一个音乐类管理音乐""" 958 def __init__(self, filename, count=0): 959 self.filename = filename 960 self.count = count 961 962 def play_music(self): 963 """播放音乐""" 964 pygame.mixer_music.load(self.filename) # 添加音乐 965 pygame.mixer_music.play(self.count) # 播放音乐 966 967 968 class BuffBullet1(Obj): 969 """创建一个子弹外挂管理的类""" 970 def __init__(self, x, y, screen, filename): 971 super().__init__(x, y, screen, filename) 972 self.time = 0 # 设置一个计时器 973 974 def buff_creat(self): 975 """buff的开关控制""" 976 if self.name == st.BUFF_1: # 如果是流星雨buff 977 st.SHOWER_BUFF = True # 打开开关,在主函数中显示 978 Factory.star_act(0, 0, self.screen, st.MY_BULLET) 979 980 elif self.name == st.BUFF_2: # 如果是金币子弹buff 981 self.buff_control(n2=True) 982 st.BUFF_TIME = 0 # 将金币buff时间计数器设为0 983 984 elif self.name == st.BUFF_3: # 如果是激光子弹buff 985 self.buff_control(n3=True) 986 st.LASER_TIME = 0 # 将buff时间计数器设为0 987 988 elif self.name == st.BUFF_4: # 如果是随机弹 989 # 随机弹开关打开,其他的关闭 990 BuffBullet1.buff_control(n1=True) 991 st.RAN_TIME = 0 # 将时间计数器设为0 992 993 @staticmethod 994 def buff_control(n1=False, n2=False, n3=False): 995 """创建管理子弹buff开关打开的函数""" 996 st.RAN_BUFF = n1 # 随机弹开关 997 st.GOD_BUFF = n2 # 金币子弹buff开关 998 st.LASER_BUFF = n3 # 激光子弹buff开关 999 1000 def draw(self): 1001 # 循环显示背景图 1002 self.screen.blit(self.image_1, (self.x, self.y)) 1003 self.y += st.BUFF_SPEED # buff移动 1004 self.time += 1 1005 if self.time > 400: # buff超过6秒后自动删除 1006 bullet_del.append(self) 1007 self.time = 0 1008 if self.y < -30 or self.y > 704: # 判断buff是否越界 1009 bullet_del.append(self) 1010 1011 1012 class Stony(Obj): 1013 """创建一个陨石类""" 1014 def __init__(self, x, y, screen, filename): 1015 """定义构造属性""" 1016 super().__init__(x, y, screen, filename) 1017 self.drec = random.randint(0, 1) # 创建一个移动的左右随机方向 1018 self.__blood = 500 # 设置血量 1019 1020 @property 1021 def blood(self): 1022 """创建血量访问方法""" 1023 return self.__blood 1024 1025 @blood.setter 1026 def blood(self, new_blood): 1027 """血量设置方法""" 1028 self.__blood = new_blood 1029 1030 def draw(self): 1031 # 循环显示背景图 1032 self.screen.blit(self.image_1, (self.x, self.y)) 1033 if self.__blood <= 0: # 血量小于0 1034 bullet_del.append(self) 1035 self.y += st.STONY_SPEED # 移动 1036 if self.drec == 0: 1037 self.x += st.STONY_SPEED - 4.2 1038 else: 1039 self.x -= st.STONY_SPEED - 4.2 1040 # 判断是否越界 1041 if self.y < -150 or self.y > 750 or self.x < -100 or self.x > 640: 1042 bullet_del.append(self)
tool.py提供一些公共使用的工具方法
1 # coding=utf-8 2 import time 3 4 def any_hit(target, element): 5 """"检测两个物体发生碰撞函数""" 6 # 定义四个开关 7 button1 = False 8 button2 = False 9 button3 = False 10 button4 = False 11 # 获取传入的类的尺寸 12 ele_rect = element.rect 13 x1 = element.x 14 y1 = element.y 15 w1 = ele_rect.w 16 h1 = ele_rect.h 17 18 # 碰撞判断 19 if x1 < target.x + target.rect.w < x1 + w1 or x1 < target.x < x1 + w1: 20 button1 = True 21 if y1 < target.y < y1 + h1 or y1 < target.y + target.rect.h < y1 + h1: 22 button2 = True 23 if target.x < x1 + w1 < target.x + target.rect.w or target.x < x1 < target.x + target.rect.w: 24 button3 = True 25 if target.y < y1 < target.y + target.rect.h or target.y < y1 + h1 < target.y + target.rect.h: 26 button4 = True 27 if (button1 and button2) or (button3 and button4): 28 return True 29 else: 30 return False 31 32 33 def delays(delay, time0=time.time()): 34 class MyDelay(object): 35 """创建一个带参数的类装饰器,用来对函数进行延时执行,每过 36 delay时间执行一次 37 """ 38 39 def __init__(self, fun): 40 self.sec = delay 41 self.time = time0 42 self.__fun = fun 43 44 def __call__(self, *args, **kwargs): 45 time1 = time.time() 46 if time1 - self.time >= self.sec: 47 self.__fun(*args, **kwargs) 48 self.time = time1 49 50 return MyDelay 51 52 53 def delay_fps(fps, fps0=0): 54 class FpsDelay(object): 55 """创建一个根据固定帧数延时执行的类装饰器,每过fps帧数执行一次""" 56 57 def __init__(self, fun): 58 self.fps = fps 59 self.fps0 = fps0 60 self.__fun = fun 61 62 def __call__(self, *args, **kwargs): 63 self.fps0 += 1 64 # print(self.fps0) 65 if self.fps0 % self.fps == 0: 66 self.__fun(*args, **kwargs) 67 68 return FpsDelay 69 70 71 def delay_run(fps, fps0=0): 72 """创建一个帧数 延时执行的装饰器""" 73 74 def delay(func): 75 def new_run(*args, **kwargs): 76 nonlocal fps0 77 fps0 += 1 78 if fps0 % fps == 0: 79 res = func(*args, **kwargs) 80 return res 81 82 return new_run 83 84 return delay 85 86 87 def delay_time(time1, time0=time.time()): 88 """创建一个延时间的装饰器""" 89 90 def delay(func): 91 def new_run(*args, **kwargs): 92 nonlocal time0 93 time2 = time.time() 94 if time2 - time0 >= time1: 95 time0 = time2 96 res = func(*args, **kwargs) 97 return res 98 99 return new_run 100 101 return delay 102 103 104 def print_say(): 105 __a = 0 106 print(locals()) 107 108 109 if __name__ == "__main__": 110 class Person(object): 111 def __init__(self, name, age, taste): 112 self.name = name 113 self._age = age 114 self.__taste = taste 115 print(locals()) 116 print(dir(Person))
setting.py创建存储所有游戏资源的模块
1 # 设置屏幕 2 SCREEN_WIDTH = 768 # 屏幕的宽度 3 SCREEN_HIGHT = 704 # 屏幕的高度 4 5 # 设置背景 6 BEIJING_SPEED = 3 # 设置背景移动速度 7 8 # 设置游戏前言界面字体显示参数 9 FRAMES = 40 # 每隔frames帧数显示一个字 10 WIN_OVER_FRAMES = 200 # 多少帧数后界面切换 11 12 # 设置游戏背景诉说界面的参数 13 WIN_FONT_FRAMES = 500 # 多少帧数后界面结束 14 15 # 我方飞机的参数 16 HERO_SPEED = 10 # 设置我方飞机移动的速度 17 HERO_BLOOD = 2000 # 我方血量 18 19 # 我方子弹的参数 20 BULLET_SPEED = 10 # 设置我方子弹的速度 21 22 # 设置敌机的血量 23 Small_Blood = 100 # 小敌机 24 Middle_Blood = 200 # 中型飞机 25 Big_Blood = 500 # 大型 26 Boss_Blood = 3000 # 敌方boss 27 28 # 敌机的数目 29 ENEMY_NUM = 50 # 普通飞机的上限 30 BOSS_NUM = 1 # boss飞机的上限 31 32 '''流星雨的速度''' 33 SHOWER_SPEED = 20 34 '''设置小敌机的速度''' 35 ENEMY_DOWN_SPEED = 1 36 ENEMY_LR_SPEED = 1 37 '''设置中型敌机的速度''' 38 ENEMY_DOWN_SPEED1 = 0.8 39 ENEMY_LR_SPEED1 = 1 40 '''设置大敌机的速度''' 41 ENEMY_DOWN_SPEED2 = 0.5 42 ENEMY_LR_SPEED2 = 0.5 43 """设置子弹的大小""" 44 BULLET_BIG = 16 45 46 47 """敌方飞机产生速度调节器""" 48 ENEMY_CREATE1 = 80 49 ENEMY_CREATE2 = 40 50 """游戏buff的移动速度""" 51 BUFF_SPEED = 5 52 """陨石移动速度""" 53 STONY_SPEED = 5 54 55 56 """金币buff的时间计数器""" 57 BUFF_TIME = 0 58 """激光buff时间计数器""" 59 LASER_TIME = 0 60 """随机子弹buff时间""" 61 RAN_TIME = 0 62 63 64 """文字字体文件""" 65 SCRIPT = './rec/font_file/songti.TTF' 66 SCRIPT1 = './rec/font_file/jingdian.TTF' 67 SCRIPT2 = './rec/font_file/kong.TTF' 68 69 # 图片资源 70 """背景图片""" 71 BEIJING_1 = 'rec/images/beijing_3.jpg' 72 """积分界面背景图片""" 73 IMAGE_BJ = 'rec/images/image_bj2.jpg' 74 '''开始界面图片''' 75 BEIJING_2 = 'rec/images/kong.jpg' 76 '''我方飞机''' 77 HREO_1 = 'rec/images/hero1.png' 78 '''我方普通子弹''' 79 MY_BULLET = 'rec/images/shot_bottom.gif' 80 """buff子弹螺旋弹""" 81 LUOXUAN_BULLET = 'rec/images/bullets.png' 82 """buff金币弹""" 83 GOD_BULLET = 'rec/images/moneybullet.png' 84 """buff激光子弹""" 85 LASER_BULLET = 'rec/images/buffbullet2.png' 86 """随机运动子弹""" 87 RAN_BULLET = 'rec/images/bzx.png' 88 '''敌方飞机1''' 89 ENEMY_1 = 'rec/images/enemy_1.gif' 90 ''''敌方飞机2''' 91 ENEMY_2 = 'rec/images/enemy_2.png' 92 '''敌方飞机3''' 93 ENEMY_3 = 'rec/images/enemy_3.gif' 94 """陨石图片""" 95 STONY_BUFF = 'rec/images/buff3.png' 96 """标准模式按钮""" 97 BUTTON_1 = 'rec/images/moshi_2.PNG' 98 BUTTON_2 = 'rec/images/moshi2.PNG' 99 BUTTON_A = [BUTTON_2, BUTTON_1] 100 """困难模式按钮""" 101 BUTTON_3 = 'rec/images/moshi1.PNG' 102 BUTTON_4 = 'rec/images/moshi_1.PNG' 103 BUTTON_B = [BUTTON_4, BUTTON_3] 104 """飞机大战名字""" 105 PLANE_NAME = 'rec/images/name.png' 106 """退出按钮""" 107 BUTTON_5 = 'rec/images/goout1.png' 108 BUTTON_6 = 'rec/images/goout2.png' 109 BUTTON_C = [BUTTON_5, BUTTON_6] 110 """结束界面退出游戏按钮""" 111 BUTTON_7 = 'rec/images/outgame3.png' 112 BUTTON_8 = 'rec/images/outgame4.png' 113 BUTTON_D = [BUTTON_7, BUTTON_8] 114 """结束界面重新开始按钮""" 115 BUTTON_9 = 'rec/images/restart3.png' 116 BUTTON_10 = 'rec/images/restart4.png' 117 BUTTON_E = [BUTTON_9, BUTTON_10] 118 """游戏下一关按钮""" 119 BUTTON_11 = 'rec/images/next3.png' 120 BUTTON_12 = 'rec/images/next4.png' 121 BUTTON_F = [BUTTON_11, BUTTON_12] 122 """游戏操作说明""" 123 FUNCTION_1 = 'rec/images/func.png' 124 """游戏buff图片""" 125 BUFF_1 = 'rec/images/buff1.png' 126 BUFF_2 = 'rec/images/moneybuff.png' 127 BUFF_3 = 'rec/images/bulletn.png' 128 BUFF_4 = 'rec/images/buff_random.png' 129 130 """游戏进入界面的前言""" 131 MY_READ = 'rec/images/mylaung1.png' 132 MY_XING = 'rec/images/xing1.jpg' 133 MY_SELF = 'rec/images/me.png' 134 MY_TEXT = 'rec/images/bg.png' 135 """创建一个BUFF列表""" 136 LIST_BUFF = [BUFF_1, BUFF_2, BUFF_3, BUFF_4] 137 """游戏开始按钮""" 138 BUTTON_START1 = 'rec/images/start.png' 139 BUTTON_START2 = 'rec/images/start1.png' 140 BUTTON_START3 = 'rec/images/start2.png' 141 BUTTON_START4 = 'rec/images/start3.png' 142 """一个开始的按钮列表""" 143 BUTTON_START = [BUTTON_START1, 144 BUTTON_START2, 145 BUTTON_START3, 146 BUTTON_START4] 147 """爆炸效果图1""" 148 LIST_BLAST = ['rec/images/blast_1.gif', 149 'rec/images/blast_2.gif', 150 'rec/images/blast_3.gif', 151 'rec/images/blast_4.gif', 152 'rec/images/blast_5.gif', 153 'rec/images/blast_6.gif', 154 'rec/images/blast_7.gif', 155 'rec/images/blast_8.gif' ] 156 """超大爆炸效果图""" 157 LIST_BLAST_BIG = ['rec/images/bz0.png', 158 'rec/images/bz1.png', 159 'rec/images/bz2.png', 160 'rec/images/bz3.png', 161 'rec/images/bz4.png', 162 'rec/images/bz5.png', 163 'rec/images/bz6.png', 164 'rec/images/bz7.png', 165 'rec/images/bz8.png', 166 'rec/images/bz9.png', 167 'rec/images/bz10.png', 168 'rec/images/bz11.png', 169 'rec/images/bz12.png', 170 'rec/images/bz13.png', 171 'rec/images/bz14.png'] 172 173 """男生角色图片""" 174 BOY_IMAGE = ['rec/images/boy0.jpg', 175 'rec/images/boy1.jpg', 176 'rec/images/boy2.jpg', 177 'rec/images/boy3.jpg', 178 'rec/images/boy4.jpg' 179 ] 180 """女生角色图片""" 181 GIRL_IMAGE = ['rec/images/girl0.jpg', 182 'rec/images/girl1.jpg', 183 'rec/images/girl2.jpg', 184 'rec/images/girl3.jpg', 185 'rec/images/girl4.jpg' 186 ] 187 188 189 '''音乐资源''' 190 FIRE_MUSIC = 'rec/music/fire.wav' 191 """爆炸音乐""" 192 BLAST_MUSIC = 'rec/music/blast.mp3' 193 """游戏开始音乐""" 194 START_MUSIC = 'rec/music/chao.mp3' 195 196 # 开关资源 197 """上按键开关""" 198 KEY_UP = False 199 """下按键开关""" 200 KEY_DOWN = False 201 """左按键开关""" 202 KEY_LEFT = False 203 """右按键开关""" 204 KEY_RIGHT = False 205 """游戏模式切换开关""" 206 GAME_MOSHI = True 207 """创建按钮颜色变化开关""" 208 BUTTON_COLOR = True 209 210 """流星雨buff的打开开关""" 211 SHOWER_BUFF = False 212 """金币子弹buff的开关""" 213 GOD_BUFF = False 214 """激光子弹buff开关""" 215 LASER_BUFF = False 216 """随机弹控制开关""" 217 RAN_BUFF = False 218 219 """boss出现的开关""" 220 BOSS_CREAT = False 221 """boss是否全部死亡""" 222 BOSS_DIE = False 223 "敌机是否可以生产开关" 224 ENEMY_START = False 225 """敌方生成器的开关""" 226 ENEMY_MAKE = True 227 228 229 '''登陆界面开关''' 230 SCREEN_CHANGE = False 231 """游戏进入前的界面控制开关""" 232 GAME_BEFORE = False 233 """游戏历史背景开关""" 234 GAME_SAY = False 235 """战斗界面控制开关""" 236 GAME_FIGHT = False 237 """游戏结束界面控制开关""" 238 GAME_END = False
_init_.py
- _init_.py 文件的作用是将文件夹变为一个Python模块,Python 中的每个模块的包中,都有_init_.py文件。
- 通常_init_.py文件为空,但是我们还可以为它增加其他的功能。我们在导入一个包时,实际上是导入了它的_init_.py文件。
__all__ = ["game_windows", "setting", "tool", "resource_game"]
main.py 游戏启动模块
# coding:utf-8 from game_file.game_windows import main if __name__ == '__main__': main()
源码及文件下载:
链接:https://pan.baidu.com/s/1f26Au3GMHO18OBYP1yMVpw
提取码:bi10
食用指南:进入the_war_of_sky目录,终端输入:python main.py