遊戲技術相關研究

2017年10月15日 星期日

【python】初體驗-打磚塊遊戲

上午8:07 Posted by Channel Chung 4 comments
Python。。是的,這次要來玩的就是Python了,礙於每天看一些程式技術網站這個語言出現率非很高,所以就新起了一探究竟的慾望,廢話不多說,直接至Python官網下載安裝包,一路Next後安裝完成,接下開始填寫第一支測試程式Hello World。。。

>>> print ("Hello World!!")


打完收工。。。喂!!給我認真一點啦!!

好啦,那就依照慣例來個打磚塊遊戲好了,google了一下發現大家在Python上寫2D Game幾乎都是用pygame套件,那我們一樣也用這套件來寫這次的主角打磚塊遊戲好了,首先用pip安裝pygame套件,請在命令列輸入以下指令:

pip install pygame 

安裝完畢後就可以開啟您習慣的編輯器鍵入程式碼:
將以下程式碼存成play.py檔名
# encoding: utf-8

import os, sys, random
import pygame 
from pygame.locals import *

from drew import *

# 視窗大小.
canvas_width = 800
canvas_height = 600

# 顏色.
block = (0,0,0)

# 磚塊數量串列.
bricks_list = []

# 移動速度.
dx =  8
dy = -8

# 遊戲狀態.
# 0:等待開球
# 1:遊戲進行中
game_mode = 0

#-------------------------------------------------------------------------
# 函數:秀字.
#-------------------------------------------------------------------------
def showFont( text, x, y):
    global canvas    
    text = font.render(text, 1, (255, 0, 0)) 
    canvas.blit( text, (x,y))

#-------------------------------------------------------------------------
# 函數:碰撞判斷.
#   x       : x 
#   y       : y 
#   boxRect : 矩形
#-------------------------------------------------------------------------
def isCollision( x, y, boxRect):
    if (x >= boxRect[0] and x <= boxRect[0] + boxRect[2] and y >= boxRect[1] and y <= boxRect[1] + boxRect[3]):
        return True;          
    return False;  

#-------------------------------------------------------------------------
# 函數:初始遊戲.
#-------------------------------------------------------------------------
def resetGame():
    # 宣告使用全域變數.
    global game_mode, brick_num, bricks_list, dx, dy

    # 磚塊
    for bricks in bricks_list:
        # 亂數磚塊顏色
        r = random.randint(100,200)
        g = random.randint(100,200)
        b = random.randint(100,200)
        bricks.color = [r,g,b]        
        # 開啟磚塊.
        bricks.visivle = True
    # 0:等待開球
    game_mode = 0
    # 磚塊數量.
    brick_num = 99    
    # 移動速度.
    dx =  8
    dy = -8

# 初始.
pygame.init()
# 顯示Title.
pygame.display.set_caption(u"打磚塊遊戲")
# 建立畫佈大小.
canvas = pygame.display.set_mode((canvas_width, canvas_height))
# 時脈.
clock = pygame.time.Clock()

# 設定字型-黑體.
font = pygame.font.SysFont('simhei', 18)

# 底板.
paddle_x = 0
paddle_y = (canvas_height - 48)
paddle = Box(pygame, canvas, "paddle", [paddle_x, paddle_y, 100, 24], (255,255,255))

# 球.
ball_x = paddle_x
ball_y = paddle_y
ball   = Circle(pygame, canvas, "ball", [ball_x, ball_x], 8, (255,255,255))

# 建立磚塊
brick_num = 0
brick_x = 70
brick_y = 60
brick_w = 0
brick_h = 0
for i in range( 0, 99):
    if((i % 11)==0):
        brick_w = 0
        brick_h = brick_h + 18        
    bricks_list.append (Box(pygame, canvas, "brick_"+str(i), [  brick_w + brick_x, brick_h+ brick_y, 58, 16], [255,255,255]))
    brick_w = brick_w + 60
# 初始遊戲.
resetGame()

#-------------------------------------------------------------------------    
# 主迴圈.
#-------------------------------------------------------------------------
running = True
while running:
    #---------------------------------------------------------------------
    # 判斷輸入.
    #---------------------------------------------------------------------
    for event in pygame.event.get():
        # 離開遊戲.
        if event.type == pygame.QUIT:
            running = False
        # 判斷按下按鈕
        if event.type == pygame.KEYDOWN:
            # 判斷按下ESC按鈕
            if event.key == pygame.K_ESCAPE:
                running = False
                
        # 判斷Mouse.
        if event.type == pygame.MOUSEMOTION:
            paddle_x = pygame.mouse.get_pos()[0] - 50
        if event.type == pygame.MOUSEBUTTONDOWN:
            if(game_mode == 0):
                game_mode = 1

    #---------------------------------------------------------------------    
    # 清除畫面.
    canvas.fill(block)
    
    # 磚塊
    for bricks in bricks_list:
        # 球碰磚塊.
        if(isCollision( ball.pos[0], ball.pos[1], bricks.rect)):
            if(bricks.visivle):                
                # 扣除磚塊.
                brick_num = brick_num -1
                # 初始遊戲.
                if(brick_num <= 0):
                    resetGame()
                    break
                # 球反彈.
                dy = -dy; 
            # 關閉磚塊.
            bricks.visivle = False

        # 更新磚塊.        
        bricks.update()
            
    #顯示磚塊數量.
    showFont( u"磚塊數量:"+str(brick_num),   8, 20)            

    # 秀板子.
    paddle.rect[0] = paddle_x
    paddle.update()

    # 碰撞判斷-球碰板子.
    if(isCollision( ball.pos[0], ball.pos[1], paddle.rect)):        
        # 球反彈.
        dy = -dy;         
            
    # 球.
    # 0:等待開球
    if(game_mode == 0):
        ball.pos[0] = ball_x = paddle.rect[0] + ( (paddle.rect[2] - ball.radius) >> 1 )
        ball.pos[1] = ball_y = paddle.rect[1] - ball.radius        
    # 1:遊戲進行中
    elif(game_mode == 1):
        ball_x += dx
        ball_y += dy
        #判斷死亡.
        if(ball_y + dy > canvas_height - ball.radius):
            game_mode = 0        
        # 右牆或左牆碰撞.
        if(ball_x + dx > canvas_width - ball.radius or ball_x + dx < ball.radius):
            dx = -dx
        # 下牆或上牆碰撞
        if(ball_y + dy > canvas_height - ball.radius or ball_y + dy < ball.radius):        
            dy = -dy
        ball.pos[0] = ball_x
        ball.pos[1] = ball_y

    # 更新球.
    ball.update()

    # 顯示中文.
    showFont( u"FPS:" + str(clock.get_fps()), 8, 2)    
    # 更新畫面.
    pygame.display.update()
    clock.tick(60)

