來源:Python 技術(shù)「ID: pythonall」
前幾天,給兒子買了個(gè)飛行棋,甚是喜歡,每天都要和我來兩盤,昨天準(zhǔn)備大戰(zhàn)一場(chǎng)時(shí),發(fā)現(xiàn)骰子弄丟了,沒有骰子就沒法玩了,正想要用橡皮做一個(gè),突然想到了個(gè)更好的辦法,經(jīng)過一頓折騰,終于搞定了,結(jié)果……
骰子是個(gè)立方體,有六個(gè)面,每個(gè)面上,標(biāo)有不同地點(diǎn),從 1 個(gè) 到 6 個(gè),代表 1 到 6 六個(gè)數(shù)字,玩的時(shí)候,將骰子一擲,等它停下,朝上的面是幾點(diǎn),就表示搖到了幾。
不同的游戲中,對(duì)搖到的點(diǎn)數(shù)有不同的玩法,例如飛行棋中,搖到 5 或者 6,可以起飛一架飛機(jī)。
現(xiàn)在我需要用程序來模擬這個(gè)過程,實(shí)際上就是產(chǎn)生 1 到 6 直接的隨機(jī)數(shù),直接用 random.randint(1, 6)
就可以搞定,不過我不想就這樣簡(jiǎn)單完成,一是對(duì)于小孩子來說,直接給出數(shù)字不夠直觀,二是,能有機(jī)會(huì)給兒子炫技一把,何樂不為?
于是構(gòu)思如下:
構(gòu)思好后,趕緊實(shí)現(xiàn)!
先從網(wǎng)上找了些骰子的素材,最終選擇了以微信擲骰子表情圖為元素的一系列 gif 圖片,通過圖片解析工具,從 gif 圖片中提取出每個(gè)幀,其中包括了點(diǎn)數(shù)朝上的圖片,和轉(zhuǎn)動(dòng)中間的圖片,這樣圖片素材就搞定了。
實(shí)踐時(shí)如果不方便獲得圖片素材,可從本文示例代碼中獲得
接下來,就是編程部分了,之前在 模擬疫情擴(kuò)散的示例 中,用到過 pygame python 游戲引擎庫,這次還用它。
首先,寫一個(gè) 骰子類,用來定義骰子的各種資源,以及管理骰子的狀態(tài),代碼如下:
import random
import pygame
class Dice:
def __init__(self):
self.diceRect = pygame.Rect(200, 225, 100, 100)
self.diceSpin = [
pygame.image.load("asset/rolling/4.png"),
pygame.image.load("asset/rolling/3.png"),
pygame.image.load("asset/rolling/2.png"),
pygame.image.load("asset/rolling/1.png")
]
self.diceStop = [
pygame.image.load("asset/dice/1.png"),
pygame.image.load("asset/dice/2.png"),
pygame.image.load("asset/dice/3.png"),
pygame.image.load("asset/dice/4.png"),
pygame.image.load("asset/dice/5.png"),
pygame.image.load("asset/dice/6.png")
]
self.StopStatus = random.randint(0, 5)
self.SpinStatus = 0
def move(self):
self.SpinStatus += 1
if self.SpinStatus == len(self.diceSpin):
self.SpinStatus = 0
pygame.Rect
方法設(shè)定了一個(gè)矩形區(qū)域,即游戲窗口坐標(biāo)為(200, 225),高度和寬度都為 100,這個(gè)矩形區(qū)域是為了在游戲窗口中繪制骰子用的pygame.image.load
方法加載圖片資源接下來,編寫一個(gè)游戲引擎類,用于驅(qū)動(dòng)游戲過程,代碼如下:
import random
import sys
import pygame
class Game:
def __init__(self, width=500, height=600):
pygame.init()
size = width, height
self.screen = pygame.display.set_mode(size)
self.clock = pygame.time.Clock()
self.screen.fill((255, 255, 255))
self.rollTimes = 0 # 擲骰子過程的幀數(shù)記錄
self.Dice = Dice()
self.start = False # 狀態(tài)標(biāo)識(shí)
self.rollCount = random.randint(3, 10) # 初始投擲幀數(shù)
def roll(self):
self.screen.blit(self.Dice.diceSpin[self.Dice.SpinStatus], self.Dice.diceRect)
self.Dice.move()
self.rollTimes += 1
if self.rollTimes > self.rollCount:
self.start = False
self.rollCount = random.randint(3, 10)
self.Dice.StopStatus = random.randint(0, 5)
self.rollTimes = 0
def stop(self):
self.screen.blit(self.Dice.diceStop[self.Dice.StopStatus], self.Dice.diceRect)
def run(self):
while True:
self.clock.tick(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if ((event.type == pygame.KEYDOWN and event.key==pygame.K_SPACE) \
or event.type == pygame.MOUSEBUTTONDOWN) \
and self.start == False:
self.start = True
if self.start:
self.roll()
else:
self.stop()
pygame.display.update()
move
方法,得到一個(gè)新的轉(zhuǎn)動(dòng)狀態(tài)StopStatus
范圍是 0 ~ 5,剛好對(duì)應(yīng) diceStop
列表的索引,這就是隨機(jī)數(shù)范圍是 0~5 的原因roll
方法,否則調(diào)用 stop
方法pygame.display.update()
刷新一次窗口這里需要說明下 clock.tick
,它的作用是讓循環(huán)每秒執(zhí)行多少次,抽象來說可以理解為動(dòng)畫的幀,即每秒多少幀。
相對(duì)于 clock.tick
,我們更熟悉 time.sleep
,后者表示等待多久再執(zhí)行,那么 clock.tick(10)
的效果就相當(dāng)于 time.sleep(0.1)
,即每秒執(zhí)行 10 次,就等于每次等待十分之一秒。
if __name__ == '__main__':
Game().run()
注意:將目錄切換到代碼目錄下運(yùn)行,否則可能提示找不到圖片文件。
運(yùn)行效果如下,像那么回事吧:
折騰完后,我迫不及待地去兒子跟前炫耀,結(jié)果,他已經(jīng)睡著了,身旁散落著一些飛行棋子兒……
無論在生活或者工作中,編程技能越來越重要了,編程已然成為了思考和創(chuàng)造的工具了,習(xí)得一項(xiàng)編程技能,不僅能幫助自己,也許可以省一筆少兒編程的花費(fèi),在提高孩子邏輯思維能力的同時(shí),還能增進(jìn)與孩子的感情,不得不說,當(dāng)兒子使用我編寫的骰子玩飛行棋時(shí),更開心了。
做硬核家長(zhǎng),我用 Python!
聯(lián)系客服