您好,登錄后才能下訂單哦!
怎么在Pygame游戲中放置平臺,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
在 Pygame 中,平臺本身也是個妖精,正像你那個可玩的妖精。這一點是重要的,因為有個是對象的平臺,可以使你的玩家妖精更容易與之互動。
創建平臺有兩個主要步驟。首先,你必須給該對象編寫代碼,然后,你必須映射出你希望該對象出現的位置。
要構建一個平臺對象,你要創建一個名為 Platform
的類。它是一個妖精,正像你的 Player
妖精 一樣,帶有很多相同的屬性。
你的 Platform
類需要知道很多平臺類型的信息,它應該出現在游戲世界的哪里、它應該包含的什么圖片等等。這其中很多信息可能還尚不存在,這要看你為你的游戲計劃了多少,但是沒有關系。正如直到移動你的游戲角色那篇文章結束時,你都沒有告訴你的玩家妖精移動速度有多快,你不必事先告訴 Platform
每一件事。
在這系列中你所寫的腳本的開頭附近,創建一個新的類。在這個代碼示例中前三行是用于說明上下文,因此在注釋的下面添加代碼:
import pygameimport sysimport os## 新代碼如下: 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.image.set_colorkey(ALPHA) self.rect = self.image.get_rect() self.rect.y = yloc self.rect.x = xloc
當被調用時,這個類在某個 X 和 Y 位置上創建一個屏上對象,具有某種寬度和高度,并使用某種圖像作為紋理。這與如何在屏上繪制出玩家或敵人非常類似。
下一步是繪制出你的平臺需要出現的地方。
實現平臺類游戲世界有幾種不同的方法。在最初的橫向滾軸游戲中,例如,馬里奧超級兄弟和刺猬索尼克,這個技巧是使用“瓷磚”方式,也就是說有幾個代表地面和各種平臺的塊,并且這些塊被重復使用來制作一個關卡。你只能有 8 或 12 種不同的塊,你可以將它們排列在屏幕上來創建地面、浮動的平臺,以及你游戲中需要的一切其它的事物。有人發現這是制作游戲最容易的方法了,因為你只需要制作(或下載)一小組關卡素材就能創建很多不同的關卡。然而,這里的代碼需要一點數學知識。
SuperTux ,一個基于瓷磚的電腦游戲。
另一種方法是將每個素材作為一個整體圖像。如果你喜歡為游戲世界創建素材,那你會在用圖形應用程序構建游戲世界的每個部分上花費很多時間。這種方法不需要太多的數學知識,因為所有的平臺都是整體的、完整的對象,你只需要告訴 Python 將它們放在屏幕上的什么位置。
每種方法都有優勢和劣勢,并且根據于你選擇使用的方式,代碼稍有不同。我將覆蓋這兩方面,所以你可以在你的工程中使用一種或另一種,甚至兩者的混合。
總的來說,繪制你的游戲世界是關卡設計和游戲編程中的一個重要的部分。這需要數學知識,但是沒有什么太難的,而且 Python 擅長數學,它會有所幫助。
你也許發現先在紙張上設計是有用的。拿一張表格紙,并繪制一個方框來代表你的游戲窗體。在方框中繪制平臺,并標記其每一個平臺的 X 和 Y 坐標,以及它的寬度和高度。在方框中的實際位置沒有必要是精確的,你只要保持數字合理即可。譬如,假設你的屏幕是 720 像素寬,那么你不能在一個屏幕上放 8 塊 100 像素的平臺。
當然,不是你游戲中的所有平臺都必須容納在一個屏幕大小的方框里,因為你的游戲將隨著你的玩家行走而滾動。所以,可以繼續繪制你的游戲世界到***屏幕的右側,直到關卡結束。
如果你更喜歡精確一點,你可以使用方格紙。當設計一個瓷磚類的游戲時,這是特別有用的,因為每個方格可以代表一個瓷磚。
一個關卡地圖示例。
你可能已經在學校中學習過笛卡爾坐標系。你學習的東西也適用于 Pygame,除了在 Pygame 中你的游戲世界的坐標系的原點 0,0
是放置在你的屏幕的左上角而不是在中間,是你在地理課上用過的坐標是在中間的。
在 Pygame 中的坐標示例。
X 軸起始于最左邊的 0,向右***增加。Y 軸起始于屏幕頂部的 0,向下延伸。
如果你不知道你的玩家、敵人、平臺是多大的,繪制出一個游戲世界是毫無意義的。你可以在圖形程序中找到你的平臺或瓷磚的尺寸。例如在 Krita 中,單擊“圖像”菜單,并選擇“屬性”。你可以在“屬性”窗口的最頂部處找到它的尺寸。
另外,你也可以創建一個簡單的 Python 腳本來告訴你的一個圖像的尺寸。打開一個新的文本文件,并輸入這些代碼到其中:
#!/usr/bin/env python3 from PIL import Imageimport os.pathimport sys if len(sys.argv) > 1: print(sys.argv[1])else: sys.exit('Syntax: identify.py [filename]') pic = sys.argv[1]dim = Image.open(pic)X = dim.size[0]Y = dim.size[1] print(X,Y)
保存該文本文件為 identify.py
。
要使用這個腳本,你必須安裝一些額外的 Python 模塊,它們包含了這個腳本中新使用的關鍵字:
$ pip3 install Pillow --user
一旦安裝好,在你游戲工程目錄中運行這個腳本:
$ python3 ./identify.py images/ground.png(1080, 97)
在這個示例中,地面平臺的圖形的大小是 1080 像素寬和 97 像素高。
如果你選擇單獨地繪制每個素材,你必須創建想要插入到你的游戲世界中的幾個平臺和其它元素,每個素材都放在它自己的文件中。換句話說,你應該讓每個素材都有一個文件,像這樣:
每個對象一個圖形文件。
你可以按照你希望的次數重復使用每個平臺,只要確保每個文件僅包含一個平臺。你不能使用一個文件包含全部素材,像這樣:
你的關卡不能是一個圖形文件。
當你完成時,你可能希望你的游戲看起來像這樣,但是如果你在一個大文件中創建你的關卡,你就沒有方法從背景中區分出一個平臺,因此,要么把對象繪制在它們自己的文件中,要么從一個更大的文件中裁剪出它們,并保存為單獨的副本。
注意: 如同你的其它素材,你可以使用 GIMP、Krita、MyPaint,或 Inkscape 來創建你的游戲素材。
平臺出現在每個關卡開始的屏幕上,因此你必須在你的 Level
類中添加一個 platform
函數。在這里特例是地面平臺,它重要到應該擁有它自己的一個組。通過把地面看作一組特殊類型的平臺,你可以選擇它是否滾動,或它上面是否可以站立,而其它平臺可以漂浮在它上面。這取決于你。
添加這兩個函數到你的 Level
類:
def ground(lvl,x,y,w,h): ground_list = pygame.sprite.Group() if lvl == 1: ground = Platform(x,y,w,h,'block-ground.png') ground_list.add(ground) if lvl == 2: print("Level " + str(lvl) ) return ground_list def platform( lvl ): plat_list = pygame.sprite.Group() if lvl == 1: plat = Platform(200, worldy-97-128, 285,67,'block-big.png') plat_list.add(plat) plat = Platform(500, worldy-97-320, 197,54,'block-small.png') plat_list.add(plat) if lvl == 2: print("Level " + str(lvl) ) return plat_list
ground
函數需要一個 X 和 Y 位置,以便 Pygame 知道在哪里放置地面平臺。它也需要知道平臺的寬度和高度,這樣 Pygame 知道地面延伸到每個方向有多遠。該函數使用你的 Platform
類來生成一個屏上對象,然后將這個對象添加到 ground_list
組。
platform
函數本質上是相同的,除了其有更多的平臺。在這個示例中,僅有兩個平臺,但是你可以想有多少就有多少。在進入一個平臺后,在列出另一個前你必須添加它到 plat_list
中。如果你不添加平臺到組中,那么它將不出現在你的游戲中。
提示: 很難想象你的游戲世界的 0 是在頂部,因為在真實世界中發生的情況是相反的;當估計你有多高時,你不會從上往下測量你自己,而是從腳到頭頂來測量。
如果對你來說從“地面”上來構建你的游戲世界更容易,將 Y 軸值表示為負數可能有幫助。例如,你知道你的游戲世界的底部是
worldy
的值。因此worldy
減去地面的高度(在這個示例中是 97)是你的玩家正常站立的位置。如果你的角色是 64 像素高,那么地面減去 128 正好是你的玩家的兩倍高。事實上,一個放置在 128 像素處平臺大約是相對于你的玩家的兩層樓高度。一個平臺在 -320 處比三層樓更高。等等。
正像你現在可能所知的,如果你不使用它們,你的類和函數是沒有價值的。添加這些代碼到你的設置部分(***行只是上下文,所以添加***兩行):
enemy_list = Level.bad( 1, eloc )ground_list = Level.ground( 1,0,worldy-97,1080,97 )plat_list = Level.platform( 1 )
并把這些行加到你的主循環(再一次,***行僅用于上下文):
enemy_list.draw(world) # 刷新敵人ground_list.draw(world) # 刷新地面plat_list.draw(world) # 刷新平臺
瓷磚類游戲世界更容易制作,因為你只需要在前面繪制一些塊,就能在游戲中一再使用它們創建每個平臺。在像 OpenGameArt.org 這樣的網站上甚至有一套瓷磚供你來使用。
Platform
類與在前面部分中的類是相同的。
ground
和 platform
在 Level
類中,然而,必須使用循環來計算使用多少塊來創建每個平臺。
如果你打算在你的游戲世界中有一個堅固的地面,這種地面是很簡單的。你只需要從整個窗口的一邊到另一邊“克隆”你的地面瓷磚。例如,你可以創建一個 X 和 Y 值的列表來規定每個瓷磚應該放置的位置,然后使用一個循環來獲取每個值并繪制每一個瓷磚。這僅是一個示例,所以不要添加這到你的代碼:
# Do not add this to your codegloc = [0,656,64,656,128,656,192,656,256,656,320,656,384,656]
不過,如果你仔細看,你可以看到所有的 Y 值是相同的,X 值以 64 的增量不斷地增加 —— 這就是瓷磚的大小。這種重復是精確地,是計算機擅長的,因此你可以使用一點數學邏輯來讓計算機為你做所有的計算:
添加這些到你的腳本的設置部分:
gloc = []tx = 64ty = 64 i=0while i <= (worldx/tx)+tx: gloc.append(i*tx) i=i+1 ground_list = Level.ground( 1,gloc,tx,ty )
現在,不管你的窗口的大小,Python 會通過瓷磚的寬度分割游戲世界的寬度,并創建一個數組列表列出每個 X 值。這里不計算 Y 值,因為在平的地面上這個從不會變化。
為了在一個函數中使用數組,使用一個 while
循環,查看每個條目并在適當的位置添加一個地面瓷磚:
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,'tile-ground.png') ground_list.add(ground) i=i+1 if lvl == 2: print("Level " + str(lvl) ) return ground_list
除了 while
循環,這幾乎與在上面一部分中提供的瓷磚類平臺的 ground
函數的代碼相同。
對于移動的平臺,原理是相似的,但是這里有一些技巧可以使它簡單。
你可以通過它的起始像素(它的 X 值)、距地面的高度(它的 Y 值)、繪制多少瓷磚來定義一個平臺,而不是通過像素繪制每個平臺。這樣,你不必操心每個平臺的寬度和高度。
這個技巧的邏輯有一點復雜,因此請仔細復制這些代碼。有一個 while
循環嵌套在另一個 while
循環的內部,因為這個函數必須考慮每個數組項的三個值來成功地建造一個完整的平臺。在這個示例中,這里僅有三個平臺以 ploc.append
語句定義,但是你的游戲可能需要更多,因此你需要多少就定義多少。當然,有一些不會出現,因為它們遠在屏幕外,但是一旦當你進行滾動時,它們將呈現在眼前。
def platform(lvl,tx,ty): plat_list = pygame.sprite.Group() ploc = [] i=0 if lvl == 1: ploc.append((200,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,'tile.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
要讓這些平臺出現在你的游戲世界,它們必須出現在你的主循環中。如果你還沒有這樣做,添加這些行到你的主循環(再一次,***行僅被用于上下文)中:
enemy_list.draw(world) # 刷新敵人 ground_list.draw(world) # 刷新地面 plat_list.draw(world) # 刷新平臺
啟動你的游戲,根據需要調整你的平臺的放置位置。如果你看不見屏幕外產生的平臺,不要擔心;你不久后就可以修復它。
到目前為止,這是游戲的圖片和代碼:
到目前為止,我們的 Pygame 平臺。
#!/usr/bin/env python3# draw a world# add a player and player control# add player movement# add enemy and basic collision# add platform # 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 os '''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.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 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) for enemy in enemy_hit_list: self.health -= 1 print(self.health) ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False) for g in ground_hit_list: self.health -= 1 print(self.health) 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.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 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 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,lloc): print(lvl) def ground(lvl,gloc,tx,ty): ground_list = pygame.sprite.Group() i=0 if lvl == 1: while i < len(gloc): print("blockgen:" + str(i)) 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 '''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)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 = 10 # how fast to move eloc = []eloc = [200,20]gloc = []#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]tx = 64 #tile sizety = 64 #tile size i=0while i <= (worldx/tx)+tx: gloc.append(i*tx) i=i+1 print("block: " + str(i)) enemy_list = Level.bad( 1, eloc )ground_list = Level.ground( 1,gloc,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'): 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'): 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 == ord('q'): pygame.quit() sys.exit() main = False # world.fill(BLACK) world.blit(backdrop, backdropbox) player.update() player_list.draw(world) #refresh player position enemy_list.draw(world) # refresh enemies ground_list.draw(world) # refresh enemies for e in enemy_list: e.move() pygame.display.flip() clock.tick(fps)
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。