用Python和Pygame写游戏-从入门到精通(10)
admin
2023-07-31 00:36:35
0

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

很自然的,我们讲述了游戏中视觉上的种种,现在开始就要学习一下游戏中的用户输入。同样我们也要探讨一下如何让用户的输入更为顺畅,换个词就是,如果让游戏的手感更好一些。

游戏设备

玩过游戏的都知道鼠标和键盘是游戏的不可或缺的输入设备。键盘可以控制有限的方向和诸多的命令操作,而鼠标更是提供了全方位的方向和位置操作。不过这两个设备并不是为游戏而生,专业的游戏手柄给玩家提供了更好的操作感,加上力反馈等技术,应该说游戏设备越来越丰富,玩家们也是越来越幸福。

键盘设备

我们先从最广泛的键盘开始讲起。

现在使用的键盘,基本都是QWERTY键盘(看看字幕键盘排布的左上就知道了),尽管这个世界上还有其他种类的键盘,比如AZERTY啥的,反正我是没见过,如果你能在写游戏的时候考虑到这些特殊用户自然是最好,个人感觉是问题不大吧。

以前第二部分也稍微使用了一下键盘,那时候是用了pygame.event.get()获取所有的事件,当event.type == KEYDOWN的时候,在判断event.key的种类,而各个种类也使用K_aK_b……等判断。这里再介绍一个pygame.key.get_pressed()来获得所有按下的键值,它会返回一个元组。这个元组的索引就是键值,对应的就是是否按下,比如说:

1234 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当做方向键来移动,我们来看一个实际的例子:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 background_image_filename = \’sushiplate.jpg\’sprite_image_filename = \’fugu.png\’ import pygamefrom pygame.locals import *from sys import exitfrom 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()

 

这个例子很简单,就是使用方向键移动小鱼。使用的知识也都讲过了,相信大家都可以理解。不过这里并不是单纯的判断按下的键来获得方向,而是通过对方向的加减来获得最终的效果,这样可能会更简短一些,也需要一些技术;如果把方向写入代码,效率更高,不过明显通用性就要低一些。记得把力气花在刀刃上!当然这个例子也不是那么完美,看代码、实践一下都能看到,左方向键的优先级大于右方向键,而上则优于下,我们是否有更好的方法?……有兴趣的自己考虑~

这个例子我们可以看到,小鱼只能在八个方向移动,如何做到全方向?如果你游戏经验足一点或许可以想到,是的,先转向,再移动,尽管不是那么快捷,但毕竟达到了目标。我们看一下这样的代码怎么写:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 background_image_filename = \’sushiplate.jpg\’sprite_image_filename = \’fugu.png\’ import pygamefrom pygame.locals import *from sys import exitfrom gameobjects.vector2 import Vector2from 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.xw/2, sprite_pos.yh/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()来获得了转向后的图片,具体参数可以参考代码。各条语句的作用也可以参考注释。

下次讲解使用鼠标控制游戏。


相关内容

热门资讯

500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
python查找阿姆斯特朗数 题目解释 如果一个n位正整数等于其各位数字的n次方之和,则称该数为阿姆斯特朗数。 例如1^3 + 5...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...