歡迎光臨
每天分享高質量文章

用 Pygame 使你的游戲角色移動起來 | Linux 中國

在本系列的第四部分,學習如何編寫移動游戲角色的控制代碼。

— Seth Kenlon

 

在這個系列的第一篇文章中,我解釋瞭如何使用 Python 創建一個簡單的基於文本的骰子游戲。在第二部分中,我向你們展示瞭如何從頭開始構建游戲,即從 創建游戲的環境 開始。然後在第三部分,我們創建了一個玩家妖精,並且使它在你的(而不是空的)游戲世界內生成。你可能已經註意到,如果你不能移動你的角色,那麼游戲不是那麼有趣。在本篇文章中,我們將使用 Pygame 來添加鍵盤控制,如此一來你就可以控制你的角色的移動。

在 Pygame 中有許多函式可以用來添加(除鍵盤外的)其他控制,但如果你正在敲擊 Python 代碼,那麼你一定是有一個鍵盤的,這將成為我們接下來會使用的控制方式。一旦你理解了鍵盤控制,你可以自己去探索其他選項。

在本系列的第二篇文章中,你已經為退出游戲創建了一個按鍵,移動角色的(按鍵)原則也是相同的。但是,使你的角色移動起來要稍微複雜一點。

讓我們從簡單的部分入手:設置控制器按鍵。

為控制你的玩家妖精設置按鍵

在 IDLE、Ninja-IDE 或文本編輯器中打開你的 Python 游戲腳本。

因為游戲需要時刻“監聽”鍵盤事件,所以你寫的代碼需要連續運行。你知道應該把需要在游戲周期中持續運行的代碼放在哪裡嗎?

如果你回答“放在主迴圈中”,那麼你是正確的!記住除非代碼在迴圈中,否則(大多數情況下)它只會運行僅一次。如果它被寫在一個從未被使用的類或函式中,它可能根本不會運行。

要使 Python 監聽傳入的按鍵,將如下代碼添加到主迴圈。目前的代碼還不能產生任何的效果,所以使用 print 陳述句來表示成功的信號。這是一種常見的除錯技術。

  1. while main == True:
  2.     for event in pygame.event.get():
  3.         if event.type == pygame.QUIT:
  4.             pygame.quit(); sys.exit()
  5.             main = False
  6.         if event.type == pygame.KEYDOWN:
  7.             if event.key == pygame.K_LEFT or event.key == ord('a'):
  8.                 print('left')
  9.             if event.key == pygame.K_RIGHT or event.key == ord('d'):
  10.                 print('right')
  11.             if event.key == pygame.K_UP or event.key == ord('w'):
  12.             print('jump')
  13.         if event.type == pygame.KEYUP:
  14.             if event.key == pygame.K_LEFT or event.key == ord('a'):
  15.                 print('left stop')
  16.             if event.key == pygame.K_RIGHT or event.key == ord('d'):
  17.                 print('right stop')
  18.             if event.key == ord('q'):
  19.                 pygame.quit()
  20.                 sys.exit()
  21.                 main = False    

一些人偏好使用鍵盤字母 WAS 和 D 來控制玩家角色,而另一些偏好使用方向鍵。因此確保你包含了兩種選項。

註意:當你在編程時,同時考慮所有用戶是非常重要的。如果你寫代碼只是為了自己運行,那麼很可能你會成為你寫的程式的唯一用戶。更重要的是,如果你想找一個通過寫代碼賺錢的工作,你寫的代碼就應該讓所有人都能運行。給你的用戶選擇權,比如提供使用方向鍵或 WASD 的選項,是一個優秀程式員的標誌。

使用 Python 啟動你的游戲,併在你按下“上下左右”方向鍵或 AD 和 W 鍵的時候查看控制台視窗的輸出。

  1. $ python ./your-name_game.py
  2.   left
  3.   left stop
  4.   right
  5.   right stop
  6.   jump

這驗證了 Pygame 可以正確地檢測按鍵。現在是時候來完成使妖精移動的艱巨任務了。

編寫玩家移動函式

為了使你的妖精移動起來,你必須為你的妖精創建一個屬性代表移動。當你的妖精沒有在移動時,這個變數被設為 0

如果你正在為你的妖精設置動畫,或者你決定在將來為它設置動畫,你還必須跟蹤幀來使走路迴圈保持在軌跡上。

在 Player 類中創建如下變數。開頭兩行作為背景關係對照(如果你一直跟著做,你的代碼中就已經有這兩行),因此只需要添加最後三行:

  1.     def __init__(self):
  2.         pygame.sprite.Sprite.__init__(self)
  3.         self.movex = 0 # 沿 X 方向移動
  4.         self.movey = 0 # 沿 Y 方向移動
  5.         self.frame = 0 # 幀計數

