用Python和Pygame写游戏-从入门到精通(10)
有时候无聊在网上翻翻小说看看,绝大多数那叫一个无聊。比如说修炼的境界分几种,都有个名字,然后每种境界再有几层,这不就是变相的打怪练级么?文笔也不咋样,故事情节的驾驭能力更是让我瞠目结舌,想到这些类小说盛行,不觉感到悲从中来。感觉看这些小说,就想在看别人打游戏一般,崩溃到极点。游戏和小说的最大区别,除了声色以外,最不同的就是玩家可以沉入进去,通过自己的双手来参与;而好的游戏,更是可以通过玩家的选择,完全掌控游戏的发展,这是传统的故事媒介无法做到的事情。

很自然的,我们讲述了游戏中视觉上的种种,现在开始就要学习一下游戏中的用户输入。同样我们也要探讨一下如何让用户的输入更为顺畅,换个词就是,如果让游戏的手感更好一些。
游戏设备
玩过游戏的都知道鼠标和键盘是游戏的不可或缺的输入设备。键盘可以控制有限的方向和诸多的命令操作,而鼠标更是提供了全方位的方向和位置操作。不过这两个设备并不是为游戏而生,专业的游戏手柄给玩家提供了更好的操作感,加上力反馈等技术,应该说游戏设备越来越丰富,玩家们也是越来越幸福。
键盘设备
我们先从最广泛的键盘开始讲起。
现在使用的键盘,基本都是QWERTY键盘(看看字幕键盘排布的左上就知道了),尽管这个世界上还有其他种类的键盘,比如AZERTY啥的,反正我是没见过,如果你能在写游戏的时候考虑到这些特殊用户自然是最好,个人感觉是问题不大吧。
以前第二部分也稍微使用了一下键盘,那时候是用了pygame.event.get()获取所有的事件,当event.type == KEYDOWN的时候,在判断event.key的种类,而各个种类也使用K_a,K_b……等判断。这里再介绍一个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
(
)
pressed_keys
=
pygame
.
key
.
get_pressed
(
)
|
当然key模块下还有很多函数:
- key.get_focused —— 返回当前的pygame窗口是否激活
- key.get_pressed —— 刚刚解释过了
- key.get_mods —— 按下的组合键(Alt, Ctrl, Shift)
- key.set_mods —— 你也可以模拟按下组合键的效果(KMOD_ALT, KMOD_CTRL, KMOD_SHIFT)
- key.set_repeat —— 无参数调用设置pygame不产生重复按键事件,二参数(delay, interval)调用设置重复事件发生的时间
- key.name —— 接受键值返回键名
注:感谢xumaomao朋友的倾情指正!
使用键盘控制方向
有了上一章向量的基础,只需一幅图就能明白键盘如何控制方向:

很多游戏也使用ASDW当做方向键来移动,我们来看一个实际的例子:
|
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
|
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
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.
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
63
64
65
66
67
68
69
70
71
72
|
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.
# 每秒转动的角度数(转速)
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.
if
pressed_keys
[
K_RIGHT
]
:
rotation_direction
=
-
1.
# 前进、后退
if
pressed_keys
[
K_UP
]
:
movement_direction
=
+
1.
if
pressed_keys
[
K_DOWN
]
:
movement_direction
=
-
1.
screen
.
blit
(
background
,
(
0
,
0
)
)
# 获得一条转向后的鱼
rotated_sprite
=
pygame
.
transform
.
rotate
(
sprite
,
sprite_rotation
)
# 转向后,图片的长宽会变化,因为图片永远是矩形,为了放得下一个转向后的矩形,外接的矩形势必会比较大
w
,
h
=
rotated_sprite
.
get_size
(
)
# 获得绘制图片的左上角(感谢pltc325网友的指正)
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
# 获得前进(x方向和y方向),这两个需要一点点三角的知识
heading_x
=
sin
(
sprite_rotation
*
pi
/
180.
)
heading_y
=
cos
(
sprite_rotation
*
pi
/
180.
)
# 转换为单位速度向量
heading
=
Vector2
(
heading_x
,
heading_y
)
# 转换为速度
heading
*=
movement_direction
sprite_pos
+
=
heading
*
sprite_speed
*
time_passed_seconds
pygame
.
display
.
update
(
)
|
我们通过上下控制前进/后退,而左右控制转向。我们通过pygame.transform.rotate()来获得了转向后的图片,具体参数可以参考代码。各条语句的作用也可以参考注释。
下次讲解使用鼠标控制游戏。
603

被折叠的 条评论
为什么被折叠?



