目录
一、背景介绍:
二、整体流程:
三、游戏的主要设计:
四、效果展示
五、代码部分
1.游戏整体部分
2.设计关卡
3.碰撞检测(核心)
项目描述:为落实抗击疫情的精神设计了一款类似于愤怒的小鸟模型的一款小游戏,基于pygame开发。
游戏关卡切换界面(体现分数)
def start(self):
# 导入所有游戏精灵
game_sprites = self.loadlevelmap() # 载入地图返回游戏精灵内容(字典类型)
doctors, covids, blocks, walls = game_sprites['doctors'], game_sprites['covids'], game_sprites['blocks'], game_sprites[
'walls'] # 得到游戏内容
slingshot = Slingshot(self.screen, 200, self.screen_size[1] - 200, 30, 200)
doctors[0].load(slingshot)
score_label = Label(self.screen, 50, 10, 100, 50)
score_label.addtext(f'SCORE: {self.score}', 25, self.cfg.FONTPATH['Comic_Kings'], (236, 240, 241))
doctors_remaining_label = Label(self.screen, 120, 50, 100, 50)
doctors_remaining_label.addtext(f"Doctor REMAINING: {len(doctors)}", 25, self.cfg.FONTPATH['Comic_Kings'],
(236, 240, 241))
covids_remaining_label = Label(self.screen, 110, 90, 100, 50)
covids_remaining_label.addtext(f"COVIDs REMAINING: {len(covids)}", 25, self.cfg.FONTPATH['Comic_Kings'],
(236, 240, 241))
charles_label = Label(self.screen, self.screen_size[0] - 450, self.screen_size[1] - 20, 300, 100)
charles_label.addtext('Against The Epidemic', 60, self.cfg.FONTPATH['arfmoochikncheez'], (113, 125, 126))
# 游戏主循环
clock = pygame.time.Clock()
blocks_to_remove, covids_to_remove = [], []
while True:
# --按键检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.quitgame()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
self.quitgame()
elif event.key == pygame.K_r:
self.start()
elif event.key == pygame.K_p or event.key == pygame.K_ESCAPE:
self.pauseinterface()
elif event.type == pygame.MOUSEBUTTONDOWN:
if doctors[0].selected():
doctors[0].is_selected = True
elif event.type == pygame.MOUSEBUTTONUP:
if doctors[0].is_selected:
doctors[0].is_selected = False
doctors[0].start_flying = True
# --背景颜色填充,绘制四色条的背景
color = self.cfg.BACKGROUND_COLOR
for i in range(3):
color = (color[0] + 5, color[1] + 5, color[2] + 5)
pygame.draw.rect(self.screen, color, (0, i * 300, self.screen_size[0], 300))
pygame.draw.rect(self.screen, (77, 86, 86), (0, self.screen_size[1], self.screen_size[0], 50))
# --判断游戏是否结束,若没有则导入新的医生
if (not doctors[0].is_loaded) and self.still(covids + doctors + blocks):
doctors.pop(0)
if self.status(covids, doctors) == 2: # 游戏胜利
self.score += len(doctors) * 100 # 剩余医生越多,得分越高
self.switchlevelinterface()
elif self.status(covids, doctors) == 1:
self.failureinterface()
doctors[0].load(slingshot)
doctors[0].start_flying = False
# --重置医生的位置
if doctors[0].is_selected:
doctors[0].reposition(slingshot)
if hasattr(doctors[0], 'start_flying') and doctors[0].start_flying: #start_flying为后添加属性,得用hasatter判断是否存在属性
doctors[0].is_loaded = False
# --弹弓
slingshot.draw(doctors[0])
# --判断病毒是否撞上木桩
for i in range(len(covids)):
for j in range(len(blocks)):
covid_magnitude_1, block_magnitude_1 = covids[i].velocity.magnitude, blocks[j].velocity.magnitude
covids[i], blocks[j], is_collision = self.collision(covids[i], blocks[j])
covid_magnitude_2, block_magnitude_2 = covids[i].velocity.magnitude, blocks[j].velocity.magnitude
if is_collision:
if abs(covid_magnitude_2 - covid_magnitude_1) > 2:
blocks_to_remove.append(blocks[j])
blocks[j].setdestroy()
if abs(block_magnitude_2 - block_magnitude_1) > 2:
covids_to_remove.append(covids[i])
covids[i].setdead()
# --判断医生是否撞上木桩
for i in range(len(doctors)):
if not (doctors[i].is_loaded or doctors[i].velocity.magnitude == 0):
for j in range(len(blocks)):
doctor_magnitude_1, block_magnitude_1 = doctors[i].velocity.magnitude, blocks[j].velocity.magnitude
doctors[i], blocks[j], is_collision = self.collision(doctors[i], blocks[j])
doctor_magnitude_2, block_magnitude_2 = doctors[i].velocity.magnitude, blocks[j].velocity.magnitude
if is_collision:
if abs(doctor_magnitude_1 - doctor_magnitude_2) > 2:
if blocks[j] not in blocks_to_remove: #木桩和医生病毒同时相撞避免重复破坏木桩
blocks_to_remove.append(blocks[j])
blocks[j].setdestroy()
# --判断病毒是否撞上病毒或者病毒撞墙
for i in range(len(covids)):
covids[i].move()
for j in range(i + 1, len(covids)):
covid1_magnitude_1, covid2_magnitude_1 = covids[i].velocity.magnitude, covids[j].velocity.magnitude
covids[i], covids[j], is_collision = self.collision(covids[i], covids[j])
covid1_magnitude_2, covid2_magnitude_2 = covids[i].velocity.magnitude, covids[j].velocity.magnitude
if abs(covid1_magnitude_1 - covid1_magnitude_2) > 2:
if covids[j] not in covids_to_remove:
covids_to_remove.append(covids[j])
covids[j].setdead()
if abs(covid2_magnitude_1 - covid2_magnitude_2) > 2:
if covids[i] not in covids_to_remove:
covids_to_remove.append(covids[i])
covids[i].setdead()
for wall in walls: covids[i] = self.collision(covids[i], wall)[0]
covids[i].draw()
# --判断医生是否撞到病毒或者医生是否撞到墙
for i in range(len(doctors)):
if (not doctors[i].is_loaded) and (doctors[i].velocity.magnitude):
doctors[i].move()
for j in range(len(covids)):
doctor_magnitude_1, covid_magnitude_1 = doctors[i].velocity.magnitude, covids[j].velocity.magnitude
doctors[i], covids[j], is_collision = self.collision(doctors[i], covids[j])
doctor_magnitude_2, covid_magnitude_2 = doctors[i].velocity.magnitude, covids[j].velocity.magnitude
if is_collision:
if abs(doctor_magnitude_2 - doctor_magnitude_1) > 2:
if covids[j] not in covids_to_remove:
covids_to_remove.append(covids[j])
covids[j].setdead()
if doctors[i].is_loaded: doctors[i].projectpath()
for wall in walls: doctors[i] = self.collision(doctors[i], wall)[0]
doctors[i].draw()
# --判断木桩是否撞到了木桩或者木桩撞到墙
for i in range(len(blocks)):
for j in range(i + 1, len(blocks)):
block1_magnitude_1, block2_magnitude_1 = blocks[i].velocity.magnitude, blocks[j].velocity.magnitude
blocks[i], blocks[j], is_collision = self.collision(blocks[i], blocks[j])
block1_magnitude_2, block2_magnitude_2 = blocks[i].velocity.magnitude, blocks[j].velocity.magnitude
if is_collision:
if abs(block1_magnitude_2 - block1_magnitude_1) > 2:
if blocks[j] not in blocks_to_remove:
blocks_to_remove.append(blocks[j])
blocks[j].setdestroy()
if abs(block2_magnitude_2 - block2_magnitude_1) > 2:
if blocks[i] not in blocks_to_remove:
blocks_to_remove.append(blocks[i])
blocks[i].setdestroy()
blocks[i].move()
for wall in walls: blocks[i] = self.collision(blocks[i], wall)[0]
blocks[i].draw()
# --墙
for wall in walls: wall.draw()
# --显示文字
score_label.addtext(f'SCORE: {self.score}', 25, self.cfg.FONTPATH['Comic_Kings'], (236, 240, 241))
score_label.draw()
doctors_remaining_label.addtext(f"DOCTORS REMAINING: {len(doctors)}", 25, self.cfg.FONTPATH['Comic_Kings'],
(236, 240, 241))
doctors_remaining_label.draw()
covids_remaining_label.addtext(f"COVID REMAINING: {len(covids)}", 25, self.cfg.FONTPATH['Comic_Kings'],
(236, 240, 241))
covids_remaining_label.draw()
charles_label.draw()
# --画面刷新
pygame.display.update()
clock.tick(self.cfg.FPS)
# --删除无效的元素
if self.still(doctors + covids + blocks):
for covid in covids_to_remove:
if covid in covids:
covids.remove(covid)
self.score += 100
for block in blocks_to_remove:
if block in blocks:
blocks.remove(block)
self.score += 50
covids_to_remove = []
blocks_to_remove = []
另外,游戏的开始游戏界面、游戏的失败界面、游戏暂停界面、游戏关卡切换界面与这里游戏界面中的部分也大同小异,主要包括相关按钮,标题的载入以及对事件(主要是按钮触发)的检测
for i in range(3):
doctors.append(
Doctor(screen=self.screen, imagepaths=self.cfg.IMAGEPATHS['doctor'],
loc_info=(45 * i, self.screen_size[1] - 40, 20))
)
if self.level_pointer == 1:
covids.append(
COVID(screen=self.screen, imagepaths=self.cfg.IMAGEPATHS['covid'],
loc_info=(1100, self.screen_size[1] - 60, 25))
)
covids.append(
COVID(screen=self.screen, imagepaths=self.cfg.IMAGEPATHS['covid'],
loc_info=(1200, self.screen_size[1] - 60, 25))
)
walls.append(
Slab(screen=self.screen, imagepaths=self.cfg.IMAGEPATHS['wall'], x=700, y=250, width=30,
height=self.screen_size[1] - 250)
)
主要通过添加相关元素(包括医生,病毒,障碍[通过木块体现],墙),设置其位置来体现关卡特点,其余关卡也是大同小异
通过检测物体之间(主要是医生与病毒,医生与障碍,医生与墙,病毒与病毒,病毒与墙,病毒与障碍)图像是否发生重叠来体现是否发生碰撞,若发生碰撞则修改碰撞物体的速度大小与方向,这里体现了病毒医生之间的碰撞,其余碰撞的产生也能通过类似功能实现
def collision(self, sprite1, sprite2):
is_collision = False
elasticity, block_elasticity = 0.8, 0.7
if sprite1.type in ['covid', 'doctor'] and sprite2.type in ['covid', 'doctor']: #病毒医生之间的碰撞
dx, dy = sprite1.loc_info[0] - sprite2.loc_info[0], sprite1.loc_info[1] - sprite2.loc_info[1]
dist = math.hypot(dx, dy)
if dist < sprite1.loc_info[2] + sprite2.loc_info[2]:
tangent = math.atan2(dy, dx)
angle = 0.5 * math.pi + tangent
angle1, angle2 = 2 * tangent - sprite1.velocity.angle, 2 * tangent - sprite2.velocity.angle
magnitude1, magnitude2 = sprite2.velocity.magnitude, sprite1.velocity.magnitude
sprite1.velocity, sprite2.velocity = VelocityVector(magnitude1, angle1), VelocityVector(magnitude2,
angle2)
sprite1.velocity.magnitude *= elasticity
sprite2.velocity.magnitude *= elasticity
overlap = 0.5 * (sprite1.loc_info[2] + sprite2.loc_info[2] - dist + 1)
sprite1.loc_info[0] += math.sin(angle) * overlap
sprite1.loc_info[1] -= math.cos(angle) * overlap
sprite2.loc_info[0] -= math.sin(angle) * overlap
sprite2.loc_info[1] += math.cos(angle) * overlap
is_collision = True