設置好了這些變數,是時候去為妖精移動編寫代碼了。

玩家妖精不需要時刻響應控制,有時它並沒有在移動。控制妖精的代碼,僅僅只是玩家妖精所有能做的事情中的一小部分。在 Python 中,當你想要使一個物件做某件事並獨立於剩餘其他代碼時,你可以將你的新代碼放入一個函式。Python 的函式以關鍵詞 def 開頭,(該關鍵詞)代表了定義函式。

在你的 Player 類中創建如下函式,來為你的妖精在屏幕上的位置增加幾個像素。現在先不要擔心你增加幾個像素,這將在後續的代碼中確定。

  1.     def control(self,x,y):
  2.         '''
  3.         控制玩家移動
  4.         '''
  5.         self.movex += x
  6.         self.movey += y

為了在 Pygame 中移動妖精,你需要告訴 Python 在新的位置重繪妖精,以及這個新位置在哪裡。

因為玩家妖精並不總是在移動,所以更新只需要是 Player 類中的一個函式。將此函式添加前面創建的 control 函式之後。

要使妖精看起來像是在行走(或者飛行,或是你的妖精應該做的任何事),你需要在按下適當的鍵時改變它在屏幕上的位置。要讓它在屏幕上移動,你需要將它的位置(由 self.rect.x 和 self.rect.y 屬性指定)重新定義為當前位置加上已應用的任意 movex 或 movey。(移動的像素數量將在後續進行設置。)

  1.     def update(self):
  2.         '''
  3.         更新妖精位置
  4.         '''
  5.         self.rect.x = self.rect.x + self.movex        

對 Y 方向做同樣的處理:

  1.         self.rect.y = self.rect.y + self.movey

