碰撞检测后,飞机没有播放碰撞动画

来源:3-9 飞机大战项目飞机碰撞及爆炸效果

慕移动4586040

2020-05-14 21:54:03

##plane类

import random

import pygame


import constants

from game.bullet import Bullet


class Plane(pygame.sprite.Sprite):
   """飞机的基础类"""
   #飞机图片
   plane_images = []

   #飞机爆炸的图片
   destroy_images = []
   #坠毁的音乐地址
   down_sound_src = None
   #飞机的状态 true表示活着,false表示毁灭
   active = True
   #该飞机发射的子弹精灵组
   bullets = pygame.sprite.Group()



   def __init__(self, screen, speed=None):
       #调用父类
       super().__init__()
       self.screen = screen
       #加载静态资源
       self.img_list = []
       self._destroy_img_list = []
       self.down_sound = None
       self.load_src()

       #飞行的速度
       self.speed = speed or 10
       #获取飞机的位置
       self.rect = self.img_list[0].get_rect()
       #游戏窗口的宽高
       self.width, self.height = self.screen.get_size()
       #飞机本身的宽高
       self.plane_w, self.plane_h = self.img_list[0].get_size()
       # 改变飞机的初始化位置,放在屏幕下方
       self.rect.left = int((self.width - self.plane_w)/2)
       self.rect.top = int(self.height/2)

   def load_src(self):
       """加载静态资源"""
       #飞机图像
       for img in self.plane_images:
           self.img_list.append(pygame.image.load(img))

       #飞机坠毁的图像
       for img in self.destroy_images:
           self._destroy_img_list.append(pygame.image.load(img))
       #坠毁的音乐
       if self.down_sound_src:
           # self.down_sound = pygame.mixer.Sound(self.down_sound_src)
           self.down_sound = pygame.mixer.Sound(self.down_sound_src)

   @property
   def image(self):
       return self.img_list[0]

   def blit_me(self):
       self.screen.blit(self.image, self.rect)

   def move_up(self):
       """
       飞机向上移动
       :return:
       """
       self.rect.top -= self.speed

   def move_down(self):
       """飞机向下移动"""
       self.rect.top += self.speed

   def move_left(self):
       """飞机向下移动"""
       self.rect.left -= self.speed

   def move_right(self):
       """飞机向下移动"""
       self.rect.left += self.speed

   def broken_down(self):
       """飞机坠毁效果"""
       #1.播放坠毁音乐
       if self.down_sound:
           self.down_sound.play()
       #2.播放坠毁动画
       for img in self._destroy_img_list:
           self.screen.blit(img, self.rect)
       #3.坠毁后
       self.active = False

   def shoot(self):
       """飞机发射子弹"""
       bullet = Bullet(self, self.screen,  15)
       self.bullets.add(bullet)
       pass


class OurPlane(Plane):
   """我方的飞机"""
   #飞机图片
   plane_images = constants.OUR_PLANE_IMG_LIST
   destroy_images = []
   #坠毁的音乐地址
   down_sound_src = None

   def update(self, war):
       """更新飞机的动画效果"""
       #1.切换飞机动画效果
       if war.frame % 5:
           self.screen.blit(self.img_list[0], self.rect)
       else:
           self.screen.blit(self.img_list[1], self.rect)
       #2.碰撞检测
       rest = pygame.sprite.spritecollide(self, war.enemies, False)
       if rest:
           #1.游戏结束
           war.status = war.OVER
           #2.敌方所有飞机清除
           war.enemies.empty()
           war.small_enemies.empty()
           #3.我方飞机坠毁效果
           self.broken_down()
           #4.游戏成绩统计


   def move_up(self):
       """向上移动,超出范围之后,拉回来"""
       super().move_up()
       if self.rect.top <= 0:
           self.rect.top = 0

   def move_down(self):
       super().move_down()
       if self.rect.bottom >= self.height - self.plane_h:
           self.rect.bottom = self.height - self.plane_h

   def move_left(self):
       super().move_left()
       if self.rect.left <= 0:
           self.rect.left = 0

   def move_right(self):
       super().move_right()
       if self.rect.left >= self.width - self.plane_w:
           self.rect.left = self.width - self.plane_w



class SmallEnemyPlane(Plane):
   """敌方小型飞机类"""
   #飞机图片
   plane_images = constants.SMALL_ENEMY_PLANE_IMG_LIST
   #飞机爆炸的图片
   destroy_images = constants.SMALL_ENEMY_DESTROY_IMG_LIST
   #坠毁的音乐地址
   down_sound_src = (constants.SMALL_ENEMY_DOWN_SOUND)
   
   def __init__(self, screen, speed):
       super().__init__(screen, speed)
       #改变生成小型飞机时,要随机出现在屏幕中
       #改变随机位置
       self.init_pos()

   def init_pos(self):
       """初始化飞机位置"""
       # 屏幕宽度-飞机宽度
       self.rect.left = random.randint(0, self.width - self.rect.width)
       # 屏幕之外随机高度
       self.rect.top = random.randint(-5 * self.plane_h, -self.plane_h)



   def update(self, *args):
       """更新飞机的移动"""
       super().move_down()

       #绘制在p屏幕上
       self.blit_me()

       #超出范围
       #1.重用
       if self.rect.top >= self.height:
           # self.kill()
           self.reset()
       #todo 2.多线程、多进程

   def reset(self):
       """重置飞机状态,达到复用效果"""
       self.active = True
       #重置飞机
       self.init_pos()
       
   def broken_down(self):
       """重写父类爆炸效果"""
       super().broken_down()
       self.reset()



