飛機大戰(zhàn)

liunx操作

安裝pygame

1,首先安裝pygame

sudo pip3 install pygame

2,驗證是否安裝pygame

python3 -m pygame.examples.aliens

如果安裝上那就完成下列步驟,完成飛機大戰(zhàn)項目:

項目準備

一. 使用 pygame 創(chuàng)建圖形窗口
二. 理解 圖像 并實現(xiàn)圖像繪制
三 理解 游戲循環(huán) 和 游戲時鐘
四. 理解 精靈 和 精靈組

一,創(chuàng)建圖形窗口
1.游戲的初始化和退出
切記

    * 要使用 pygame 提供的所有功能之前,需要調(diào)用 init 方法
    * 在游戲結(jié)束前需要調(diào)用一下 quit 方法

import pygame

導入并初始化所有 pygame 模塊,使用其他模塊之前,必須先調(diào)用 init 方法

pygame.init()

游戲代碼...

卸載所有 pygame 模塊,在游戲結(jié)束之前調(diào)用!

pygame.quit()
2.游戲中的坐標系

* 坐標系

    * 原點 在 左上角 (0, 0)
    * x 軸 水平方向向 右,逐漸增加
    * y 軸 垂直方向向 下,逐漸增加
 SCREEN_RECT = pygame.Rect(0, 0, 480,600)
依次是英雄的x,y軸,寬度和長度 

3.創(chuàng)建游戲主窗口
pygame 專門提供了一個 模塊 pygame.display 用于創(chuàng)建、管理 游戲窗口

)初始化游戲顯示窗口

pygame.display.set_mode()

刷新屏幕內(nèi)容顯示,稍后使用

pygame.display.update()

基礎類的構(gòu)建

導彈類

  • 1.導彈是從飛機上發(fā)射的(無論是玩家的飛機還是敵機),導彈的位置需要根據(jù)飛機的位置確定,還需要根據(jù)是玩家飛機還是敵機確定導彈的圖片名和發(fā)射方向,因此需要傳入圖片名和位置參數(shù)。


    這里寫圖片描述

    pygame框架加載圖片為圖像函數(shù)為:

    pygame.image.load(image).convert()
    

    傳入的參數(shù)是圖片的相對路徑

  • 2.描繪出導彈的位置,導彈并且需要在初始化的self.xself.y基礎上移動位置,位置是在屏幕上描繪的,需要傳入屏幕參數(shù)。

    這里寫圖片描述

    pygame顯示圖片函數(shù)為:

    screen.blit(self.image,(self.x,self.y))
    pygame.display.update()
    

    第一個參數(shù)為加載的圖像,第二個參數(shù)為左上角坐標。兩個函數(shù)是配合使用的,需要第二個函數(shù)去刷新界面。

飛機類

  • 1.Plane類是接下來要創(chuàng)建的玩家類Hero和敵機類Enemy的基類?;惏褍烧吖餐膶傩院头椒ǘx出來,方便子類繼承。飛機要發(fā)射導彈,有一定的發(fā)射間隔,因此定義一個對象屬性self.bulletSleepTime。還需要一個列表存儲導彈,定義一個對象屬性為空列表self.bulletList。

    這里寫圖片描述

    time.time()可以用來確定當前時間,按照一定的格式可以轉(zhuǎn)換

  • 2.在初始化的時候我們定義了導彈的發(fā)射間隔時間,大于間隔時間的話我們就往定義的列表中添加導彈對象,因為我現(xiàn)在只想讓玩家飛機發(fā)射子彈,因此初始化導彈對象特意往self.x加了36(是玩家飛機72x72圖片寬度的一半),讓導彈在玩家飛機的正中間開始顯示。

    這里寫圖片描述

  • 3.描繪出飛機的位置


    這里寫圖片描述

繼承類的構(gòu)建

玩家飛機類

  • 1.在飛機基類中我們定義了一些共同的對象屬性,不同的對象屬性有圖像和原始位置,而且玩家飛機類對象還想擁有基類對象的屬性,所以需要調(diào)用Plane.__init__(self)函數(shù),通過這個函數(shù)就擁有了Plane基類的對象屬性bulletSleepTime、lastShootTime、bulletList。

    這里寫圖片描述

  • 2.玩家飛機通過鍵盤的上下左右控制飛機的位置


    這里寫圖片描述

敵人飛機類

1.jpg
  • 1.敵人飛機類中還多了速度對象屬性,考慮到隨著游戲難度的增加,敵人飛機速度越來越快,這個參數(shù)需要外界傳入。而且敵人飛機有小中大三種類型,是隨機的,起始的位置x軸也是隨機的,y軸固定從最上方開始。

    這里寫圖片描述

    用到了隨機數(shù)函數(shù),需要導入random模塊

    random.randint(1,3)
    

    其中用到了super(Enemy,self).__init__()與玩家類中的Plane.__init__(self)效果是相同的。direction對象屬性可以忽略,現(xiàn)在沒有用到。

  • 2.敵人的飛機不斷往下掉,改變self.y,其實不用判斷,direction沒有用到

    這里寫圖片描述

游戲初始化類(封裝功能)

  • 1.GameInit類創(chuàng)建了幾個類屬性,g_enemyList=[]列表用于存儲敵人飛機對象,初始化玩家對象hero=object,object是元類,和用于統(tǒng)計玩家分數(shù)的屬性score。

    這里寫圖片描述
  • 2.接下來定義了幾個類方法和靜態(tài)方法,用于封裝功能,在主函數(shù)里調(diào)用的都是這些類方法和靜態(tài)方法

    • 往敵機列表中添加敵機對象,忽略下我的代碼英語好像打錯了


      這里寫圖片描述
    • 創(chuàng)建玩家飛機對象


      這里寫圖片描述
    • 游戲初始化


      這里寫圖片描述
    • 玩家飛機對象處理鍵盤操作,在玩家飛機類中已經(jīng)定義了鍵盤處理函數(shù),這里再封裝一層


      這里寫圖片描述
    • 更新敵人飛機位置,敵人飛機對象都在g_enemyList列表中

      這里寫圖片描述

    • 有3種類型的對象需要描繪,玩家飛機對象,敵人飛機對象和導彈,這個函數(shù)就是用來描繪這些對象,其中導彈和敵機需要判斷哪些對象超出屏幕從列表中刪除,這里用了del函數(shù),記錄下索引值并從列表中刪除,同樣也可以用pop函數(shù),這里的j為索引值

      這里寫圖片描述

    • 玩家飛機對象發(fā)射子彈,同時也要判斷打中了敵機就讓敵機對象和和子彈對象同時從列表中刪除。通過pygame.Rect(self.image.get_rect())獲得矩形的值,但是只獲得了圖像的widthheight兩個屬性,前兩個屬性lefttop都為0,因此還需要設置這兩個屬性,然后通過collidetect判斷兩個矩形是否有相交處,其中索引值enemyIndexbulletIndex需要仔細分析下

      這里寫圖片描述

    • 判斷玩家飛機是否與敵機相撞判斷游戲是否結(jié)束


      這里寫圖片描述
  • 3.幾個靜態(tài)方法,靜態(tài)方法不需要cls這個參數(shù),通過類和實例都可以調(diào)用

    • 退出整個程序


      這里寫圖片描述
    • 進入游戲后可以按space鍵停止游戲,其實就是就是個死循壞,按鍵按下后跳出函數(shù)

      這里寫圖片描述

    • 游戲開始后和結(jié)束后把分數(shù)顯示出來,第一個參數(shù)是分數(shù),第二個參數(shù)是通過pygame的字體庫創(chuàng)建出來的,例如font = pygame.font.SysFont(None,64),參數(shù)分別為字體樣式和大小,可以選擇字體樣式例如arialsimsun(宋體),第三個參數(shù)是屏幕,第四和第五個參數(shù)是字體顯示的lefttop值。

      這里寫圖片描述

1,首先安裝pygame
sudo pip3 install pygame
2,驗證是否安裝pygame
python3 -m pygame.examples.aliens
如果安裝上那就完成下列步驟,完成飛機大戰(zhàn)項目:
項目準備
一. 使用 pygame 創(chuàng)建圖形窗口
二. 理解 圖像 并實現(xiàn)圖像繪制
三 理解 游戲循環(huán) 和 游戲時鐘
四. 理解 精靈 和 精靈組
一,創(chuàng)建圖形窗口
1.游戲的初始化和退出
切記
* 要使用 pygame 提供的所有功能之前,需要調(diào)用 init 方法
* 在游戲結(jié)束前需要調(diào)用一下 quit 方法

import pygame

導入并初始化所有 pygame 模塊,使用其他模塊之前,必須先調(diào)用 init 方法

pygame.init()

游戲代碼...

卸載所有 pygame 模塊,在游戲結(jié)束之前調(diào)用!

pygame.quit()
2.游戲中的坐標系

  • 坐標系

    • 原點 在 左上角 (0, 0)
    • x 軸 水平方向向 右,逐漸增加
    • y 軸 垂直方向向 下,逐漸增加

SCREEN_RECT = pygame.Rect(0, 0, 480,600)
依次是英雄的x,y軸,寬度和長度
3.創(chuàng)建游戲主窗口
pygame 專門提供了一個 模塊 pygame.display 用于創(chuàng)建、管理 游戲窗口

)初始化游戲顯示窗口

pygame.display.set_mode()

刷新屏幕內(nèi)容顯示,稍后使用

pygame.display.update()

主函數(shù)

  • 1.運行一個模塊,有if __name__ == 'main':標識,會直接運行里面的代碼。第一步初始化pygame庫,調(diào)用pygame.init(),第二步創(chuàng)建一個窗口與背景圖片一樣大:screen = pygame.display.set_mode((ScreenWidth,ScreenHeight),0,32),然后可以設置窗口標題:pygame.display.set_caption('飛機大戰(zhàn)'),第三步做一些初始化常量設置。其中紀錄了游戲開始的時間,因為按照我的思想游戲開始后難度會逐漸增加,我是通過時間來增加難度的

    這里寫圖片描述

    啟動時顯示start圖片,直到Enter鍵按下才進入游戲

  • 2.進入while 循壞后,調(diào)用游戲初始化類封裝好的函數(shù),通過時間間隔interval選定游戲困難模式,通過改變敵機刷新的時間和敵機的速度增加難度,游戲結(jié)束后,再次按下Enter 按鍵退出程序。這里存在一個bug,一旦游戲進行過程中按下Space暫停游戲,interval時間間隔仍然再計算(按道理應該讓時間暫停),再次按下Space恢復游戲后,當前模式設定時間減少了或者進入更困難模式了。

    這里寫圖片描述

1.jpg

game.py


import pygame
import random
SCREEN_RECT = pygame.Rect(0, 0, 480,600)


# 接下來我們就開始寫我們敵機方面的內(nèi)容 (產(chǎn)生敵機)
# 我先定義一個事件常量
CREATE_ENEMY_EVENT = pygame.USEREVENT

# 我們還可以定義一個事件常量 (發(fā)射子彈)
HERO_FIRE_EVENT = pygame.USEREVENT + 1

bg1 = pygame.image.load('./images/enemy0_down1.png')
bg2 = pygame.image.load('./images/enemy0_down2.png')
bg3 = pygame.image.load('./images/enemy0_down3.png')
bg4= pygame.image.load('./images/enemy0_down4.png')

#爆炸的精靈組
enemy1_down_group = pygame.sprite.Group()

#把爆炸圖片放到列表中
enemy1_down_surface = []
enemy1_down_surface.append(bg1)
enemy1_down_surface.append(bg2)
enemy1_down_surface.append(bg3)
enemy1_down_surface.append(bg4)


class GameSprite(pygame.sprite.Sprite):
    """游戲精靈的基礎類"""
    # 我們其實可以給我們的基礎類的速度 設置一個默認值
    def __init__(self,new_image,new_speed=1):
        super().__init__()
        # 我們需要以下3個屬性
        # 考慮到通用性  我們需要改造一下代碼
        # pygame.image.load pygame提供的方法 主要是加載圖片
        self.image = pygame.image.load(new_image)
        # self.image.get_rect() 獲取圖片的寬高 get_rect() 是pygame提供
        self.rect = self.image.get_rect()
        # 這是將來精靈的移動速度 精靈有:英雄精靈 背景精靈 敵機精靈 子彈精靈
        self.speed = new_speed

    def update(self):
        # 默認垂直方向移動 (這個時候我就要有一個概念 坐標系的y軸控制垂直
        self.rect.y += self.speed


# 那么以上就是我們游戲的基礎類 接下來我們需要設置我們的 背景類
# 首先我們需要先明確我們的背景類  繼承自我們的游戲精靈類
class Background(GameSprite):
    """背景精靈類"""
    def __init__(self,is_alt=False):
        """is_alt 判斷是否為另外一張圖像
        False表示第一張圖像 
        True表示另外一張圖像     我們最開始說了  我們是2張圖像交替
        在這里我先設置一下 vim快捷鍵
        """
        # 因為背景圖片是固定的  所以我們可以在背景精靈類直接傳圖片
        super().__init__('./images/background.png')
        if is_alt:
            # 如果是地二張圖片 我們讓他的初始位置為 -self.rect.height
            self.rect.y = -self.rect.height

    def update(self):
        # 1 調(diào)用父類的方法實現(xiàn) 這是實現(xiàn)父類方法
        super().update()
        # 2 判斷是否移除屏幕 如果移出屏幕 我們就要將圖像設置到屏幕到上方
        # SCREEN_RECT.height 這是我們自己設置的常量  我們可以往上看
        # 其實到這一步 我們就已經(jīng)把我們的背景類設計完了 接下來我們就去我們的主程序模塊調(diào)用就行了
        if self.rect.y >= SCREEN_RECT.height:
            self.rect.y = -self.rect.height

# 接下來我們就要設置我們的敵機類
# 我們的敵機類 同樣也是繼承自我們的精靈基類
class Enemy(GameSprite):
    """敵機精靈類"""
    def __init__(self):
        # 1 調(diào)用父類方法 創(chuàng)建敵機精靈類 并且指定敵機圖像
        super().__init__('./images/enemy1.png')
        # 2 設置敵機初始速度 稍后設置 (隨機數(shù))
        self.speed = random.randint(1, 3)
        # 3 設置敵機的隨機初始位置 稍后設置
        # self.rect.y  = self.rect.bottom - self.rect.height
        self.rect.bottom = 0
        # 敵機x軸最大值 需要用屏幕的寬度-敵機自身的寬度
        max_x = SCREEN_RECT.width - self.rect.width
        # 隨機一個位置
        self.rect.x = random.randint(0, max_x)


        # 我們發(fā)現(xiàn)。。。。。敵機出來的位置在 一條線上
        # 說明  x軸的位置一直沒有變 

        def update(self):
            # 1 調(diào)用父類方法
            super().update()

            # 2 判斷是否飛出屏幕 如果是 需要敵機從精靈組刪除
            if self.rect.y >= SCREEN_RECT.height:
                print("敵機飛出屏幕")
                # 移出屏幕  就銷毀
                self.kill()
# 接下來我們就設計英雄類和子彈類

# 英雄精靈類
class Hero(GameSprite):
    """英雄精靈類"""
    def __init__(self,a):
        # 英雄的初始速度我設置為0
        super().__init__('./images/plane.png',0)

        # 設置初始位置 這是是讓我英雄X軸的中心點等于屏幕X軸中心點
        self.rect.centerx = SCREEN_RECT.centerx + a
        # 這里是設置我飛機的y軸
        self.rect.bottom = SCREEN_RECT.bottom 

        # 子彈組
        self.bullets = pygame.sprite.Group()
        # 這樣 我們的子彈精靈組 就創(chuàng)建完畢了 我們就要去fire里面修改我們的
        # 方法
        self.speed1 = 0

    def update(self):
        # 飛機水平移動
        self.rect.x += self.speed
        self.rect.y += self.speed1
        # 控制英雄邊界 屏幕邊界
        if self.rect.left < 0:
            self.rect.left = 0
        if self.rect.right >SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right
        if self.rect.bottom > SCREEN_RECT.height:
            self.rect.bottom = SCREEN_RECT.height
        if self.rect.top < 0:
            self.rect.top = 0
    def fire(self):
        # 英雄的方法。。。發(fā)射子彈  是一個動作  是一個行為 。。。
        print("發(fā)射子彈....")

        for i in (1,2,3):
            # 子彈精靈 我們在 英雄的這個fire()方法里面去創(chuàng)建
            #1 創(chuàng)建 子彈精靈
            bullet = Bullet()
            gws = Bullet()
            sst = Bullet()
            #2 設置精靈位置
            bullet.rect.bottom = self.rect.y -20
            bullet.rect.centerx = self.rect.centerx
            gws.rect.bottom = self.rect.y -20
            gws.rect.centerx = self.rect.centerx +15
            sst.rect.bottom = self.rect.y -20
            sst.rect.centerx = self.rect.centerx -15
            #3 將精靈添加到精靈組
            
            self.bullets.add(bullet,gws,sst)


class Bullet(GameSprite):
    """子彈精靈"""
    def __init__(self):
        super().__init__('./images/bullet1.png',-20)
    def update(self):
        super().update()
        # 判斷是否超出屏幕
        if self.rect.bottom < 0:
            self.kill()

飛機大戰(zhàn).py

import pygame
from game import *
pygame.mixer.init()
#pygame.mixer.music.load('/home/share/MC天佑 - 又.mp3')
#pygame.mixer.music.play()
class PlaneGame(object):
    """飛機大戰(zhàn)主游戲類"""
    # 初始化方法

    def __init__(self):
        print("游戲初始化")
        """在開始游戲我們做這么幾件事
        1 創(chuàng)建游戲窗口
        2 創(chuàng)建游戲時鐘
        3 調(diào)用創(chuàng)建精靈和精靈組的方法 (私有方法)
        """
        self.screen = pygame.display.set_mode(SCREEN_RECT.size)
        self.clock = pygame.time.Clock()
        
        self.__create_sprites()
        pygame.time.set_timer(CREATE_ENEMY_EVENT, 1000)

    def start_game(self):
        """在開始游戲這里我們需要做下面幾件事"""
        while True:
            # 1 設置幀率
            self.clock.tick(10)
            # 2 事件監(jiān)聽 主要是要監(jiān)聽我們鼠標 鍵盤的一些事件
            self.__event_handler()
            # 3 碰撞檢測 碰撞檢測的內(nèi)容比較  在這里我還沒有定義 現(xiàn)在需要補上
            self.__check_collide()
            # 4 更新精靈和精靈組
            self.__update_sprites()
            # 5  更新顯示
            pygame.display.update()
            # 在上面  我們調(diào)用類方法 并且關于幀率的設置
            # 更新精靈組 碰撞檢測 刷新屏幕這些事情 是要實時檢測的
            # 所以我寫在游戲循環(huán)里面
            # 沒1/60秒 就會調(diào)用一次

    # 創(chuàng)建精靈和精靈組
    def __create_sprites(self):
        bg1 = Background()
        # True 就表示是第二張圖片
        bg2 = Background(True)
        # 英雄
        self.hero = Hero(10)
        self.hero1 = Hero(10)
        self.back_group = pygame.sprite.Group(bg1, bg2)
        # 敵機組
        self.enemy_group = pygame.sprite.Group()
        # 英雄組
        self.hero_group = pygame.sprite.Group(self.hero,self.hero1)

    # 事件監(jiān)聽
    def __event_handler(self):

        # 在這里我先寫 事件監(jiān)聽  為啥呢?在調(diào)試過程中我好關閉窗口呀
        for event in pygame.event.get():
            # 另外一個方案 返回按鍵元組  這個我們觀察一下就知道了
            # 如果 某個按鍵按下 對應的值應該會是
            key_pressed = pygame.key.get_pressed()
            key_pressed1 = pygame.key.get_pressed()
            if key_pressed[pygame.K_KP1]:
                self.hero.fire()
            if key_pressed[pygame.K_RIGHT]:
                print("向右邊移動")
                # 給英雄一個移動速度
                self.hero.speed = 15
            elif key_pressed[pygame.K_LEFT]:
                self.hero.speed = -15
                print("向左邊移動")

            elif key_pressed[pygame.K_UP]:
                print("向上邊移動")
                self.hero.speed1 = -15
            elif key_pressed[pygame.K_DOWN]:
                print("想下邊移動")
                self.hero.speed1 = 15
            else:
                self.hero.speed = 0
                self.hero.speed1 = 0
            # pygame.event.get():這是 獲取到我們所有的事件
            if event.type == pygame.QUIT:

                # 在開發(fā)的過程中需要  有這種思想 專門的事情由專門的方法去做
                self.__game_over()
                # 去創(chuàng)建敵機  因為我的目的 就是每秒創(chuàng)建一家敵機
            elif event.type == CREATE_ENEMY_EVENT:
                # 因為我的敵機精靈類還沒有寫
                # 看看有沒有出錯  看看是不是每秒調(diào)用一次
                print("新的敵機產(chǎn)生")
                # 我們添加了敵機  但是但是但是
                # 沒有刷新呀!
                self.enemy_group.add(Enemy())
            if key_pressed1[pygame.K_SPACE]:
                self.hero1.fire()
            if key_pressed1[pygame.K_d]:
                print("向右邊移動")
                # 給英雄一個移動速度
                self.hero1.speed = 8
            elif key_pressed1[pygame.K_a]:
                self.hero1.speed = -8
                print("向左邊移動")

            elif key_pressed1[pygame.K_w]:
                print("向上邊移動")
                self.hero1.speed1 = -8

            elif key_pressed1[pygame.K_s]:
                print("想下邊移動")
                self.hero1.speed1 = 8
            else:
                self.hero1.speed = 0
                self.hero1.speed1 = 0

    # 更新精靈和精靈組
    def __update_sprites(self):
        """更新精靈組"""

        #  到這里我們就可以簡寫代碼了 改造 看了比較清爽
        for xxx in [self.back_group, self.enemy_group, self.hero_group, self.hero.bullets, self.hero1.bullets]:
            xxx.update()
            xxx.draw(self.screen)

    def __check_collide(self):
        # 地三個參數(shù)為 Ture的時候 就是當碰撞的時候 被碰撞的精靈從精靈組移出
        pygame.sprite.groupcollide(
            self.enemy_group, self.hero.bullets,True, True)
        # 2 敵機撞毀飛機
        enemies = pygame.sprite.spritecollide(
            self.hero, self.enemy_group, True)
        pygame.sprite.groupcollide(
            self.enemy_group, self.hero1.bullets, True, True)
        enemies1 = pygame.sprite.spritecollide(
            self.hero1, self.enemy_group, True)
        # 判斷列表時候有內(nèi)容
        if len(enemies) == 1:
            # 讓英雄犧牲
            self.hero.rect.x = -SCREEN_RECT.width
        if len(enemies1) == 1:
            
            self.hero1.kill()
            self.hero1.rect.x = -SCREEN_RECT.width
        if self.hero.rect.x == -SCREEN_RECT.width and self.hero1.rect.x == -SCREEN_RECT.width:
            # 結(jié)束游戲
            self.__game_over()

    def __game_over(self):
        """游戲結(jié)束"""
        print("游戲結(jié)束")
        # 這是pygame提供的卸載模塊的功能
        pygame.quit()
        # 這是python本身提供的退出腳本的功能
        exit()
        # 總結(jié) :我們需要先卸載我們的pygame模塊  然后退出我們的腳本



# 這個方法就是在我當前方法內(nèi)生效 在其他模塊調(diào)不到
if __name__ == "__main__":
    # 創(chuàng)建游戲?qū)ο?    game = PlaneGame()
    # 開始游戲
    game.start_game()

最后,我想說 :顯然,程序員的生活是很枯燥的

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容