安裝 PyGame


In [1]:
!conda install -y --channel https://conda.anaconda.org/CogSci pygame


Fetching package metadata: ......
Solving package specifications: .........

# All requested packages already installed.
# packages in environment at D:\Users\tzerj_000\Anaconda2:
#
pygame                    1.9.2a0                  py27_0    CogSci
Using Anaconda Cloud api site https://api.anaconda.org

最簡單的骨架


In [1]:
# import pygame
import pygame
from pygame.locals import *

# 初始化
pygame.init()

# 設定螢幕視窗
DISPLAYSURF = pygame.display.set_mode((640, 480))

# main event loop
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()


---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-1-280a1947a41b> in <module>()
     11 # main event loop
     12 while True:
---> 13     for event in pygame.event.get():
     14         if event.type == QUIT:
     15             pygame.quit()

error: video system not initialized

優雅的結束


In [2]:
import pygame
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

# 設定一個變數 running 用來判斷是遊戲是否在跑
running = True
while running: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            # 將 running 設成 False
            running = False

一點畫面 (兩個小問題)


In [3]:
import pygame
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

# 設定視窗標題
pygame.display.set_caption('你好!')

running = True
while running: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False        
    # 用顏色 (0,0,255) 填滿畫面
    DISPLAYSURF.fill( (0,0,255))
    #畫一個圓
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (100,100), 50)
    
    # 真的更新到硬體
    #pygame.display.update()


---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-3-c2e5327a32e2> in <module>()
     15             running = False
     16     # 用顏色 (0,0,255) 填滿畫面
---> 17     DISPLAYSURF.fill( (0,0,255))
     18     #畫一個圓
     19     pygame.draw.circle(DISPLAYSURF, (255,255,0), (100,100), 50)

error: display Surface quit

In [4]:
import pygame
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

# 設定視窗標題
pygame.display.set_caption('你好!')

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False    
    if not running:
        break
    # 試著畫出一個笑臉
    DISPLAYSURF.fill( (0,0,255))
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (100,100), 50)
    # 畫弧形
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (100-25,100, 50, 30), -3.14, 0, 3)
    pygame.display.update()

先將畫出笑臉的步驟整理成一個函數


In [5]:
import pygame
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')

# 畫圖函數
def draw_smiley(x,y):
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    # 請填入你的畫圖程式碼
    
running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False    
    if not running:
        break
        
    # 呼叫函數
    DISPLAYSURF.fill( (0,0,255))
    draw_smiley(100,100)
    draw_smiley(200,200)
    pygame.display.update()

In [6]:
import pygame
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')
# 取得時鐘 
fpsClock = pygame.time.Clock()
def draw_smiley(x,y):
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

# 設定一開始的位置
x,y = 300,300
# 設定初速度。 dx, dy 代表 dt 移動的距離
dx, dy = 2, 2

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False    
    if not running:
        break
    # 更新位置
    x+=dx
    y+=dy
    # 這裡,增加程式碼,試試看,讓笑臉碰到邊界時可以反彈
    # 當 x > 600 或 x < 0 時, 讓 dx = -dx
    # 當 y > 400 或 y < 0 時, 讓 dy = -dy
    
    # 在 x,y 位置畫出笑臉
    DISPLAYSURF.fill( (0,0,255))
    draw_smiley(x,y)
    pygame.display.update()

    # 等到下一個畫格 (60fps)
    fpsClock.tick(60)

增加一點亂數


In [7]:
import pygame
from pygame.locals import *
# import 隨機亂數
from random import random

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')
fpsClock = pygame.time.Clock()
def draw_smiley(x,y):
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

x,y = 300,300
dx, dy = 2, 2

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False    
    if not running:
        break
    x+=dx
    y+=dy
    
    # 讓反彈時的速度有點變化
    if x > 590 or x < 50:
        dx = -dx+0.5*(random()-0.5)
    if y > 430 or y < 50:
        dy = -dy+0.5*(random()-0.5)
    
    DISPLAYSURF.fill( (0,0,255))
    # 因為現在 x,y 是浮點數, 所以要記得轉成整數
    draw_smiley(int(x),int(y))
    pygame.display.update()
    fpsClock.tick(60)

