模仿对象: Rush Hero by Ketchapp
规则:天空中会随机掉落物块,玩家需要控制“英雄”左右移动来躲避这些物块。每个物块砸中地面时玩家都会得1分。
1. 代码开始
import pygame, sys, random, time
class GameObj(pygame.sprite.Sprite):
def __init__(self, size, location, color):
pygame.sprite.Sprite.__init__(self)
self.size = size
image_surface = pygame.surface.Surface([self.size, self.size])
image_surface.fill(color)
self.image = image_surface.convert()
self.rect = self.image.get_rect()
self.rect.left = location[0]
self.rect.top = location[1]
def display(self):
screen.blit(self.image, self.rect)
screenW = 800
screenH = 600
pygame.init()
screen = pygame.display.set_mode([screenW, screenH])
screen.fill([0,0,50])
pygame.display.flip()
while True:
time.sleep(0.02)
screen.fill([0,0,50])
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.display.flip()
这里创建了一个长800高600的窗口,并且用[0, 0, 50]
这样一个深蓝色来填充背景。帧数设定为50。
此处还定义了GameObj
精灵类。出于简化程序的目的,此游戏中的每一个gameobject都是正方形的。display
方法用于渲染。
2. Player
类
class Player(GameObj):
def __init__(self):
global screenW
global screenH
size = 40
GameObj.__init__(self, size, [0, screenH - size], (255,0,0))
Player
类继承了GameObj
类,将其位置设定在整个窗口的左下角。边长为40,可以根据个人喜好来改动这个属性。
player = Player()
while True:
time.sleep(0.02) time.sleep(0.02)
screen.fill([0,0,50])
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEMOTION:
player.rect.centerx = event.pos[0]
screen.fill([0,0,50])
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEMOTION:
player.rect.centerx = event.pos[0]
在初始化中创建player实例并在事件检测中加入对光标的检测,player的水平位置和光标的水平位置一致。
3. Ball
类
class Ball(GameObj):
def __init__(self):
global screenW
global screenH
size = random.randint(100, 150)
location = [random.choice([-size, screenW]), screenH - 400]
GameObj.__init__(self, size, location, (255,255,255))
self.direction = -1
if location[0] < 0:
self.direction = 1
self.speed = [random.randint(1,3) * self.direction, 0]
self.g = 0.1
此处我们给球(其实这里是个方块)一个随机的边长,初始位置随机给定在窗口的左侧或者右侧,高度则是一个固定值。
接下来我们根据球的水平位置来判读它是要向左移动还是向右移动。如果球在屏幕左侧,则向右移动,反之亦然。
方向是用正负1
来表示,这个主要是用于下面一行对其移动速度的定义。
球的重力加速度设为0.1
def gravity(self):
global screenH
global score
global score_text
self.speed[1] += self.g
self.rect.left += self.speed[0]
self.rect.top += self.speed[1]
if self.rect.bottom >= screenH:
self.speed[1] = -5
这里使用物理公式模拟平抛运动,之所以说是平抛是因为球本身是有水平速度的。
当球碰到窗口底部时会反弹,这里我并没有直接将垂直速度取反,而是直接赋值-5
,这一来是为了调整球的反弹高度,进而调整游戏难度,二来是为了确保球不会因为计算问题而越蹦越高。
4. 初始化
player = Player()
balls = pygame.sprite.Group()
pygame.time.set_timer(pygame.USEREVENT, 1500)
创建player
实例和balls
精灵组。并定义一个定时器用于生成球。
5. 生成球
#每隔1.5妙生成一个球并添加至精灵组
elif event.type == pygame.USEREVENT:
newBall = Ball()
balls.add(newBall)
将上述代码加入事件检测中
6. 球的移动,所有GameObj
的渲染
for i in balls:
i.gravity()
i.display()
if i.out():
balls.remove(i)
player.display()
pygame.display.flip()
这里出现了一个out
方法,是用于判断球是否是已经离开了窗口,如果已经离开那么就删除掉这个球。
def out(self):
global screenW
if self.rect.right <= 0 or self.rect.left >= screenW:
return True
return False
#这个是添加在Ball类中的方法
7. 碰撞检测
检测player
是否和某一个球相撞
if pygame.sprite.spritecollide(player, balls, False):
init()
init()
是用于暂停整个游戏的,当玩家按下R
时,整个游戏初始化并重新开始。
def init():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.__init__()
for i in balls:
balls.remove(i)
8. 完整代码(加入了得分)
import pygame, sys, random, time
class GameObj(pygame.sprite.Sprite):
def __init__(self, size, location, color):
pygame.sprite.Sprite.__init__(self)
self.size = size
image_surface = pygame.surface.Surface([self.size, self.size])
image_surface.fill(color)
self.image = image_surface.convert()
self.rect = self.image.get_rect()
self.rect.left = location[0]
self.rect.top = location[1]
def display(self):
screen.blit(self.image, self.rect)
class Player(GameObj):
def __init__(self):
global screenW
global screenH
size = 40
GameObj.__init__(self, size, [0, screenH - size], (255,0,0))
class Ball(GameObj):
def __init__(self):
global screenW
global screenH
size = random.randint(100, 150)
location = [random.choice([-size, screenW]), screenH - 400]
GameObj.__init__(self, size, location, (255,255,255))
self.direction = -1
if location[0] < 0:
self.direction = 1
self.speed = [random.randint(1,3) * self.direction, 0]
self.g = 0.1
def gravity(self):
global screenH
global score
global score_text
self.speed[1] += self.g
self.rect.left += self.speed[0]
self.rect.top += self.speed[1]
if self.rect.bottom >= screenH:
self.speed[1] = -5
score += 1
score_text = font.render(str(score), 1, (255,255,255))
def out(self):
global screenW
if self.rect.right <= 0 or self.rect.left >= screenW:
return True
return False
def init():
global score
global score_text
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.__init__()
for i in balls:
balls.remove(i)
score = 0
score_text = font.render(str(score), 1, (255,255,255))
return 0
screenW = 800
screenH = 600
pygame.init()
screen = pygame.display.set_mode([screenW, screenH])
screen.fill([0,0,50])
player = Player()
balls = pygame.sprite.Group()
score = 0
font = pygame.font.Font(None, 50)
score_text = font.render(str(score), 1, (255,255,255))
pygame.time.set_timer(pygame.USEREVENT, 1500)
pygame.display.flip()
while True:
time.sleep(0.02)
screen.fill([0,0,50])
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEMOTION:
player.rect.centerx = event.pos[0]
elif event.type == pygame.USEREVENT:
newBall = Ball()
balls.add(newBall)
if pygame.sprite.spritecollide(player, balls, False):
init()
for i in balls:
i.gravity()
i.display()
if i.out():
balls.remove(i)
player.display()
screen.blit(score_text, [10,10])
pygame.display.flip()
效果
9. 后记
可以通过修改一下属性来修改游戏难度:
Player
类
player.size
Ball
类
size = random.randint(X, Y)
Ball.speed #包括gravity方法中的
Ball.g