首頁>Club>
8
回覆列表
  • 1 # IT培訓觀察

    python 專案:DIY 街機遊戲

    這個練習是一個小遊戲程式,如果要是給它起個名字的話,應該叫:快躲,香蕉。 主要的遊戲內容就是,遊戲開始會從螢幕上方不斷隨便的掉一些鐵塊,在螢幕下 方有一個小香蕉是受你控制的,你需要不斷的左右移動來躲避鐵塊。在你躲避完 一定數量的鐵塊之後,就會進入下一關。下一關依然是讓你躲鐵塊,不過鐵塊下 降的速度就快了很多。在遊戲中你可以按下任意鍵暫停,再次按則繼續,按下 ESC 鍵退出。這就是全部的功能了,下面我們來看遊戲的實現。

    首先對所有程式碼分類:

    1、整體上程式碼有一個配置模組,來對遊戲的速度、螢幕 的寬度、香蕉移動速度、字型大小、各個物體的圖片等進行配置。

    2、然後是有 一個元素模組,即遊戲中的兩個元素落下來的鐵塊以及被砸的香蕉,其中還要包 含他們具有的行為。

    3、然後還有遊戲中的各種狀態模組,狀態模組中的類繼承 關係稍微多一些,處於家譜最上方的就是 state 類,由它來衍生其他的所有狀態, 它的直接子類是 Level 和 Pause,其中 Pause 有衍生出子類 Info、levelCleared、 GameOver、StartUp。

    4、最後就是遊戲的主模組,用來讓其他模組協調工作 的。

    然後再來看一個整體圖:

    有了上面整體的認識,下面就要細揪一下了。我自己看程式碼的方法是這樣的,首先整體分析,然後在從程式的入口點開始分析。我估計大多數人也是這麼做的。

    首先是 squish.py 檔案中的 game 類:

    class Game:

    def init (self,*args):

    path = os.path.abspath(args[0])

    dir = os.path.split(path)[0]

    os.chdir(dir)

    self.state = None

    self.nextState = StartUp()

    def run(self):

    pygame.init()

    flag = 0

    if config.full_screen:

    flag = FULLSCREEN

    screen_size = config.screen_size

    screen = pygame.display.set_mode(screen_size,flag)

    pygame.display.set_caption("Fruit Self Defense")

    pygame.mouse.set_visible(False)

    while True:

    if self.state != self.nextState:

    self.state = self.nextState

    self.state.firstDisplay(screen)

    for event in pygame.event.get():

    self.state.handle(event)

    self.state.update(self)

    self.state.display(screen)

    if name == " main ":

    game = Game(*sys.argv)

    game.run()

    忽略掉 init 中的設定程式碼,在 run 中,該管理類首先呼叫 pygame 初始化並啟動遊戲介面,然後在一個 whileTrue 的死迴圈中不斷的進行狀態判斷,事件處理,然後根據事件更新當前狀態,並且繪製介面。

    讓我們把焦點放在那個死迴圈中,因為他就是整個程式的流程所在。 其中狀態和事件的關係就是,當發生某一事件之後,狀態就會發生變化,比如點選事件、過關事件、死亡事件。這些事件的來源分別是:使用者操作、系統判斷、系統判斷。要繼續深入分析就需要再拿一部分程式碼出來。

    依然是來自 squish.py 檔案中剩餘的所有程式碼:

    import os, sys, pygame

    from pygame.locals import *

    import objects, config

    class State:

    def handle(self,event):

    if event.type == QUIT:

    sys.exit()

    if event.type == KEYDOWN and event.key == K_ESCAPE:

    sys.exit()

    def firstDisplay(self, screen):

    screen.fill(config.background_color)

    pygame.display.flip()

    def display(self, screen):

    pass

    class Level(State):

    def init (self,number=1):

    self.number = number

    self.remaining = config.weights_per_level

    speed = config.drop_speed

    speed += (self.number - 1) * config.speed_increase

    self.weight = objects.Weight(speed)

    self.banana = objects.Banana()

    both = self.weight,self.banana

    self.sprites = pygame.sprite.RenderUpdates(both)

    def update(self, game):

    self.sprites.update()

    if self.banana.touches(self.weight):

    game.nextState = GameOver()

    elif self.weight.landed:

    self.weight.reset()

    self.remaining -= 1

    if self.remaining == 0:

    game.nextState = LevelCleared(self.number)

    def display(self, screen):

    screen.fill(config.background_color)

    updates = self.sprites.draw(screen)

    pygame.display.update(updates)

    class Paused(State ):

    finished = 0

    image = None

    text = ""

    def handle(self, event):

    State.handle(self, event)

    if event.type in [MOUSEBUTTONDOWN,KEYDOWN]:

    self.finished = 1

    def update(self, game):

    if self.finished:

    game.nextState = self.nextState()

    def firstDisplay(self, screen):

    screen.fill(config.background_color)

    font = pygame.font.Font(None, config.font_size)

    lines = self.text.strip().splitlines()

    height = len(lines) * font.get_linesize()

    center,top = screen.get_rect().center

    top -= height // 2

    if self.image:

    image = pygame.image.load(self.image).convert()

    r = image.get_rect()

    top += r.height // 2

    r.midbottom = center, top -20

    screen.blit(image, r)

    antialias = 1

    black = 0,0,0

    for line in lines:

    text = font.render(line.strip(),antialias,black)

    r = text.get_rect()

    r.midtop = center,top

    screen.blit(text, r)

    top += font.get_linesize()

    pygame.display.flip()

    class Info(Paused):

    nextState = Level

    text = """

    In this game you are a banana,

    trying to survive a course in

    self-defense against fruit,where the

    participants will "defend" themselves

    against you with a 16 ton weight."""

    class StartUp(Paused):

    nextState = Info

    image = config.splash_image

    text = """

    Welcome to Squish.

    the game of Fruit Self-Defense"""

    class LevelCleared(Paused):

    def init (self, number):

    self.number = number

    self.text = """Level %i cleared

    Click to start next level""" % self.number

    def nextState(self):

    return Level(self.number + 1)

    class GameOver(Paused):

    nextState = Level

    text = """

    Game Over

    Click to Restart, Esc to Quit"""

    其中使用者判斷部分就是 Paused 類中的 update 方法和 handle 方法,而系統判斷就是 Level 類中的 update 方法。還有一個要注意的地方就是 Level 類中update 方法中的第一行程式碼:self.sprites.update(),這是讓鐵塊不斷下落的關鍵程式碼。使用者判斷部分的程式碼已經有了,下面需要貼上系統判斷時用到的程式碼.

    objects.py 中的程式碼:

    import pygame,config,os

    from random import randrange

    class SquishSprite(pygame.sprite.Sprite):

    def init (self, image):

    pygame.sprite.Sprite. init (self)

    self.image = pygame.image.load(image).convert()

    self.rect = self.image.get_rect()

    screen = pygame.display.get_surface()

    shrink = -config.margin*2

    self.area = screen.get_rect().inflate(shrink,shrink)

    class Weight(SquishSprite):

    def init (self, speed):

    SquishSprite. init (self,config.weight_image)

    self.speed = speed

    self.reset()

    def reset(self):

    x = randrange(self.area.left, self.area.right)

    self.rect.midbottom = x, 0

    def update(self):

    self.rect.top += self.speed

    self.landed = self.rect.top >= self.area.bottom

    class Banana(SquishSprite):

    def init (self):

    SquishSprite. init (self, config.banana_image)

    self.rect.bottom = self.area.bottom

    self.pad_top = config.banana_pad_top

    self.pad_side = config.banana_pad_side

    def update(self):

    self.rect.centerx = pygame.mouse.get_pos()[0]

    self.rect = self.rect.clamp(self.area)

    def touches(self, other):

    bounds = self.rect.inflate(-self.pad_side,-self.pad_top)

    bounds.bottom = self.rect.bottom

    return bounds.colliderect(other.rect)

    在類 Banana 和 Weight 中的 update 和 touches 方法,用於進行系統判斷。好了,到這主要的東西都分析完了,剩下的只需要稍看一下就能夠懂得了。 最後還有一個配置模組的程式碼 config.py:banana_image = "banana.png"weight_image = "weight.png"splash_image = "weight.png"screen_size = 800,600background_color = 255,255,255margin = 30full_screen = 1font_size = 48drop_speed = 1banana_speed = 10speed_increase = 1weights_per_level = 10banana_pad_top = 40banana_pad_side = 20

    到此為止,《python 基礎教程》中的十個專案都已經分析了一遍,下一步要做的就是做幾個實用軟體出來,然後把 python 再好好深入研究下。

    應曉勇要求,上幾個執行圖:

  • 2 # 四川點贊哥

    作業系統:Win10,語言版本:python3.7,IDE:VSCode,需要引入的模組:PIL(用於影象的處理),pymouse(用於控制滑鼠點選),numpy(用於構造數字矩陣),win32gui(用於切換遊戲視窗)。模組的安裝很簡單,直接在命令列裡用“pip install 模組名”就可以了,需要注意的是PIL只支援到python2.7,python3+用“pip install pillow”安裝。之所以選擇VSCode作為開發工具,是因為它比jupyter notebook更強大,比PyCharm更輕量,保準你用過之後就會愛上它。

  • 中秋節和大豐收的關聯?
  • 2018/2019年度玉米產需缺口擴大至3331萬噸,是否意味著2019年玉米價格有上漲空間?