In [8]:
import pygame
from pygame.locals import *
from random import random

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')
fpsClock = pygame.time.Clock()
def draw_smiley(x,y):
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

x,y = 300,300
dx, dy = 2, 2

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False
        # 當 event 是 KEYDOWN 時
        elif event.type == KEYDOWN:
            # 印出 event
            print event
            #if event.key == K_RIGHT: 
            #    dx+=1
            # 請處理其他方向
    if not running:
        break
    x+=dx
    y+=dy
    if x > 590 or x < 50:
        dx = -dx+0.5*(random()-0.5)
    if y > 430 or y < 50:
        dy = -dy+0.5*(random()-0.5)
    DISPLAYSURF.fill( (0,0,255))
    draw_smiley(int(x),int(y))
    pygame.display.update()
    fpsClock.tick(60)

處理滑鼠輸入


In [9]:
import pygame
from pygame.locals import *
from random import random

pygame.init()
DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')
fpsClock = pygame.time.Clock()
def draw_smiley(x,y):
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

x,y = 300,300
dx, dy = 2, 2

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False
        elif event.type == KEYDOWN:
            if event.key == K_RIGHT: 
                dx += 1
            elif event.key == K_LEFT:
                dx -= 1
            elif event.key == K_UP:
                dy -= 1
            elif event.key == K_DOWN:
                dy += 1
        # 按下滑鼠按鈕的事件
        elif event.type == MOUSEBUTTONDOWN:
            # 觀察滑鼠 event
            print event
            # event,pos[0], event.pos[1] 分別是滑鼠按下去的 x,y 座標
            # 下面請寫出程式碼, 讓笑臉從現在的座標 x,y, 慢慢移動到 event.pos
    if not running:
        break
    x+=dx
    y+=dy
    if x > 590 or x < 50:
        dx = -dx+0.5*(random()-0.5)
    if y > 430 or y < 50:
        dy = -dy+0.5*(random()-0.5)
    DISPLAYSURF.fill( (0,0,255))
    draw_smiley(int(x),int(y))
    pygame.display.update()
    fpsClock.tick(60)

加上食物


In [3]:
import pygame
from pygame.locals import *
# import randint 函數
from random import random, randint

pygame.init()

# 設定字型和標籤, 用來顯示分數
font = pygame.font.SysFont("monospace", 32, bold=True)
score_label = font.render("score: 0", 1, (255,255,255))

DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')
fpsClock = pygame.time.Clock()
def draw_smiley(x,y):
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

x,y = 300,300
dx, dy = 2, 2

# 隨機產生座標
def random_pos():
    return (randint(0,639), randint(0,479))

# 產生五個隨機的食物
food_pos = [random_pos() for i in range(5)]
# 定義分數
score = 0

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False
        elif event.type == KEYDOWN:
            if event.key == K_RIGHT: 
                dx += 1
            elif event.key == K_LEFT:
                dx -= 1
            elif event.key == K_UP:
                dy -= 1
            elif event.key == K_DOWN:
                dy += 1
        elif event.type == MOUSEBUTTONDOWN:
            dx, dy = event.pos[0]-x, event.pos[1]-y
            r = (dx**2+dy**2)**0.5
            if r!=0:
                dx, dy = dx/r, dy/r
    if not running:
        break
    x+=dx
    y+=dy
    if x > 590 or x < 50:
        dx = -dx+0.5*(random()-0.5)
    if y > 430 or y < 50:
        dy = -dy+0.5*(random()-0.5)
    # 接下來要處理吃掉食物這件事情
    # "之後"的食物狀態
    new_food_pos = []
    for pos in food_pos:
        # 如果笑臉和食物的距離夠近, 就吃掉食物
        if (pos[0]-x)**2 + (pos[1]-y)**2 < 55**2:
            # 增加分數
            score += 1
            score_label = font.render("score: %d"%score, 1, (255,255,255))
            # 生出一個新的食物
            pos = random_pos()
        # 將 pos 加入新的食物位置狀態
        new_food_pos.append(pos)
    # 將 food_pos 設定成處理後的狀態
    food_pos = new_food_pos
    DISPLAYSURF.fill( (0,0,255))
    draw_smiley(int(x),int(y))
    # 在每個有食物的位置, 畫一個綠色的小圓圈代表食物
    for pos in food_pos:
        pygame.draw.circle(DISPLAYSURF, (0,255,0), pos, 5)
    
    # 顯示分數
    DISPLAYSURF.blit(score_label, (10, 10))
    
    pygame.display.update()
    fpsClock.tick(60)

