python 飞机大战等游戏类编程思路

  • Post author:
  • Post category:python




一.  类与对象的概念

一个游戏里面的组成元素其实都是一个个的对象,而

对象又是在类中的一个实例

比如你是一个人,而你所属的类别叫做人类,你是人类中的一个实例。类中可以定义属性和方法,而对象是具有这些属性和方法的。方法可以就理解为函数。

比如人类有身高体重等属性,有走路和奔跑等方法。


属性是静态特征,方法是动态行为

那么由此我们可以类比到游戏里面,我们可以定义一个飞机类。

飞机要呈现出来要有属性图像吧,你的飞机要移动得有属性速度吧,如果给飞机一个生命值,那是不是得有一个属性血量值,这是最基本得属性,还有别的属性我们后面讲。

上面的属性有感觉了吧,是不是就是用来描述飞机得静态特征的。

飞机要动起来是不是得有一个移动方法,比如键盘上得↑↓←→来控制飞机的移动;飞机要发射子弹是不是得有一个发射子弹的方法;上面我们给出了飞机的图像属性,那么飞机如何搬到游戏界面上 是不是得再来一个方法,把飞机得那张图像搬到游戏界面上。

方法是不是用来描述飞机的动态行为的

咱们对属性和方法有了初步的了解,现在我们对类再来深入了解一下。

我们是人类,但同时我们是不是也是动物,我们不是植物所以我们没有植物的那一套东西。但是我们是动物,动物会呼吸吧,动物会移动吧。所以我们人类会呼吸会移动。同时,鸟类是不是也是动物,他们也会呼吸会移动。所以

人类是动物,鸟类也是动物。动物也是一个类,人类是动物的子类,动物称作父类,动物所具备的,我们人类也具备,鸟类也具备。所以子类可以继承父类。

动物会进食,人类和鸟类也会进食,但是人类和鸟类进食的方式是不一样的,人类进食需要先将食物搞熟,将食物搞美味,并且在用餐的时候会使用工具,而鸟类直接通过喙进食。进食是动物的方法,也是人类和鸟类的方法,但动物的进食方法很抽象,人类和鸟类的进食方法很具体,所以在写子类的时候可以将父类抽象的方法写得更具体。

所以

子类在继承父类的时候可以将父类的方法覆盖重写。这被称为继承的多态性。



二. 模块与包 — 我们站在巨人的肩膀上

我们在了解上面的内容之后,我在想一个问题,既然子类可以继承父类,那么我的飞机类是不是也可以继承它的父类,那样的话,我不就可以在他的父类上面修修补补不就行了。

对的,由于类的继承性,我们可以站在巨人的肩膀上,父类让别人给我写好,我直接继承,拿来吧你。

所以面向对象语言生态圈里就有这么一群人,他们专门写一些父类与模块,然后供别人使用。

pygame模块里就有一个精灵类,游戏里面的飞机类,子弹类,都可以继承这个精灵类。最下面有介绍精灵类里面的一些方法。

面向对象语言中,多个类和多个对象的关系是一个树形图的关系,大类就是树干,子类就是枝干,对象就是叶子。比如pygame.sprite.Sprite就是pygame.sprite的子类

pygame里面的各种类和方法,就是给出了树干,剩下的叶子根据我们的需求自己去完善



三. 思路大纲

我方飞机类  Class MyPlane(pygame.sprite.Sprite):

敌方飞机类  Class EnemyPlane(pygame.sprite.Sprite):

我方子弹类  Class MyBullet(pygame.sprite.Sprite):

敌方子弹类  Class EnemyBullet(pygame.sprite.Sprite):

游戏声音类  Class GameSound:

爆炸类         Class Bomb:

游戏背景类  Class GameBackgroud:

游戏管理类  Class Manager:

————————————————————————-

“由于我方飞机与敌方飞机共用的属性和方法非常少(本例中 他们的图片 速度 矩形区域等等属性都不一样)所以直接定义两个类(如果他们共用的属性和方法很多的话,我们可以定义一个他们的父类Plane)。”

细讲类里面的方法与属性(实例属性定义在初始化方法中,类属性的值在所有实例之间共享):

Class MyPlane(pygame.sprite.Sprite):

初始化方法       def __init__(self,screen):  # 初始化就相当于一个具体对象的出生,定义各项属性

键盘控制方法   def key_control(self):         # 飞机要移动需定义键盘控制方法

显示方法          def display(self):                # 显示飞机图像,显示子弹图像,

更新方法          def update(self):                 # 更新飞机按键状态和显示状态

清除子弹方法  @classmethod

def clear_bullets(cls):          # 类方法,清除子弹,避免子弹对象占用过多系统资源

Class EnemyPlane(pygame.sprite.Sprite):

