Pygame游戲開發(fā)之太空射擊實戰(zhàn)碰撞改進篇
視頻
碰撞是怎么回事
在上一次教程中,我們添加了圖形,將精靈從普通矩形更改為更漂亮的PNG圖像。然而,這帶來了一個問題:有時游戲會認為玩家和流星之間發(fā)生了碰撞,而看起來他們根本沒有擊中。為了理解發(fā)生了什么,讓我們看一個圖:
Pygame中的默認沖突類型是使用collide_rect()
函數(shù),該函數(shù)使用兩個精靈的rect
屬性來計算它們是否重疊。這被稱為AABB
碰撞,它非??焖倏煽俊5?,如果精靈圖像不是矩形,那么您會遇到類似于圖片中的矩形重疊情況。這時collide_rect()
函數(shù)返回值為True
,玩家會感到沮喪,因為他們覺得自己應(yīng)該成功地躲過了流星。
如果您遇到這種情況,可以嘗試以下幾種方法:
通過使用collide_rect_ratio()
函數(shù),您可以使用較小的矩形,從而減少可計為重疊的空間量。根據(jù)精靈的形狀,這可以很好地工作。請注意上圖中機翼的尖端是在矩形外的。這意味著在某些情況星似乎會穿過機翼,而不會算作撞擊。這其實是個好情況!以游戲中事物移動的速度,玩家不會直接注意到這一點,而只會覺得他們“逃脫”了一個非常接近的閃避。他們不會感到沮喪,而是會覺得自己做得很好。
另一種選擇是使用圓形邊界框。對于流星,這是一個非常好的選擇。它不太適合這艘船,但同樣,機翼在碰撞之外不是一件壞事。
設(shè)置精靈的半徑
根據(jù)上面的選項,我們將為流星與玩家的碰撞選擇圓圈。Pygame使這變得容易 - 我們只需要在每個精靈上設(shè)置一個self.radius
新屬性:.
讓我們從玩家開始。碰撞圈應(yīng)該有多大?可能需要一點點實驗才能獲得正確的值。以下是在玩家精靈__init()__
中執(zhí)行此操作的方法:
self.rect = self.image.get_rect() self.radius = 25 pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
關(guān)于pygame繪圖知識可以在這里了解詳細信息:draw類繪制圖形
我們在玩家圖像的頂部繪制一個紅色圓圈,以便我們可以看到它的外觀。讓我們對流星做同樣的事情:
self.rect = self.image.get_rect() self.radius = int(self.rect.width / 2) pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
在這種情況下,我們正在提前計劃一下。我們可能會決定使用不同大小的流星圖像。通過將半徑設(shè)置為圖像寬度的1⁄2
,我們可以做到這一點,而無需稍后調(diào)整代碼。
以下是我們最終得到的結(jié)果:
你可以看到,對于玩家精靈來說,我們的半徑可能太大了——它實際上在y軸上比飛船的大小大。為了更接近上面的例子,讓我們設(shè)置玩家self.radius = 20
。
對于流星,我們希望突出一點角,所以讓我們將圓圈縮放到大小的85%:
self.radius = int(self.rect.width * .85 / 2)
更改碰撞類型
要讓游戲開始使用這些圓圈進行碰撞測試,我們只需要更改spritecollide
命令以使用圓圈函數(shù)而不是AABB
函數(shù):
# check to see if a mob hit the player hits = pygame.sprite.spritecollide(player, mobs, False, pygame.sprite.collide_circle) if hits: running = False
一旦你嘗試了一下,并且你對碰撞的工作方式感到滿意,你就可以刪除紅色圓圈。我建議你只是注釋掉命令,而不是刪除它們,以防將來你想再次使用它們。
結(jié)束語
確定正確的碰撞樣式可以極大地改變游戲的感覺。我們現(xiàn)在有一個更好的流星與玩家碰撞,但請注意,我們沒有改變子彈與流星碰撞的風(fēng)格。圓形對于子彈的形狀來說是一個糟糕的選擇,所以最好將它們保留為矩形。
在下一部分中,我們將通過學(xué)習(xí)如何向精靈添加動畫來使事情變得生動起來
# KidsCanCode - Game Development with Pygame video series # Shmup game - part 5 # Video link: https://www.youtube.com/watch?v=_y5U8tB36Vk # Improved collisions import pygame import random from os import path img_dir = path.join(path.dirname(__file__), 'img') 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.transform.scale(player_img, (50, 38)) self.image.set_colorkey(BLACK) self.rect = self.image.get_rect() self.radius = 20 # pygame.draw.circle(self.image, RED, self.rect.center, self.radius) 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 = meteor_img self.image.set_colorkey(BLACK) self.rect = self.image.get_rect() self.radius = int(self.rect.width * .85 / 2) # pygame.draw.circle(self.image, RED, self.rect.center, self.radius) 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 = bullet_img self.image.set_colorkey(BLACK) 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() # Load all game graphics background = pygame.image.load(path.join(img_dir, "starfield.png")).convert() background_rect = background.get_rect() player_img = pygame.image.load(path.join(img_dir, "playerShip1_orange.png")).convert() meteor_img = pygame.image.load(path.join(img_dir, "meteorBrown_med1.png")).convert() bullet_img = pygame.image.load(path.join(img_dir, "laserRed16.png")).convert() 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, pygame.sprite.collide_circle) if hits: running = False # Draw / render screen.fill(BLACK) screen.blit(background, background_rect) all_sprites.draw(screen) # *after* drawing everything, flip the display pygame.display.flip() pygame.quit()
到此這篇關(guān)于Pygame游戲開發(fā)之太空射擊實戰(zhàn)碰撞改進篇的文章就介紹到這了,更多相關(guān)Pygame碰撞改進內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何使用python的subprocess執(zhí)行命令、交互、等待、是否結(jié)束及解析JSON結(jié)果
這篇文章主要給大家介紹了關(guān)于如何使用python的subprocess執(zhí)行命令、交互、等待、是否結(jié)束及解析JSON結(jié)果的相關(guān)資料,subprocess模塊提供了一種簡單的方法來創(chuàng)建和管理子進程,它可以讓我們在Python程序中執(zhí)行外部命令,獲取命令的輸出和錯誤信息,需要的朋友可以參考下2023-12-12Python機器學(xué)習(xí)logistic回歸代碼解析
這篇文章主要介紹了Python機器學(xué)習(xí)logistic回歸代碼解析,具有一定借鑒價值,需要的朋友可以參考下2018-01-01Python數(shù)組拼接np.concatenate實現(xiàn)過程
這篇文章主要介紹了Python數(shù)組拼接np.concatenate實現(xiàn)過程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-04-04Python爬取數(shù)據(jù)保存為Json格式的代碼示例
今天小編就為大家分享一篇關(guān)于Python爬取數(shù)據(jù)保存為Json格式的代碼示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-04-04