500行代碼,教你用Python寫個微信飛機大戰
這幾天在重溫微信小游戲的飛機大戰,玩著玩著就在思考人生了,這飛機大戰怎么就可以做的那么好,操作簡單,簡單上手。
幫助蹲廁族、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/
具體實現
首先我們先指定素材文件的文件目錄.方便我們后面的使用。
- import os
- # 得到當前文件夾下面的material_images目錄的路徑
- source_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'material_images')
實現一個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(),這個函數就能夠得到系統中所有的自帶字體文件。不過,當我們游戲中有中文的時候,我們也得選擇支持中文的字體,否則的話是顯示不出中文的。
實現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
實現飛機類,完成飛機的主要操作。飛機的操作包括:飛機位置、飛機子彈、發射子彈等。
- # 飛機類,繼承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
實現敵機類,完成敵機的主要操作。主要是用來更新位置。
- # 敵機類,繼承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
實現子彈類,完成子彈的主要操作
- # 飛機子彈類
- 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(),就可以運行我們的游戲了。