<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          做硬核老爸,我用 Python

          共 4716字,需瀏覽 10分鐘

           ·

          2020-09-23 20:35

          文 |?太陽(yáng)雪

          來(lái)源:Python 技術(shù)「ID: pythonall」


          前幾天,給兒子買了個(gè)飛行棋,甚是喜歡,每天都要和我來(lái)兩盤,昨天準(zhǔn)備大戰(zhàn)一場(chǎng)時(shí),發(fā)現(xiàn)骰子弄丟了,沒有骰子就沒法玩了,正想要用橡皮做一個(gè),突然想到了個(gè)更好的辦法,經(jīng)過(guò)一頓折騰,終于搞定了,結(jié)果……

          構(gòu)思

          骰子是個(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)在我需要用程序來(lái)模擬這個(gè)過(guò)程,實(shí)際上就是產(chǎn)生 1 到 6 直接的隨機(jī)數(shù),直接用 random.randint(1, 6) 就可以搞定,不過(guò)我不想就這樣簡(jiǎn)單完成,一是對(duì)于小孩子來(lái)說(shuō),直接給出數(shù)字不夠直觀,二是,能有機(jī)會(huì)給兒子炫技一把,何樂不為?

          于是構(gòu)思如下:

          • 找一些骰子的素材,需要有每個(gè)數(shù)字向上的圖片
          • 為了制造骰子的轉(zhuǎn)動(dòng)效果,還需要一些處于轉(zhuǎn)動(dòng)中間狀態(tài)的圖片
          • 隨機(jī)產(chǎn)生 0 到 5 之間的數(shù)字,0 代表點(diǎn)數(shù) 1,1 代表點(diǎn)數(shù) 2,依次類推,5 代表點(diǎn)數(shù) 6,為什么不直接生成 1 到 6 呢?后面有解答
          • 擲骰子過(guò)程有兩種狀態(tài),即 顯示點(diǎn)數(shù) 和 轉(zhuǎn)動(dòng),那么就需要有觸發(fā)機(jī)制,考慮到小孩子對(duì)鼠標(biāo)操作不靈活,選用空格鍵來(lái)控制,按一下就相當(dāng)于擲一次

          實(shí)現(xiàn)

          構(gòu)思好后,趕緊實(shí)現(xiàn)!

          素材

          先從網(wǎng)上找了些骰子的素材,最終選擇了以微信擲骰子表情圖為元素的一系列 gif 圖片,通過(guò)圖片解析工具,從 gif 圖片中提取出每個(gè)幀,其中包括了點(diǎn)數(shù)朝上的圖片,和轉(zhuǎn)動(dòng)中間的圖片,這樣圖片素材就搞定了。

          實(shí)踐時(shí)如果不方便獲得圖片素材,可從本文示例代碼中獲得

          接下來(lái),就是編程部分了,之前在 模擬疫情擴(kuò)散的示例 中,用到過(guò) pygame python 游戲引擎庫(kù),這次還用它。

          骰子

          首先,寫一個(gè) 骰子類,用來(lái)定義骰子的各種資源,以及管理骰子的狀態(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ū)域是為了在游戲窗口中繪制骰子用的
          • diceSpin 存儲(chǔ)了骰子轉(zhuǎn)動(dòng)過(guò)程中的圖片素材,注意需要用 pygame.image.load 方法加載圖片資源
          • diceStop 存儲(chǔ)了骰子點(diǎn)數(shù)的圖片素材
          • StopStatus 記錄骰子停止?fàn)顟B(tài)的點(diǎn)數(shù)值,在 0 ~ 5 之間,初始化為一個(gè)隨機(jī)數(shù)
          • SpinStatus 記錄轉(zhuǎn)動(dòng)過(guò)程中當(dāng)前幀的圖片索引,默認(rèn)為 0
          • move 方法相當(dāng)于一個(gè)轉(zhuǎn)動(dòng)控制器,每調(diào)用一次會(huì)改變一次轉(zhuǎn)動(dòng)中圖片的索引,骰子轉(zhuǎn)動(dòng)過(guò)程中會(huì)反復(fù)被調(diào)用

          引擎

          接下來(lái),編寫一個(gè)游戲引擎類,用于驅(qū)動(dòng)游戲過(guò)程,代碼如下:

          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??#?擲骰子過(guò)程的幀數(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()
          • 初始化方法中,做了游戲窗口的初始化,并設(shè)定了窗口大小,然后對(duì)過(guò)程中的控制類變量做了初始化
          • roll 方法為拋擲,拋擲過(guò)程中會(huì)被反復(fù)調(diào)用,先設(shè)置一個(gè)轉(zhuǎn)動(dòng)中圖片,然后,調(diào)用骰子的 move 方法,得到一個(gè)新的轉(zhuǎn)動(dòng)狀態(tài)
          • roll 方法中,接下來(lái)是一個(gè)控制器,如果達(dá)到了設(shè)定的轉(zhuǎn)動(dòng)次數(shù),就停止,并得到隨機(jī)的點(diǎn)數(shù)
          • stop 方法,在停止轉(zhuǎn)動(dòng)時(shí)調(diào)用,將轉(zhuǎn)動(dòng)停止時(shí)的點(diǎn)數(shù)圖片繪制到窗口上,這里 StopStatus 范圍是 0 ~ 5,剛好對(duì)應(yīng) diceStop 列表的索引,這就是隨機(jī)數(shù)范圍是 0~5 的原因
          • run 方法是引擎的啟動(dòng)入口,它啟動(dòng)了一個(gè)事件循環(huán)
          • 循環(huán)中,檢查一遍事件記錄,如果接收到了退出事件,則結(jié)束循環(huán)
          • 如果接收到了按下空格鍵或者鼠標(biāo)鍵,且投擲狀態(tài)為停止時(shí),將投擲狀態(tài)設(shè)置為開始
          • 檢查完事件記錄,判斷投擲狀態(tài),如果是開始狀態(tài),調(diào)用 roll 方法,否則調(diào)用 stop 方法
          • 最后每次循環(huán)都需要調(diào)用 pygame.display.update() 刷新一次窗口

          這里需要說(shuō)明下 clock.tick,它的作用是讓循環(huán)每秒執(zhí)行多少次,抽象來(lái)說(shuō)可以理解為動(dòng)畫的幀,即每秒多少幀。

          相對(duì)于 clock.tick,我們更熟悉 time.sleep,后者表示等待多久再執(zhí)行,那么 clock.tick(10) 的效果就相當(dāng)于 time.sleep(0.1),即每秒執(zhí)行 10 次,就等于每次等待十分之一秒。

          運(yùn)行

          if?__name__?==?'__main__':
          ????Game().run()

          注意:將目錄切換到代碼目錄下運(yùn)行,否則可能提示找不到圖片文件。

          運(yùn)行效果如下,像那么回事吧:

          擲骰子效果

          折騰完后,我迫不及待地去兒子跟前炫耀,結(jié)果,他已經(jīng)睡著了,身旁散落著一些飛行棋子兒……

          總結(jié)

          無(wú)論在生活或者工作中,編程技能越來(lái)越重要了,編程已然成為了思考和創(chuàng)造的工具了,習(xí)得一項(xiàng)編程技能,不僅能幫助自己,也許可以省一筆少兒編程的花費(fèi),在提高孩子邏輯思維能力的同時(shí),還能增進(jìn)與孩子的感情,不得不說(shuō),當(dāng)兒子使用我編寫的骰子玩飛行棋時(shí),更開心了。

          做硬核家長(zhǎng),我用 Python!

          參考

          • https://www.mscto.com/smartprogram/299581.html
          • https://baike.baidu.com/item/骰子/1823190
          • https://www.yiibai.com/python/time_sleep.html

          PS公號(hào)內(nèi)回復(fù)「Python」即可進(jìn)入Python 新手學(xué)習(xí)交流群,一起 100 天計(jì)劃!


          老規(guī)矩,兄弟們還記得么,右下角的 “在看” 點(diǎn)一下,如果感覺文章內(nèi)容不錯(cuò)的話,記得分享朋友圈讓更多的人知道!

          代碼獲取方式

          識(shí)別文末二維碼,回復(fù):200923

          瀏覽 78
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  有码一区二区三区 | 日本亚洲欧洲免费 | 日日操屄 | 大香焦久久 | 学生妹的一级片 |