用户可以有很多种方式与游戏交互,这一章详细讲解多种输入设备。除了从设备获取信息,我们也要探索如何将用户所做的事情翻译成游戏中有意义的事件。容易交互对任何游戏都至关重要,不管你有多好的外观和声音。
控制游戏
玩过游戏的都知道鼠标和键盘是游戏不可或缺的输入设备。键盘可以控制有限的方向和诸多的命令操作,而鼠标更是提供了全方位的方向和位置操作。不过这两个设备并不是为游戏而生,专业的游戏手柄给玩家提供了更好的操作感,加上力反馈等技术,应该说游戏设备越来越丰富,玩家们也是越来越幸福。
理解键盘控制
现在大多数键盘都是qwerty键盘。我们可以使用pygame.key模块检测所有的键。
检测键盘按下
在Pygame里面有两种方式检测键盘按下。一种方式是处理KEYDOWN事件和KEYUP事件,分别对应键盘按下和键盘松开。当我们使用键盘输入代表移动时,我们只需知道键是否被按下,这种情况可以直接使用pygame.key模块。
每一个键盘上的键都有一个常量键值关联它。每一个常量以**K_**开头,比如字母是K_a到K_z,数字是K_0到K_9,其它的如K_F1,K_LEFT,K_RETURN等。完整列表参考(http://www.pygame.org/docs/ref/key.html)。没有大写字母对应的键值,因为大写字母是小写字母和其它键的组合。
我们可以使用pygame.key.get_pressed函数检查一个键是否被按下。它返回一个布尔值列表,每一个布尔值对应一个键值常量。要查询某一个键,使用其键值常量作为列表下标。比如查看空格是否被按下:
1
2
3
4
|
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_SPACE]:
# Space key has been pressed
fire()
|
注意 由于硬件的限制,有些键组合不能被检测。原因请看http://www.sjbaker.org/steve/omniv/keyboards_are_evil.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import pygame
from pygame.locals import *
from sys import exit
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
font = pygame.font.SysFont('arial', 32)
font_height = font.get_linesize()
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
screen.fill((255, 255, 255))
pressed_key_text = []
pressed_keys = pygame.key.get_pressed()
y = font_height
for key_constant, pressed in enumerate(pressed_keys):
if pressed:
key_name = pygame.key.name(key_constant)
text_surface = font.render(key_name + ' pressed', True, (0, 0, 0))
screen.blit(text_surface, (8, y))
y += font_height
pygame.display.update()
|
让我们更详细地复习pygame.key:
- pygame.key.get_focused - Pygame窗口只有获得焦点后才会接受键事件。如果窗口获得焦点,get_focused函数返回真,否则返回假。全屏模式,总是返回真。
- pygame.key.get_pressed - 返回一个包含每一个键的布尔值列表。如果值为True,则对应键被按下。
- pygame.key.get_mods - 返回一个值,指示哪一个修饰键被按下。要检查哪一个修饰键被按下,可以对KMOD_常量使用位与操作。比如检查左shift键被按下,pygame.key.get_mods() & KMOD_LSHIFT。
- pygame.key.set_mods - 可以设置修饰键模拟组合键按下的效果。要设置一个或多个修饰键,对KMOD_常量使用位或操作。比如设置shift和alt键,可以使用pygame.key.set_mods(KMOD_SHIFT | KMOD_ALT)。
- pygame.key.set_repeat - 可以使用set_repeat函数重复KEY_DOWN事件,它接受一个初始延迟时间和重复事件延迟时间,单位为毫秒。set_repeat不带参数禁用重复按键事件。
- pygame.key.name - 接受一个KEY_常量返回一个描述该键的字符串。
使用键盘控制方向
四个基本方向向量:
方向 |
向量 |
Left |
(-1.0, 0.0) |
Right |
(1.0, 0.0) |
Up |
(0.0, –1.0) |
Down |
(0.0, 1.0) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
background_image_filename = 'sushiplate.jpg'
sprite_iamge_filename = 'fugu.png'
import pygame
from pygame.locals import *
from sys import exit
from gameobjects.vector2 import Vector2
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
background = pygame.image.load(background_image_filename).convert()
sprite = pygame.image.load(sprite_iamge_filename).convert_alpha()
clock = pygame.time.Clock()
sprite_pos = Vector2(200, 150)
sprite_speed = 300.
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
pressed_keys = pygame.key.get_pressed()
key_direction = Vector2(0, 0)
if pressed_keys[K_LEFT]:
key_direction.x = -1
elif pressed_keys[K_RIGHT]:
key_direction.x = +1
if pressed_keys[K_UP]:
key_direction.y = -1
elif pressed_keys[K_DOWN]:
key_direction.y = +1
key_direction.normalize()
screen.blit(background, (0, 0))
screen.blit(sprite, sprite_pos)
time_passed = clock.tick(30)
time_passed_seconds = time_passed / 1000.0
sprite_pos += key_direction * sprite_speed * time_passed_seconds
pygame.display.update()
|
键盘旋转移动
往八个方向移动有点像人造的,现实中很少看到这样移动的,大多数东西都能自由转向。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
background_image_filename = 'sushiplate.jpg'
sprite_image_filename = 'fugu.png'
import pygame
from pygame.locals import *
from sys import exit
from gameobjects.vector2 import Vector2
from math import *
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
background = pygame.image.load(background_image_filename).convert()
sprite = pygame.image.load(sprite_image_filename).convert_alpha()
clock = pygame.time.Clock()
sprite_pos = Vector2(200, 150)
sprite_speed = 300.
sprite_rotation = 0.
sprite_rotation_speed = 360. # Degrees per second
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
pressed_keys = pygame.key.get_pressed()
rotation_direction = 0.
movement_direction = 0.
if pressed_keys[K_LEFT]:
rotation_direction = +1.0
if pressed_keys[K_RIGHT]:
rotation_direction = -1.0
if pressed_keys[K_UP]:
movement_direction = +1.0
if pressed_keys[K_DOWN]:
movement_direction = -1.0
screen.blit(background, (0, 0))
rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation)
w, h = rotated_sprite.get_size()
sprite_draw_pos = Vector2(sprite_pos.x - w / 2, sprite_pos.y - h / 2)
screen.blit(rotated_sprite, sprite_draw_pos)
time_passed = clock.tick()
time_passed_seconds = time_passed / 1000.0
sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds
heading_x = sin(sprite_rotation * pi / 180.0)
heading_y = cos(sprite_rotation * pi / 180.0)
heading = Vector2(heading_x, heading_y)
heading *= movement_direction
sprite_pos += heading * sprite_speed * time_passed_seconds
pygame.display.update()
|