您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何添加計分到你的Python游戲”,在日常操作中,相信很多人在如何添加計分到你的Python游戲問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何添加計分到你的Python游戲”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
現在,既然你有了可以被玩家收集的獎勵,那就有充分的理由來記錄分數,以便你的玩家看到他們收集了多少獎勵。你也可以跟蹤玩家的生命值,以便當他們被敵人擊中時會有相應結果。
你已經有了跟蹤分數和生命值的變量,但是這一切都發生在后臺。這篇文章教你在游戲期間在游戲屏幕上以你選擇的一種字體來顯示這些統計數字。
大多數 Python 模塊都有文檔,即使那些沒有文檔的模塊,也能通過 Python 的幫助功能來進行最小的文檔化。Pygame 的主頁面 鏈接了它的文檔。不過,Pygame 是一個帶有很多文檔的大模塊,并且它的文檔不像在 Opensource.com 上的文章一樣,以同樣易理解的(和友好的、易解釋的、有用的)敘述風格來撰寫的。它們是技術文檔,并且列出在模塊中可用的每個類和函數,各自要求的輸入類型等等。如果你不適應參考代碼組件描述,這可能會令人不知所措。
在煩惱于庫的文檔前,第一件要做的事,就是來想想你正在嘗試達到的目標。在這種情況下,你想在屏幕上顯示玩家的得分和生命值。
在你確定你需要的結果后,想想它需要什么的組件。你可以從變量和函數的方面考慮這一點,或者,如果你還沒有自然地想到這一點,你可以進行一般性思考。你可能意識到需要一些文本來顯示一個分數,你希望 Pygame 在屏幕上繪制這些文本。如果你仔細思考,你可能會意識到它與在屏幕上渲染一個玩家、獎勵或一個平臺并多么大的不同。
從技術上講,你可以使用數字圖形,并讓 Pygame 顯示這些數字圖形。它不是達到你目標的最容易的方法,但是如果它是你唯一知道的方法,那么它是一個有效的方法。不過,如果你參考 Pygame 的文檔,你看到列出的模塊之一是 font
,這是 Pygame 使得在屏幕上來使打印文本像輸入文字一樣容易的方法。
font
文檔頁面以 pygame.font.init()
開始,它列出了用于初始化字體模塊的函數。它由 pygame.init()
自動地調用,你已經在代碼中調用了它。再強調一次,從技術上講,你已經到達一個足夠好的點。雖然你尚不知道如何做,你知道你能夠使用 pygame.font
函數來在屏幕上打印文本。
然而,如果你閱讀更多一些,你會找到這里還有一種更好的方法來打印字體。pygame.freetype
模塊在文檔中的描述方式如下:
pygame.freetype
模塊是pygame.fontpygame
模塊的一個替代品,用于加載和渲染字體。它有原函數的所有功能,外加很多新的功能。
在 pygame.freetype
文檔頁面的下方,有一些示例代碼:
import pygameimport pygame.freetype
你的代碼應該已經導入了 Pygame,不過,請修改你的 import
語句以包含 Freetype 模塊:
import pygameimport sysimport osimport pygame.freetype
從 font
模塊的描述中可以看出,顯然 Pygame 使用一種字體(不管它的你提供的或內置到 Pygame 的默認字體)在屏幕上渲染字體。滾動瀏覽 pygame.freetype
文檔來找到 pygame.freetype.Font
函數:
pygame.freetype.Font從支持的字體文件中創建一個新的字體實例。 Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font pygame.freetype.Font.name 符合規則的字體名稱。 pygame.freetype.Font.path 字體文件路徑。 pygame.freetype.Font.size 在渲染中使用的默認點大小
這描述了如何在 Pygame 中構建一個字體“對象”。把屏幕上的一個簡單對象視為一些代碼屬性的組合對你來說可能不太自然,但是這與你構建英雄和敵人精靈的方式非常類似。你需要一個字體文件,而不是一個圖像文件。在你有一個字體文件后,你可以在你的代碼中使用 pygame.freetype.Font
函數來創建一個字體對象,然后使用該對象來在屏幕上渲染文本。
因為并不是世界上的每個人的電腦上都有完全一樣的字體,因此將你選擇的字體與你的游戲捆綁在一起是很重要的。要捆綁字體,首先在你的游戲文件夾中創建一個新的目錄,放在你為圖像而創建的文件目錄旁邊。稱其為 fonts
。
即使你的計算機操作系統隨附了幾種字體,但是將這些字體給予其他人是非法的。這看起來很奇怪,但法律就是這樣運作的。如果想與你的游戲一起隨附一種字體,你必需找到一種開源或知識共享的字體,以允許你隨游戲一起提供該字體。
專門提供自由和合法字體的網站包括:
Font Library
Font Squirrel
League of Moveable Type
當你找到你喜歡的字體后,下載下來。解壓縮 ZIP 或 TAR 文件,并移動 .ttf
或 .otf
文件到你的項目目錄下的 fonts
文件夾中。
你沒有安裝字體到你的計算機上。你只是放置字體到你游戲的 fonts
文件夾中,以便 Pygame 可以使用它。如果你想,你可以在你的計算機上安裝該字體,但是沒有必要。重要的是將字體放在你的游戲目錄中,這樣 Pygame 可以“描繪”字體到屏幕上。
如果字體文件的名稱復雜且帶有空格或特殊字符,只需要重新命名它即可。文件名稱是完全任意的,并且對你來說,文件名稱越簡單,越容易將其鍵入你的代碼中。
現在告訴 Pygame 你的字體。從文檔中你知道,當你至少提供了字體文件路徑給 pygame.freetype.Font
時(文檔明確指出所有其余屬性都是可選的),你將在返回中獲得一個字體對象:
Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font
創建一個稱為 myfont
的新變量來充當你在游戲中字體,并放置 Font
函數的結果到這個變量中。這個示例中使用 amazdoom.ttf
字體,但是你可以使用任何你想使用的字體。在你的設置部分放置這些代碼:
font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"fonts","amazdoom.ttf")font_size = txmyfont = pygame.freetype.Font(font_path, font_size)
現在你已經創建一個字體對象,你需要一個函數來繪制你想繪制到屏幕上的文本。這和你在你的游戲中繪制背景和平臺是相同的原理。
首先,創建一個函數,并使用 myfont
對象來創建一些文本,設置顏色為某些 RGB 值。這必須是一個全局函數;它不屬于任何具體的類:
def stats(score,health): myfont.render_to(world, (4, 4), "Score:"+str(score), WHITE, None, size=64) myfont.render_to(world, (4, 72), "Health:"+str(health), WHITE, None, size=64)
當然,你此刻已經知道,如果它不在主循環中,你的游戲將不會發生任何事,所以在文件的底部添加一個對你的 stats
函數的調用:
for e in enemy_list: e.move() stats(player.score,player.health) # draw text pygame.display.flip()
嘗試你的游戲。
當玩家收集獎勵品時,得分會上升。當玩家被敵人擊中時,生命值下降。成功!
Keeping score in Pygame
不過,這里有一個問題。當一個玩家被敵人擊中時,健康度會一路下降,這是不公平的。你剛剛發現一個非致命的錯誤。非致命的錯誤是這些在應用程序中小問題,(通常)不會阻止應用程序啟動或甚至導致停止工作,但是它們要么沒有意義,要么會惹惱用戶。這里是如何解決這個問題的方法。
當前生命值系統的問題是,敵人接觸玩家時,Pygame 時鐘的每一次滴答,健康度都會減少。這意味著一個緩慢移動的敵人可能在一次遭遇中將一個玩家降低健康度至 -200 ,這不公平。當然,你可以給你的玩家一個 10000 的起始健康度得分,而不用擔心它;這可以工作,并且可能沒有人會注意。但是這里有一個更好的方法。
當前,你的代碼偵查出一個玩家和一個敵人發生碰撞的時候。生命值問題的修復是檢測兩個獨立的事件:什么時候玩家和敵人碰撞,并且,在它們碰撞后,什么時候它們停止碰撞。
首先,在你的玩家類中,創建一個變量來代表玩家和敵人碰撞在一起:
self.frame = 0 self.health = 10 self.damage = 0
在你的 Player
類的 update
函數中,移除這塊代碼塊:
for enemy in enemy_hit_list: self.health -= 1 #print(self.health)
并且在它的位置,只要玩家當前沒有被擊中,檢查碰撞:
if self.damage == 0: for enemy in enemy_hit_list: if not self.rect.contains(enemy): self.damage = self.rect.colliderect(enemy)
你可能會在你刪除的語句塊和你剛剛添加的語句塊之間看到相似之處。它們都在做相同的工作,但是新的代碼更復雜。最重要的是,只有當玩家當前沒有被擊中時,新的代碼才運行。這意味著,當一個玩家和敵人碰撞時,這些代碼運行一次,而不是像以前那樣一直發生碰撞。
新的代碼使用兩個新的 Pygame 函數。self.rect.contains
函數檢查一個敵人當前是否在玩家的邊界框內,并且當它是 true
時, self.rect.colliderect
設置你的新的 self.damage
變量為 1,而不管它多少次是 true
。
現在,即使被一個敵人擊中 3 秒,對 Pygame 來說仍然看作一次擊中。
我通過通讀 Pygame 的文檔而發現了這些函數。你沒有必要一次閱讀完全部的文檔,并且你也沒有必要閱讀每個函數的每個單詞。不過,花費時間在你正在使用的新的庫或模塊的文檔上是很重要的;否則,你極有可能在重新發明輪子。不要花費一個下午的時間來嘗試修改拼接一個解決方案到一些東西,而這些東西已經被你正在使用的框架的所解決。閱讀文檔,知悉函數,并從別人的工作中獲益!
最后,添加另一個代碼語句塊來偵查出什么時候玩家和敵人不再接觸。然后直到那時,才從玩家減少一個生命值。
if self.damage == 1: idx = self.rect.collidelist(enemy_hit_list) if idx == -1: self.damage = 0 # set damage back to 0 self.health -= 1 # subtract 1 hp
注意,只有當玩家被擊中時,這個新的代碼才會被觸發。這意味著,在你的玩家在你的游戲世界正在探索或收集獎勵時,這個代碼不會運行。它僅當 self.damage
變量被激活時運行。
當代碼運行時,它使用 self.rect.collidelist
來查看玩家是否仍然接觸在你敵人列表中的敵人(當其未偵查到碰撞時,collidelist
返回 -1)。在它沒有接觸敵人時,是該處理 self.damage
的時機:通過設置 self.damage
變量回到 0 來使其無效,并減少一點生命值。
現在嘗試你的游戲。
現在,你有一個來讓你的玩家知道它們分數和生命值的方法,當你的玩家達到某些里程碑時,你可以確保某些事件發生。例如,也許這里有一個特殊的恢復一些生命值的獎勵項目。也許一個到達 0 生命值的玩家不得不從一個關卡的起始位置重新開始。
你可以在你的代碼中檢查這些事件,并且相應地操縱你的游戲世界。你已經知道該怎么做,所以請瀏覽文檔來尋找新的技巧,并且獨立地嘗試這些技巧。
這里是到目前為止所有的代碼:
#!/usr/bin/env python3# draw a world# add a player and player control# add player movement# add enemy and basic collision# add platform# add gravity# add jumping# add scrolling# add loot# add score # GNU All-Permissive License# Copying and distribution of this file, with or without modification,# are permitted in any medium without royalty provided the copyright# notice and this notice are preserved. This file is offered as-is,# without any warranty. import pygameimport sysimport osimport pygame.freetype '''Objects''' class Platform(pygame.sprite.Sprite): # x location, y location, img width, img height, img file def __init__(self,xloc,yloc,imgw,imgh,img): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(os.path.join('images',img)).convert() self.image.convert_alpha() self.rect = self.image.get_rect() self.rect.y = yloc self.rect.x = xloc class Player(pygame.sprite.Sprite): ''' Spawn a player ''' def __init__(self): pygame.sprite.Sprite.__init__(self) self.movex = 0 self.movey = 0 self.frame = 0 self.health = 10 self.damage = 0 self.collide_delta = 0 self.jump_delta = 6 self.score = 1 self.images = [] for i in range(1,9): img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert() img.convert_alpha() img.set_colorkey(ALPHA) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() def jump(self,platform_list): self.jump_delta = 0 def gravity(self): self.movey += 3.2 # how fast player falls if self.rect.y > worldy and self.movey >= 0: self.movey = 0 self.rect.y = worldy-ty def control(self,x,y): ''' control player movement ''' self.movex += x self.movey += y def update(self): ''' Update sprite position ''' self.rect.x = self.rect.x + self.movex self.rect.y = self.rect.y + self.movey # moving left if self.movex < 0: self.frame += 1 if self.frame > ani*3: self.frame = 0 self.image = self.images[self.frame//ani] # moving right if self.movex > 0: self.frame += 1 if self.frame > ani*3: self.frame = 0 self.image = self.images[(self.frame//ani)+4] # collisions enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False) if self.damage == 0: for enemy in enemy_hit_list: if not self.rect.contains(enemy): self.damage = self.rect.colliderect(enemy) if self.damage == 1: idx = self.rect.collidelist(enemy_hit_list) if idx == -1: self.damage = 0 # set damage back to 0 self.health -= 1 # subtract 1 hp loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False) for loot in loot_hit_list: loot_list.remove(loot) self.score += 1 print(self.score) plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False) for p in plat_hit_list: self.collide_delta = 0 # stop jumping self.movey = 0 if self.rect.y > p.rect.y: self.rect.y = p.rect.y+ty else: self.rect.y = p.rect.y-ty ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False) for g in ground_hit_list: self.movey = 0 self.rect.y = worldy-ty-ty self.collide_delta = 0 # stop jumping if self.rect.y > g.rect.y: self.health -=1 print(self.health) if self.collide_delta < 6 and self.jump_delta < 6: self.jump_delta = 6*2 self.movey -= 33 # how high to jump self.collide_delta += 6 self.jump_delta += 6 class Enemy(pygame.sprite.Sprite): ''' Spawn an enemy ''' def __init__(self,x,y,img): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(os.path.join('images',img)) self.movey = 0 #self.image.convert_alpha() #self.image.set_colorkey(ALPHA) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.counter = 0 def move(self): ''' enemy movement ''' distance = 80 speed = 8 self.movey += 3.2 if self.counter >= 0 and self.counter <= distance: self.rect.x += speed elif self.counter >= distance and self.counter <= distance*2: self.rect.x -= speed else: self.counter = 0 self.counter += 1 if not self.rect.y >= worldy-ty-ty: self.rect.y += self.movey plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False) for p in plat_hit_list: self.movey = 0 if self.rect.y > p.rect.y: self.rect.y = p.rect.y+ty else: self.rect.y = p.rect.y-ty ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False) for g in ground_hit_list: self.rect.y = worldy-ty-ty class Level(): def bad(lvl,eloc): if lvl == 1: enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy enemy_list = pygame.sprite.Group() # create enemy group enemy_list.add(enemy) # add enemy to group if lvl == 2: print("Level " + str(lvl) ) return enemy_list def loot(lvl,tx,ty): if lvl == 1: loot_list = pygame.sprite.Group() loot = Platform(200,ty*7,tx,ty, 'loot_1.png') loot_list.add(loot) if lvl == 2: print(lvl) return loot_list def ground(lvl,gloc,tx,ty): ground_list = pygame.sprite.Group() i=0 if lvl == 1: while i < len(gloc): ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png') ground_list.add(ground) i=i+1 if lvl == 2: print("Level " + str(lvl) ) return ground_list def platform(lvl,tx,ty): plat_list = pygame.sprite.Group() ploc = [] i=0 if lvl == 1: ploc.append((20,worldy-ty-128,3)) ploc.append((300,worldy-ty-256,3)) ploc.append((500,worldy-ty-128,4)) while i < len(ploc): j=0 while j <= ploc[i][2]: plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png') plat_list.add(plat) j=j+1 print('run' + str(i) + str(ploc[i])) i=i+1 if lvl == 2: print("Level " + str(lvl) ) return plat_list def stats(score,health): myfont.render_to(world, (4, 4), "Score:"+str(score), SNOWGRAY, None, size=64) myfont.render_to(world, (4, 72), "Health:"+str(health), SNOWGRAY, None, size=64) '''Setup'''worldx = 960worldy = 720 fps = 40 # frame rateani = 4 # animation cyclesclock = pygame.time.Clock()pygame.init()main = True BLUE = (25,25,200)BLACK = (23,23,23 )WHITE = (254,254,254)SNOWGRAY = (137,164,166)ALPHA = (0,255,0) world = pygame.display.set_mode([worldx,worldy])backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()backdropbox = world.get_rect()player = Player() # spawn playerplayer.rect.x = 0player.rect.y = 0player_list = pygame.sprite.Group()player_list.add(player)steps = 10forwardx = 600backwardx = 230 eloc = []eloc = [200,20]gloc = []tx = 64 #tile sizety = 64 #tile size font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"fonts","amazdoom.ttf")font_size = txmyfont = pygame.freetype.Font(font_path, font_size) i=0while i <= (worldx/tx)+tx: gloc.append(i*tx) i=i+1 enemy_list = Level.bad( 1, eloc )ground_list = Level.ground( 1,gloc,tx,ty )plat_list = Level.platform( 1,tx,ty )loot_list = Level.loot(1,tx,ty) '''Main loop'''while main == True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit(); sys.exit() main = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT or event.key == ord('a'): print("LEFT") player.control(-steps,0) if event.key == pygame.K_RIGHT or event.key == ord('d'): print("RIGHT") player.control(steps,0) if event.key == pygame.K_UP or event.key == ord('w'): print('jump') if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT or event.key == ord('a'): player.control(steps,0) if event.key == pygame.K_RIGHT or event.key == ord('d'): player.control(-steps,0) if event.key == pygame.K_UP or event.key == ord('w'): player.jump(plat_list) if event.key == ord('q'): pygame.quit() sys.exit() main = False # scroll the world forward if player.rect.x >= forwardx: scroll = player.rect.x - forwardx player.rect.x = forwardx for p in plat_list: p.rect.x -= scroll for e in enemy_list: e.rect.x -= scroll for l in loot_list: l.rect.x -= scroll # scroll the world backward if player.rect.x <= backwardx: scroll = backwardx - player.rect.x player.rect.x = backwardx for p in plat_list: p.rect.x += scroll for e in enemy_list: e.rect.x += scroll for l in loot_list: l.rect.x += scroll world.blit(backdrop, backdropbox) player.gravity() # check gravity player.update() player_list.draw(world) #refresh player position enemy_list.draw(world) # refresh enemies ground_list.draw(world) # refresh enemies plat_list.draw(world) # refresh platforms loot_list.draw(world) # refresh loot for e in enemy_list: e.move() stats(player.score,player.health) # draw text pygame.display.flip() clock.tick(fps)
到此,關于“如何添加計分到你的Python游戲”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。