###war类

import pygame
import sys

import constants
from game.plane import OurPlane, SmallEnemyPlane


class PlaneWar(object):
   READY = 0 #游戏准备中
   PLAY = 1 #正在游戏中
   OVER = 2 #游戏结束

   #游戏状态
   status =  READY  #准备中 1游戏中 2游戏结束

   #实例化我方飞机
   our_plane = None
   #播放帧数
   frame = 0
   #一架飞机可以属于多个精灵组
   small_enemies = pygame.sprite.Group()
   enemies = pygame.sprite.Group()

   def __init__(self):
       #初始化方法
       pygame.init()
       self.width, self.height = 480, 852
       # 屏幕对象
       self.screen = pygame.display.set_mode((self.width, self.height))
       # 设置窗口标题
       pygame.display.set_caption('飞机大战')
       # 加载背景图片
       self.bg = pygame.image.load(constants.BG_IMG)

       # 游戏标题图片
       self.img_game_title = pygame.image.load(constants.IMG_GAME_TITLE)
       self.img_game_title_rect = self.img_game_title.get_rect()
       # 游戏标题图片宽高
       t_width, t_height = self.img_game_title.get_size()
       self.img_game_title_rect.topleft = (int((self.width - t_width) / 2),
                                      int(self.height / 2 - t_height))

       # 开始按钮图片
       self.btn_start = pygame.image.load(constants.IMG_GAME_START_BTN)
       self.btn_start_rect = self.btn_start.get_rect()
       btn_width, btn_height = self.btn_start.get_size()
       self.btn_start_rect.topleft = (int((self.width - btn_width) / 2),
                                 int(self.height / 2 + btn_height))

       # 加载背景音乐
       pygame.mixer.music.load(constants.BG_MUSIC)
       # 无限循环播放
       pygame.mixer.music.play(-1)
       # 调整音乐播放音量
       pygame.mixer.music.set_volume(20)

       #我方飞机对象
       self.our_plane = OurPlane(self.screen, speed = 20)

       self.clock = pygame.time.Clock()

   def bind_event(self):
       """绑定事件"""

       # 1.监听事件
       for event in pygame.event.get():
           # 退出游戏
           if event.type == pygame.QUIT:
               pygame.quit()
               sys.exit()
           elif event.type == pygame.MOUSEBUTTONDOWN:
               # 鼠标点击进入游戏
               # 游戏正在准备中, 点击才能进入游戏
               if self.status == self.READY:
                   self.status = self.PLAY
           elif event.type == pygame.KEYDOWN:
               # 键盘事件
               # 游戏正在游戏中,才能够控制键盘事件
               if self.status == self.PLAY:
                   if event.key == pygame.K_w or event.key == pygame.K_UP:
                       self.our_plane.move_up()
                   elif event.key == pygame.K_s or event.key == pygame.K_DOWN:
                       self.our_plane.move_down()
                   elif event.key == pygame.K_a or event.key == pygame.K_LEFT:
                       self.our_plane.move_left()
                   elif event.key == pygame.K_d or event.key == pygame.K_RIGHT:
                       self.our_plane.move_right()
                   elif event.key == pygame.K_SPACE:
                       # 发射子弹
                       self.our_plane.shoot()

   def add_small_enemies(self, num):
       """

       :param num: 飞机产生数量
       :return:
       """
       # 随机添加num架小型敌机
       for i in range(num):
           plane = SmallEnemyPlane(self.screen, 8)
           plane.add(self.small_enemies, self.enemies)


   def run_game(self):
       """游戏主循环"""
       while True:
           #1 设置帧速率
           self.clock.tick(60)
           self.frame += 1
           if self.frame >= 60:
               self.frame = 0
           #2 绑定事件
           self.bind_event()
           # 3 更新游戏的状态
           if self.status == self.READY:
               # 游戏正在准备中
               # 绘制背景
               self.screen.blit(self.bg, self.bg.get_rect())
               # 标题
               self.screen.blit(self.img_game_title, self.img_game_title_rect)
               # 开始按钮
               self.screen.blit(self.btn_start, self.btn_start_rect)
               pygame.display.flip()


           elif self.status == self.PLAY:
               # 游戏进行中
               # 绘制背景
               self.screen.blit(self.bg, self.bg.get_rect())
               # 绘制飞机
               self.our_plane.update(self)
               # 绘制子弹
               self.our_plane.bullets.update(self)

               # 绘制敌方飞机
               self.small_enemies.update()

               pygame.display.flip()

           # #绘制游戏的状态
           # screen.blit(bg,bg.get_rect())
           # #更新屏幕
           # pygame.display.flip()



