我们将制作这样一个游戏,移动挡板挡住笑脸球,不让它掉到屏幕底部。
制作游戏的两个能力:绘制动画的能力和处理用户交互的能力。
设计游戏要考虑的要素(以Smiley Pong为例):
玩游戏的区域或游戏板 一个黑色的屏幕,表示一个Ping-Pong游戏板的一半。
目标和成就 玩家试图得分并避免丢掉命。
游戏部件(游戏角色和对象) 玩家有一个球和一个挡板。
规则 “如果球碰到了挡板,玩家得到1分;如果球碰到了屏幕的底部,玩家丢掉一条命。
机制 我们使用鼠标来左右移动挡板,守卫屏幕的底部;随着游戏的进行,球将会移动得更快。
资源 玩家将会有5条命,或者尽可能多地得分。
# SmileyBounce2.py
import pygame # Setup
pygame.init()
screen = pygame.display.set_mode([800,600])
keep_going = True
pic = pygame.image.load("CrazySmile.bmp")
colorkey = pic.get_at((0,0))
pic.set_colorkey(colorkey)
picx = 0
picy = 0
BLACK = (0,0,0)
timer = pygame.time.Clock()
speedx = 5
speedy = 5
while keep_going: # Game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
picx += speedx
picy += speedy
if picx <= 0 or picx + pic.get_width() >= 800:
speedx = -speedx
if picy <= 0 or picy + pic.get_height() >= 600:
speedy = -speedy
screen.fill(BLACK)
screen.blit(pic, (picx, picy))
pygame.display.update()
timer.tick(60)
pygame.quit() # Exit
挡板的设置:
WHITE = (255,255,255) #挡板的颜色
paddlew = 200 #宽度
paddleh = 25 #高度
paddlex = 300 #起始x坐标
paddley = 550 #起始y坐标
我们让挡板跟随鼠标在屏幕底部左右移动,并让鼠标的x坐标位于挡板中央:
paddlex = pygame.mouse.get_pos()[0]
paddlex -= paddlew/2
绘制挡板:
pygame.draw.rect(screen, WHITE, (paddlex, paddley, paddlew, paddleh))
points = 0
lives = 5
为了游戏更具一般性,作如下设置:
screenw=800
screenh=600
screen = pygame.display.set_mode([screenw,screenh])
picw = 100 #笑脸球的宽度
pich = 100 #笑脸球的高度
当笑脸球碰到屏幕底部时,笑脸球的y坐标等于screenh-pich,所以picy>=screenh-pich时,命数要减少,所以修改笑脸球碰到屏幕上下边缘时的代码:
if picy <= 0:
speedy = -speedy
if picy >= screenh-pich:
lives -= 1
speedy = -speedy
因为笑脸与挡板都是虚拟的,所以笑脸可以穿过挡板再反弹上来,那么也能符合上面的规定,但是不符合现实情况,所以我们要确保笑脸是向下运动的时候,符合上面的规定,所以得出挡板碰到球的条件:
if picy + pich >= paddley and picy + pich <= paddley + paddleh \
and speedy > 0:
if picx + picw / 2 >= paddlex and picx + picw / 2 <= paddlex + \
paddlew:
反斜杠“\”的作用是连接代码,当代码太长时,我们分行写,用反斜杠连接。
当挡板碰到球后,添加一分并使球反弹。
points += 1
speedy = -speedy
我们在屏幕顶端中间向下走10个像素那里绘制得分和命数。
确定用哪种字体,多大字体来绘制文本:
font = pygame.font.SysFont("Times", 24)
在每次游戏循环中绘制文本:
# Draw text on screen
draw_string = "Lives: " + str(lives) + " Points: " + str(points)
text = font.render(draw_string, True, WHITE)
text_rect = text.get_rect()
text_rect.centerx = screen.get_rect().centerx
text_rect.y = 10
screen.blit(text, text_rect)
说明:
render(text, antialias, color, background=None) -> Surface
draw text on a new Surface
The antialias argument is a boolean: if True the characters will have smooth edges.
# SmileyBounce2.py
import pygame # Setup
pygame.init()
screenw=800
screenh=600
screen = pygame.display.set_mode([screenw,screenh])
picw = 100
pich = 100
keep_going = True
pic = pygame.image.load("CrazySmile.bmp")
colorkey = pic.get_at((0,0))
pic.set_colorkey(colorkey)
picx = 0
picy = 0
BLACK = (0,0,0)
timer = pygame.time.Clock()
speedx = 5
speedy = 5
WHITE = (255,255,255) #挡板的颜色
paddlew = 200 #宽度
paddleh = 25 #高度
paddlex = 300 #起始x坐标
paddley = 550 #起始y坐标
points = 0
lives = 5
font = pygame.font.SysFont("Times",24)
while keep_going: # Game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
picx += speedx
picy += speedy
if picx <= 0 or picx + pic.get_width() >= screenw:
speedx = -speedx
if picy <= 0:
speedy = -speedy
if picy >= screenh-pich:
lives -= 1
speedy = -speedy
screen.fill(BLACK)
screen.blit(pic, (picx, picy))
paddlex = pygame.mouse.get_pos()[0]
paddlex -= paddlew/2
pygame.draw.rect(screen, WHITE, (paddlex, paddley, paddlew, paddleh))
# Check for paddle bounce
if picy + pich >= paddley and picy + pich <= paddley + paddleh \
and speedy > 0:
if picx + picw / 2 >= paddlex and picx + picw / 2 <= paddlex + \
paddlew:
points += 1
speedy = -speedy
# Draw text on screen
draw_string = "Lives: " + str(lives) + " Points: " + str(points)
text = font.render(draw_string, True, WHITE)
text_rect = text.get_rect()
text_rect.centerx = screen.get_rect().centerx
text_rect.y = 10
screen.blit(text, text_rect)
pygame.display.update()
timer.tick(60)
pygame.quit() # Exit
在 draw_string = "Lives: " + str(lives) + " Points: " + str(points) 下面添加游戏结束要干嘛:
# Check whether the game is over
if lives < 1:
speedx = speedy = 0
draw_string = "Game Over. Your score was: " + str(points)
draw_string += ". Press F1 to play again. "
在处理事件的for循环中添加如下代码:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_F1: # F1 = New Game
points = 0
lives = 5
picx = 0
picy = 0
speedx = 5
speedy = 5
查找哪个键用什么表示:pygame.key — pygame v2.5.0 documentation
我们想要在笑脸回弹的时候增加笑脸的速度:
if picx <= 0 or picx + pic.get_width() >= screenw:
speedx = -speedx * 1.1
if picy <= 0:
speedy = -speedy + 1
每次玩家都掉一条性命的时候,我们将重新设置速度:
if picy >= screenh-pich:
lives -= 1
speedx = 5
speedy = -5
随着挡板不断地挡住笑脸,speedy的值变得越来越大,假如我们不去挡笑脸并且当前帧笑脸的y坐标是screenh-pich-1,那么下一帧笑脸的y坐标可能是screenh,那么再下一帧就是screenh-5,那么笑脸(pich=100)并不能都在屏幕之上,而且又要减少生命,所以生命立即减少到0,所以在玩家丢掉一条生命的时候,我们设置:
picy = screenh-pich+1
# SmileyBounce2.py
import pygame # Setup
pygame.init()
screenw=800
screenh=600
screen = pygame.display.set_mode([screenw,screenh])
picw = 100
pich = 100
keep_going = True
pic = pygame.image.load("CrazySmile.bmp")
colorkey = pic.get_at((0,0))
pic.set_colorkey(colorkey)
picx = 0
picy = 0
BLACK = (0,0,0)
timer = pygame.time.Clock()
speedx = 5
speedy = 5
WHITE = (255,255,255) #挡板的颜色
paddlew = 200 #宽度
paddleh = 25 #高度
paddlex = 300 #起始x坐标
paddley = 550 #起始y坐标
points = 0
lives = 5
font = pygame.font.SysFont("Times",24)
BLUE = (0,0,255) #文本的背景色
while keep_going: # Game loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_F1: # F1 = New Game
points = 0
lives = 5
picx = 0
picy = 0
speedx = 5
speedy = 5
picx += speedx
picy += speedy
if picx <= 0 or picx + pic.get_width() >= screenw:
speedx = -speedx * 1.1
if picy <= 0:
speedy = -speedy + 100
if picy >= screenh-pich:
lives -= 1
speedx = 5
speedy = -5
picy = screenh-pich+1
screen.fill(BLACK)
screen.blit(pic, (picx, picy))
paddlex = pygame.mouse.get_pos()[0]
paddlex -= paddlew/2
pygame.draw.rect(screen, WHITE, (paddlex, paddley, paddlew, paddleh))
# Check for paddle bounce
if picy + pich >= paddley and picy + pich <= paddley + paddleh \
and speedy > 0:
if picx + picw / 2 >= paddlex and picx + picw / 2 <= paddlex + \
paddlew:
points += 1
speedy = -speedy
# Draw text on screen
draw_string = "Lives: " + str(lives) + " Points: " + str(points)
# Check whether the game is over
if lives < 1:
speedx = speedy = 0
draw_string = "Game Over. Your score was: " + str(points)
draw_string += ". Press F1 to play again. "
text = font.render(draw_string, True, WHITE, BLUE)
text_rect = text.get_rect()
text_rect.centerx = screen.get_rect().centerx
text_rect.y = 10
screen.blit(text, text_rect)
pygame.display.update()
timer.tick(60)
pygame.quit() # Exit
以SmileyPop1.0版为基础
在程序的设置部分,初始化混合器,创建声音对象:
pygame.mixer.init()
pop = pygame.mixer.Sound("pop.wav")
如果有笑脸被点中,发出声音:
if len(clicked_smileys) > 0:
pop.play()
设置存储创建的笑脸数量和被击中的笑脸数量的变量:
WHITE = (255,255,255)
font = pygame.font.SysFont("Arial", 24)
count_smileys = 0
count_popped = 0
计算创建的笑脸数:
if mousedown:
speedx = random.randint(-5, 5)
speedy = random.randint(-5, 5)
newSmiley = Smiley(pygame.mouse.get_pos(), speedx, speedy)
sprite_list.add(newSmiley)
count_smileys += 1
被点击的笑脸数:
if len(clicked_smileys) > 0:
pop.play()
count_popped += len(clicked_smileys)
被点破笑脸所占百分比:
round(count_popped/count_smileys*100, 1)
显示玩家进度等:
draw_string = "Bubbles created: " + str(count_smileys)
draw_string += " - Bubbles popped: " + str(count_popped)
if (count_smileys > 0):
draw_string += " - Percent: "
draw_string += str(round(count_popped/count_smileys*100, 1))
draw_string += "%"
text = font.render(draw_string, True, WHITE)
text_rect = text.get_rect()
text_rect.centerx = screen.get_rect().centerx
text_rect.y = 10
screen.blit (text, text_rect)
# SmileyPop.py
import pygame
import random
BLACK = (0,0,0)
WHITE = (255,255,255)
pygame.init()
screen = pygame.display.set_mode([800,600])
pygame.display.set_caption("Pop a Smiley")
mousedown = False
keep_going = True
clock = pygame.time.Clock()
pic = pygame.image.load("CrazySmile.bmp")
colorkey = pic.get_at((0,0))
pic.set_colorkey(colorkey)
sprite_list = pygame.sprite.Group()
pygame.mixer.init()
pop = pygame.mixer.Sound("pop.wav")
font = pygame.font.SysFont("Arial", 24)
count_smileys = 0
count_popped = 0
class Smiley(pygame.sprite.Sprite):
pos = (0,0)
xvel = 1
yvel = 1
scale = 100
def __init__(self, pos, xvel, yvel):
pygame.sprite.Sprite.__init__(self)
self.image = pic
self.scale = random.randrange(10,100)
self.image = pygame.transform.scale(self.image, (self.scale,self.scale))
self.rect = self.image.get_rect()
self.pos = pos
self.rect.x = pos[0] - self.scale/2
self.rect.y = pos[1] - self.scale/2
self.xvel = xvel
self.yvel = yvel
def update(self):
self.rect.x += self.xvel
self.rect.y += self.yvel
if self.rect.x <= 0 or self.rect.x > screen.get_width() - self.scale:
self.xvel = -self.xvel
if self.rect.y <= 0 or self.rect.y > screen.get_height() - self.scale:
self.yvel = -self.yvel
while keep_going:
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
if event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed()[0]: # Regular left mouse button, draw
mousedown = True
elif pygame.mouse.get_pressed()[2]: # Right mouse button, pop
pos = pygame.mouse.get_pos()
clicked_smileys = [s for s in sprite_list if s.rect.collidepoint(pos)]
sprite_list.remove(clicked_smileys)
if len(clicked_smileys) > 0:
pop.play()
count_popped += len(clicked_smileys)
if event.type == pygame.MOUSEBUTTONUP:
mousedown = False
screen.fill(BLACK)
sprite_list.update()
sprite_list.draw(screen)
clock.tick(60)
draw_string = "Bubbles created: " + str(count_smileys)
draw_string += " - Bubbles popped: " + str(count_popped)
if (count_smileys > 0):
draw_string += " - Percent: "
draw_string += str(round(count_popped/count_smileys*100, 1))
draw_string += "%"
text = font.render(draw_string, True, WHITE)
text_rect = text.get_rect()
text_rect.centerx = screen.get_rect().centerx
text_rect.y = 10
screen.blit (text, text_rect)
pygame.display.update()
if mousedown:
speedx = random.randint(-5, 5)
speedy = random.randint(-5, 5)
newSmiley = Smiley(pygame.mouse.get_pos(),speedx,speedy)
sprite_list.add(newSmiley)
count_smileys += 1
pygame.quit()