對於動畫,在妖精移動時推進動畫幀,並使用相應的動畫幀作為玩家的圖像:

  1.         # 向左移動
  2.         if self.movex < 0:
  3.             self.frame += 1
  4.             if self.frame > 3*ani:
  5.                 self.frame = 0
  6.             self.image = self.images[self.frame//ani]
  7.         # 向右移動
  8.         if self.movex > 0:
  9.             self.frame += 1
  10.             if self.frame > 3*ani:
  11.                 self.frame = 0
  12.             self.image = self.images[(self.frame//ani)+4]

通過設置一個變數來告訴代碼為你的妖精位置增加多少像素,然後在觸發你的玩家妖精的函式時使用這個變數。

首先,在你的設置部分創建這個變數。在如下代碼中,開頭兩行是背景關係對照,因此只需要在你的腳本中增加第三行代碼:

  1. player_list = pygame.sprite.Group()
  2. player_list.add(player)
  3. steps = 10  # 移動多少個像素

現在你已經有了適當的函式和變數,使用你的按鍵來觸發函式並將變數傳遞給你的妖精。

為此,將主迴圈中的 print 陳述句替換為玩家妖精的名字(player)、函式(.control)以及你希望玩家妖精在每個迴圈中沿 X 軸和 Y 軸移動的步數。

  1.         if event.type == pygame.KEYDOWN:
  2.             if event.key == pygame.K_LEFT or event.key == ord('a'):
  3.                 player.control(-steps,0)
  4.             if event.key == pygame.K_RIGHT or event.key == ord('d'):
  5.                 player.control(steps,0)
  6.             if event.key == pygame.K_UP or event.key == ord('w'):
  7.                 print('jump')
  8.         if event.type == pygame.KEYUP:
  9.             if event.key == pygame.K_LEFT or event.key == ord('a'):
  10.                 player.control(steps,0)
  11.             if event.key == pygame.K_RIGHT or event.key == ord('d'):
  12.                 player.control(-steps,0)
  13.             if event.key == ord('q'):
  14.                 pygame.quit()
  15.                 sys.exit()
  16.                 main = False

記住,steps 變數代表了當一個按鍵被按下時,你的妖精會移動多少個像素。如果當你按下 D 或右方向鍵時,你的妖精的位置增加了 10 個像素。那麼當你停止按下這個鍵時,你必須(將 step)減 10(-steps)來使你的妖精的動量回到 0。

現在嘗試你的游戲。註意:它不會像你預想的那樣運行。

為什麼你的妖精仍無法移動?因為主迴圈還沒有呼叫 update 函式。

將如下代碼加入到你的主迴圈中來告訴 Python 更新你的玩家妖精的位置。增加帶註釋的那行:

  1.     player.update()  # 更新玩家位置
  2.     player_list.draw(world)
  3.     pygame.display.flip()
  4.     clock.tick(fps)

再次啟動你的游戲來見證你的玩家妖精在你的命令下在屏幕上來回移動。現在還沒有垂直方向的移動,因為這部分函式會被重力控制,不過這是另一篇文章中的課程了。

與此同時,如果你擁有一個搖桿,你可以嘗試閱讀 Pygame 中 joystick 模塊相關的文件,看看你是否能通過這種方式讓你的妖精移動起來。或者,看看你是否能通過滑鼠與你的妖精互動。

最重要的是,玩的開心!

本教程中用到的所有代碼

為了方便查閱,以下是目前本系列文章用到的所有代碼。

  1. #!/usr/bin/env python3
  2. # 繪製世界
  3. # 添加玩家和玩家控制
  4. # 添加玩家移動控制
  5. # GNU All-Permissive License
  6. # Copying and distribution of this file, with or without modification,
  7. # are permitted in any medium without royalty provided the copyright
  8. # notice and this notice are preserved. This file is offered as-is,
  9. # without any warranty.
  10. import pygame
  11. import sys
  12. import os
  13. '''
  14. Objects
  15. '''
  16. class Player(pygame.sprite.Sprite):
  17. '''
  18. 生成玩家
  19. '''
  20. def __init__(self):
  21. pygame.sprite.Sprite.__init__(self)
  22. self.movex = 0
  23. self.movey = 0
  24. self.frame = 0
  25. self.images = []
  26. for i in range(1,5):
  27. img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
  28. img.convert_alpha()
  29. img.set_colorkey(ALPHA)
  30. self.images.append(img)
  31. self.image = self.images[0]
  32. self.rect = self.image.get_rect()
  33. def control(self,x,y):
  34. '''
  35. 控制玩家移動
  36. '''
  37. self.movex += x
  38. self.movey += y
  39. def update(self):
  40. '''
  41. 更新妖精位置
  42. '''
  43. self.rect.x = self.rect.x + self.movex
  44. self.rect.y = self.rect.y + self.movey
  45. # 向左移動
  46. if self.movex < 0:
  47. self.frame += 1
  48. if self.frame > 3*ani:
  49. self.frame = 0
  50. self.image = self.images[self.frame//ani]
  51. # 向右移動
  52. if self.movex > 0:
  53. self.frame += 1
  54. if self.frame > 3*ani:
  55. self.frame = 0
  56. self.image = self.images[(self.frame//ani)+4]
  57. '''
  58. 設置
  59. '''
  60. worldx = 960
  61. worldy = 720
  62. fps = 40 # 幀掃清率
  63. ani = 4 # 動畫迴圈
  64. clock = pygame.time.Clock()
  65. pygame.init()
  66. main = True
  67. BLUE = (25,25,200)
  68. BLACK = (23,23,23 )
  69. WHITE = (254,254,254)
  70. ALPHA = (0,255,0)
  71. world = pygame.display.set_mode([worldx,worldy])
  72. backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
  73. backdropbox = world.get_rect()
  74. player = Player() # 生成玩家
  75. player.rect.x = 0
  76. player.rect.y = 0
  77. player_list = pygame.sprite.Group()
  78. player_list.add(player)
  79. steps = 10 # 移動速度
  80. '''
  81. 主迴圈
  82. '''
  83. while main == True:
  84. for event in pygame.event.get():
  85. if event.type == pygame.QUIT:
  86. pygame.quit(); sys.exit()
  87. main = False
  88. if event.type == pygame.KEYDOWN:
  89. if event.key == pygame.K_LEFT or event.key == ord('a'):
  90. player.control(-steps,0)
  91. if event.key == pygame.K_RIGHT or event.key == ord('d'):
  92. player.control(steps,0)
  93. if event.key == pygame.K_UP or event.key == ord('w'):
  94. print('jump')
  95. if event.type == pygame.KEYUP:
  96. if event.key == pygame.K_LEFT or event.key == ord('a'):
  97. player.control(steps,0)
  98. if event.key == pygame.K_RIGHT or event.key == ord('d'):
  99. player.control(-steps,0)
  100. if event.key == ord('q'):
  101. pygame.quit()
  102. sys.exit()
  103. main = False
  104. # world.fill(BLACK)
  105. world.blit(backdrop, backdropbox)
  106. player.update()
  107. player_list.draw(world) # 更新玩家位置
  108. pygame.display.flip()
  109. clock.tick(fps)

你已經學了很多,但還仍有許多可以做。在接下來的幾篇文章中,你將實現添加敵方妖精、模擬重力等等。與此同時,練習 Python 吧!

已同步到看一看
赞(0)

分享創造快樂