You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
9.1 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 第17讲 | 如何用鼠标和键盘来操作游戏?
**如果一款游戏不能用鼠标和键盘操作,那我们只能当动画来看。**
所以在一款游戏中鼠标和键盘的操作是必不可少的有时候甚至鼠标和键盘都要同时操作比如FPS游戏比如即时战略等等。鼠标和键盘的操作在Pygame中需要进行实时检测这个上一节我有提到过然后我们就可以对游戏画面进行操作。
我们在Pygame中有两种方式可以检测和编写键盘事件一种是使用**event事件**操作,一种是使用**keypressed函数**来进行键盘的判断操作。
我们先来尝试一下使用事件进行操作的键盘事件。我们在之前的代码中,已经使用事件来判断是不是退出,我们来看如下代码:
```
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
```
在这段代码里面event.type的类型如果是QUIT的话就让pygame退出那么举一反三我们也可以在里面写上如下代码
```
if event.type == KEYDOWN:
if event.key == pygame.K_w:
.....
```
在这里我们判断事件的类型是KEYDOWN也就是键盘按下的事件随后我们再在下面的代码里,判断event所返回键盘key值是pygame.K\_w这个K\_w是pygame里面定义的虚拟键盘的按键代表的是Key值为键盘w的按键所以你只要按下w键就会出现对应的操作。
我们来写下一系列的操作代码,在编写代码之前,我们首先要来定义一下规则。
我们的目的是要让主角的飞机移动起来所谓的飞机的移动我们在前面几篇课程里面都有阐述。如果我们要让飞机在画面上移动起来就需要修正飞机的x轴和y轴。
相应的如果飞机往左侧飞就需要减少飞机的x轴如果飞机往右侧飞就要增加飞机的x轴如果往上面飞就要减少飞机的y轴如果往底下飞就要增加飞机的y轴。我们先理清楚了这些内容之后就可以编写键盘操作代码了。
我们先来修正飞机的x轴和y轴。我们要在游戏的循环之外定义两个变量xx和yy以修正键盘操作后的飞机坐标。
```
xx = 0
yy = 0
```
在定义完了这些内容后,我们再来看看按键的定义。
```
if event.type == KEYDOWN:
if event.key == pygame.K_w:
yy -= 1
if event.key == pygame.K_s:
yy += 1
if event.key == pygame.K_a:
xx -= 1
if event.key == pygame.K_d:
xx += 1
```
首先和普通的游戏一样我们将电脑键盘上的WSAD按键用作上下左右的操作按键所以我们判断了一系列的按键值比如K\_wK\_s等等然后我们看到xx, yy 的一系列操作,然后我们进行飞机的贴图和操作:
```
screen.blit(pln, (100+xx, 300+yy))
```
我们看到基础坐标值是100300。我们经过键盘操作对xx和yy进行位置的修正。到这里为止我们可以看到只要我们按下WSAD中的任意一个按键飞机就会往指定的位置移动。
所以如果你认为到这里按键的内容就结束了那就错了就像我们今天开头所说的Pygame下的键盘类还有另外一种方式可以检测你可以考虑下面的代码。
```
key = pygame.key.get_pressed()
if key[pygame.K_w]:
yy -= 1
if key[pygame.K_s]:
yy += 1
if key[pygame.K_a]:
xx -= 1
if key[pygame.K_d]:
xx +=
```
是的我们看到了pygame.key.get\_pressed(); 函数。这个函数返回一个Key值。和event事件不同的是我们直接可以在每一次循环内进行判断。返回的Key是一个tuple类型在里面存放了各种按键对应的值。如果没有按键所有值都是0如果有按键其中一个值是1。
再来看接下来的代码如果key值的tuple里正好是pygame.K\_w的话那么判断结果就是真我们来将这个内容打印出来看一下。
```
print key
```
我们打印了key并且按下w按键随后我们可以在游戏界面命令行看到如下内容输出
![](https://static001.geekbang.org/resource/image/48/4a/480b8b53350ddb06e6a70e6987c84a4a.jpg)
找到那个1没有那个1就是对应的K\_w值在key\[pygame.K\_w\]判断的时候返回一个1也就是True那么就产生yy-=1的操作。接下来就是类似的代码了我就不再作重复的阐述了。
看到这里或许你就要问了那有很多的游戏都有组合键比如我按下Ctrl键再按下w键就会出现对应的操作这又该怎么实现呢
你思考一下,我们是不是可以把两个按键写在同一个判断语句下?是的,你没有猜错,确实可以这么写,这就是**组合键**的效果。
```
if key[pygame.K_w] and key[pygame.K_LCTRL]:
yy -= 2
```
在这里我们看到只要同时按下了w和左侧CTRLLCTRL的意思是Left Control就是左侧Control的意思那么yy的坐标值就减去2我们操作一下就知道结果了。所以组合键可以在同一个判断里面使用and连接起来。
然后,事情并没有到这里结束,请你将这些代码写在自己的电脑里,并做一下实验,第一种方式是事件判断,第二种方式是按键判断。这两种方式的区别是什么?
看到区别了吗?如果你按照我说的去做,你会发现,第一种方式,只要按下一个键,飞机就会往指定方向移动一格,然而如果你一直按着这个键,飞机是不会移动的,要等你再按下键盘才行。而第二种方式,只要你一直按着这个键,飞机就会一直不停往指定位置移动。
问题究竟出在哪里呢?
问题在于事件判断首先判断了KEYDOWN当你按下按键的时候KEYDOWN已经被判断了随后我们再进入event的按键类型的判断但是如果你这时候一直按着键盘KEYDOWN事件并没有被唤起所以一直按着按键并没有起到作用所以你要按下键盘松开再按下一次飞机才会移动。
而第二种方式在循环里面只要键盘按下去就会一直返回一个tuple给key然后在继续做判断所以我们只要一直按着键盘一直会做判断直到按下的键盘是WSAD为止。
接下来,我们要做一下鼠标的操作。鼠标的操作我们在前几次的课程中也进行了介绍,我们再来温习一遍,并且添加一些新的内容进去。
我们今天要把一幅图片贴在鼠标的位置,并且随着鼠标的移动而移动,我们先来看下列代码:
```
mouse = 'mouse.png'
mouse_cursor = pygame.image.load(mouse).convert_alpha()
mouse_scale = pygame.transform.scale(mouse_cursor, (40, 40))
While True:
#获取 x, y 值
x-= mouse_scale.get_width() / 2
y-= mouse_scale.get_height() / 2
screen.blit(mouse_scale, (x, y))
...
```
首先我们要定义的一幅图片名叫 mouse.png随后载入图片并且处理alpha混合这在我们先前的课程中都有过阐述。
随后我们看到了一个叫pygame.transform.scale的函数。这个函数的意思是我们要重新将mouse这个surface进行缩放其中缩放的大小长宽是4040并且返回一个新的 surface。
随后在循环里我们获取到这个surface的中心点也就是计算需要绘制鼠标的xy值我们需要得到图片的长宽并且除以2最后blit开始贴图我们看到的效果是这样的。
![](https://static001.geekbang.org/resource/image/28/a1/2840dec856ac2ed69eb6d3c8956926a1.jpg)
那么我们如果要判断鼠标的按键怎么办呢?我们来温习一下上一次所讲的内容,鼠标的按键,也是类似的判断方式:
```
x, y = pygame.mouse.get_pos()
if pygame.mouse.get_pressed()[0]:
....
```
前面那段代码用到的 xy的值在这里进行代码获取。
我们看到pygame.mouse.get\_pos() 函数获取两个值x和y坐标后面一段代码就是获取鼠标点击的内容其中 get\_pressed函数下标0返回是不是左键点击下标1返回是不是中键点击下标2返回是不是右键点击最后再做出判断。
## 小结
今天的内容基本到这里了,我带你将内容梳理并总结一下。
1. 首先是键盘事件判断这里会出现按一下键盘做一下操作的情况问题出在KEYDOWN事件判断上。但是如果你需要一直按键的判断可以使用get\_pressed函数。
2. 组合键可以写在同一个判断下使用and连起来做判断。
3. get\_pressed会返回一个tuple里面存放了所有的key值只要判断key值是不是为True就是判断了有没有按键。
4. 鼠标操作也可以使用get\_pressed函数也是返回tuple其中下标0、1、2分别代表了左、中、右三个按键。
最后,给你留一个小问题。
如果将组合键写在第一个按键的判断下,会出现什么情况?
```
if key[pygame.K_LCTRL]:
if key[pygame.K_w]:
...
```
欢迎留言说出你的看法,我在下一节的挑战中等你!