增加敵人


In [1]:
import pygame
from pygame.locals import *
# import randint 函數
from random import random, randint

pygame.init()
font = pygame.font.SysFont("monospace", 32, bold=True)
# 結束的字型
font_gg = pygame.font.SysFont("monospace", 72, bold=True)

score_label = font.render("score: 0", 1, (255,255,255))

# 顯示生命
life_label =  font.render("life: 10", 1, (255,255,255))
# Game Over 文字
game_over_label =  font_gg.render("Game Over", 1, (255,100, 100))

DISPLAYSURF = pygame.display.set_mode((640, 480))

pygame.display.set_caption('你好!')
fpsClock = pygame.time.Clock()
def draw_smiley(x,y):
    DISPLAYSURF.fill( (0,0,255))
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

x,y = 300,300
dx, dy = 2, 2

def random_pos():
    return (randint(0,639), randint(0,479))

food_pos = [random_pos() for i in range(5)]

# 產生隨機的敵人位置和方向
def random_enemy():
    if randint(0,1):
        direction = (-2,0)
        position = (700, randint(20, 460))
    else:
        direction = (0, -2)
        position = (randint(20, 620), 520)
    return direction, position
        
# 產生五個隨機敵人
enemy_dir = [] 
enemy_pos = []
for i in range(5):
    direction, position = random_enemy()
    enemy_dir.append(direction)
    enemy_pos.append(position) 

# 定義分數
score = 0

# 生命數量
life = 10

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False
        # 生命值 > 0 才可以操作
        elif life>0 and event.type == KEYDOWN:
            if event.key == K_RIGHT: 
                dx += 1
            elif event.key == K_LEFT:
                dx -= 1
            elif event.key == K_UP:
                dy -= 1
            elif event.key == K_DOWN:
                dy += 1
        # 生命值 > 0 才可以操作
        elif life>0 and event.type == MOUSEBUTTONDOWN:
            dx, dy = event.pos[0]-x, event.pos[1]-y
            r = (dx**2+dy**2)**0.5
            if r!=0:
                dx, dy = dx/r, dy/r
    if not running:
        break
    x+=dx
    y+=dy
    if x > 590 or x < 50:
        dx = -dx+0.5*(random()-0.5)
    if y > 430 or y < 50:
        dy = -dy+0.5*(random()-0.5)
        
    new_food_pos = []
    for pos in food_pos:
        if (pos[0]-x)**2 + (pos[1]-y)**2 < 55**2:
            score += 1
            score_label = font.render("score: %d"%score, 1, (255,255,255))
            pos = random_pos()
        new_food_pos.append(pos)
    food_pos = new_food_pos
    
    # 處理敵人
    for i in range(5):
        direction = enemy_dir[i]
        position = enemy_pos[i]
        # 更新位置
        position = (position[0]+direction[0], position[1]+direction[1])
        # 超過邊界時, 製造新敵人
        if position[0] < 0 or position[1]<0:
            direction, position = random_enemy()
        # 和笑臉很接近時, 生命減少, 製造新敵人
        elif (position[0]-x)**2 + (position[1]-y)**2 < 55**2:
            life -= 1
            life_label = font.render("life: %d"%life, 1, (255,255,255))
            direction, position = random_enemy()
        enemy_dir[i] = direction
        enemy_pos[i] = position
    
    draw_smiley(int(x),int(y))
    for pos in food_pos:
        pygame.draw.circle(DISPLAYSURF, (0,255,0), pos, 5)
    
    # 畫出敵人
    for pos in enemy_pos:
        pygame.draw.circle(DISPLAYSURF, (255,0, 0), pos, 5)
    
    # 生命值 <=0 時結束
    if life <= 0:
        life = dx = dy = 0
        DISPLAYSURF.blit(game_over_label, (150, 200))
    
    # 顯示生命
    DISPLAYSURF.blit(life_label, (450, 10))
    
    DISPLAYSURF.blit(score_label, (10, 10))

    pygame.display.update()
    fpsClock.tick(60)

