您好,登錄后才能下訂單哦!
這篇文章主要介紹“Pygame游戲開發之怎么實現太空射擊實戰子彈與碰撞”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Pygame游戲開發之怎么實現太空射擊實戰子彈與碰撞”文章能幫助大家解決問題。
碰撞是游戲開發的基本組成部分。碰撞檢測就是要檢測游戲中的一個對象是否正在接觸另一個對象。碰撞處理決定了當碰撞發生時你想要發生什么。
在我們的游戲中,我們目前有許多敵人的精靈沿著屏幕飛向玩家,我們想知道其中一個精靈何時出現。對于我們游戲的這個階段,我們只會說敵人擊中玩家意味著游戲結束了。
請記住,Pygame 中的每個精靈都有一個rect
定義其坐標和大小的屬性。Pygame中的一個Rect
對象的格式是[x, y, width, height]
,其中 x
和 y
表示矩形的左上角。此矩形的另一個詞是邊界框,因為它表示對象的邊界。
這種碰撞檢測稱為AABB,代表“軸對齊邊界框”,因為矩形與屏幕軸對齊 - 它們不會傾斜一定角度。AABB碰撞非常受歡迎,因為它速度很快 - 計算機可以非常快速地比較矩形的坐標,如果您要比較大量對象,這將非常有用。
要檢測碰撞,我們需要查看玩家的rect
碰撞,并將其與每個敵人的rect
碰撞進行比較。現在,我們可以通過循環遍歷敵人并對執行此比較的每個敵人來執行此操作:
在這張圖片中,您可以看到只有矩形#3
與大黑色矩形相撞。#1
在 x 軸上重疊,但在 y 軸上不重疊; #2
在 y 中重疊,但在 x 中不重疊。為了使兩個矩形重疊,它們的邊界必須在每個軸上重疊。在代碼中編寫以下內容:
if mob.rect.right > player.rect.left and \ mob.rect.left < player.rect.right and \ mob.rect.bottom > player.rect.top and \ mob.rect.top < player.rect.bottom: collide = True
對我們來說幸運的是,Pygame有一個內置的方式,通過使用這個spritecollide()
函數來做到這一點。
我們將此命令添加到游戲循環的“更新”部分:
#Update all_sprites.update() #check to see if a mob hit the player hits = pygame.sprite.spritecollide(player, mobs, False) if hits: running = False
spritecollide()語法
#Find sprites in a group that intersect another sprite. spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
該spritecollide()
函數采用 3 個參數:要檢查的 sprite 的名稱、要與之進行比較的組的名稱,以及名為dokill
的 True/False 參數。
dokill
參數如果設置為 True,則所有發生碰撞的sprite都將從組中刪除。例如,如果我們試圖查看玩家是否撿到了一枚硬幣,我們希望將其設置為True
硬幣消失。
collied
參數是一個回調函數,用于計算兩個精靈是否發生沖突。它應該將兩個精靈作為值,并返回一個bool
值,指示它們是否發生沖突。如果未傳遞collied
參數,則所有精靈都必須具有“rect”值,該值是精靈區域的矩形,將用于計算碰撞。
該spritecollide()
命令的返回結果是被擊中的精靈列表(請記住,玩家可能一次與多個敵人相撞)。我們將該列表分配給變量hits
。
如果hits
列表不為空,則if
語句將為True
,并且我們設置running
為False
游戲將結束。
現在我們準備添加一個新的精靈:子彈。這將是一個精靈,在我們射擊時生成,出現在玩家精靈的頂部,并以相當高的速度向上移動。定義精靈現在應該開始看起來很熟悉了,所以下面是完整的Bullet
類:
class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((10, 20)) self.image.fill(YELLOW) self.rect = self.image.get_rect() self.rect.bottom = y self.rect.centerx = x self.speedy = -10 def update(self): self.rect.y += self.speedy # kill if it moves off the top of the screen if self.rect.bottom < 0: self.kill()
在子彈精靈的__init__()
方法中,我們傳遞x
和y
值,以便我們可以告訴精靈出現在哪里。由于玩家精靈可以移動,因此將設置為玩家射擊時玩家所在的位置。我們設置speedy
為負值,以便它將向上移動。
最后,我們檢查子彈是否從屏幕頂部脫落,如果是這樣,我們將其刪除。
為了保持簡單,我們將讓它每次玩家按下空格鍵時,都會發射一顆子彈。我們需要將其添加到事件檢查中:
for event in pygame.event.get(): # check for closing window if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: player.shoot()
我們的新代碼檢查事件,如果存在KEYDOWN
事件,則檢查它是否是K_SPACE
按鍵。如果是這樣,我們將運行玩家精靈的shoot()
方法。
首先,我們需要添加一個新組來保存所有項目符號:
bullets = pygame.sprite.Group()
現在,我們可以將以下方法添加到Player
類中:
def shoot(self): bullet = Bullet(self.rect.centerx, self.rect.top) all_sprites.add(bullet) bullets.add(bullet)
該shoot()
方法所做的就是生成一顆子彈,使用玩家的頂部中心作為生成點。然后,我們確保將子彈精靈添加到all_sprites
(以便將其繪制和更新)和 bullets
,我們將用于碰撞。
現在我們需要檢查子彈是否擊中了敵人。這里的區別在于,我們有多個子彈(在bullets
組中)和多個敵人(在mobs
組中),所以我們不能像以前那樣使用spritecollide()
,因為這只會將一個精靈與一個組進行比較。相反,我們將使用groupcollide()
:
groupcollide()
語法
# Find all sprites that collide between two groups. groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
發現兩組中的所有精靈之間的沖突。通過比較每個 Sprite 的Sprite.rect
屬性或使用collided
函數(如果不是 None)來確定碰撞。
返回值是個字典,未發生碰撞時,字典為空。發生碰撞時,字典的keys是group1中發生碰撞的對象(一直以為字典的keys值是個字符串之類的東西,沒想到還可以是對象),values是一個列表,其元素是group2中與每一個group1發生碰撞的所有對象。
Groupcollide返回值的形態和使用是個難點,舉例說明:比如group1有三架飛機對象p1、p2、p3,group2有八個敵人對象b1、b2、b3、b4、b5、b6、b7、b8,假如p1與b1、b4、b7發生碰撞,p2與b2、b5、b8發生碰撞,
groupcollide(group1, group2, 1, 1)
返回值是如下的字典:
{p1:[b1, b4, b7], p2:[b2, b5, b8]}
group1
中的每個發生碰撞的Sprite 都會添加到返回字典中,作為鍵。每個項的值是組 2 中相交的精靈列表。
如果任一 dokill 參數為 True,則碰撞的精靈將從其各自的組中刪除。
collieded
參數是一個回調函數,用于計算兩個精靈是否發生沖突。它應該將兩個精靈作為值,并返回一個 bool 值,指示它們是否正在碰撞。如果未傳遞collided
,則所有精靈都必須具有“rect”值,該值是精靈區域的矩形,將用于計算碰撞。
# Update all_sprites.update() # check to see if a bullet hit a mob hits = pygame.sprite.groupcollide(mobs, bullets, True, True) for hit in hits: m = Mob() all_sprites.add(m) mobs.add(m)
該groupcollide()
函數類似于spritecollide()
,除了您命名兩個組進行比較,并且您將獲得的是被擊中的敵人列表。有兩個dokill
選項,每個組一個。
如果我們只是刪除敵人,我們將遇到一個問題:敵人用完了!因此,我們要做的就是hits
循環,對于我們摧毀的每個敵人,將生成另一個新的敵人。
現在它實際上開始感覺像一個游戲:
在下一課中,我們將學習如何向游戲添加圖形,而不是使用那些純色矩形。
此部分的完整代碼
# KidsCanCode - Game Development with Pygame video series # Shmup game - part 3 # Video link: https://www.youtube.com/watch?v=33g62PpFwsE # Collisions and bullets import pygame import random WIDTH = 480 HEIGHT = 600 FPS = 60 # define colors WHITE = (255, 255, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) # initialize pygame and create window pygame.init() pygame.mixer.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Shmup!") clock = pygame.time.Clock() class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((50, 40)) self.image.fill(GREEN) self.rect = self.image.get_rect() self.rect.centerx = WIDTH / 2 self.rect.bottom = HEIGHT - 10 self.speedx = 0 def update(self): self.speedx = 0 keystate = pygame.key.get_pressed() if keystate[pygame.K_LEFT]: self.speedx = -8 if keystate[pygame.K_RIGHT]: self.speedx = 8 self.rect.x += self.speedx if self.rect.right > WIDTH: self.rect.right = WIDTH if self.rect.left < 0: self.rect.left = 0 def shoot(self): bullet = Bullet(self.rect.centerx, self.rect.top) all_sprites.add(bullet) bullets.add(bullet) class Mob(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((30, 40)) self.image.fill(RED) self.rect = self.image.get_rect() self.rect.x = random.randrange(WIDTH - self.rect.width) self.rect.y = random.randrange(-100, -40) self.speedy = random.randrange(1, 8) self.speedx = random.randrange(-3, 3) def update(self): self.rect.x += self.speedx self.rect.y += self.speedy if self.rect.top > HEIGHT + 10 or self.rect.left < -25 or self.rect.right > WIDTH + 20: self.rect.x = random.randrange(WIDTH - self.rect.width) self.rect.y = random.randrange(-100, -40) self.speedy = random.randrange(1, 8) class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((10, 20)) self.image.fill(YELLOW) self.rect = self.image.get_rect() self.rect.bottom = y self.rect.centerx = x self.speedy = -10 def update(self): self.rect.y += self.speedy # kill if it moves off the top of the screen if self.rect.bottom < 0: self.kill() all_sprites = pygame.sprite.Group() mobs = pygame.sprite.Group() bullets = pygame.sprite.Group() player = Player() all_sprites.add(player) for i in range(8): m = Mob() all_sprites.add(m) mobs.add(m) # Game loop running = True while running: # keep loop running at the right speed clock.tick(FPS) # Process input (events) for event in pygame.event.get(): # check for closing window if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: player.shoot() # Update all_sprites.update() # check to see if a bullet hit a mob hits = pygame.sprite.groupcollide(mobs, bullets, True, True) for hit in hits: m = Mob() all_sprites.add(m) mobs.add(m) # check to see if a mob hit the player hits = pygame.sprite.spritecollide(player, mobs, False) if hits: running = False # Draw / render screen.fill(BLACK) all_sprites.draw(screen) # *after* drawing everything, flip the display pygame.display.flip() pygame.quit()
關于“Pygame游戲開發之怎么實現太空射擊實戰子彈與碰撞”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。