"""这个程序实现道具的设计。
dead死亡道具,骷髅头,skeleton.png,不小心接到它后ball.lives减一,出现机率大
life生命道具,15.png 核桃图形,接到后ball.lives加一
speedup加速道具,speedup.png,接到它后球的速度翻倍
slowdown减速道具,slowdown.png,接到它后球的速度减倍。
"""
import time
import pygame
from pygame.locals import *
from random import choice,randint
class Brick(pygame.sprite.Sprite):
"""砖块类"""
counter = 0 # 类变量,统计本关数量
def __init__(self,image,position,group):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.topleft = position
self.group = group
self.group.add(self)
class Prop(pygame.sprite.Sprite):
"""道具类"""
def __init__(self,images,position,group,screen):
"""images是一个字典 images['dead'] = ....life,speedup,slowdown"""
pygame.sprite.Sprite.__init__(self)
self.images = images
#self.position = position
self.group = group
self.group.add(self)
self.screen = screen
self.screen_height = screen.get_height() # 屏幕高度
self.key = choice(list(self.images.keys())) # 随机选择一个
self.image = self.images[self.key] # 图形surface
self.rect = self.image.get_rect() # 矩形对象,描述坐标与宽高的
self.rect.center = position
self.yspeed = 0 # 垂直速度
self.aspeed = 0.2 # 加速度
def update(self):
self.rect.move_ip(0,self.yspeed)
self.yspeed += self.aspeed
if self.rect.top >= self.screen_height :
self.group.remove(self) # 超出下边界,则移除自己
class Board(pygame.sprite.Sprite):
"""拦板类"""
def __init__(self,images,screen):
pygame.sprite.Sprite.__init__(self)
self.images = images # board有5个造型,从长到短为5,4,3,2,1.png
self.amounts = len(images) # 造型数量
self.index = 0
self.image = self.images[0]
self.rect = self.image.get_rect() # 矩形对象
self.screen = screen # 能访问屏幕对象
self.rect.bottom = screen.get_height() - 25 #初始底坐标
def update(self,pos):
self.rect.centerx = pos[0]
def draw(self):
self.screen.blit(self.image,self.rect)
def lost_ball(self):
"""没接到球,它要变短"""
pass
def get_prop(self):
"""得到道具球,它要变长"""
oldx = self.rect.centerx
self.index = max(0,self.index - 1)
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.rect.bottom = self.screen.get_height() - 25
self.rect.centerx = oldx
class Ball(pygame.sprite.Sprite):
"""弹球类"""
def __init__(self,image,screen,board):
pygame.sprite.Sprite.__init__(self)
self.image = image
pass
def shoot(self):
if self.shoot_flag == 0: # 只有小球呆在拦板上才可以发射,否则在空中也能发射
self.dx = choice([-10,-9,-8,-7,-6,-5,5,6,7,8,9,10])
self.dy = choice([-10,-9,-8,-7,-6,-5])
self.shoot_flag = 1
def update(self):
if self.shoot_flag == 0 :
self.rect.bottom = self.board.rect.top
self.rect.centerx = self.board.rect.centerx
else:
self.rect.move_ip(self.dx,self.dy)
if self.rect.top > self.screen_height + 200: # 弹球丢失,重新开始或结束游戏
self.lives -= 1 # 数量减去1
self.shoot_flag = 0 # 发射标志
self.board.lost_ball() # 变短拦板
pygame.display.set_caption("埃及爆破砖:" + str(self.lives))
if self.rect.left <= 0 or self.rect.right >= self.screen_width: # 碰到左右边缘反弹
self.dx = -self.dx
if abs(self.dy) < 0.1 : # 特殊情况可能dy为0,这时球永远不会下来
self.dy = randint(1,2)
if self.rect.top <= 0: # 碰到上边缘反弹
self.dy = -self.dy
def draw(self):
self.screen.blit(self.image,self.rect)
class Explosion(pygame.sprite.Sprite):
"""爆炸类"""
def __init__(self,images,position,group,screen):
pygame.sprite.Sprite.__init__(self)
self.images = images
self.index = 0
self.amounts = len(images)
self.interval = 0.1 # 造型切换时间(秒)
self.begin_time = time.time() # 起始时间
self.image = self.images[0] # 最初的图形对象
self.rect = self.image.get_rect() # 矩形对象
self.rect.center = position # 爆炸坐标
self.group = group
self.group.add(self)
self.screen = screen
def update(self):
if self.index < self.amounts:
if time.time() - self.begin_time > self.interval: # 超时换造型
oldcenter = self.rect.center
self.image = self.images[self.index]
self.index = self.index + 1
self.rect = self.image.get_rect()
self.rect.center = oldcenter
self.begin_time = time.time()
else:
self.group.remove(self)
def display_cover(cover_image):
"""显示封面"""
cover_image = pygame.image.load(cover_image)
clock = pygame.time.Clock()
exit_game = False
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
exit_game = True
break
if event.type == KEYDOWN:
if event.key == K_SPACE:
running = False
break
screen.blit(cover_image,(0,0))
pygame.display.update()
clock.tick(10)
return exit_game
def start_level(level_index):
"""生成砖块,启动这一关"""
rows,cols = level_design[level_index]
all_bricks_width = cols * 100 + (cols-1) * 20 # 所有砖块的宽度
left_pad = (width - all_bricks_width) // 2 # 砖块两边的到屏幕边缘的距离
up_pad = 50 # 顶端距离
for r in range(rows): # 摆砖块
for c in range(cols):
x = left_pad + c * 120
y = up_pad +r * 60
Brick(brick_image,(x,y),brick_group)
exit_game = False
while len(brick_group) > 0 and exit_game ==False:
for event in pygame.event.get():
if event.type == QUIT:
exit_game = True
break
if event.type == MOUSEMOTION:
board.update(event.pos)
if event.type == MOUSEBUTTONUP:
ball.shoot()
print(ball.shoot_flag)
if ball.lives == 0:
exit_game = True
break
ball.update()
brick_group.update()
explosion_group.update()
prop_group.update()
collision_check() #这个函数是检测所有对象之间的碰撞检测
screen.fill((0,0,0))
board.draw()
ball.draw()
brick_group.draw(screen)
explosion_group.draw(screen)
prop_group.draw(screen)
pygame.display.update()
clock.tick(60)
print("退出本关")
"关卡完后,弹球归位"
explosion_group.empty() # 爆炸组清空
prop_group.empty() # 道具组清空
ball.shoot_flag = 0
return exit_game
def collision_check():
"小球和砖块组的碰撞"
b = pygame.sprite.spritecollideany(ball, brick_group) # 球和砖块组的碰撞,返回碰到的砖块
if b!=None:
position = b.rect.center # 移除砖块前记录坐标
brick_group.remove(b)
Explosion(explosion_images,b.rect.center,explosion_group,screen)
ball.dy = -ball.dy # 球的垂直速度反转
"以一定的机率生成一个道具"
if randint(1,2) ==1 : #生成一个道具
Prop(prop_images,position,prop_group,screen)
print("生成了一个道具")
"小球和拦板在碰撞"
t = pygame.sprite.collide_rect(ball,board) # 球和拦板的碰撞
if t :
ball.dy = -ball.dy
ball.dx = ball.dx + randint(-3,3) # 不确定的左右速度改变
"拦板和道具组的碰撞"
p = pygame.sprite.spritecollideany(board, prop_group) # 返回碰到的道具
if p!=None:
name = p.key # 道具的名字,就是它几个surface对应的key
prop_group.remove(p) # 拦板碰到一个道具,马上移除它
if name == 'life': # 如果收到生命道具,生命数量加1,拦板变长
ball.lives +=1
board.get_prop() # 变长
pygame.display.set_caption("埃及爆破砖:" + str(ball.lives))
elif name == 'dead': # 收到死亡道具内,骷髅头,生命数量减1
ball.lives -=1
pygame.display.set_caption("埃及爆破砖:" + str(ball.lives))
elif name =='speedup': # 加速道具
ball.dx = 2 * ball.dx
ball.dy = 2 * ball.dy
elif name == 'slowdown': # 减速道具
ball.dx = 0.5 * ball.dx
ball.dy = 0.5 * ball.dy
def wait_press_any_key():
clock = pygame.time.Clock()
exit_game = False
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
exit_game = True
break
if event.type == KEYDOWN:
running = False
break
screen.blit(level_images[level_index],(0,0))
pygame.display.update()
clock.tick(10)
return exit_game
if __name__ == "__main__":
width,height = 960,720
ball_image = "resources/15.png" # 弹球图
brick_image = "resources/brick.png" # 砖图
cover_image = "resources/cover.png" # 封面图
explosion_images = ["resources/" + str(i) + ".png" for i in range(7,13)] # 爆炸序列图
board_images = ["resources/" + str(i) + ".png" for i in range(5,0,-1)] # 拦板序列图,从长到短
level_images = ["resources/" + str(i) + ".png" for i in range(17,22)] # 关卡完后显示的图
level_design = [(2,4),(4,4),(6,6),(8,6),(9,8)] # 记录每关的砖块行列数
level_amounts = len(level_design)
pygame.init()
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption("埃及爆破砖_道具的设计")
ball_image = pygame.image.load(ball_image).convert_alpha()
brick_image = pygame.image.load(brick_image).convert_alpha()
board_images = [pygame.image.load(image).convert_alpha() for image in board_images]
level_images = [pygame.image.load(image).convert_alpha() for image in level_images]
explosion_images = [pygame.image.load(image).convert_alpha() for image in explosion_images]
prop_images = {}
prop_images['life'] = ball_image
prop_images['dead'] = pygame.image.load("resources/skeleton.png").convert_alpha()
prop_images['speedup'] = pygame.image.load("resources/speedup.png").convert_alpha()
prop_images['slowdown'] = pygame.image.load("resources/slowdown.png").convert_alpha()
exit_game = display_cover(cover_image) # 按空格键开始游戏
if exit_game :
pygame.quit()
else:
brick_group = pygame.sprite.Group() # 砖块组
explosion_group = pygame.sprite.Group() # 爆炸组
prop_group = pygame.sprite.Group() # 道具组
board= Board(board_images,screen)
ball = Ball(ball_image,screen,board)
exit_game1 = False
exit_game2 = False
clock = pygame.time.Clock()
level_index = 0
while level_index < level_amounts: # 遍历关卡
exit_game1 = start_level(level_index)
if exit_game1 != True:
exit_game2 = wait_press_any_key() # 没有在游戏中按关闭按钮,那就等待按任意键开始下一关
level_index += 1
if exit_game2:break
else:
break
if exit_game1 == False and exit_game2 == False:
"以下是显示结束时的画面"
running = True
while running:
event = pygame.event.poll()
if event.type in ( QUIT,KEYDOWN,MOUSEBUTTONDOWN ):
running = False
break
screen.blit(level_images[level_index-1],(0,0))
pygame.display.update()
clock.tick(10)
pygame.quit()
print("游戏结束!")