有和上面类似的初始化方法,显示方法,更新方法。

自动移动方法  def auto_move(self):           # 敌方飞机自动移动

自动开火方法  def auto_fire(self):               # 敌方飞机自动开火

清除子弹方法

Class MyBullet(pygame.sprite.Sprite):

初始化方法

更新方法

Class EnemyBullet(pygame.sprite.Sprite):

初始化方法

更新方法

Class GameSound:

初始化方法                   #加载下面的两种音乐

背景音乐方法

爆炸音效方法

Class Bomb:

初始化方法

爆炸触发方法   def action(self,rect):        # 爆炸的位置与是否爆炸的开关

爆炸绘画方法   def draw(self):                 # 爆炸的动画绘制


# 爆炸与背景移动本质上是类似的  两张图片的切换形成爆炸图像效果


都有触发方法和绘制


只不过一个需要触发条件  一个是一直触发

Class GameBackgroud:

初始化方法

背景移动方法   def move(self):

背景绘制方法   def draw(self):

Class Manager:

类属性定义(给其他方法共享)

初始化方法

游戏退出方法                      def exit(self):

显示游戏结束文字方法       def show_over_text(self):

游戏结束倒计时方法           def game_over_timer(self):

游戏重新开始方法              def start_game(self):

更新玩家飞机方法              def new_player(self):

更新敌方飞机方法              def new_enemy(self):

显示文本方法                     def drawText(self,text,x,y, textHeight=30,

fontColor=(255,0,0), backgroundColor=None):

主方法                                def main(self):



四. 代码实现细节

我方飞机类

class HeroPlane(pygame.sprite.Sprite):
    # group to store all aircraft bullets
    bullets = pygame.sprite.Group()

将子弹添加到pygame.sprite.Group()中,方便对子弹对象进行批量处理和管理

    def __init__(self, screen):
        # The initialization method of this sprite must be called:
        pygame.sprite.Sprite.__init__(self)

        # Create a picture as a player's plane
        self.player = pygame.image.load("./photo/hero1.png")
        # getting a rectangle object based on the image
        self.rect = self.player.get_rect()
        self.rect.topleft = [Manager.bg_size[0]/ 2 - 134 / 2 , 580]
        # aircraft speed
        self.speed = 4
        self.screen = screen
        # list of loaded bullets
        self.bullets = pygame.sprite.Group()

初始化,将我方飞机像生小孩一样生下来。然后给飞机加载图像,“ . ”表示当前目录,“ .. ”表示上级目录。”./photo/hero1.png”表示在当前python脚本目录下的’photo’目录中查找’hero1.png’文件。

先定义一下 self.player ,加载玩家飞机图像 然后再self.rect=self.player.get_rect 相当于self.rect=pygame.image.load(“./photo/hero1.png”).get_rect

topleft是get_rect里面的,代表着图像坐上角的坐标,x定为背景图片的x/2-飞机x/2  y定为靠下方就行了(根据你背景图片的像素)  飞机速度自己定  self.screen = screen 以便后续飞机的display方法使用,将飞机显示到窗口上。

self.bullets = pygame.sprite.Group()将飞机子弹放入精灵组方便后续统一处理和管理
    def key_control(self):
        # Listen for keyboard events
        key_pressed = pygame.key.get_pressed()

        if key_pressed[K_w] or key_pressed[K_UP]:
            self.rect.top -= self.speed
        if key_pressed[K_s] or key_pressed[K_DOWN]:
            self.rect.bottom += self.speed
        if key_pressed[K_a] or key_pressed[K_LEFT]:
            self.rect.left -= self.speed
        if key_pressed[K_d] or key_pressed[K_RIGHT]:
            self.rect.right += self.speed
        if key_pressed[K_SPACE]:
            # Create a new bullet
            bullet = Bullet(self.screen, self.rect.left, self.rect.top)
            self.bullets.add(bullet)
            HeroPlane.bullets.add(bullet)

因为窗口坐标左上角为原点,所以飞机往上就是y值(top)减小,往左就是x值(left)减小

我们把飞机的左上角的坐标参数传给我方子弹类,

self.bullets.add(bullet)是将子弹添加到此飞机的列表里方便后续管理

HeroPlane.bullets.add(bullet)是将子弹添加到我方的所有飞机的列表里,如果我方只有一个飞机,此行代码可不要

    def display(self):
        # 3.Paste the player picture into the window
        self.screen.blit(self.player, self.rect)
        # updating the coordinates of the bullet
        self.bullets.update()
        # adding all bullets to the screen
        self.bullets.draw(self.screen)

    def update(self):
        self.key_control()
        self.display()

    @classmethod
    def clear_bullets(cls):
        # clearing bullets
        cls.bullets.empty()

blit是block transfer的缩写,将图像复制到屏幕上。参数为图像self.player,和位置self.rect


@classmethod

是 Python 中的一个装饰器(decorator),它可以将一个方法转换为类方法(classmethod)。类方法是针对类而不是针对实例的方法,它可以通过类名直接调用,而不需要创建实例对象。类方法的第一个参数通常被命名为

cls

,它指代当前的类本身。cls缩写自class

前面在定义HeroPlane类时定义了bullets为类属性,所以在类方法中用

cls.bullets

这种方式来访问类属性


empty()

方法是

pygame.sprite.Group

类的一个方法,用于清空一个 sprite 组中所有的 sprite 对象

class EnemyPlane(pygame.sprite.Sprite):
    # all enemy bullets
    enemy_bullets = pygame.sprite.Group()

    def __init__(self, screen):
        # The initialization method of this sprite must be called:
        pygame.sprite.Sprite.__init__(self)
        # Create a picture as a player's plane
        self.player = pygame.image.load("./photo/enemy0.png")
        # getting a rectangle object based on the image
        self.rect = self.player.get_rect()
        x = random.randrange(1, Manager.bg_size[0], 50)
        self.rect.topleft = [x, 0]
        # aircraft speed
        self.speed = 4
        self.screen = screen
        # list of loaded bullets
        self.bullets = pygame.sprite.Group()
        # direction of enemy aircraft movement
        self.direction = 'right'

    def display(self):
        # Paste the player picture into the window
        self.screen.blit(self.player, self.rect)
        # updating the coordinates of the bullet
        self.bullets.update()
        # adding all bullets to the screen
        self.bullets.draw(self.screen)

敌方飞机类与我方飞机类定义差不多,敌方飞机时随机生成的

x = random.randrange(1, Manager.bg_size[0], 50) (python内置函数,1到窗口x值大小,生成步长为50的随机数)

    def update(self):
        self.auto_move()
        self.auto_fire()
        self.display()

    def auto_move(self):
        if self.direction == 'right':
            self.rect.right += self.speed
        elif self.direction == 'left':
            self.rect.right -= self.speed

        if self.rect.right > Manager.bg_size[0] - 51:
            self.direction = 'left'
        elif self.rect.right < 0 :
            self.direction = 'right'

        self.rect.bottom += self.speed

    def auto_fire(self):
        """automatic firing,creating a bullet object,and adding it to the list"""
        random_num = random.randint(1, 40)
        if random_num == 8 :
            bullet = EnemyBullet(self.screen,self.rect.left,self.rect.top)
            self.bullets.add(bullet)
            # adding bullets to the bullet group of the class property
            EnemyPlane.enemy_bullets.add(bullet)

    @classmethod
    def clear_bullets(cls):
        # clearing bullets
        cls.enemy_bullets.empty()

同前面类似

# bullet class
# attribute
class Bullet(pygame.sprite.Sprite):
    def __init__(self, screen, x, y):
        # sprite class initialization
        pygame.sprite.Sprite.__init__(self)

        # creating an image
        self.image = pygame.image.load('./photo/bullet.png')

        # getting a rectangle object
        self.rect = self.image.get_rect()
        self.rect.topleft = [x + 100/2 - 22/2 , y - 22]

        # screen
        self.screen = screen
        # speed
        self.speed = 30

    def update(self):
        # modifying the bullet's coordinates
        self.rect.top -= self.speed
        # if the bullet moves above the screen , destroy the bullet
        if self.rect.top < -22:
            self.kill()


# enemy bullet class
# attribute
class EnemyBullet(pygame.sprite.Sprite):
    def __init__(self, screen, x, y):
        # sprite class initialization
        pygame.sprite.Sprite.__init__(self)

        # creating an image
        self.image = pygame.image.load('./photo/bullet1.png')

        # getting a rectangle object
        self.rect = self.image.get_rect()
        self.rect.topleft = [x + 50/2 - 8/2, y + 39 ]

        # screen
        self.screen = screen
        # speed
        self.speed = 6

    def update(self):
        # modifying the bullet's coordinates
        self.rect.top += self.speed
        # if the bullet moves above the screen , destroy the bullet
        if self.rect.top > Manager.bg_size[1]:
         self.kill()
class GameSound(object):
    def __init__(self):
        pygame.mixer.init() # music module initialization
        pygame.mixer.music.load('./photo/bg2.ogg')
        pygame.mixer.music.set_volume(0.5) # sound level

        self.__bomb = pygame.mixer.Sound('./photo/bomb.wav')

    def playBackgroundMusic(self):
        pygame.mixer.music.play(-1) # begin playing music

    def playBombSound(self):
        pygame.mixer.Sound.play(self.__bomb)


class Bomb(object):
    # initializing collision
    def __init__(self,screen , type):
        self.screen = screen
        if type == "enemy":
            # loading explosion resources
            self.mImages = [pygame.image.load("./photo/enemy0_down" + str(v) + ".png") for v in range(1, 5)]
        else:
            self.mImages = [pygame.image.load("./photo/hero_blowup_n" + str(v) + ".png") for v in range(1, 5)]
        # setting the current explosion playback index
        self.mIndex = 0
        # explosing settings
        self.mPos = [0, 0]
        self.mVisible = False

    # setting the position
    def action(self,rect):
        # triggering the explosing method draw
        # explosing coordinates
        self.mPos[0] = rect.left
        self.mPos[1] = rect.top
        # turning on the explosing switch
        self.mVisible = True

    # drawing the explosing
    def draw(self):
        if not self.mVisible :
            return
        self.screen.blit(self.mImages[self.mIndex],(self.mPos[0], self.mPos[1]))
        self.mIndex += 1
        if self.mIndex >= len(self.mImages):
            self.mIndex = 0
            self.mVisible = False


class GameBackground(object):
    # map initialization
    def __init__(self, screen):
        self.mImage1 = pygame.image.load("./photo/background.jpg")
        self.mImage2 = pygame.image.load("./photo/background.jpg")
        # window
        self.screen = screen
        # assist in moving the map
        self.y1 = 0
        self.y2 = -Manager.bg_size[1] # -768

    # moving the map
    def move(self):
        self.y1 += 2
        self.y2 += 2
        if self.y1 >= Manager.bg_size[1]:
            self.y1 = 0
        if self.y2 >= 0:
            self.y2 = -Manager.bg_size[1]

    # drawing the map
    def draw(self):
        self.screen.blit(self.mImage1, (0, self.y1))
        self.screen.blit(self.mImage2, (0, self.y2))
class Manager:
    bg_size = (512, 768)
    # ID of the timer for creating enemy aircraft
    create_enemy_id = 10
    # countdown ID when the game ends
    game_over_id = 11
    # if the game is over
    is_game_over = False
    # countdown time
    over_time = 2

    def __init__(self):
        pygame.init()
        # 1.Create a window
        self.screen = pygame.display.set_mode(Manager.bg_size, 0, 32)
        # 2.Create a picture as a background
        # self.background = pygame.image.load("./photo/background.jpg")
        self.map = GameBackground(self.screen)

        # initializing a group to hold the player sprite
        self.players = pygame.sprite.Group()
        # initializing a group to hold the enemy sprite
        self.enemys = pygame.sprite.Group()
        # initializing an object for player explosion
        self.player_bomb = Bomb(self.screen, 'player')
        # initializing an object for enemy explosion
        self.enemy_bomb = Bomb(self.screen, 'enemy')
        # initializing an object for sound playback
        self.sound = GameSound()

    def exit(self):
        print('exit')
        pygame.quit()
        exit()

    def show_over_text(self):
        # game over, restarting the game after the countdown
        self.drawText('gameover %d'% Manager.over_time, 100, Manager.bg_size[1]/2, textHeight=50, fontColor=[255,0,0])

    def game_over_timer(self):
        self.show_over_text()
        # decrementing the countdown by 1
        Manager.over_time -= 1
        if Manager.over_time == 0 :
            # halting the timer
            pygame.time.set_timer(Manager.game_over_id, 0)
            # restarting the game after the countdown
            Manager.over_time = 3
            Manager.is_game_over = False
            self.start_game()

    def start_game(self):
        # restarting game, some class properties need to be cleared
        EnemyPlane.clear_bullets()
        HeroPlane.clear_bullets()
        manager = Manager()
        manager.main()

    def new_player(self):
        # creating an aircraft object and adding it to the player's group
        player = HeroPlane(self.screen)
        self.players.add(player)

    def new_enemy(self):
        # creating an enemy aircraft object and adding it to the player's group
        enemy = EnemyPlane(self.screen)
        self.enemys.add(enemy)

    # drawing text
    def drawText(self,text,x,y, textHeight=30, fontColor=(255,0,0), backgroundColor=None):
        # getting a font object from a text file
        font_obj = pygame.font.Font('./photo/baddf.ttf', textHeight)
        # configuring the text to be displayed
        text_obj = font_obj.render(text,True,fontColor,backgroundColor)
        # getting the rect of the object to be displayed
        text_rect = text_obj.get_rect()
        # setting the coordinates of the display object
        text_rect.topleft = (x, y)
        # drawing text to a specified area
        self.screen.blit(text_obj, text_rect)

    def main(self):
        # playing background music
        self.sound.playBackgroundMusic()
        # creating a player aircraft
        self.new_player()
        # starting the timer to creat enemy aircraft
        pygame.time.set_timer(Manager.create_enemy_id, 1000)
        while True:
            # 3.Paste the background picture into the window
            # self.screen.blit(self.background, (0, 0))
            # moving the map
            self.map.move()
            # attaching the map to the window
            self.map.draw()

            # drawing text
            self.drawText('hp: 1000', 0, 0)
            if Manager.is_game_over:
                # displaying the game over text only when the game is over
                self.show_over_text()

            # Get the event
            for event in pygame.event.get():
                # Determine the even type
                if event.type == pygame.QUIT:
                    self.exit()
                elif event.type == Manager.create_enemy_id:
                    # creating an enemy aircraft
                    self.new_enemy()
                elif event.type == Manager.game_over_id:
                    # the event that is triggered by the timer
                    self.game_over_timer()

            # calling the explosion object
            self.player_bomb.draw()
            self.enemy_bomb.draw()

            # collision detection between player aircraft and enemy bullets
            if self.players.sprites():
                isover = pygame.sprite.spritecollide(self.players.sprites()[0], EnemyPlane.enemy_bullets, True)
                if isover:
                    Manager.is_game_over = True
                    pygame.time.set_timer(Manager.game_over_id, 1000)
                    print('being hit')
                    self.player_bomb.action(self.players.sprites()[0].rect)
                    # removing the player aircraft from the sprite group
                    self.players.remove(self.players.sprites()[0])
                    # explosion sound
                    self.sound.playBombSound()

            # detecting collision
            iscollide = pygame.sprite.groupcollide(self.players, self.enemys, True, True)

            if iscollide:
                Manager.is_game_over = True # indicates that the game is over
                pygame.time.set_timer(Manager.game_over_id, 1000) # starting the game countdown

                items = list(iscollide.items())[0]
                print(items)
                x = items[0]
                y = items[1][0]
                # player aircraft explosion image
                self.player_bomb.action(x.rect)
                # enemy aircraft explosion image
                self.enemy_bomb.action(y.rect)
                # explosion sound
                self.sound.playBombSound()

            # collision detection between player bullets and all enemy aircraft
            is_enemy = pygame.sprite.groupcollide(HeroPlane.bullets,self.enemys,True,True)
            if is_enemy:
                items = list(is_enemy.items())[0]
                y = items[1][0]
                # enemy aircraft explosion image
                self.enemy_bomb.action(y.rect)
                # explosion sound
                self.sound.playBombSound()

            # display of the player aircraft and bullets
            self.players.update()
            # display of the enemy aircraft and bullets
            self.enemys.update()

            # refreshing the window content
            pygame.display.update()
            time.delay(15)


if __name__ == '__main__':
    manager = Manager()
    manager.main()

管理类中先定义类属性,然后再定义初始化方法,退出方法,显示结束文字方法,游戏结束倒计时方法,重新开始游戏方法,创建新的玩家角色方法,创建新的敌机方法,显示文本方法和主方法

主方法是面向过程的,你要把管理的过程逻辑写出来



五. pygame里的一些类与方法

Pygame.sprite.Sprite 类中常用的一些方法:

__init__(self):初始化方法,用于设置精灵的初始属性,例如位置、速度、图像等。


update(self):精灵的更新方法,用于处理精灵的行为逻辑,例如移动、旋转、发射子弹等。


kill(self):从所有精灵组中删除精灵。


add(self, *groups):将精灵添加到一个或多个精灵组中。


remove(self, *groups):将精灵从一个或多个精灵组中删除。


groups(self):返回包含精灵所属精灵组的列表。


alive(self):返回一个布尔值,表示精灵是否存活。


collide_rect(self, other_sprite):检测精灵与另一个精灵是否碰撞。


collide_rectangle(self, rect):检测精灵与一个矩形区域是否碰撞。


collide_mask(self, other_sprite):检测精灵与另一个精灵的透明像素是否重叠。


image(self):返回精灵的图像。


rect(self):返回精灵的矩形区域,用于碰撞检测和绘制。


rect.x 和 rect.y:表示精灵的位置,可以直接修改来移动精灵。


rect.centerx 和 rect.centery:表示精灵的中心位置。


rect.width 和 rect.height:表示精灵的宽度和高度。


rect.left、rect.right、rect.top、rect.bottom:表示精灵的左、右、上、下边缘的位置。


需要注意的是,Pygame.sprite.Sprite 类只是一个基类,它并没有实现所有的方法。我们通常需要自己定义子类来实现一些具体的方法和属性。

——————————————————————————————————–


pygame.sprite.Group

是 Pygame 中用于管理和操作 Sprite 对象的类。以下是

pygame.sprite.Group

