您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么在Python做的游戲中添加投擲機制”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么在Python做的游戲中添加投擲機制”吧!
四處奔跑躲避敵人是一回事,反擊敵人是另一回事。學習如何在這系列的第十二篇文章中在 Pygame 中創建平臺游戲。
這是仍在進行中的關于使用 Pygame 模塊在 Python 3 中創建電腦游戲的第十二部分。先前的文章是:
通過構建一個簡單的擲骰子游戲去學習怎么用 Python 編程
使用 Python 和 Pygame 模塊構建一個游戲框架
如何在你的 Python 游戲中添加一個玩家
用 Pygame 使你的游戲角色移動起來
如何向你的 Python 游戲中添加一個敵人
在 Pygame 游戲中放置平臺
在你的 Python 游戲中模擬引力
為你的 Python 平臺類游戲添加跳躍功能
使你的 Python 游戲玩家能夠向前和向后跑
在你的 Python 平臺類游戲中放一些獎勵
添加計分到你的 Python 游戲
我的上一篇文章本來是這一系列文章的最后一篇,它鼓勵你為這個游戲編寫自己的附加程序。你們很多人都這么做了!我收到了一些電子郵件,要求幫助我還沒有涵蓋的常用機制:戰斗。畢竟,跳起來躲避壞人是一回事,但是有時候讓他們走開是一件非常令人滿意的事。在電腦游戲中向你的敵人投擲一些物品是很常見的,不管是一個火球、一支箭、一道閃電,還是其它適合游戲的東西。
與迄今為止你在這個系列中為你的平臺游戲編程的任何東西不同,可投擲物品有一個生存時間。在你投擲一個物品后,它會如期在移動一段距離后消失。如果它是一支箭或其它類似的東西,它可能會在通過屏幕的邊緣時而消失。如果它是一個火球或一道閃電,它可能會在一段時間后熄滅。
這意味著每次生成一個可投擲的物品時,也必須生成一個獨特的衡量其生存時間的標準。為了介紹這個概念,這篇文章演示如何一次只投擲一個物品。(換句話說,每次僅存在一個投擲物品)。 一方面,這是一個游戲的限制條件,但另一方面,它卻是游戲本身的運行機制。你的玩家不能每次同時投擲 50 個火球,因為每次僅允許一個投擲物品,所以當你的玩家釋放一個火球來嘗試擊中一名敵人就成為了一項挑戰。而在幕后,這也使你的代碼保持簡單。
如果你想啟用每次投擲多個項目,在完成這篇教程后,通過學習這篇教程所獲取的知識來挑戰你自己。
如果你跟隨學習這系列的其它文章,那么你應該熟悉在屏幕上生成一個新的對象基礎的 __init__
函數。這和你用來生成你的 玩家 和 敵人 的函數是一樣的。這里是生成一個 throwable
對象的 __init__
函數來:
class Throwable(pygame.sprite.Sprite): """ 生成一個 throwable 對象 """ def __init__(self, x, y, img, throw): 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.firing = throw
同你的 Player
類或 Enemy
類的 __init__
函數相比,這個函數的主要區別是,它有一個 self.firing
變量。這個變量保持跟蹤一個投擲的物品是否在當前屏幕上活動,因此當一個 throwable
對象創建時,將變量設置為 1
的合乎情理的。
接下來,就像使用 Player
和 Enemy
一樣,你需要一個 update
函數,以便投擲的物品在瞄準敵人拋向空中時,它會自己移動。
測定一個投擲的物品存活時間的最簡單方法是偵測它何時離開屏幕。你需要監視的屏幕邊緣取決于你投擲的物品的物理特性。
如果你的玩家正在投擲的物品是沿著水平軸快速移動的,像一只弩箭或箭或一股非常快的魔法力量,而你想監視你游戲屏幕的水平軸極限。這可以通過 worldx
定義。
如果你的玩家正在投擲的物品是沿著垂直方向或同時沿著水平方向和垂直方向移動的,那么你必須監視你游戲屏幕的垂直軸極限。這可以通過 worldy
定義。
這個示例假設你投擲的物品向前移動一點并最終落到地面上。不過,投擲的物品不會從地面上反彈起來,而是繼續掉落出屏幕。你可以嘗試不同的設置來看看什么最適合你的游戲:
def update(self,worldy): ''' 投擲物理學 ''' if self.rect.y < worldy: #垂直軸 self.rect.x += 15 #它向前移動的速度有多快 self.rect.y += 5 #它掉落的速度有多快 else: self.kill() #移除投擲對象 self.firing = 0 #解除火力發射
為使你的投擲物品移動地更快,增加 self.rect
的動量值。
如果投擲物品不在屏幕上,那么該物品將被銷毀,以及釋放其所占用的寄存器。另外,self.firing
將被設置回 0
以允許你的玩家來進行另一次射擊。
就像使用你的玩家和敵人一樣,你必須在你的設置部分中創建一個精靈組來保持投擲對象。
此外,你必須創建一個非活動的投擲對象來供開始的游戲使用。如果在游戲開始時卻沒有一個投擲對象,那么玩家在第一次嘗試投擲一柄武器時,投擲將失敗。
這個示例假設你的玩家使用一個火球作為開始的武器,因此,每一個投擲實例都是由 fire
變量指派的。在后面的關卡中,當玩家獲取新的技能時,你可以使用相同的 Throwable
類來引入一個新的變量以使用一張不同的圖像。
在這代碼塊中,前兩行已經在你的代碼中,因此不要重新鍵入它們:
player_list = pygame.sprite.Group() #上下文player_list.add(player) #上下文fire = Throwable(player.rect.x,player.rect.y,'fire.png',0)firepower = pygame.sprite.Group()
注意,每一個投擲對象的起始位置都是和玩家所在的位置相同。這使得它看起來像是投擲對象來自玩家。在第一個火球生成時,使用 0
來顯示 self.firing
是可用的。
沒有在主循環中出現的代碼不會在游戲中使用,因此你需要在你的主循環中添加一些東西,以便能在你的游戲世界中獲取投擲對象。
首先,添加玩家控制。當前,你沒有火力觸發器。在鍵盤上的按鍵是有兩種狀態的:釋放的按鍵,按下的按鍵。為了移動,你要使用這兩種狀態:按下按鍵來啟動玩家移動,釋放按鍵來停止玩家移動。開火僅需要一個信號。你使用哪個按鍵事件(按鍵按下或按鍵釋放)來觸發你的投擲對象取決于你的品味。
在這個代碼語句塊中,前兩行是用于上下文的:
if event.key == pygame.K_UP or event.key == ord('w'): player.jump(platform_list) if event.key == pygame.K_SPACE: if not fire.firing: fire = Throwable(player.rect.x,player.rect.y,'fire.png',1) firepower.add(fire)
與你在設置部分創建的火球不同,你使用一個 1
來設置 self.firing
為不可用。
最后,你必須更新和繪制你的投擲物品。這個順序很重要,因此把這段代碼放置到你現有的 enemy.move
和 player_list.draw
的代碼行之間:
enemy.move() # 上下文 if fire.firing: fire.update(worldy) firepower.draw(world) player_list.draw(screen) # 上下文 enemy_list.draw(screen) # 上下文
注意,這些更新僅在 self.firing
變量被設置為 1 時執行。如果它被設置為 0 ,那么 fire.firing
就不為 true
,接下來就跳過更新。如果你嘗試做上述這些更新,不管怎樣,你的游戲都會崩潰,因為在游戲中將不會更新或繪制一個 fire
對象。
啟動你的游戲,嘗試挑戰你的武器。
如果你玩使用了新投擲技巧的游戲,你可能會注意到,你可以投擲對象,但是它卻不會對你的敵人有任何影響。
原因是你的敵人沒有被查到碰撞事故。一名敵人可能會被你的投擲物品所擊中,但是敵人卻從來不知道被擊中了。
你已經在你的 Player
類中完成了碰撞檢測,這非常類似。在你的 Enemy
類中,添加一個新的 update
函數:
def update(self,firepower, enemy_list): """ 檢測火力碰撞 """ fire_hit_list = pygame.sprite.spritecollide(self,firepower,False) for fire in fire_hit_list: enemy_list.remove(self)
代碼很簡單。每個敵人對象都檢查并看看它自己是否被 firepower
精靈組的成員所擊中。如果它被擊中,那么敵人就會從敵人組中移除和消失。
為集成這些功能到你的游戲之中,在主循環中調用位于新觸發語句塊中的函數:
if fire.firing: # 上下文 fire.update(worldy) # 上下文 firepower.draw(screen) # 上下文 enemy_list.update(firepower,enemy_list) # 更新敵人
你現在可以嘗試一下你的游戲了,大多數的事情都如預期般的那樣工作。不過,這里仍然有一個問題,那就是投擲的方向。
當前,你英雄的火球只會向右移動。這是因為 Throwable
類的 update
函數將像素添加到火球的位置,在 Pygame 中,在 X 軸上一個較大的數字意味著向屏幕的右側移動。當你的英雄轉向另一個方向時,你可能希望它投擲的火球也拋向左側。
到目前為止,你已經知道如何實現這一點,至少在技術上是這樣的。然而,最簡單的解決方案卻是使用一個變量,在一定程度上對你來說可能是一種新的方法。一般來說,你可以“設置一個標記”(有時也被稱為“翻轉一個位”)來標明你的英雄所面向的方向。在你做完后,你就可以檢查這個變量來得知火球是向左移動還是向右移動。
首先,在你的 Player
類中創建一個新的變量來代表你的游戲所面向的方向。因為我的游戲天然地面向右側,由此我把面向右側作為默認值:
self.score = 0 self.facing_right = True # 添加這行 self.is_jumping = True
當這個變量是 True
時,你的英雄精靈是面向右側的。當玩家每次更改英雄的方向時,變量也必須重新設置,因此,在你的主循環中相關的 keyup
事件中這樣做:
if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT or event.key == ord('a'): player.control(steps, 0) player.facing_right = False # 添加這行 if event.key == pygame.K_RIGHT or event.key == ord('d'): player.control(-steps, 0) player.facing_right = True # 添加這行
最后,更改你的 Throwable
類的 update
函數,以檢測英雄是否面向右側,并恰當地添加或減去來自火球位置的像素:
if self.rect.y < worldy: if player.facing_right: self.rect.x += 15 else: self.rect.x -= 15 self.rect.y += 5
再次嘗試你的游戲,清除掉你游戲世界中的一些壞人。
Python 平臺類使用投擲能力
作為一項額外的挑戰,當徹底打敗敵人時,嘗試增加你玩家的得分。
#!/usr/bin/env python3# 作者: Seth Kenlon # GPLv3# This program is free software: you can redistribute it and/or# modify it under the terms of the GNU General Public License as# published by the Free Software Foundation, either version 3 of the# License, or (at your option) any later version.## This program is distributed in the hope that it will be useful, but# WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU# General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program. If not, see <[http://www.gnu.org/licenses/>][17]. import pygameimport pygame.freetypeimport sysimport os '''變量''' worldx = 960worldy = 720fps = 40ani = 4world = pygame.display.set_mode([worldx, worldy])forwardx = 600backwardx = 120 BLUE = (80, 80, 155)BLACK = (23, 23, 23)WHITE = (254, 254, 254)ALPHA = (0, 255, 0) tx = 64ty = 64 font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "fonts", "amazdoom.ttf")font_size = txpygame.freetype.init()myfont = pygame.freetype.Font(font_path, font_size) '''對象''' def stats(score, health): myfont.render_to(world, (4, 4), "Score:"+str(score), BLUE, None, size=64) myfont.render_to(world, (4, 72), "Health:"+str(health), BLUE, None, size=64) class Throwable(pygame.sprite.Sprite): """ 生成一個投擲的對象 """ def __init__(self, x, y, img, throw): 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.firing = throw def update(self, worldy): ''' 投擲物理學 ''' if self.rect.y < worldy: if player.facing_right: self.rect.x += 15 else: self.rect.x -= 15 self.rect.y += 5 else: self.kill() self.firing = 0 # x 位置, y 位置, img 寬度, img 高度, img 文件class Platform(pygame.sprite.Sprite): 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 class Player(pygame.sprite.Sprite): """ 生成一名玩家 """ def __init__(self): pygame.sprite.Sprite.__init__(self) self.movex = 0 self.movey = 0 self.frame = 0 self.health = 10 self.damage = 0 self.score = 0 self.facing_right = True self.is_jumping = True self.is_falling = True self.images = [] for i in range(1, 5): img = pygame.image.load(os.path.join('images', 'walk' + 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 gravity(self): if self.is_jumping: self.movey += 3.2 def control(self, x, y): """ 控制玩家移動 """ self.movex += x def jump(self): if self.is_jumping is False: self.is_falling = False self.is_jumping = True def update(self): """ 更新精靈位置 """ # 向左移動 if self.movex < 0: self.is_jumping = True self.frame += 1 if self.frame > 3 * ani: self.frame = 0 self.image = pygame.transform.flip(self.images[self.frame // ani], True, False) # 向右移動 if self.movex > 0: self.is_jumping = True self.frame += 1 if self.frame > 3 * ani: self.frame = 0 self.image = self.images[self.frame // ani] # 碰撞 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 # 設置傷害回 0 self.health -= 1 # 減去 1 單位健康度 ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False) for g in ground_hit_list: self.movey = 0 self.rect.bottom = g.rect.top self.is_jumping = False # 停止跳躍 # 掉落世界 if self.rect.y > worldy: self.health -=1 print(self.health) self.rect.x = tx self.rect.y = ty plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False) for p in plat_hit_list: self.is_jumping = False # 停止跳躍 self.movey = 0 if self.rect.bottom <= p.rect.bottom: self.rect.bottom = p.rect.top else: self.movey += 3.2 if self.is_jumping and self.is_falling is False: self.is_falling = True self.movey -= 33 # 跳躍多高 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) self.rect.x += self.movex self.rect.y += self.movey class Enemy(pygame.sprite.Sprite): """ 生成一名敵人 """ 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): """ 敵人移動 """ 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 def update(self, firepower, enemy_list): """ 檢測火力碰撞 """ fire_hit_list = pygame.sprite.spritecollide(self, firepower, False) for fire in fire_hit_list: enemy_list.remove(self) class Level: 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 def bad(lvl, eloc): if lvl == 1: enemy = Enemy(eloc[0], eloc[1], 'enemy.png') enemy_list = pygame.sprite.Group() enemy_list.add(enemy) if lvl == 2: print("Level " + str(lvl)) return enemy_list # x 位置, y 位置, img 寬度, img 高度, img 文件 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((550, 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 def loot(lvl): if lvl == 1: loot_list = pygame.sprite.Group() loot = Platform(tx*5, ty*5, tx, ty, 'loot_1.png') loot_list.add(loot) if lvl == 2: print(lvl) return loot_list '''Setup 部分''' backdrop = pygame.image.load(os.path.join('images', 'stage.png'))clock = pygame.time.Clock()pygame.init()backdropbox = world.get_rect()main = True player = Player() # 生成玩家player.rect.x = 0 # 轉到 xplayer.rect.y = 30 # 轉到 yplayer_list = pygame.sprite.Group()player_list.add(player)steps = 10fire = Throwable(player.rect.x, player.rect.y, 'fire.png', 0)firepower = pygame.sprite.Group() eloc = []eloc = [300, worldy-ty-80]enemy_list = Level.bad(1, eloc)gloc = [] i = 0while i <= (worldx / tx) + tx: gloc.append(i * tx) i = i + 1 ground_list = Level.ground(1, gloc, tx, ty)plat_list = Level.platform(1, tx, ty)enemy_list = Level.bad( 1, eloc )loot_list = Level.loot(1) '''主循環''' while main: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() try: sys.exit() finally: main = False if event.type == pygame.KEYDOWN: if event.key == ord('q'): pygame.quit() try: sys.exit() finally: main = False 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() if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT or event.key == ord('a'): player.control(steps, 0) player.facing_right = False if event.key == pygame.K_RIGHT or event.key == ord('d'): player.control(-steps, 0) player.facing_right = True if event.key == pygame.K_SPACE: if not fire.firing: fire = Throwable(player.rect.x, player.rect.y, 'fire.png', 1) firepower.add(fire) # 向向滾動世界 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 # 向后滾動世界 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.update() player.gravity() player_list.draw(world) if fire.firing: fire.update(worldy) firepower.draw(world) enemy_list.draw(world) enemy_list.update(firepower, enemy_list) loot_list.draw(world) ground_list.draw(world) plat_list.draw(world) for e in enemy_list: e.move() stats(player.score, player.health) pygame.display.flip() clock.tick(fps)
到此,相信大家對“怎么在Python做的游戲中添加投擲機制”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。