# 離開遊戲.
pygame.quit()
quit()

將以下程式碼存成drew.py檔名
# encoding: utf-8

#-------------------------------------------------------------------------
# 畫Box.
#-------------------------------------------------------------------------
class Box(object):
    #-------------------------------------------------------------------------
    # 建構式.
    #   pygame    : pygame.
    #   canvas    : 畫佈.
    #   name    : 物件名稱.
    #   rect      : 位置、大小.
    #   color     : 顏色.
    #-------------------------------------------------------------------------
    def __init__( self, pygame, canvas, name, rect, color):
        self.pygame = pygame
        self.canvas = canvas
        self.name = name
        self.rect = rect
        self.color = color

        self.visivle = True
        
    #-------------------------------------------------------------------------
    # 更新.
    #-------------------------------------------------------------------------
    def update(self):
        if(self.visivle):
            self.pygame.draw.rect( self.canvas, self.color, self.rect)

#-------------------------------------------------------------------------
# 畫圓.
#-------------------------------------------------------------------------
class Circle(object):
    #-------------------------------------------------------------------------
    # 建構式.
    #   pygame  : pygame.
    #   canvas  : 畫佈.
    #   name    : 物件名稱.
    #   pos     : 位置.  
    #   radius  : 大小.
    #   color   : 顏色.    
    #-------------------------------------------------------------------------
    def __init__( self, pygame, canvas, name, pos, radius, color):
        self.pygame = pygame
        self.canvas = canvas
        self.name = name
        self.pos = pos
        self.radius = radius
        self.color = color
        
        self.visivle = True

    #-------------------------------------------------------------------------
    # 更新.
    #-------------------------------------------------------------------------
    def update(self):
        if(self.visivle):
            self.pygame.draw.circle( self.canvas, self.color, self.pos , self.radius)

在命令列輸入以下指令以執行打磚塊遊戲:

python play.py

以下是試玩影片

運作原理就不多說了,有興趣的同學可以到GitHub下載程式碼來研究,程式碼裡面寫了大量的註解與說明,相信不難理解,那就先這樣咱們下次見囉。

點我到GitHub下載範例程式

-2017/10/23 更新
[新增經典灰階美術風格]
在命令列輸入以下指令以執行遊戲:

python play_old_school.py


















4 則留言:

  1. 那個...
    我不知道是甚麼問題
    他一直出問題...
    Traceback (most recent call last):
    File "C:\Users\Single Programmer\Desktop\Python_Arkanoid-master\play_old_school.py", line 80, in
    font = pygame.font.SysFont('simhei', 18)
    File "C:\Users\Single Programmer\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pygame\sysfont.py", line 320, in SysFont
    return constructor(fontname, size, set_bold, set_italic)
    File "C:\Users\Single Programmer\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pygame\sysfont.py", line 243, in font_constructor
    font = pygame.font.Font(fontpath, size)
    OSError: unable to read font file 'C:\Users\Single Programmer\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pygame\freesansbold.ttf'
    之後我去掉好多東西他才成功...
    但是我還是想知道是甚麼問題...

    回覆刪除
    回覆
    1. Hi..
      File "C:\Users\Single Programmer\Desktop\Python_Arkanoid-master\play_old_school.py", line 80, in
      font = pygame.font.SysFont('simhei', 18)
      主要是設定黑體字型,會發生錯誤我猜您電腦因該沒黑體字形..所以建議可以將pygame.font.SysFont的第一個參數傳入您電腦有的字型檔名稱,如:
      font = pygame.font.SysFont('新細明體', 18)

      刪除
  2. 可以詢問一下pygame的問題嗎?現在遇到的瓶頸是出現以下這個情況
    ModuleNotFoundError: No module named 'pygame'
    我們是按照你網站的模式打code,本人下載的是python3.5版本,但在編譯就出現上述的問題了,我們也有去裝pygame也在cmd中執行成功,但就是在編譯的時候還是一樣的問題
    想請問要怎麼處理這個步驟,麻煩了

    回覆刪除
    回覆
    1. Hi 家廉幫你問了一下google大神..希望對你有幫助..^^

      *pycharm import pygame 出現報錯:No module named 'pygame'
      https://hk.saowen.com/a/359b4f9d66d285b5838464b0b7c169d23d22df3f016e8e4c0ed47ae3f28cf527

      *安裝pygame中出現的問題
      https://blog.csdn.net/qq_29012939/article/details/79107735

      *python – ImportError:沒有名為“pygame”的模塊
      https://codeday.me/bug/20180717/194946.html

      刪除