中常用的方法的详细解释:


  1. __init__(self, *sprites)

    : 初始化 Group 对象。可以传入一个或多个 Sprite 对象作为参数,也可以不传入任何参数。


  2. add(self, *sprites)

    : 将一个或多个 Sprite 对象添加到 Group 中。


  3. remove(self, *sprites)

    : 将一个或多个 Sprite 对象从 Group 中移除。


  4. sprites(self) -> List[Sprite]

    : 返回 Group 中所有 Sprite 对象的列表。


  5. clear(self)

    : 将 Group 中所有 Sprite 对象移除。


  6. empty(self) -> bool

    : 返回一个布尔值,表示 Group 是否为空。


  7. update(self, *args)

    : 更新 Group 中所有 Sprite 对象的状态。可以传入任意数量的参数,这些参数将会被传递给每个 Sprite 对象的

    update()

    方法。


  8. draw(self, surface)

    : 在指定的 Surface 对象上绘制 Group 中所有 Sprite 对象



六. 飞机大战所需图片及音乐素材包

留言领取



七. 飞机大战完整代码示例

import random
import time
import pygame
from pygame import *


class HeroPlane(pygame.sprite.Sprite):
    # group to store all aircraft bullets
    bullets = pygame.sprite.Group()

    def __init__(self, screen):
        # The initialization method of this sprite must be called:
        pygame.sprite.Sprite.__init__(self)

        # Create a picture as a player's plane
        self.player = pygame.image.load("./photo/hero1.png")
        # getting a rectangle object based on the image
        self.rect = self.player.get_rect()
        self.rect.topleft = [Manager.bg_size[0]/ 2 - 134 / 2 , 580]
        # aircraft speed
        self.speed = 4
        self.screen = screen
        # list of loaded bullets
        self.bullets = pygame.sprite.Group()

    def key_control(self):
        # Listen for keyboard events
        key_pressed = pygame.key.get_pressed()

        if key_pressed[K_w] or key_pressed[K_UP]:
            self.rect.top -= self.speed
        if key_pressed[K_s] or key_pressed[K_DOWN]:
            self.rect.bottom += self.speed
        if key_pressed[K_a] or key_pressed[K_LEFT]:
            self.rect.left -= self.speed
        if key_pressed[K_d] or key_pressed[K_RIGHT]:
            self.rect.right += self.speed
        if key_pressed[K_SPACE]:
            # Create a new bullet
            bullet = Bullet(self.screen, self.rect.left, self.rect.top)
            self.bullets.add(bullet)
            HeroPlane.bullets.add(bullet)

    def display(self):
        # 3.Paste the player picture into the window
        self.screen.blit(self.player, self.rect)
        # updating the coordinates of the bullet
        self.bullets.update()
        # adding all bullets to the screen
        self.bullets.draw(self.screen)

    def update(self):
        self.key_control()
        self.display()

    @classmethod
    def clear_bullets(cls):
        # clearing bullets
        cls.bullets.empty()


class EnemyPlane(pygame.sprite.Sprite):
    # all enemy bullets
    enemy_bullets = pygame.sprite.Group()

    def __init__(self, screen):
        # The initialization method of this sprite must be called:
        pygame.sprite.Sprite.__init__(self)
        # Create a picture as a player's plane
        self.player = pygame.image.load("./photo/enemy0.png")
        # getting a rectangle object based on the image
        self.rect = self.player.get_rect()
        x = random.randrange(1, Manager.bg_size[0], 50)
        self.rect.topleft = [x, 0]
        # aircraft speed
        self.speed = 4
        self.screen = screen
        # list of loaded bullets
        self.bullets = pygame.sprite.Group()
        # direction of enemy aircraft movement
        self.direction = 'right'

    def display(self):
        # Paste the player picture into the window
        self.screen.blit(self.player, self.rect)
        # updating the coordinates of the bullet
        self.bullets.update()
        # adding all bullets to the screen
        self.bullets.draw(self.screen)

    def update(self):
        self.auto_move()
        self.auto_fire()
        self.display()

    def auto_move(self):
        if self.direction == 'right':
            self.rect.right += self.speed
        elif self.direction == 'left':
            self.rect.right -= self.speed

        if self.rect.right > Manager.bg_size[0] - 51:
            self.direction = 'left'
        elif self.rect.right < 0 :
            self.direction = 'right'

        self.rect.bottom += self.speed

    def auto_fire(self):
        """automatic firing,creating a bullet object,and adding it to the list"""
        random_num = random.randint(1, 40)
        if random_num == 8 :
            bullet = EnemyBullet(self.screen,self.rect.left,self.rect.top)
            self.bullets.add(bullet)
            # adding bullets to the bullet group of the class property
            EnemyPlane.enemy_bullets.add(bullet)

    @classmethod
    def clear_bullets(cls):
        # clearing bullets
        cls.enemy_bullets.empty()


