引言
最近小伙伴告訴我一種新的方法,可以使用wasm來(lái)使瀏覽器網(wǎng)頁(yè)能夠運(yùn)行Python代碼。這一下子激起了我的興趣,因?yàn)檫@意味著用戶無(wú)需安裝Python環(huán)境就能直接運(yùn)行我的demo,這真是太方便了。所以,我們的主要目標(biāo)今天就是讓網(wǎng)頁(yè)能夠直接運(yùn)行我的貪吃蛇游戲。貪吃蛇游戲其實(shí)很簡(jiǎn)單,因?yàn)镻ython有一個(gè)很棒的pygame庫(kù)可以供我們使用。所以編寫(xiě)起來(lái)也不會(huì)太復(fù)雜。廢話不多說(shuō),讓我們開(kāi)始吧。
何為wasm
全稱為WebAssembly ,簡(jiǎn)稱為Wasm,是一種能夠在web上加載非常快速的一種格式。它可以被視為HTML、JS等其他表達(dá)形式的一種補(bǔ)充。對(duì)于我來(lái)說(shuō),這就是它的簡(jiǎn)單定義。然而,我們今天的任務(wù)并不是去介紹Wasm,而是探討如何實(shí)現(xiàn)Python在web中直接運(yùn)行的方法。
當(dāng)然有興趣的同學(xué)可以直接去看官方網(wǎng)站:https://webassembly.org/
emscripten
我們現(xiàn)在已經(jīng)了解到,WebAssembly可以在web上運(yùn)行,但我想知道如何將我的Python代碼轉(zhuǎn)換成WebAssembly。當(dāng)然,肯定有相應(yīng)的工具可供使用。在網(wǎng)上,最常被提及的工具就是emscripten,可以說(shuō)是WebAssembly的核心工具。它的主要功能是將其他高級(jí)語(yǔ)言編譯成WebAssembly。然而,我在本地嘗試過(guò)后發(fā)現(xiàn),emscripten無(wú)法直接將Python代碼轉(zhuǎn)換成WebAssembly格式。你需要使用其他工具先將Python轉(zhuǎn)換成其他高級(jí)語(yǔ)言如C語(yǔ)言,然后再使用emscripten將其轉(zhuǎn)換成WebAssembly。如果你知道其他更好的方法,可以在下方提出來(lái),非常感謝。
我就不實(shí)驗(yàn)了,畢竟后臺(tái)報(bào)錯(cuò),如果你有興趣可以看看emscripten官方網(wǎng)站:https://emscripten.org/
在網(wǎng)站的頂部導(dǎo)航欄中,找到并點(diǎn)擊 "Get Started"(開(kāi)始使用)。
pyodide
如果你嘗試過(guò)在Web上運(yùn)行Python代碼,那你肯定了解到pyodide方案,它確實(shí)是一個(gè)功能強(qiáng)大的工具。然而,它也存在明顯的缺點(diǎn),例如它所支持的第三方庫(kù)非常有限,而且加載速度也很慢。盡管如此,它仍然是最便捷的選擇,因?yàn)槟憧梢灾苯釉贖TML中編寫(xiě)代碼,而不需要額外的工具。唯一需要注意的是需要引用它的JavaScript文件。test.html
代碼示例如下:
<script src="https://cdn.jsdelivr.net/pyodide/v0.18.1/full/pyodide.js"></script>
<script type="text/javascript">
loadPyodide({ indexURL : "https://cdn.jsdelivr.net/pyodide/v0.18.1/full/" }).then((pyodide) => {
pyodide.runPython(`
def hello_world():
return "Hello, World!"
print(hello_world())
`);
});
</script>
對(duì)于我們來(lái)說(shuō),使用pyodide是相對(duì)簡(jiǎn)單的。只需點(diǎn)擊文件后,瀏覽器就能正常運(yùn)行其中的Python代碼。但是要直接使用Python的pygame庫(kù)是不可能的。不過(guò),一些簡(jiǎn)單的代碼還是可以運(yùn)行的。那么,是否還有其他解決方案呢?答案是肯定的。
pygbag
開(kāi)發(fā)人員在尋找解決方案時(shí),最好的資源就是Github了。幾乎所有開(kāi)源的代碼倉(cāng)庫(kù)都可以在那里找到,只要你能想到的,幾乎都能找到。我也是通過(guò)搜索找到了一個(gè)解決方案,真的有一個(gè)開(kāi)源的第三方庫(kù)叫做pygbag。雖然這個(gè)庫(kù)很新,但它是由Python官方支持的。只是要依靠官方文檔和瀏覽器去尋找示例代碼。連gpt這樣的人工智能模型都不知道有這么一個(gè)東西存在。此外,pygbag專門(mén)集成了pygame,可以直接將Python代碼編譯成wasm,在瀏覽器中運(yùn)行。它還有官方開(kāi)發(fā)人員制作的游戲可供參考,當(dāng)然如果你也制作了游戲,也可以上傳到這里。
官方Github地址:https://github.com/pygame-web/pygbag
官方游戲首頁(yè):https://itch.io/games/tag-roguelike
他的宗旨也很簡(jiǎn)單:Python WebAssembly for everyone ( packager + test server ),但是他也有一些編碼要求,我們先來(lái)實(shí)現(xiàn)一個(gè)貪吃蛇游戲吧。
貪吃蛇游戲
在開(kāi)始使用pygbag三方庫(kù)之前,我們需要確保已經(jīng)在本地實(shí)現(xiàn)了貪吃蛇游戲?,F(xiàn)在,請(qǐng)跟著我一起按照以下步驟進(jìn)行操作。
安裝 Pygame
命令如下:pip install pygame
Pygame是一套專門(mén)用于編寫(xiě)游戲的Python模組,它在SDL庫(kù)的基礎(chǔ)上添加了各種游戲功能的實(shí)現(xiàn)。借助Python語(yǔ)言的靈活性,你可以快速、輕松地創(chuàng)建各種類型的游戲。正如之前所提到的,Python擁有豐富的庫(kù)和模組,我們只需直接使用它們,而不必重復(fù)造輪子。
我已經(jīng)為你寫(xiě)好了貪吃蛇游戲的代碼,你可以直接使用。這是一個(gè)大家都很熟悉的游戲,所以沒(méi)有太多需要解釋的。
import pygame
import random
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
running = True
dt = 0
player_pos = [pygame.Vector2(screen.get_width() / 2, screen.get_height() / 2)]
player_speed = 300
player_radius = 30
food_pos = pygame.Vector2(random.randint(0, screen.get_width()), random.randint(0, screen.get_height()))
food_radius = 15
direction = pygame.Vector2(0, 0)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill("black")
keys = pygame.key.get_pressed()
if keys[pygame.K_w] or keys[pygame.K_UP]:
direction = pygame.Vector2(0, -1)
if keys[pygame.K_s] or keys[pygame.K_DOWN]:
direction = pygame.Vector2(0, 1)
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
direction = pygame.Vector2(-1, 0)
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
direction = pygame.Vector2(1, 0)
# Move the player's head
player_pos[0] += direction * player_speed * dt
# Check if player eats the food
if player_pos[0].distance_to(food_pos) < player_radius + food_radius:
player_pos.append(player_pos[-1].copy()) # Add new segment to the player
food_pos = pygame.Vector2(random.randint(0, screen.get_width()), random.randint(0, screen.get_height())) # Generate new food
# Move the player's body
for i in range(len(player_pos)-1, 0, -1):
player_pos[i] = player_pos[i-1].copy()
pygame.draw.circle(screen, "white", food_pos, food_radius) # Draw the food
for pos in player_pos:
pygame.draw.circle(screen, "red", pos, player_radius) # Draw the player
pygame.display.flip()
dt = clock.tick(60) / 1000
pygame.quit()
啟動(dòng)命令就是python main.py
。運(yùn)行效果如下:我想要說(shuō)明的是,我只是簡(jiǎn)單地實(shí)現(xiàn)了一下,并沒(méi)有進(jìn)行太多的校驗(yàn)。另外,值得注意的是,盡管我吃完食物后,并沒(méi)有在身體上感受到太大的變化,但當(dāng)我吃了很多食物之后,你就可以看到明顯的變化了。
pygbag改造
使用 pygbag 將 pygame 制作的游戲打包,使游戲可在瀏覽器中直接運(yùn)行。 pygbag 的使用可參考 Pygbag Wiki。官方文檔:https://pygame-web.github.io/
使用 pip 安裝 pygbag:pip install pygbag
使用 pygbag 打包游戲前,待打包的目錄下的游戲代碼文件須名為 main.py。 然后僅需對(duì)游戲代碼做簡(jiǎn)易修改,修改后代碼如下:
import pygame
import random
import asyncio
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
running = True
dt = 0
player_pos = [pygame.Vector2(screen.get_width() / 2, screen.get_height() / 2)]
player_speed = 300
player_radius = 30
food_pos = pygame.Vector2(random.randint(0, screen.get_width()), random.randint(0, screen.get_height()))
food_radius = 15
direction = pygame.Vector2(0, 0)
async def main():
global screen, clock, running, dt ,player_pos ,player_speed,player_radius,food_pos,food_radius,direction
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill("black")
keys = pygame.key.get_pressed()
if keys[pygame.K_w] or keys[pygame.K_UP]:
direction = pygame.Vector2(0, -1)
if keys[pygame.K_s] or keys[pygame.K_DOWN]:
direction = pygame.Vector2(0, 1)
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
direction = pygame.Vector2(-1, 0)
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
direction = pygame.Vector2(1, 0)
# Move the player's head
player_pos[0] += direction * player_speed * dt
# Check if player eats the food
if player_pos[0].distance_to(food_pos) < player_radius + food_radius:
player_pos.append(player_pos[-1].copy()) # Add new segment to the player
food_pos = pygame.Vector2(random.randint(0, screen.get_width()), random.randint(0, screen.get_height())) # Generate new food
# Move the player's body
for i in range(len(player_pos)-1, 0, -1):
player_pos[i] = player_pos[i-1].copy()
pygame.draw.circle(screen, "white", food_pos, food_radius) # Draw the food
for pos in player_pos:
pygame.draw.circle(screen, "red", pos, player_radius) # Draw the player
pygame.display.flip()
dt = clock.tick(60) / 1000
await asyncio.sleep(0)
pygame.quit()
if __name__ == '__main__':
# 使用 asyncio.run() 調(diào)用主函數(shù) main()
asyncio.run(main())
可以看到,基本上必須引入另一個(gè)包:導(dǎo)入 asyncio。剩下的就沒(méi)啥了。我們?cè)賮?lái)啟動(dòng)下。
啟動(dòng)命令需要修改下:python -m pygbag pyGame
,這里注意下,pygbag打包的是整個(gè)目錄,所以不能像Python那樣啟動(dòng),所以我基本上都是回退到父級(jí)目錄后,在進(jìn)行終端控制臺(tái)打包。命令會(huì)直接在本地啟動(dòng)游戲服務(wù)。你稍等片刻。
然后直接字啊瀏覽器查看URL地址:http://localhost:8000/,仍然是稍等片刻,讓他加載一下。這時(shí)候,你就可以看到瀏覽器的游戲界面了,如下:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-779948.html
總結(jié)
經(jīng)過(guò)努力,我成功完成了任務(wù)。如果你有興趣,也可以將你的游戲上傳到官方網(wǎng)站,但作為示例,我并不打算上傳。不過(guò),我已經(jīng)提供了源代碼給你,所以你可以直接復(fù)制粘貼并運(yùn)行它。雖然Python現(xiàn)在可以直接在web端使用,但我個(gè)人不太喜歡這種方式。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-779948.html
到了這里,關(guān)于wasm+pygbag讓你在網(wǎng)頁(yè)上也能運(yùn)行Python代碼:【貪吃蛇游戲】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!