处理事件
- 用while True:处理事件
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif event.type == MOUSEMOTION:
pass
elif event.type == MOUSEBUTTONUP:
pass
键盘事件
-
响应键盘按键的最佳方式其实是:设置标志变量,让程序进行后续响应。
-
对于多种事件处理,用事件轮询或者查看key.name属性
-
如果需要按键连按,必须设置:
pygame.key.set_repeat(x_ms)
鼠标事件
import pygame
from pygame.locals import *
"""对于MOUSEMOTION事件,属性是event.pos,event.rel和event.button"""
for event in pygame.event.get():
if event.type == MOUSEMOTION:
mouse_x, mouse_y = event.pos
move_x, mov_y = event.rel
"""对于MOUSEBUTTONDOWN和UP事件,属性是event.pos和event.button"""
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
mouse_down = event.button
mouse_down_x, mouse_down_y = event.pos
elif event.type == MOUSEBUTTONUP:
mouse_up = event.button
mouse_up_x, mouse_up_y = event.pos
除了查询事件来获得鼠标按键信息外,还可以用以下方法:
x, y = pygame.mouse.get_pos() # 获得鼠标坐标位置
b1, b2, b3 = pygame.mouse.get_pressed() # 读取鼠标按钮数组
r1, r2 = pygame.mouse.get_rel() # 获得鼠标相对位置
设备轮询
pygame.key.get_pressed()返回一个全部键位的布尔值列表。直接通过键位对应的常量进行索引即可获得对应状态位
keys = pygame.key.get_pressed()
if keys[k_ESCAPE]:
sys.exit()
- 实际上,所有的常量都有对应的ASCII码值。可以通过chr()函数获得一个ASCII编码数字的字符串表示。
打字速度小游戏
import sys, random, time, pygame
from pygame.locals import *
def print_text(font, x, y, text, color = (255,255,255)):
imgText = font.render(text, True, color)
screen.blit(imgText, (x, y))
pygame.init()
screen = pygame.display.set_mode((600, 500))
pygame.display.set_caption("Keyboard Demo")
font1 = pygame.font.Font(None, 24)
font2 = pygame.font.Font(None, 200)
white = 255, 255, 255
yellow = 255, 255, 0
green = 0,255,0
key_flag = False
correct_answer = 97
seconds = 10
score = 0
clock_start = 0
game_over = True
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif event.type == KEYDOWN:
key_flag = True
elif event.type == KEYUP:
key_flag = False
keys = pygame.key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
if keys[K_RETURN]:
if game_over:
game_over = False
score = 0
seconds = 11
clock_start = time.clock() # 注意这里,一开始缩进写错了。导致无法倒计时。
current = time.clock() - clock_start
speed = score * 6
if seconds - current < 0:
game_over = True
elif current <= 10:
if keys[correct_answer]:
correct_answer = random.randint(97, 122)
score += 1
# clear the screen
screen.fill((0, 100, 0))
print_text(font1, 0, 0, "Let's see how fast you can type!")
print_text(font1, 0, 20, "Try to keep up for 10 seconds...")
if key_flag:
print_text(font1, 500, 0, "<key>")
if not game_over:
print_text(font1, 0, 80, "Time: " + str(int(seconds - current)))
print_text(font1, 0, 100, "Speed: " + str(speed) + " letters/min")
if game_over:
print_text(font1, 0, 160, "Press Enter to start...")
print_text(font2, 0, 240, chr(correct_answer - 32), yellow)
# update the display
pygame.display.update()
鼠标游戏:
import pygame,sys
from pygame.locals import *
def print_text(font, x, y, text, color=(255,255,255)):
imgText = font.render(text, True, color)
screen.blit(imgText, (x,y))
pygame.init()
screen = pygame.display.set_mode((600,500))
pygame.display.set_caption("Mouse Demo")
font1 = pygame.font.Font(None, 24)
white = 255,255,255
mouse_x = mouse_y = 0
move_x = move_y = 0
mouse_down = mouse_up = 0
mouse_down_x = mouse_down_y = 0
mouse_up_x = mouse_up_y = 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif event.type == MOUSEMOTION:
mouse_x, mouse_y = event.pos
move_x,move_y = event.rel
elif event.type == MOUSEBUTTONDOWN:
mouse_down = event.button
mouse_down_x, mouse_down_y = event.pos
elif event.type == MOUSEBUTTONUP:
mouse_up = event.button
mouse_up_x, mouse_down_y = event.pos
keys = pygame.key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
screen.fill((0, 100, 0))
print_text(font1, 0, 0, "Mouse Events")
print_text(font1, 0, 20, "Mouse position: " + str(mouse_x) +
"," + str(mouse_y))
print_text(font1, 0, 40, "Mouse relative: " + str(move_x) +
"," + str(move_y))
print_text(font1, 0, 60, "Mouse button down: " + str(mouse_down) +
" at " + str(mouse_down_x) + "," + str(mouse_down_y))
print_text(font1, 0, 80, "Mouse button up: " + str(mouse_up) +
" at " + str(mouse_up_x) + "," + str(mouse_up_y))
print_text(font1, 0, 160, "Mouse Polling")
x, y = pygame.mouse.get_pos()
print_text(font1, 0, 180, "Mouse position: " + str(x) + "," + str(y))
b1, b2, b3 = pygame.mouse.get_pressed()
print_text(font1, 0, 200, "Mouse buttons: " +
str(b1) + "," + str(b2) + "," + str(b3))
r1, r2 = pygame.mouse.get_rel()
print_text(font1, 0, 220, "Mouse rel :"+str(r1)+","+str(r2))
pygame.display.update()
效果:
接炸弹游戏
思路:
- 炸弹就是个圆形,每次y坐标初始值都在屏幕外面,x是随机的范围在(0,500)中间。
- 在循环中,如果game_over标志为假,那么让炸弹y坐标增加一个值,使其下落。
- 判断逻辑:
如果炸弹没有接住,也就是它的y坐标超过屏宽最大值,那么将炸弹的x,y坐标重置到屏幕上面。同时让生命值减少,如果到零则让游戏结束;
如果炸弹接住,也就是判断它的y是否在屏幕底部而且x是否在挡板宽度以内。 - 更新挡板位置,如果越界则让它的坐标限定在某个区域。
- 最后就是绘制更新整个屏幕。(一般来说都是先判定逻辑,再更新屏幕)
import sys,random,time,pygame
from pygame.locals import *
def print_text(font, x, y, text, color=(255, 255, 255)):
imgText = font.render(text, True, color)
screen.blit(imgText, (x, y))
# main program begins
pygame.init()
screen = pygame.display.set_mode((600, 500))
pygame.display.set_caption("Bomb Catching Game")
font1 = pygame.font.Font(None, 24)
white = 255, 255, 255
red = 220, 50, 50
yellow = 230, 230, 50
black = 0, 0, 0
lives = 3
score = 0
clock_start = 0
game_over = True
mouse_x = mouse_y = 0
pos_x = 300
pos_y = 460
bomb_x = random.randint(0, 500)
bomb_y = -50
vel_y = 0.7
# repeating loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif event.type == MOUSEMOTION:
mouse_x, mouse_y = event.pos
move_x, move_y = event.rel
elif event.type == MOUSEBUTTONUP:
if game_over:
game_over = False
lives = 3
score = 0
keys = pygame.key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
# 清屏
screen.fill((0, 0, 100))
if game_over:
print_text(font1, 220, 250, "<CLICK TO PLAY>")
pygame.mouse.set_visible(True)
else:
pygame.mouse.set_visible(False)
bomb_y += vel_y
# 是否没接住炸弹
if bomb_y > 500:
bomb_x = random.randint(0,500)
bomb_y = -50
lives -= 1
if lives == 0:
game_over = True
# 是否已经接住炸弹
elif bomb_y > pos_y:
if bomb_x > pos_x and bomb_x < pos_x + 120:
# 炸弹是否在挡板的宽度以内,120是挡板的宽
score += 10
bomb_x = random.randint(0, 500)
bomb_y = -50
# 绘制炸弹
pygame.draw.circle(screen, black, (bomb_x - 4, int(bomb_y) - 4), 30, 0)
pygame.draw.circle(screen, yellow, (bomb_x, int(bomb_y)), 30, 0)
# 更新挡板位置
pos_x = mouse_x
if pos_x < 0:
pos_x = 0
elif pos_x > 500:
pos_x = 500
#绘制挡板
pygame.draw.rect(screen, black, (pos_x-4,pos_y-4,120,40), 0)
pygame.draw.rect(screen, red, (pos_x, pos_y, 120, 40), 0)
# print # of lives
print_text(font1, 0, 0, "LIVES: " + str(lives))
# print score
print_text(font1, 500, 0, "SCORE: " + str(score))
pygame.display.update()
效果:个人想法:
- 加一个等级系统,当分数达到不同的分值时,适当加大难度,炸弹下落速度会越来越快!
- 可以加上打字爆破:在炸弹上绘制字母,并存到一个变量中。轮询键盘事件,如果对应标志位是1,让炸弹GG
课后挑战:
- 炸弹碰撞时候,显示“BOOM!”并且使用延时。
- 炸弹下落时候加上一个不停变换颜色的拖尾。
- 加入一个水平速度,让炸弹以一定的角度进行下落。
注:pro版本加入了等级机制,分数每增加50,上升一个难度,速度增加。炸弹有角度下落并且有碰撞检测。
import sys,random,time,pygame
from pygame.locals import *
def print_text(font, x, y, text, color=(255, 255, 255)):
imgText = font.render(text, True, color)
screen.blit(imgText, (x, y))
# main program begins
pygame.init()
screen = pygame.display.set_mode((600, 500))
pygame.display.set_caption("Bomb Catching Game")
font1 = pygame.font.Font(None, 24)
font2 = pygame.font.Font(None, 30)
white = 255, 255, 255
red = 220, 50, 50
yellow = 230, 230, 50
black = 0, 0, 0
lives = 6
score = 0
clock_start = 0
game_over = True
mouse_x = mouse_y = 0
pos_x = 300
pos_y = 460
# 爆炸字样位置坐标
boom_x = -50
boom_y = -50
boom_flag = False
bomb_x = random.randint(0, 500)
bomb_y = -50
vel_y = 0.5
vel_x = 0.2
level = 0 # 游戏难度
a = 0.05 # 速度递增系数
k = 0
# repeating loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
elif event.type == MOUSEMOTION:
mouse_x, mouse_y = event.pos
move_x, move_y = event.rel
elif event.type == MOUSEBUTTONUP:
if game_over:
game_over = False
lives = 3
score = 0
level = 0
keys = pygame.key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
# 清屏
screen.fill((0, 0, 100))
if game_over:
print_text(font1, 220, 250, "<CLICK TO PLAY>")
pygame.mouse.set_visible(True)
else:
pygame.mouse.set_visible(False)
bomb_y += (vel_y + level*a)
bomb_x += (vel_x + level*a)
if bomb_x>500 or bomb_x<0:
vel_x = -(vel_x + level*a)
# print(boom_x)
# 是否没接住炸弹
if bomb_y > 500:
bomb_x = random.randint(0,500)
bomb_y = -50
lives -= 1
if lives == 0:
game_over = True
# 是否已经接住炸弹
elif bomb_y > pos_y:
if bomb_x > pos_x and bomb_x < pos_x + 120:
# 炸弹是否在挡板的宽度以内,120是挡板的宽
boom_x = bomb_x
boom_y = bomb_y
score += 10
bomb_x = random.randint(0, 500)
bomb_y = -50
if boom_flag:
clock_start = time.clock()
current = time.clock() - clock_start
# 等级机制
if score >= 50*k and score <= 50*(k+1):
level = k
else:
k += 1
# 绘制炸弹
pygame.draw.circle(screen, black, (int(bomb_x) - 4, int(bomb_y) - 4), 30, 0)
pygame.draw.circle(screen, yellow, (int(bomb_x), int(bomb_y)), 30, 0)
# 更新挡板位置
pos_x = mouse_x
if pos_x < 0:
pos_x = 0
elif pos_x > 500:
pos_x = 500
# 绘制挡板
pygame.draw.rect(screen, black, (pos_x-4,pos_y-4,120,40), 0)
pygame.draw.rect(screen, red, (pos_x, pos_y, 120, 40), 0)
# 绘制爆炸字样
# print(current)
if current < 0.5:
print_text(font2, boom_x-2, boom_y-2, "BOOM!",(255,0,0))
print_text(font2, boom_x, boom_y, "BOOM!", (255,255, 0))
else:
boom_flag = True
# print # of lives
print_text(font1, 0, 0, "LIVES: " + str(lives))
# print score
print_text(font1, 500, 0, "SCORE: " + str(score))
print_text(font1, 250, 0, "LEVEL: " + str(level))
pygame.display.update()
效果:
**后记:**可以通过pyinstaller把游戏打包成exe文件,让大家一起玩吧!