# bullet class
# attribute
class Bullet(pygame.sprite.Sprite):
    def __init__(self, screen, x, y):
        # sprite class initialization
        pygame.sprite.Sprite.__init__(self)

        # creating an image
        self.image = pygame.image.load('./photo/bullet.png')

        # getting a rectangle object
        self.rect = self.image.get_rect()
        self.rect.topleft = [x + 100/2 - 22/2 , y - 22]

        # screen
        self.screen = screen
        # speed
        self.speed = 30

    def update(self):
        # modifying the bullet's coordinates
        self.rect.top -= self.speed
        # if the bullet moves above the screen , destroy the bullet
        if self.rect.top < -22:
            self.kill()


# enemy bullet class
# attribute
class EnemyBullet(pygame.sprite.Sprite):
    def __init__(self, screen, x, y):
        # sprite class initialization
        pygame.sprite.Sprite.__init__(self)

        # creating an image
        self.image = pygame.image.load('./photo/bullet1.png')

        # getting a rectangle object
        self.rect = self.image.get_rect()
        self.rect.topleft = [x + 50/2 - 8/2, y + 39 ]

        # screen
        self.screen = screen
        # speed
        self.speed = 6

    def update(self):
        # modifying the bullet's coordinates
        self.rect.top += self.speed
        # if the bullet moves above the screen , destroy the bullet
        if self.rect.top > Manager.bg_size[1]:
         self.kill()


class GameSound(object):
    def __init__(self):
        pygame.mixer.init() # music module initialization
        pygame.mixer.music.load('./photo/bg2.ogg')
        pygame.mixer.music.set_volume(0.5) # sound level

        self.__bomb = pygame.mixer.Sound('./photo/bomb.wav')

    def playBackgroundMusic(self):
        pygame.mixer.music.play(-1) # begin playing music

    def playBombSound(self):
        pygame.mixer.Sound.play(self.__bomb)


class Bomb(object):
    # initializing collision
    def __init__(self,screen , type):
        self.screen = screen
        if type == "enemy":
            # loading explosion resources
            self.mImages = [pygame.image.load("./photo/enemy0_down" + str(v) + ".png") for v in range(1, 5)]
        else:
            self.mImages = [pygame.image.load("./photo/hero_blowup_n" + str(v) + ".png") for v in range(1, 5)]
        # setting the current explosion playback index
        self.mIndex = 0
        # explosing settings
        self.mPos = [0, 0]
        self.mVisible = False

    # setting the position
    def action(self,rect):
        # triggering the explosing method draw
        # explosing coordinates
        self.mPos[0] = rect.left
        self.mPos[1] = rect.top
        # turning on the explosing switch
        self.mVisible = True

    # drawing the explosing
    def draw(self):
        if not self.mVisible :
            return
        self.screen.blit(self.mImages[self.mIndex],(self.mPos[0], self.mPos[1]))
        self.mIndex += 1
        if self.mIndex >= len(self.mImages):
            self.mIndex = 0
            self.mVisible = False


class GameBackground(object):
    # map initialization
    def __init__(self, screen):
        self.mImage1 = pygame.image.load("./photo/background.jpg")
        self.mImage2 = pygame.image.load("./photo/background.jpg")
        # window
        self.screen = screen
        # assist in moving the map
        self.y1 = 0
        self.y2 = -Manager.bg_size[1] # -768

    # moving the map
    def move(self):
        self.y1 += 2
        self.y2 += 2
        if self.y1 >= Manager.bg_size[1]:
            self.y1 = 0
        if self.y2 >= 0:
            self.y2 = -Manager.bg_size[1]

    # drawing the map
    def draw(self):
        self.screen.blit(self.mImage1, (0, self.y1))
        self.screen.blit(self.mImage2, (0, self.y2))


class Manager:
    bg_size = (512, 768)
    # ID of the timer for creating enemy aircraft
    create_enemy_id = 10
    # countdown ID when the game ends
    game_over_id = 11
    # if the game is over
    is_game_over = False
    # countdown time
    over_time = 2

    def __init__(self):
        pygame.init()
        # 1.Create a window
        self.screen = pygame.display.set_mode(Manager.bg_size, 0, 32)
        # 2.Create a picture as a background
        # self.background = pygame.image.load("./photo/background.jpg")
        self.map = GameBackground(self.screen)

        # initializing a group to hold the player sprite
        self.players = pygame.sprite.Group()
        # initializing a group to hold the enemy sprite
        self.enemys = pygame.sprite.Group()
        # initializing an object for player explosion
        self.player_bomb = Bomb(self.screen, 'player')
        # initializing an object for enemy explosion
        self.enemy_bomb = Bomb(self.screen, 'enemy')
        # initializing an object for sound playback
        self.sound = GameSound()

    def exit(self):
        print('exit')
        pygame.quit()
        exit()

    def show_over_text(self):
        # game over, restarting the game after the countdown
        self.drawText('gameover %d'% Manager.over_time, 100, Manager.bg_size[1]/2, textHeight=50, fontColor=[255,0,0])

    def game_over_timer(self):
        self.show_over_text()
        # decrementing the countdown by 1
        Manager.over_time -= 1
        if Manager.over_time == 0 :
            # halting the timer
            pygame.time.set_timer(Manager.game_over_id, 0)
            # restarting the game after the countdown
            Manager.over_time = 3
            Manager.is_game_over = False
            self.start_game()

    def start_game(self):
        # restarting game, some class properties need to be cleared
        EnemyPlane.clear_bullets()
        HeroPlane.clear_bullets()
        manager = Manager()
        manager.main()

    def new_player(self):
        # creating an aircraft object and adding it to the player's group
        player = HeroPlane(self.screen)
        self.players.add(player)

    def new_enemy(self):
        # creating an enemy aircraft object and adding it to the player's group
        enemy = EnemyPlane(self.screen)
        self.enemys.add(enemy)

    # drawing text
    def drawText(self,text,x,y, textHeight=30, fontColor=(255,0,0), backgroundColor=None):
        # getting a font object from a text file
        font_obj = pygame.font.Font('./photo/baddf.ttf', textHeight)
        # configuring the text to be displayed
        text_obj = font_obj.render(text,True,fontColor,backgroundColor)
        # getting the rect of the object to be displayed
        text_rect = text_obj.get_rect()
        # setting the coordinates of the display object
        text_rect.topleft = (x, y)
        # drawing text to a specified area
        self.screen.blit(text_obj, text_rect)

    def main(self):
        # playing background music
        self.sound.playBackgroundMusic()
        # creating a player aircraft
        self.new_player()
        # starting the timer to creat enemy aircraft
        pygame.time.set_timer(Manager.create_enemy_id, 1000)
        while True:
            # 3.Paste the background picture into the window
            # self.screen.blit(self.background, (0, 0))
            # moving the map
            self.map.move()
            # attaching the map to the window
            self.map.draw()

            # drawing text
            self.drawText('hp: 1000', 0, 0)
            if Manager.is_game_over:
                # displaying the game over text only when the game is over
                self.show_over_text()

            # Get the event
            for event in pygame.event.get():
                # Determine the even type
                if event.type == pygame.QUIT:
                    self.exit()
                elif event.type == Manager.create_enemy_id:
                    # creating an enemy aircraft
                    self.new_enemy()
                elif event.type == Manager.game_over_id:
                    # the event that is triggered by the timer
                    self.game_over_timer()

            # calling the explosion object
            self.player_bomb.draw()
            self.enemy_bomb.draw()

            # collision detection between player aircraft and enemy bullets
            if self.players.sprites():
                isover = pygame.sprite.spritecollide(self.players.sprites()[0], EnemyPlane.enemy_bullets, True)
                if isover:
                    Manager.is_game_over = True
                    pygame.time.set_timer(Manager.game_over_id, 1000)
                    print('being hit')
                    self.player_bomb.action(self.players.sprites()[0].rect)
                    # removing the player aircraft from the sprite group
                    self.players.remove(self.players.sprites()[0])
                    # explosion sound
                    self.sound.playBombSound()

            # detecting collision
            iscollide = pygame.sprite.groupcollide(self.players, self.enemys, True, True)

            if iscollide:
                Manager.is_game_over = True # indicates that the game is over
                pygame.time.set_timer(Manager.game_over_id, 1000) # starting the game countdown

                items = list(iscollide.items())[0]
                print(items)
                x = items[0]
                y = items[1][0]
                # player aircraft explosion image
                self.player_bomb.action(x.rect)
                # enemy aircraft explosion image
                self.enemy_bomb.action(y.rect)
                # explosion sound
                self.sound.playBombSound()

            # collision detection between player bullets and all enemy aircraft
            is_enemy = pygame.sprite.groupcollide(HeroPlane.bullets,self.enemys,True,True)
            if is_enemy:
                items = list(is_enemy.items())[0]
                y = items[1][0]
                # enemy aircraft explosion image
                self.enemy_bomb.action(y.rect)
                # explosion sound
                self.sound.playBombSound()

            # display of the player aircraft and bullets
            self.players.update()
            # display of the enemy aircraft and bullets
            self.enemys.update()

            # refreshing the window content
            pygame.display.update()
            time.delay(15)


if __name__ == '__main__':
    manager = Manager()
    manager.main()







版权声明:本文为hulongkang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。