###bullets

import pygame


import constants


class Bullet(pygame.sprite.Sprite):
   """子弹类"""
   #子弹状态 True 活的;
   active = True

   def __init__(self, plane, screen, speed= None):
       super().__init__()
       self.screen = screen
       #速度
       self.speed = speed or 10
       self.plane = plane

       #加载子弹图片
       self.image = pygame.image.load(constants.BULLET_IMG)

       #改变子弹的位置
       self.rect = self.image.get_rect()
       self.rect.centerx = plane.rect.centerx
       self.rect.top = plane.rect.top

       #发射的音乐效果
       self.shoot_sound = pygame.mixer.Sound(constants.BULLET_SHOOT_SOUND)
       self.shoot_sound.set_volume(0.3)
       self.shoot_sound.play()


   def update(self, war):
       """更新子弹位置"""
       self.rect.top -= self.speed
       #超出屏幕范围
       if self.rect.top < 0:
           self.remove(self.plane.bullets)
           print(self.plane.bullets)

       #绘制子弹
       self.screen.blit(self.image, self.rect)

       #碰撞检测,检测子弹是否碰撞到了敌机
       rest = pygame.sprite.spritecollide(self, war.enemies, False)
       print(rest, 666)
       for r in rest:
           #1.子弹消失
           self.kill()
           #2.飞机爆炸 坠毁
           r.broken_down()
           #3.统计游戏成绩



####main

import sys

import pygame

import constants
from game.plane import Plane, OurPlane, SmallEnemyPlane
from game.war import PlaneWar


def main():
   """游戏入口,main方法"""
   war = PlaneWar()
   #添加小型敌方飞机
   war.add_small_enemies(6)
   war.run_game()



if __name__ == '__main__':
   main()




####constants

import os


#项目根目录
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
#静态文件目录
ASSETS_DIR = os.path.join(BASE_DIR, 'assets')

#背景图片
BG_IMG = os.path.join(ASSETS_DIR, 'images\\background.png')
#标题图片
IMG_GAME_TITLE = os.path.join(ASSETS_DIR, 'images\\game_title.png')
#游戏按钮图片
IMG_GAME_START_BTN = os.path.join(ASSETS_DIR, 'images\\game_start.png')

#背景音乐
BG_MUSIC = os.path.join(ASSETS_DIR, 'sounds\\game_bg_music.mp3')


#我方飞机的静态资源
OUR_PLANE_IMG_LIST = [os.path.join(ASSETS_DIR,'images\\hero1.png'),os.path.join(ASSETS_DIR,'images\\hero2.png')]

OUR_DESTROY_IMG_LIST = [
   os.path.join(ASSETS_DIR,'images\\hero_broken_n1.png'),
   os.path.join(ASSETS_DIR,'images\\hero_broken_n2.png'),
   os.path.join(ASSETS_DIR,'images\\hero_broken_n3.png'),
   os.path.join(ASSETS_DIR,'images\\hero_broken_n4.png')]

#子弹图片和发射声音
BULLET_IMG = os.path.join(ASSETS_DIR, 'images\\bullet1.png')
BULLET_SHOOT_SOUND = os.path.join(ASSETS_DIR, 'sounds\\bullet.wav')


#敌方小型飞机图片及音效
SMALL_ENEMY_PLANE_IMG_LIST = [os.path.join(ASSETS_DIR, 'images\\enemy1.png')]
SMALL_ENEMY_DESTROY_IMG_LIST = [
   os.path.join(ASSETS_DIR,'images\\enemy1_down1.png'),
   os.path.join(ASSETS_DIR,'images\\enemy1_down2.png'),
   os.path.join(ASSETS_DIR,'images\\enemy1_down3.png'),
   os.path.join(ASSETS_DIR,'images\\enemy1_down4.png')]
#小型飞机坠毁音效
SMALL_ENEMY_DOWN_SOUND = (os.path.join(ASSETS_DIR,'sounds\\enemy1_down.wav'))


请问老师,为什么碰撞检测后调用坠毁动画等失败?

写回答

1回答

好帮手慕觉浅

2020-05-15

同学你好:在plane.py中的OuoPlane类里destroy_images需要赋值为constants.OUR_DESTROY_IMG_LIST,而不是空列表。就是因为这里图片没有添加进来因此无法播放碰撞后的图片的。修改后即可正常播放。

http://img.mukewang.com/climg/5ebe0d33092011d405880208.jpg

如果解决了你的疑惑,请采纳,祝学习愉快~


0

0 学习 · 8160 问题

查看课程