聲音


In [1]:
import pygame
from pygame.locals import *
from random import random, randint

pygame.init()
font = pygame.font.SysFont("monospace", 32, bold=True)
font_gg = pygame.font.SysFont("monospace", 72, bold=True)

score_label = font.render("score: 0", 1, (255,255,255))
life_label =  font.render("life: 10", 1, (255,255,255))
game_over_label =  font_gg.render("Game Over", 1, (255,100, 100))

DISPLAYSURF = pygame.display.set_mode((640, 480))
pygame.display.set_caption('你好!')
fpsClock = pygame.time.Clock()

# 讀取聲音
eat_sound_effect = pygame.mixer.Sound('pacman_eatfruit.wav')
damage_sound_effect = pygame.mixer.Sound('pacman_eatghost.wav')

def draw_smiley(x,y):
    DISPLAYSURF.fill( (0,0,255))
    pygame.draw.circle(DISPLAYSURF, (255,255,0), (x,y), 50)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x-20,y-15), 10)
    pygame.draw.circle(DISPLAYSURF, (0,0,0), (x+20,y-15), 10)
    pygame.draw.arc(DISPLAYSURF, (255,0,0), (x-25,y, 50, 30), -3.14, 0, 3)

x,y = 300,300
dx, dy = 2, 2

def random_pos():
    return (randint(0,639), randint(0,479))

food_pos = [random_pos() for i in range(5)]

def random_enemy():
    if randint(0,1):
        direction = (-2,0)
        position = (700, randint(20, 460))
    else:
        direction = (0, -2)
        position = (randint(20, 620), 520)
    return direction, position
        
enemy_dir = [] 
enemy_pos = []
for i in range(5):
    direction, position = random_enemy()
    enemy_dir.append(direction)
    enemy_pos.append(position) 

score = 0
life = 10

running = True
while True: 
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            running = False
        elif life>0 and event.type == KEYDOWN:
            if event.key == K_RIGHT: 
                dx += 1
            elif event.key == K_LEFT:
                dx -= 1
            elif event.key == K_UP:
                dy -= 1
            elif event.key == K_DOWN:
                dy += 1
        elif life>0 and event.type == MOUSEBUTTONDOWN:
            dx, dy = event.pos[0]-x, event.pos[1]-y
            r = (dx**2+dy**2)**0.5
            if r!=0:
                dx, dy = dx/r, dy/r
    if not running:
        break
    x+=dx
    y+=dy
    if x > 590 or x < 50:
        dx = -dx+0.5*(random()-0.5)
    if y > 430 or y < 50:
        dy = -dy+0.5*(random()-0.5)
        
    new_food_pos = []
    for pos in food_pos:
        if (pos[0]-x)**2 + (pos[1]-y)**2 < 55**2:
            score += 1
            # 撥放聲音
            eat_sound_effect.play()
            score_label = font.render("score: %d"%score, 1, (255,255,255))
            pos = random_pos()
        new_food_pos.append(pos)
    food_pos = new_food_pos
    
    for i in range(5):
        direction = enemy_dir[i]
        position = enemy_pos[i]
        position = (position[0]+direction[0], position[1]+direction[1])
        if position[0] < 0 or position[1]<0:
            direction, position = random_enemy()
        elif (position[0]-x)**2 + (position[1]-y)**2 < 55**2:
            damage_sound_effect.play()
            life -= 1
            life_label = font.render("life: %d"%life, 1, (255,255,255))
            direction, position = random_enemy()
        enemy_dir[i] = direction
        enemy_pos[i] = position
    
    draw_smiley(int(x),int(y))
    for pos in food_pos:
        pygame.draw.circle(DISPLAYSURF, (0,255,0), pos, 5)
    
    for pos in enemy_pos:
        pygame.draw.circle(DISPLAYSURF, (255,0, 0), pos, 5)
    
    if life <= 0:
        life = dx = dy = 0
        DISPLAYSURF.blit(game_over_label, (150, 200))
    
    DISPLAYSURF.blit(life_label, (450, 10))
    DISPLAYSURF.blit(score_label, (10, 10))

    pygame.display.update()
    fpsClock.tick(60)

In [ ]: