500行程式碼,教你用python寫個微信飛機大戰

上海小胖發表於2019-10-15

在這裡插入圖片描述

這幾天在重溫微信小遊戲的飛機大戰,玩著玩著就在思考人生了,這飛機大戰怎麼就可以做的那麼好,操作簡單,簡單上手。

幫助蹲廁族、YP族、飯圈女孩在無聊之餘可以有一樣東西讓他們振作起來!讓他們的左手 / 右手有節奏有韻律的朝著同一個方向來回移動起來!

這是史詩級的發明,是濃墨重彩的一筆,是……

在一陣抽搐後,我結束了遊戲,瞬時覺得一切都索然無味,正在我進入賢者模式時,突然想到,如果我可以讓更多人已不同的方式體會到這種美輪美奐的感覺豈不美哉?

所以我開啟電腦,建立了一個 plan_game.py……

先看效果圖

在這裡插入圖片描述

操作環境

  • 作業系統:windows10
  • python版本:python 3.7
  • 程式碼編輯器:pycharm 2018.2
  • 使用模組:os,sys,random,pygame

因為實現程式碼使用到了一個pygame的第三方模組,沒有的先 pip install 一下,這裡順便提供一個比較好的pygame的教程.

https://eyehere.net/2011/python-pygame-novice-professional-index/

具體實現

  1. 首先我們先指定素材檔案的檔案目錄.方便我們後面的使用。這些素材已經全部上傳至公眾號Python專欄,後臺回覆:飛機大戰,即可獲得。
import os

# 得到當前資料夾下面的material_images目錄的路徑
source_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'material_images')
  1. 實現一個Game類,用來完成這個遊戲的主要邏輯。
import pygame


class Game():
    def __init__(self, background_image_path, size=(480, 700), title='飛機大戰', font_name='方正舒體', font_size=30, speed=2000):
        '''
        :param background_image_path: 背景圖片的路徑地址
        :param size: 遊戲視窗的大小
        :param title: 遊戲視窗的標題
        :param font_name: 指定字型
        :param font_size: 指定字型大小
        :param speed: 背景圖滾動整個視窗一次所用時間,單位為ms
        '''
        self.size = size
        self.screen = pygame.display.set_mode(size)
        self.title = title
        self.background_image_path = background_image_path
        self.background = pygame.image.load(self.background_image_path).convert()
        # 設定字型物件,得到系統中自帶的字型
        self.font = pygame.font.SysFont(font_name, font_size)
        # 得到Clock物件,我們可以使用它來獲取距離上次繪製影象的時間
        self.clock = pygame.time.Clock()
        # 背景圖初始位置
        self.height = 0
        # 使用視窗的高度處於滾動的時間,就能得到每ms滾動的距離
        self.every_ms_move_distance = self.size[1] / speed   # 2秒
        # 分數
        self.score = 0
        # 存放所有的敵機
        self.enemies = []


    def show_score(self):
        '''
        顯示分數, 在視窗的的最上方距離上邊距10px, 左右居中
        '''
        pass


    def set_time_passed(self):
        # 控制畫 的幀, 越大越快
        # 得到上一次繪製影象到到現在的時間, ms
        self.time_passed = self.clock.tick()


    def draw_background(self):
        '''
        繪製背景圖片,一直向下滾動,營造飛機一直往上面飛的感覺
        '''
        # 每次移動的距離 = 每ms移動的距離 * 上次到現在的時間(ms)
        pass


    def create_enemy(self, image_path=os.path.join(source_dir,'enemy1.png'), enemy_number=5):
        '''
        建立敵機
        :param image_path: 敵機的圖片地址
        :param enemy_number: 最多有幾個敵機在螢幕上
        '''
        pass


    def draw_enemies(self, time_passed, screen):
        '''
        繪製敵機到螢幕上,清理跑出視窗的敵機,
        :param time_passed: 上次繪製導向現在經過的時間
        :param screen: 繪製的視窗物件
        '''
        pass


    def bullet_and_enemy_crash_detection(self, bullets):
        '''
        檢測子彈是否擊中敵機
        :param bullets: 飛機的所有子彈
        '''
        pass


    def plan_and_enemy_crash_detection(self, plan, allow_crash_size=None):
        '''
        檢測敵機與飛機是否相撞
        :param plan: 飛機物件
        :param allow_crash_size: 允許飛機碰撞的大小,只有左右有效
        '''
        pass


    def draw_plan(self, plan, time_passed):
        '''
        繪製飛機
        :param plan: 飛機物件
        :param time_passed: 距離上次繪製的時間
        :return:
        '''
        pass


    def game_over(self):
        '''
        遊戲結束
        '''
        while True:
            # 繪製背景圖
            pass


    def run(self):
        '''
        遊戲入口函式,開始函式,主體函式
        :return:
        '''

        # 設定遊戲視窗的大小
        pygame.display.set_caption(self.title)
        # 初始化一個飛機物件
        plan = Plan()

        while True:
            # 如果飛機自毀完成, 遊戲結束, 呼叫game_over函式
            pass

            # 檢測監聽事件
            pass

            # 檢測上下左右的移動案件.
            # w,a,s,d 和 上,下,左,右鍵都可以
            # 然後執行plan.update函式,改變飛機的位置
            pass

            # 子彈和敵機的碰撞檢測
            self.bullet_and_enemy_crash_detection(plan.bullets)
            # 飛機與敵機的碰撞檢測
            self.plan_and_enemy_crash_detection(plan)
            # 設定屬性time_passed的值, 距離上次的時間,方便後面使用
            self.set_time_passed()
            # 繪製背景圖片
            self.draw_background()
            # 顯示分數
            self.show_score()
            # 生成敵機
            self.create_enemy()
            # 繪製敵機
            self.draw_enemies(time_passed=self.time_passed, screen=self.screen)
            # 繪製飛機
            self.draw_plan(plan=plan, time_passed=self.time_passed)
            # 繪製子彈
            plan.draw_bullets(time_passed=self.time_passed, screen=self.screen)
            # 顯示我們的影象
            pygame.display.update()

