1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        保姆級教程:用Python做游戲有多簡單

        共 8556字,需瀏覽 18分鐘

         ·

        2022-06-02 08:42


        我520的公眾號圖片發(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做游戲非常簡單,我們今天第一篇文章,讓大家實(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(素材對象,?(素材左上角的橫坐標(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ù)是我們剛剛加載的素材對象。第二個(gè)參數(shù)是一個(gè)元組,標(biāo)記這個(gè)圖片左上角在畫布上面的坐標(biāo)。整個(gè)畫布左上角對應(yīng)坐標(biāo)(0, 0)。由于背景圖的尺寸也是(800, 600),所以背景圖的左上角放到(0, 0),就剛好可以鋪滿整個(gè)畫布。

        哪里找素材?

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

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

        怎么我的素材長這樣?

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

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

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

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

        一般來說,像素風(fēng)格的素材,尺寸大多是16x16,32x32,64x64,128x128。素材作者正常情況下會(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)是我試了很多次,試出來的。

        使用小精靈來管理對象

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

        但我們可以使用面向?qū)ο蟮脑O(shè)計(jì)方法,讓代碼更容易維護(hù),也更簡單。PyGame里面,有一個(gè)類叫做Sprite,我們可以為每一個(gè)對象實(shí)現(xiàn)一個(gè)類,繼承Sprite,然后把對象的素材設(shè)置成.surf屬性,把對象的位置設(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]??#?注意添加順序,后添加的對象圖層在先添加的對象的圖層上面

        ????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ì)有更高級的數(shù)據(jù)結(jié)構(gòu)SpriteGroup來儲(chǔ)存他們。今天使用列表就足夠了。

        素材對象.get_rect()會(huì)返回一個(gè)坐標(biāo)定位對象,這個(gè)對象有多個(gè)屬性,例如.left, .top, .center, .width, .height。在不傳參數(shù)的情況下,默認(rèn).left=0, .top=0,PyGame會(huì)自動(dòng)根據(jù)這個(gè)對象的尺寸計(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è)類里面,素材對象可以用任何名字,不一定要用.surf。坐標(biāo)定位對象也不一定要用.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ù),也就是素材對象的坐標(biāo)有細(xì)微的差異,那么在人眼看起來,這個(gè)素材對象就在運(yùn)動(dòng)了。

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

        keys?=?pygame.key.get_pressed()

        它返回的是一個(gè)長得像列表的對象(但不是列表),當(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,就是我們按鍵返回的長得像列表的對象。然后判斷是哪個(gè)方向鍵被按下了。根據(jù)被按下的鍵,.rect坐標(biāo)定位對象修改相應(yīng)方向的值。rect.move_ip這里的ipinplace的簡寫,也就是修改.rect這個(gè)屬性自身。它的參數(shù)是一個(gè)元組,對應(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]??#?注意添加順序,后添加的對象圖層在先添加的對象的圖層上面

        ????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做游戲真的非常簡單,只要會(huì)加載素材,就能做出一個(gè)還能看得過去的游戲。今天我們學(xué)會(huì)了怎么添加素材,怎么捕獲鍵盤事件。

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

        參考資料

        [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做游戲有多簡單
        點(diǎn)擊關(guān)注公眾號,閱讀更多精彩內(nèi)容
        瀏覽 42
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            亭亭玉立四月天月色阑珊处情 | 东京热精品| 人人肏人人操 | 岳扒开下面让我舔是什么意思 | 日韩视频第一页 | 欧美一级婬片A片免费老牛 | 在线无码国产一区二区三区性色 | 两个黑人挺进娇妻体内 | 骚逼被草| 好大好爽好舒服 |