python飛機大戰(zhàn)03-碰撞檢測
1 碰撞
?? 碰撞是游戲開發(fā)的基本部分。 碰撞檢測意味著你要檢測游戲世界中的一個對象是否正在觸碰另一個對象匾竿。 碰撞反應(yīng)決定了碰撞發(fā)生時你想要做什么——馬里奧拿起硬幣瓦宜,子彈傷害敵人等等。
1.1 邊框
?? 請記住岭妖,pygame中的每個sprite都有一個 rect 屬性定義其坐標及其大小临庇。 rect 在pygame的對象格式為 [x, y, width, height] 反璃,其中 x 和 y 表示矩形的左上角。
?? 為了檢測碰撞假夺,需要查看玩家的 角色rect 并將其與每個怪物 rect 進行比較』打冢現(xiàn)在可以通過循環(huán)遍歷怪物并為執(zhí)行此比較的每個人執(zhí)行此操作:
在此圖片中,您可以看到只有紅色矩形1與大黑色矩形相撞已卷。2在y中重疊梧田,但在x軸不重疊;3在x軸上重疊侧蘸,但不在y軸重疊 裁眯。為了使兩個矩形重疊,它們的邊界必須在每個軸上重疊讳癌。在代碼中寫這個:
# if mob.rect.right > player.rect.left and \ # 反斜杠表示續(xù)行
# mob.rect.left < player.rect.right and \
# mob.rect.bottom > player.rect.top and \
# mob.rect.top < player.rect.bottom:
# collide = True
spritecollide()
幸運的是穿稳,pygame通過使用一個內(nèi)置函數(shù) spritecollide() 來完成上述操作。
spritecollide()
參數(shù):
- 要檢查的玩家精靈
- 要比較的敵人組的名稱
- dokill 參數(shù)(True / False)晌坤。dokill 參數(shù)設(shè)置是否應(yīng)該在命中對象時刪除該對象逢艘。
返回值:
spritecollide() 命令的返回值是被擊中的精靈列表(記住,玩家可能一次與多個暴徒相撞)骤菠。
2 與玩家碰撞的怪物
?? 將把這個命令添加到游戲循環(huán)的“更新”部分:
# Update # 游戲結(jié)束的話直接將running設(shè)為False即可
all_sprites.update()
# check to see id a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, False)
if hits:
running = False
將碰撞列表分配給變量 hits 它改。如果 hits 列表不為空,設(shè)置 running 為 False 娩怎,使得游戲結(jié)束搔课。
3 回擊
3.1 子彈精靈
添加一個新精靈:子彈。這將是按鍵時產(chǎn)生的精靈截亦,出現(xiàn)在玩家精靈的頂部爬泥,并以相當高的速度向上移動。
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 值袍啡,以便可以告訴精靈在哪里出現(xiàn)。由于玩家精靈可以移動却桶,設(shè)置為玩家射擊時的位置境输。設(shè)置 speedy 為負值,以便它會向上移動颖系。
最后嗅剖,檢查子彈是否已經(jīng)脫離屏幕頂部,如果是嘁扼,將其刪除信粮。
3.2 keypress事件
?? 為了讓事情變得簡單,要做到這一點趁啸,每次玩家按下空格鍵時强缘,都會發(fā)射子彈督惰。需要將其添加到事件檢查中:
# Process input(events) # 這是游戲主循環(huán),通過變量running控制旅掂,如果需要
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() 方法。
3.3 大量子彈
首先称龙,需要添加一個新精靈組來保存所有子彈對象:
bullets = pygame.sprite.Group()
現(xiàn)在留拾,可以在 Player 類中添加以下方法:
def shoot(self):
bullet = Bullet(self.rect.centerx,self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
shoot() 方法會產(chǎn)生一顆子彈,使用玩家的頂部中心作為生成點鲫尊。然后將子彈添加到 all_sprites精靈組 (繪制和更新)痴柔。以及 bullets精靈組 (碰撞檢查)。
3.3.1 子彈碰撞
現(xiàn)在需要檢查子彈是否擊中怪物疫向。這里的區(qū)別是有多個子彈(在 bullets 組中)和多個小怪
(在 mobs 組中)咳蔚,所以不能用 spritecollide() ,因為它只比較一個精靈與一個組搔驼。將使
用 groupcollide() :
# Update # 游戲結(jié)束的話直接將running設(shè)為False即可
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() 谈火,除了命名兩個組進行比較,您將獲得的是被擊中的怪物字典舌涨,鍵為參數(shù)1中的其中一個糯耍,值為參數(shù)2中的其中一個。有兩個 dokill 選項囊嘉,每個選項對應(yīng)一個組温技。
?? 如果只是刪除小怪,就會遇到一個問題:怪物用完了扭粱!所以做的是循環(huán) hits 舵鳞,對于銷毀的每個怪物,將產(chǎn)生另一個新的怪物琢蛤。
整合到一起
# Shmup game - part 3
# shmup.py
# Collisions and bullets
import pygame
import random
WIDTH = 480 # width of our game window
HEIGHT = 600 # height of our game window
FPS = 60 # 60 frames per second
# Colors(R,G,B),define color
BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
YELLOW = (255,255,0)
# initialize pygame and create windw
pygame.init() # 啟動pygame并初始化
pygame.mixer.init() # 聲音初始化
screen = pygame.display.set_mode((WIDTH, HEIGHT)) # 游戲屏幕蜓堕,按照在配置常量中設(shè)置的大小創(chuàng)建
pygame.display.set_caption("Shmup!")
icon = pygame.image.load("img/alien.ico")
pygame.display.set_icon(icon)
clock = pygame.time.Clock() # 創(chuàng)建一個時鐘以便于確保游戲能以指定的FPS運行
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):
# any code here will happen every time the game loop updates
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.speedx = random.randrange(-3, 3)
self.speedy = random.randrange(1, 8)
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -50 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) # 這是游戲主循環(huán),通過變量running控制博其,如果需要
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 # 游戲結(jié)束的話直接將running設(shè)為False即可
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
# Render(draw) # 現(xiàn)在還沒有確定具體的代碼套才,先用一些基本代碼填充,后續(xù)再補充
screen.fill(BLACK)
all_sprites.draw(screen)
# *after* drawing everything,flip the display
pygame.display.flip()
pygame.quit()
項目代碼可以查看我的github慕淡,網(wǎng)址為
alien-invasion