這裡說以下怎樣檢視自己的系統中有哪些自帶的字型.
pygame.font.get_fonts(),這個函式就能夠得到系統中所有的自帶字型檔案。不過,當我們遊戲中有中文的時候,我們也得選擇支援中文的字型,否則的話是顯示不出中文的。

在這裡插入圖片描述

  1. 實現DestroyAnimationMixin類,這個類主要是用來顯示飛機或敵機的自毀動畫
# 顯示飛機自毀動畫的Mixin類, 可用於飛機和敵機的自毀動畫顯示
class DestroyAnimationMixin():

    def show_destroy_animation(self, time_passed, destroy_time=200):
        '''
        顯示自毀動畫
        動畫其實就是幾張圖片切換的比較快,我們的眼睛識別不出來,所以認為他是動態的,也就是動畫
        :param time_passed: 距離上次繪製影象到現在的時間,單位ms
        :param destroy_time: 自毀動畫總共顯示時間,單位ms
        '''

        # 因為我們的自毀圖片有四張,需要依次顯示,首先動畫的效果
        # self.destroy_image_position 表示第幾章自毀圖片,從零開始
        # 如果大於等於4了,說明自毀動畫顯示完成,設定self.destroyed變數為True, 方便別處呼叫
        if self.destroy_image_position >= 4:
            self.destroyed = True
            return

        # 依次載入自毀圖片
        if self.time_passed >= destroy_time / 4:
            self.image = pygame.image.load(os.path.join(source_dir, self.destroy_images[self.destroy_image_position])).convert_alpha()
            self.destroy_image_position += 1
            self.time_passed = 0
        else:
            self.time_passed += time_passed

在這裡插入圖片描述

  1. 實現飛機類,完成飛機的主要操作。飛機的操作包括:飛機位置、飛機子彈、發射子彈等。
