七、小白如何用Pygame制作一款跑酷类游戏(碰撞检测)
前言
本篇文章主要介绍主角人物与障碍物和金币之间的碰撞检测,在设计过程中对于障碍物只是选择了其1/3的部分与主角的全面部分进行碰撞检测。对于金币则是金币图片的整个矩形框与主角矩形框之间的碰撞检测。
一、金币碰撞音效和障碍物碰撞受伤音效的添加
二、代码部分
1.障碍物碰撞
为了降低游戏难度,选择图片的中间三分之一部分与主角进行碰撞检测
#计算中间三分之一的起始 x 坐标和宽度
start_x = arect.width // 3
middle_third_width = arect.width // 3
# 提取中间三分之一区域
middle_third_rect = (start_x, 0, middle_third_width, arect.height)
middle_third_surface = a.subsurface(middle_third_rect)
mrect=middle_third_surface.get_rect()
mrect.topleft=(arect.left+arect.width//3,arect.top)
if mrect.colliderect(myself.rect):
injure = pygame.mixer.Sound('music/injure1.mp3')
pygame.mixer.Sound.play(injure)
myself.life-=1
barrier[i]=1
else:
screen.blit(a, arect)
2.金币碰撞
代码如下:
#及时从金币精灵族移除不需要的金币精灵
for goldsprite in goldGroup:
# 人与金币碰撞检测 发生碰撞之后 金币增加
if pygame.sprite.collide_mask(goldsprite, myself):
# 响一下音效
nosun = pygame.mixer.Sound('material/music/gold.mp3')
pygame.mixer.Sound.play(nosun)
goldGroup.remove(goldsprite)
if goldsprite.rect.right<=0:
goldGroup.remove(goldsprite)
3.runner_main的全部代码
import pygame
from Gold import Gold
import random
from Myself import Myself
import os
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((1080, 600))
pygame.display.set_caption('跑酷游戏')
#背景图
bg_image_path1 = 'material/image/background4.jpg'
bg_img_obj1 = pygame.image.load(bg_image_path1).convert_alpha()
#道路图
road_image_path= 'material/image/road1.png'
road_img_obj=pygame.image.load(road_image_path).convert_alpha()
#距离图
km_image_path= 'material/image/km.png'
km_img_obj=pygame.image.load(km_image_path).convert_alpha()
#按键图
keyUp_image_path= 'material/image/keyboardUpUp.png'
keyUp_img_obj=pygame.image.load(keyUp_image_path).convert_alpha()
keyLeft_image_path= 'material/image/keyboardLEFT.png'
keyLeft_img_obj=pygame.image.load(keyLeft_image_path).convert_alpha()
keyDown_image_path= 'material/image/keyboardDown.png'
keyDown_img_obj=pygame.image.load(keyDown_image_path).convert_alpha()
font_path = 'material/ziti/AlimamaFangYuanTiVF-Thin-2.ttf' # 例如 'SimSun.ttf'
chinese_font = pygame.font.Font(font_path, 30)
text_surface = chinese_font.render('跳跃', True, (0, 0, 255))
text1_surface = chinese_font.render('疾跑', True, (0, 0, 255))
text2_surface = chinese_font.render('滑行', True, (0, 0, 255))
#创建两个存放障碍图片对象的数组
#存放向上的
uplist=[]
#存放向下的
downlist=[]
upadress=['up1.png','up2.png','up3.png','up4.png']
downadress=['platform1.png','platform2.png','platform3.png','platform4.png','platform5.png']
#根据图像的位置加入到相应的数组当中
for i in range(len(downadress)):
stone_image_path= 'material/image/stone/'+downadress[i]
stone_img_obj=pygame.image.load(stone_image_path).convert_alpha()
downlist.append(stone_img_obj)
for i in range(len(upadress)):
stone_image_path= 'material/image/stone/'+upadress[i]
stone_img_obj=pygame.image.load(stone_image_path).convert_alpha()
uplist.append(stone_img_obj)
#因为金币不唯一,所以创建一个精灵族来存放所有的金币精灵
goldGroup = pygame.sprite.Group()
barriarMargin=290
def init():
fps = 60
running = True
index = 0
left = 0
right = 1080
margin = 3
myself = Myself()
pygame.mixer.music.load(os.path.join('material/music', 'bgm1.mp3'))
pygame.mixer.music.play(-1)
km = '0'
#标志位是否暂停
isPause = False
barrier = []
while running:
# 获取键盘的按下事件,与抬起不同
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#空格键作为暂停键 当空格键抬起时触发暂停动作
#如果当前是运动状态,抬起空格变为暂停
#如果当前是暂停状态,抬起空格变为运动
elif event.type == pygame.KEYUP:
if not isPause:
if event.key == pygame.K_SPACE:
isPause = True
else:
if event.key == pygame.K_SPACE:
isPause = False
#暂停状态下,道路不会向左滑动
if isPause:
margin=0
else:
margin=3
#通过提升道路的滑动效果体现出疾跑的效果
if keys[pygame.K_RIGHT]:
margin=8
screen.blit(bg_img_obj1, (0, 0))
screen.blit(road_img_obj, (left, 465))
screen.blit(road_img_obj, (right, 465))
#键位介绍
screen.blit(keyUp_img_obj, (900, 5))
screen.blit(text_surface, (980, 23))
screen.blit(keyLeft_img_obj, (900, 70))
screen.blit(text1_surface, (980, 88))
screen.blit(keyDown_img_obj, (900, 135))
screen.blit(text2_surface, (980, 148))
if left<=-1080:
left=left+2160
if right<=-1080:
right=right+2160
#计划在右半边的时候加入静态的障碍,所以要在某一时刻确定要加入的对象
#于是在当右半边移动到左边尽头的时候确定下来接下来的对象
#这里采用随机数的方法
barrier = []
for i in range(0,4):
random_number = random.randint(1, 15)
if 10 <= random_number <= 15:
gold1=Gold()
gold2=Gold()
gold3=Gold()
gold1.loc=i*barriarMargin
gold2.loc=i*barriarMargin+1*70
gold3.loc=i*barriarMargin+2*70
goldGroup.add(gold1)
goldGroup.add(gold2)
goldGroup.add(gold3)
barrier.append(1)
elif random_number == 1:
barrier.append(2)
elif random_number == 2:
barrier.append(3)
elif random_number == 3:
barrier.append(4)
elif random_number == 4:
barrier.append(5)
elif random_number == 5:
barrier.append(6)
elif random_number == 6:
barrier.append(7)
elif random_number == 7:
barrier.append(8)
elif random_number == 8:
barrier.append(9)
elif random_number == 9:
barrier.append(10)
if -1080<right<1080:
for sprite in goldGroup:
sprite.rect.left=sprite.loc+right
goldGroup.draw(screen)
goldGroup.update(index)
for i in range(len(barrier)):
if barrier[i]==2:
a = uplist[0]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 465)
elif barrier[i]==1:
continue
elif barrier[i]==3:
a = uplist[1]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 460)
elif barrier[i]==4:
a = uplist[2]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 455)
elif barrier[i]==5:
a = uplist[3]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 460)
elif barrier[i]==6:
a = downlist[0]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 330)
elif barrier[i]==7:
a = downlist[1]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 350)
elif barrier[i]==8:
a = downlist[2]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 365)
elif barrier[i]==9:
a = downlist[3]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 350)
elif barrier[i]==10:
a = downlist[4]
arect = a.get_rect()
arect.topleft = (right + i*barriarMargin, 210)
start_x = arect.width // 3
middle_third_width = arect.width // 3
# 提取中间三分之一区域
middle_third_rect = (start_x, 0, middle_third_width, arect.height)
middle_third_surface = a.subsurface(middle_third_rect)
mrect = middle_third_surface.get_rect()
mrect.topleft = (arect.left + arect.width // 3, arect.top)
if mrect.colliderect(myself.rect):
injure = pygame.mixer.Sound('material/music/injure1.mp3')
pygame.mixer.Sound.play(injure)
barrier[i] = 1
else:
screen.blit(a, arect)
#及时从金币精灵族移除不需要的金币精灵
for goldsprite in goldGroup:
# 人与金币碰撞检测 发生碰撞之后 金币增加
if pygame.sprite.collide_mask(goldsprite, myself):
# 响一下音效
nosun = pygame.mixer.Sound('material/music/gold.mp3')
pygame.mixer.Sound.play(nosun)
goldGroup.remove(goldsprite)
if goldsprite.rect.right<=0:
goldGroup.remove(goldsprite)
# 暂停状态下,主角也要保持静止,也就是说主角直保持一个动作,因此要传递一个参数给主角精灵
# 通过按下键盘的事件更改主角的状态,因此也需传递一个参数给主角来决定状态比如奔跑、跳跃以及滑行
screen.blit(myself.image, myself.rect)
myself.update(index,keys,isPause)
screen.blit(km_img_obj, (10, 70))
km_font = pygame.font.SysFont('arial', 30)
km_num_surface = km_font.render(km, True, (0, 0, 255))
screen.blit(km_num_surface, (80, 88))
if index%6==0:
km = str(int(km) + margin)
index += 1
pygame.display.update()
clock.tick(fps)
left -= margin
right -= margin
if __name__=="__main__":
init()
实现效果
跑酷游戏碰撞检测效果