<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>

          保姆級(jí)教程:用Python做游戲有多簡(jiǎn)單

          共 8556字,需瀏覽 18分鐘

           ·

          2022-06-02 08:42


          我520的公眾號(hào)圖片發(fā)了以后,有很多同學(xué)問我這個(gè)游戲是怎么做的,難不難。我就用兩篇文章來介紹一下,如果使用Python做游戲。

          這個(gè)游戲是使用PyGame做的,貼圖素材是從itch.io[1]找的。我之前也沒有用過PyGame,這次屬于是現(xiàn)學(xué)現(xiàn)用,參考的教程是PyGame: A Primer on Game Programming in Python[2]

          用PyGame做游戲非常簡(jiǎn)單,我們今天第一篇文章,讓大家實(shí)現(xiàn)一個(gè)可以在地圖上移動(dòng)的小豬。

          基本框架

          首先,無論你是做什么游戲,別管三七二十一,先把下面這段代碼復(fù)制粘貼到你的編輯器里面。所有游戲都需要這幾行代碼:

          import?pygame


          def?main():
          ????pygame.init()
          ????pygame.display.set_caption('未聞Code:青南做的游戲')??#?游戲標(biāo)題
          ????win?=?pygame.display.set_mode((800,?600))??#?窗口尺寸,寬800高600
          ????running?=?True
          ????while?running:
          ????????for?event?in?pygame.event.get():
          ????????????if?event.type?==?pygame.QUIT:??#?點(diǎn)擊左上角或者右上角的x關(guān)閉窗口時(shí),停止程序
          ????????????????running?=?False


          main()

          運(yùn)行效果如下圖所示:

          加載素材

          現(xiàn)在,我們隨便找兩張圖片,一張作為背景,一張作為主角。尺寸不用太在意,差不多就可以了,因?yàn)槲覀兛梢杂么a動(dòng)態(tài)調(diào)整。下面兩張圖是我隨便找的素材,大家注意圖中紅框框住的地方,是這兩張圖片的尺寸。

          我們使用如下代碼加載圖片:

          img_surf?=?pygame.image.load('圖片地址').convert_alpha()

          其中的.convert_alpha()是保留png圖片的透明背景。如果你加載的圖片不png圖片,可以把convert_alpha()改成convert()

          如果要修改圖片尺寸,使用如下代碼:

          img_surf?=?pygame.transform.scale(img_surf,?(寬,?高))

          要把圖片顯示在窗口中,使用下面兩行代碼:

          win.blit(素材對(duì)象,?(素材左上角的橫坐標(biāo),?素材左上角的縱坐標(biāo)))
          pygame.display.flip()

          完整的代碼如下:

          import?pygame


          def?main():
          ????pygame.init()
          ????pygame.display.set_caption('未聞Code:青南做的游戲')??#?游戲標(biāo)題
          ????win?=?pygame.display.set_mode((800,?600))??#?窗口尺寸
          ????bg_small?=?pygame.image.load('bg.png').convert_alpha()
          ????bg_big?=?pygame.transform.scale(bg_small,?(800,?600))
          ????pig?=?pygame.image.load('pig_in_car.png').convert_alpha()
          ????running?=?True
          ????while?running:
          ????????for?event?in?pygame.event.get():
          ????????????if?event.type?==?pygame.QUIT:??#?點(diǎn)擊左上角或者右上角的x關(guān)閉窗口時(shí),停止程序
          ????????????????running?=?False

          ????????win.blit(bg_big,?(0,?0))??#?背景圖最先加載,坐標(biāo)是(left,?top)
          ????????win.blit(pig,?(200,?300))
          ????????pygame.display.flip()


          main()

          運(yùn)行效果如下圖所示:

          需要注意的是,win.blitpygame.display.flip()都要放到while循環(huán)里面。其中win.blit的第一個(gè)參數(shù)是我們剛剛加載的素材對(duì)象。第二個(gè)參數(shù)是一個(gè)元組,標(biāo)記這個(gè)圖片左上角在畫布上面的坐標(biāo)。整個(gè)畫布左上角對(duì)應(yīng)坐標(biāo)(0, 0)。由于背景圖的尺寸也是(800, 600),所以背景圖的左上角放到(0, 0),就剛好可以鋪滿整個(gè)畫布。

          哪里找素材?

          我們做的是一個(gè)像素風(fēng)格的游戲,可以到itch.io上面找素材:

          這個(gè)網(wǎng)站提高了大量的游戲素材,并且絕大部分素材,在個(gè)人非商業(yè)用途的情況下是免費(fèi)的。你找到自己喜歡的素材以后,就可以直接下載,整個(gè)過程你甚至都不需要登錄(比國(guó)內(nèi)的垃圾素材網(wǎng)站可良心多了)。

          怎么我的素材長(zhǎng)這樣?

          你下載了素材以后,可能會(huì)發(fā)現(xiàn)一件非常奇怪的事情,怎么素材全部畫在一張圖上?

          實(shí)際上,這就是業(yè)界慣例,做素材的人會(huì)把每一類素材排列到一張圖片上,你要用的時(shí)候,需要自己去裁剪。例如所有植物放在一張圖上,所有雕像放在一張圖上,地基貼圖也放在一張圖上。

          上面我們演示用的背景圖,初看起來是一張綠色的圖,但是它實(shí)際上包含了多個(gè)地基元素,請(qǐng)注意我用紅框框住的部分:

          在正式游戲中,我們要把每一個(gè)基本元素拆出來,重新組合起來使用。重組的時(shí)候,有些元素要復(fù)制多份重復(fù)使用,有些元素要旋轉(zhuǎn)縮放。最終組合成下面這樣看起來好看的地圖:

          一般來說,像素風(fēng)格的素材,尺寸大多是16x1632x3264x64128x128。素材作者正常情況下會(huì)提供裁剪說明。如果沒有提供的話,你也可以肉眼觀察,然后猜一猜。

          例如我要從雕像素材里面剪切出紅框框住的女神像:

          那么,我可以這樣寫代碼:

          img_surf?=?pygame.image.load('雕像素材.png').convert_alpha()
          goddess=?img_surf.subsurface((?女神像左上角的橫坐標(biāo)?,?女神像左上角的縱坐標(biāo),?女神像的寬,?女神像的高))

          運(yùn)行效果如下圖所示:

          可能有同學(xué)問:為什么女神的坐標(biāo)是這樣的呢?我只能說,這個(gè)坐標(biāo)是我試了很多次,試出來的。

          使用小精靈來管理對(duì)象

          除了背景圖,我們添加的每一個(gè)元素都是一個(gè)對(duì)象,例如上面的小豬和女神像。原則上來講,上面的代碼就足夠讓你把游戲做得漂亮了,想加什么東西,就不停加載圖片素材,然后放到合適的位置就可以了。

          但我們可以使用面向?qū)ο蟮脑O(shè)計(jì)方法,讓代碼更容易維護(hù),也更簡(jiǎn)單。PyGame里面,有一個(gè)類叫做Sprite,我們可以為每一個(gè)對(duì)象實(shí)現(xiàn)一個(gè)類,繼承Sprite,然后把對(duì)象的素材設(shè)置成.surf屬性,把對(duì)象的位置設(shè)置為.rect屬性。例如上面的代碼,我們修改一下:

          import?pygame


          class?Bg(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Bg,?self).__init__()
          ????????bg_small?=?pygame.image.load('bg.png').convert_alpha()
          ????????grass_land?=?bg_small.subsurface((0,?0,?128,?128))
          ????????self.surf?=?pygame.transform.scale(grass_land,?(800,?600))
          ????????self.rect?=?self.surf.get_rect(left=0,?top=0)??#?左上角定位


          class?Pig(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Pig,?self).__init__()
          ????????self.surf?=?pygame.image.load('pig_in_car.png').convert_alpha()
          ????????self.rect?=?self.surf.get_rect(center=(400,?300))??#?中心定位


          class?Goddess(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Goddess,?self).__init__()
          ????????building?=?pygame.image.load('building.png').convert_alpha()
          ????????self.surf?=?building.subsurface(((7?*?64?-?10,?0,?50,?100)))
          ????????self.rect?=?self.surf.get_rect(center=(500,?430))??#?女神像的中心放到畫布(500,?430)的位置


          def?main():
          ????pygame.init()
          ????pygame.display.set_caption('未聞Code:青南做的游戲')??#?游戲標(biāo)題
          ????win?=?pygame.display.set_mode((800,?600))??#?窗口尺寸

          ????bg?=?Bg()
          ????goddess?=?Goddess()
          ????pig?=?Pig()
          ????all_sprites?=?[bg,?goddess,?pig]??#?注意添加順序,后添加的對(duì)象圖層在先添加的對(duì)象的圖層上面

          ????running?=?True
          ????while?running:
          ????????for?event?in?pygame.event.get():
          ????????????if?event.type?==?pygame.QUIT:??#?點(diǎn)擊左上角或者右上角的x關(guān)閉窗口時(shí),停止程序
          ????????????????running?=?False

          ????????for?sprite?in?all_sprites:
          ????????????win.blit(sprite.surf,?sprite.rect)
          ????????pygame.display.flip()


          if?__name__?==?'__main__':
          ????main()

          運(yùn)行效果如下圖所示:

          注意代碼中的all_sprites = [bg, goddess, pig],這里我使用的是列表。后面會(huì)有更高級(jí)的數(shù)據(jù)結(jié)構(gòu)SpriteGroup來儲(chǔ)存他們。今天使用列表就足夠了。

          素材對(duì)象.get_rect()會(huì)返回一個(gè)坐標(biāo)定位對(duì)象,這個(gè)對(duì)象有多個(gè)屬性,例如.left, .top, .center, .width, .height。在不傳參數(shù)的情況下,默認(rèn).left=0, .top=0,PyGame會(huì)自動(dòng)根據(jù)這個(gè)對(duì)象的尺寸計(jì)算.width.height.center。我們可以通過傳入?yún)?shù)的形式主動(dòng)設(shè)定。當(dāng)你設(shè)定左上角的時(shí)候,它自動(dòng)就能算出中心點(diǎn)的坐標(biāo);當(dāng)你傳入中心坐標(biāo)的時(shí)候,它自動(dòng)就能算出左上角的坐標(biāo)。

          理論上來講,在每個(gè)類里面,素材對(duì)象可以用任何名字,不一定要用.surf。坐標(biāo)定位對(duì)象也不一定要用.rect,只要你在win.blit的時(shí)候?qū)?yīng)起來就可以了。但是如果你統(tǒng)一使用.surf.rect會(huì)給你帶來很多好處。這一點(diǎn)我們到物體碰撞那個(gè)地方再講。因此我建議你就使用這兩個(gè)名字。

          讓小豬動(dòng)起來

          既然是游戲,那肯定要按鍵盤讓主角動(dòng)起來。否則跟一幅畫有什么區(qū)別呢?大家注意main()函數(shù)里面的while running這個(gè)循環(huán),如果你在循環(huán)里面加上一行代碼:print(111),你會(huì)發(fā)現(xiàn)當(dāng)你運(yùn)行這個(gè)游戲的時(shí)候,111會(huì)一直不停的打印出來。

          PyGame本質(zhì)上,就是通過win.blit不停地畫圖,由于這個(gè)while循環(huán)每秒要運(yùn)行很多次,如果每次運(yùn)行的時(shí)候,我們讓win.blit的第二個(gè)參數(shù),也就是素材對(duì)象的坐標(biāo)有細(xì)微的差異,那么在人眼看起來,這個(gè)素材對(duì)象就在運(yùn)動(dòng)了。

          我們的目標(biāo)是按住鍵盤的上下左右方向鍵,小豬向4個(gè)不同的方向移動(dòng)。在PyGame里面,獲得鍵盤按住不放的鍵,使用如下代碼實(shí)現(xiàn):

          keys?=?pygame.key.get_pressed()

          它返回的是一個(gè)長(zhǎng)得像列表的對(duì)象(但不是列表),當(dāng)我們要判斷某個(gè)鍵是否被按下的時(shí)候,只需要判斷if keys[想要判斷的鍵],如果返回True,說明被按住了。基于這個(gè)原理,我們來寫兩段代碼。首先修改Pig類,新增一個(gè).update方法:

          class?Pig(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Pig,?self).__init__()
          ????????self.surf?=?pygame.image.load('pig_in_car.png').convert_alpha()
          ????????self.rect?=?self.surf.get_rect(center=(400,?300))??#?中心定位

          ????def?update(self,?keys):
          ????????if?keys[pygame.K_LEFT]:
          ????????????self.rect.move_ip((-5,?0))??#?橫坐標(biāo)向左
          ????????elif?keys[pygame.K_RIGHT]:
          ????????????self.rect.move_ip((5,?0))??#?橫坐標(biāo)向右
          ????????elif?keys[pygame.K_UP]:
          ????????????self.rect.move_ip((0,?-5))??#縱坐標(biāo)向上
          ????????elif?keys[pygame.K_DOWN]:
          ????????????self.rect.move_ip((0,?5))??#?縱坐標(biāo)向下

          ????????#?防止小豬跑到屏幕外面
          ????????if?self.rect.left?0:
          ????????????self.rect.left?=?0
          ????????if?self.rect.right?>?800:
          ????????????self.rect.right?=?800
          ????????if?self.rect.top?0:
          ????????????self.rect.top?=?0
          ????????if?self.rect.bottom?>?600:
          ????????????self.rect.bottom?=?600

          .update方法接收一個(gè)參數(shù)keys,就是我們按鍵返回的長(zhǎng)得像列表的對(duì)象。然后判斷是哪個(gè)方向鍵被按下了。根據(jù)被按下的鍵,.rect坐標(biāo)定位對(duì)象修改相應(yīng)方向的值。rect.move_ip這里的ipinplace的簡(jiǎn)寫,也就是修改.rect這個(gè)屬性自身。它的參數(shù)是一個(gè)元組,對(duì)應(yīng)橫坐標(biāo)和縱坐標(biāo)。橫縱坐標(biāo)小于0表示向左或者向上,大于0表示向右或者向下。

          原來的main()函數(shù)只需要在win.blit之前增加兩行代碼:

          keys?=?pygame.key.get_pressed()
          pig.update(keys)

          完整代碼如下:

          import?pygame


          class?Bg(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Bg,?self).__init__()
          ????????bg_small?=?pygame.image.load('bg.png').convert_alpha()
          ????????grass_land?=?bg_small.subsurface((0,?0,?128,?128))
          ????????self.surf?=?pygame.transform.scale(grass_land,?(800,?600))
          ????????self.rect?=?self.surf.get_rect(left=0,?top=0)??#?左上角定位


          class?Pig(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Pig,?self).__init__()
          ????????self.surf?=?pygame.image.load('pig_in_car.png').convert_alpha()
          ????????self.rect?=?self.surf.get_rect(center=(400,?300))??#?中心定位

          ????def?update(self,?keys):
          ????????if?keys[pygame.K_LEFT]:
          ????????????self.rect.move_ip((-5,?0))
          ????????elif?keys[pygame.K_RIGHT]:
          ????????????self.rect.move_ip((5,?0))
          ????????elif?keys[pygame.K_UP]:
          ????????????self.rect.move_ip((0,?-5))
          ????????elif?keys[pygame.K_DOWN]:
          ????????????self.rect.move_ip((0,?5))

          ????????#?防止小豬跑到屏幕外面
          ????????if?self.rect.left?0:
          ????????????self.rect.left?=?0
          ????????if?self.rect.right?>?800:
          ????????????self.rect.right?=?800
          ????????if?self.rect.top?0:
          ????????????self.rect.top?=?0
          ????????if?self.rect.bottom?>?600:
          ????????????self.rect.bottom?=?600


          class?Goddess(pygame.sprite.Sprite):
          ????def?__init__(self):
          ????????super(Goddess,?self).__init__()
          ????????building?=?pygame.image.load('building.png').convert_alpha()
          ????????self.surf?=?building.subsurface(((7?*?64?-?10,?0,?50,?100)))
          ????????self.rect?=?self.surf.get_rect(center=(500,?430))??#?女神像的中心放到畫布(500,?430)的位置


          def?main():
          ????pygame.init()
          ????pygame.display.set_caption('未聞Code:青南做的游戲')??#?游戲標(biāo)題
          ????win?=?pygame.display.set_mode((800,?600))??#?窗口尺寸

          ????bg?=?Bg()
          ????goddess?=?Goddess()
          ????pig?=?Pig()
          ????all_sprites?=?[bg,?goddess,?pig]??#?注意添加順序,后添加的對(duì)象圖層在先添加的對(duì)象的圖層上面

          ????running?=?True
          ????while?running:
          ????????for?event?in?pygame.event.get():
          ????????????if?event.type?==?pygame.QUIT:??#?點(diǎn)擊左上角或者右上角的x關(guān)閉窗口時(shí),停止程序
          ????????????????running?=?False

          ????????keys?=?pygame.key.get_pressed()
          ????????pig.update(keys)
          ????????for?sprite?in?all_sprites:
          ????????????win.blit(sprite.surf,?sprite.rect)
          ????????pygame.display.flip()


          if?__name__?==?'__main__':
          ????main()

          最后的運(yùn)行效果如下面這個(gè)視頻所示:

          總結(jié)

          PyGame做游戲真的非常簡(jiǎn)單,只要會(huì)加載素材,就能做出一個(gè)還能看得過去的游戲。今天我們學(xué)會(huì)了怎么添加素材,怎么捕獲鍵盤事件。

          PyGame可以讀取Gif圖片,但是你會(huì)發(fā)現(xiàn)加載進(jìn)來以后,Gif不會(huì)動(dòng)。下一篇文章,我們來講講如何讓你控制的角色動(dòng)起來,例如控制一個(gè)小娃娃,移動(dòng)的時(shí)候,它的腳也跟著動(dòng)。以及對(duì)象的碰撞檢測(cè)。

          參考資料

          [1]

          itch.io: https://itch.io/game-assets

          [2]

          PyGame: A Primer on Game Programming in Python: https://realpython.com/pygame-a-primer


          往期推薦
          1、寫 Python 腳本,一定要加上這個(gè)!
          2、Python 3.11 ,即將變得更快!
          3、如何只用一行Python代碼制作一個(gè)GUI(圖形界面)?
          4、Python實(shí)戰(zhàn)之將頭像轉(zhuǎn)成動(dòng)漫風(fēng)
          5、用Python做游戲有多簡(jiǎn)單
          點(diǎn)擊關(guān)注公眾號(hào),閱讀更多精彩內(nèi)容
          瀏覽 42
          點(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>
                  日韩成人av影视 日韩成人一级AV 日韩电影无码麻豆 | 特级西西444www无码视频免费看 | 欧美性生交大片免费看A片免费 | 中字无码 | 久久精品三级电影 |