# 飛機類,繼承DestroyAnimationMixin, 方便使用顯示自毀動畫的函式
class Plan(DestroyAnimationMixin):
    def __init__(self, image_path=os.path.join(source_dir,'plan.png'), background_size=(480, 700)):
        '''
        :param image_path: 飛機圖片地址
        :param background_size: 遊戲視窗大小
        '''
        self.background_size = background_size
        self.image = pygame.image.load(image_path).convert_alpha()
        self.image_size = self.image.get_size()
        self.position = [(background_size[0]-self.image_size[0]) / 2, 500]
        # 飛機每次移動的距離
        self.every_time_move_distance = 0.5
        # 飛機的子彈
        self.bullets = []
        # destroy association attributes, 自毀相關屬性
        # 開始自毀
        self.start_destroy = False
        # 自毀結束
        self.destroyed = False
        # 自毀圖片
        self.destroy_images = ['me_destroy_1.png', 'me_destroy_2.png', 'me_destroy_3.png', 'me_destroy_4.png']
        # 自毀圖片位置
        self.destroy_image_position = 0
        # 距離上次繪製影象到現在的時間
        self.time_passed = 0

    def update(self, direction):
        '''
        更新飛機位置
        :param direction: 飛機移動方向
        '''
        pass

    def shut(self, image_path=os.path.join(source_dir,'bullet.png')):
        '''
        飛機發射子彈
        :param image_path: 子彈圖片
        '''
        pass

    def draw_bullets(self, time_passed, screen):
        '''
        繪製飛機的所有子彈
        :param time_passed: 距離上次繪製影象到現在的時間
        :param screen: 繪製到哪一個視窗中
        '''
        pass

在這裡插入圖片描述

  1. 實現敵機類,完成敵機的主要操作。主要是用來更新位置。
# 敵機類,繼承DestroyAnimationMixin, 方便使用顯示自毀動畫的函式
class Enemy(DestroyAnimationMixin):
    def __init__(self, image_path=os.path.join(source_dir, 'enemy1.png'), speed=2000, background_size=(480, 700)):
        '''
        :param image_path: 敵機圖片地址
        :param speed: 敵機移動整個視窗需要的時間,單位ms,也就是速度
        :param background_size: 遊戲視窗的尺寸
        '''
        self.image = pygame.image.load(image_path).convert_alpha()
        self.speed = background_size[1] / speed
        self.background_size = background_size
        self.position = [random.randint(0, background_size[0]-self.image.get_size()[0]), -self.image.get_size()[1]]
        # 開始自毀
        self.start_destroy = False
        # 自毀完成
        self.destroyed = False
        # 自毀圖片路徑
        self.destroy_images = ['enemy1_down1.png', 'enemy1_down2.png', 'enemy1_down3.png', 'enemy1_down3.png']
        # 距離上次繪製影象到現在的時間
        self.time_passed = 0
        # 自毀圖片在self.destroy_images的位置
        self.destroy_image_position = 0

    def update(self, time_passed):
        '''
        更新敵機的位置
        :param time_passed: 距離上次繪製影象到現在的時間
        :return:
        '''
        pass
  1. 實現子彈類,完成子彈的主要操作
# 飛機子彈類
class Bullet():
    def __init__(self, image_path=os.path.join(source_dir,'bullet.png'), background_size=(480, 700), plan=None, speed=1000):
        '''
        :param image_path: 子彈的圖片地址
        :param background_size: 遊戲視窗大小
        :param plan: 飛機物件
        :param speed: 子彈飛行速度
        '''
        self.image = pygame.image.load(image_path).convert_alpha()
        self.background_size = background_size
        self.speed = background_size[1] / speed
        # 子彈是否擊中敵機
        self.destroyed = False
        self.position = self._get_position(plan)

    def _get_position(self, plan):
        '''
        根據plan得到子彈發出位置
        :param plan: 飛機物件
        '''
        bullet_size = self.image.get_size()
        plan_width = plan.image_size[0]
        x = (plan_width-bullet_size[0]) / 2
        return [plan.position[0] + x, plan.position[1]]

    def update(self, time_passed):
        '''
        改變子彈位置
        :param time_passed: 距離上次繪製影象到現在的時間
        '''
        # 如果子彈超出螢幕或者擊中敵機,就設定self.position[1]為-100,在plan.draw的時候就移除它
        if self.position[1] + self.image.get_size()[1] <= 0 or self.destroyed:
            self.position[1] = -100
            return

        # 改變的距離 = 時間 * 速率
        self.position[1] -= time_passed * self.speed

在這裡插入圖片描述

這樣,我們就把所有的操作都實現完了,接下來只需要使用 Game().run(),就可以執行我們的遊戲了。

關注公眾號:Python專欄,後臺回覆:飛機大戰,即可獲得完整程式碼及素材包。

500行程式碼,教你用python寫個微信飛機大戰

相關文章