Merge pull request #20297 from wxy/20200918-Add-throwing-mechanics-to-your-Python-game

PRF&PUB:20200918 Add throwing mechanics to your Python game
This commit is contained in:
Xingyu.Wang 2020-11-30 13:06:15 +08:00 committed by GitHub
commit ac2391d857
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,19 +1,20 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12872-1.html)
[#]: subject: (Add throwing mechanics to your Python game)
[#]: via: (https://opensource.com/article/20/9/add-throwing-python-game)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
在你的 Python 游戏中添加投掷技巧
在你的 Python 游戏中添加投掷机制
======
四处奔跑躲避敌人是一回事。反击敌人是另一回事。
学习如何在这系列的第十二篇文章中创建在 Pygame 中的平台游戏
![使用企鹅兵来在格子上完游戏][1]
这是仍在进行中的关于使用 [Pygame][3] 模块来 [Python 3][2] 中创建电脑游戏的第十二部分。先前的文章是:
> 四处奔跑躲避敌人是一回事,反击敌人是另一回事。学习如何在这系列的第十二篇文章中在 Pygame 中创建平台游戏。
![](https://img.linux.net.cn/data/attachment/album/202011/30/124457xcj9mztw9kx9c7zj.jpg)
这是仍在进行中的关于使用 [Pygame][3] 模块在 [Python 3][2] 中创建电脑游戏的第十二部分。先前的文章是:
1. [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][4]
2. [使用 Python 和 Pygame 模块构建一个游戏框架][5]
@ -27,25 +28,22 @@
10. [在你的 Python 平台类游戏中放一些奖励][13]
11. [添加计分到你的 Python 游戏][14]
我的上一篇文章本来是这一系列文章的最后一篇,它鼓励你为这个游戏编写自己的附加程序。你们很多人都这么做了!我收到了一些电子邮件,要求帮助我还没有涵盖的常用机制:战斗。毕竟,跳起来躲避坏人是一回事,但是有时候让他们走开是一件非常令人满意的事。在电脑游戏中向你的敌人投掷一些物品是很常见的,不管是一个火球、一支箭、一道闪电,还是其它适合游戏的东西。
与迄今为止你在这个系列中为你的平台游戏编程的任何东西不同,可投掷物品有一个*生存时间*。在你投掷一个物品后,它会如期在移动一段距离后消失。如果它是一支箭或其它类似的东西,它可能会在通过屏幕的边缘时而消失。如果它是一个火球或一道闪电,它可能会在一段时间后熄灭。
上一篇文章是这一系列文章的最后一篇,它鼓励你为这个游戏编写自己的附加程序。你们很多人都这么做了!我收到了一名普通的机械师的一些电子邮件,要求帮助我还没有涵盖的服务:战斗。毕竟,跳起来躲避坏人是一回事,但是有时候让他们走开是一件非常令人满意的事。在电脑游戏中向你的敌人投掷一些东西是很常见的,不管是一个火球,一支箭,一道闪电,还是其它适合游戏的东西。
在这个系列中,到目前为止,投掷项目不像你在平台类游戏中编程的任何东西,它有一个 _生存时间_。 在你投掷一个对象后,它会如期在移动一段距离后消失。如果它是一支箭或其它类似的东西,它可能会在通过屏幕的边缘时而消失。如果它是一个火球或一道闪电,它可能会在一段时间后熄灭。
这意味着每次生成一个可丢弃的项目时,它的生存时间也必需生成一个独特的衡量标准。为了介绍这个概念,这篇文章演示如何一次只投掷一个项目。(换句话说,每次仅存在一个投掷项目)。 一方面,这是一个游戏的限制条件,但另一方面,它却是游戏本身的运行机制。你的玩家不能每次都投掷 50 个火球,因为每次仅允许一个投掷项目,所以当你的玩家释放一个火球来尝试击中一名敌人就成为了的一项挑战。在幕后,这也使你的代码保持简单。
这意味着每次生成一个可投掷的物品时,也必须生成一个独特的衡量其生存时间的标准。为了介绍这个概念,这篇文章演示如何一次只投掷一个物品。(换句话说,每次仅存在一个投掷物品)。 一方面,这是一个游戏的限制条件,但另一方面,它却是游戏本身的运行机制。你的玩家不能每次同时投掷 50 个火球,因为每次仅允许一个投掷物品,所以当你的玩家释放一个火球来尝试击中一名敌人就成为了一项挑战。而在幕后,这也使你的代码保持简单。
如果你想启用每次投掷多个项目,在完成这篇教程后,通过学习这篇教程所获取的知识来挑战你自己。
### 创建 throwable 类
如果你跟随学习这系列的其它文章,那么你应该熟悉基础的在屏幕上生成一个新的对象的 `__init__` 函数。这和你用来生成你的 [玩家][6] 和 [敌人][8] 的功能是一样的。这里是一个 `__init__` 函数来生成一个 投掷对象:
### 创建 Throwable 类
如果你跟随学习这系列的其它文章,那么你应该熟悉在屏幕上生成一个新的对象基础的 `__init__` 函数。这和你用来生成你的 [玩家][6] 和 [敌人][8] 的函数是一样的。这里是生成一个 `throwable` 对象的 `__init__` 函数来:
```
class Throwable(pygame.sprite.Sprite):
"""
生成一个投掷对象
生成一个 throwable 对象
"""
def __init__(self, x, y, img, throw):
pygame.sprite.Sprite.__init__(self)
@ -58,21 +56,18 @@ class Throwable(pygame.sprite.Sprite):
self.firing = throw
```
同你的 `Player` 类或 `Enemy` 类的 `__init__` 函数相比,这个函数的主要区别是,它有一个 `self.firing` 变量。这个变量保持跟踪一个投掷对象是否在当前屏幕上活动,因此当一个投掷对象创建时,将变量设置为 `1` 的合乎情理的。
同你的 `Player` 类或 `Enemy` 类的 `__init__` 函数相比,这个函数的主要区别是,它有一个 `self.firing` 变量。这个变量保持跟踪一个投掷的物品是否在当前屏幕上活动,因此当一个 `throwable` 对象创建时,将变量设置为 `1` 的合乎情理的。
### 判断活时间
### 判断活时间
接下来,就像使用 `Player``Enemy` 一样,你需要一个 `update` 函数,以便投掷对象在瞄准敌人抛向空中时,它会自己移动。
接下来,就像使用 `Player``Enemy` 一样,你需要一个 `update` 函数,以便投掷的物品在瞄准敌人抛向空中时,它会自己移动。
测定一个投掷对象活动时间的最简单方法是侦测它何时离开屏幕。你需要监视的屏幕边缘取决于你投掷对象的物理特性。
测定一个投掷的物品存活时间的最简单方法是侦测它何时离开屏幕。你需要监视的屏幕边缘取决于你投掷的物品的物理特性。
* 如果你的玩家正在投掷的东西是沿着水平轴快速移动的,像一只弩箭或箭或一股非常快的魔法力量,而你想监视你游戏屏幕的水平轴极限。这可以通过 `worldx` 定义。
* 如果你的玩家正在投掷的东西是沿着垂直方向或同时沿着水平方向和垂直方向移动的,那么吗必需监视你游戏屏幕的垂直轴极限。这可以通过 `worldy` 定义。
这个示例假设你的投掷对象向前移动一点并最终落地地面上。不过,投掷对象不会从地面上反弹起来,而是继续掉落出屏幕。你可以尝试不同的设置来看看什么最适合你的游戏:
* 如果你的玩家正在投掷的物品是沿着水平轴快速移动的,像一只弩箭或箭或一股非常快的魔法力量,而你想监视你游戏屏幕的水平轴极限。这可以通过 `worldx` 定义。
* 如果你的玩家正在投掷的物品是沿着垂直方向或同时沿着水平方向和垂直方向移动的,那么你必须监视你游戏屏幕的垂直轴极限。这可以通过 `worldy` 定义。
这个示例假设你投掷的物品向前移动一点并最终落到地面上。不过,投掷的物品不会从地面上反弹起来,而是继续掉落出屏幕。你可以尝试不同的设置来看看什么最适合你的游戏:
```
def update(self,worldy):
@ -87,21 +82,20 @@ class Throwable(pygame.sprite.Sprite):
self.firing = 0 #解除火力发射
```
为使你的投掷对象移动地更快,增加 `self.rect` 的动量值。
为使你的投掷物品移动地更快,增加 `self.rect` 的动量值。
如果投掷对象不在屏幕上,那么对象将被销毁,以及释放其所占用的寄存器。另外,`self.firing` 将被设置回 `0` 以允许你的玩家来进行另一次射击。
如果投掷物品不在屏幕上,那么该物品将被销毁,以及释放其所占用的寄存器。另外,`self.firing` 将被设置回 `0` 以允许你的玩家来进行另一次射击。
### 设置你的投掷对象
就像使用你的玩家和敌人一样,你必需在你的 setup 部分中创建一个精灵组来保持投资对象。
就像使用你的玩家和敌人一样,你必须在你的设置部分中创建一个精灵组来保持投掷对象。
此外,你必创建一个非活动的投掷对象来供开始的游戏使用。如果在游戏开始时却没有一个投掷对象,那么玩家在第一次尝试投掷一柄武器时,投掷将失败。
此外,你必创建一个非活动的投掷对象来供开始的游戏使用。如果在游戏开始时却没有一个投掷对象,那么玩家在第一次尝试投掷一柄武器时,投掷将失败。
这个示例假设你的玩家使用一个火球作为开始的武器,因此,每一个投掷实例都是由 `fire` 变量指派的。在后面的关卡中,当玩家获取新的技能时,你可以使用相同的 `Throwable` 类来引入一个新的变量以使用一张不同的图像。
在这代码块中,前两行已经在你的代码中,因此不要重新键入它们:
```
player_list = pygame.sprite.Group() #上下文
player_list.add(player) #上下文
@ -111,14 +105,13 @@ firepower = pygame.sprite.Group()
注意,每一个投掷对象的起始位置都是和玩家所在的位置相同。这使得它看起来像是投掷对象来自玩家。在第一个火球生成时,使用 `0` 来显示 `self.firing` 是可用的。
### 在主循环中获取 throwing
### 在主循环中获取投掷行为
没有在主循环中出现的代码不会在游戏中使用,因此你需要在你的主循环中添加一些东西,以便能在你的游戏世界中获取投掷东西
没有在主循环中出现的代码不会在游戏中使用,因此你需要在你的主循环中添加一些东西,以便能在你的游戏世界中获取投掷对象
首先,添加玩家控制。当前,你没有火力触发器。在键盘上的按键是有两种状态的:按键能够在上面,也能够在下面。为了移动,你要使用这两种状态:按下按键来启动玩家移动,释放按键 ( 按键是在上面的 ) 来停止玩家移动。开火仅需要一个信号。你使用哪个按键事件 ( 按键按下或按键释放 ) 来触发你的投掷对象取决于你的品味。
在这个代码语句块中,前两行是用于上下文的:
首先,添加玩家控制。当前,你没有火力触发器。在键盘上的按键是有两种状态的:释放的按键,按下的按键。为了移动,你要使用这两种状态:按下按键来启动玩家移动,释放按键来停止玩家移动。开火仅需要一个信号。你使用哪个按键事件(按键按下或按键释放)来触发你的投掷对象取决于你的品味。
在这个代码语句块中,前两行是用于上下文的:
```
if event.key == pygame.K_UP or event.key == ord('w'):
@ -129,10 +122,9 @@ firepower = pygame.sprite.Group()
firepower.add(fire)
```
与你在你 setup 部分创建的火球不同,你使用一个 `1` 来设置 `self.firing` 为不可用。
最后,你必需更新和绘制你的投掷对象。这个顺序很重要,因此把这段代码放置到你现有的 `enemy.move``player_list.draw` 的代码行之间:
与你在设置部分创建的火球不同,你使用一个 `1` 来设置 `self.firing` 为不可用。
最后,你必须更新和绘制你的投掷物品。这个顺序很重要,因此把这段代码放置到你现有的 `enemy.move``player_list.draw` 的代码行之间:
```
enemy.move() # 上下文
@ -144,18 +136,17 @@ firepower = pygame.sprite.Group()
enemy_list.draw(screen) # 上下文
```
注意,这些更新仅在 `self.firing` 变量被设置为 1 时执行。如果它被设置为 0 ,那么 `fire.firing` 就不是真的,接下来就跳过更新。如果你尝试做上述这些更新,不管怎样,你的游戏都会崩溃,因为在游戏中将不会更新或绘制一个 `火球` 对象。
注意,这些更新仅在 `self.firing` 变量被设置为 1 时执行。如果它被设置为 0 ,那么 `fire.firing` 就不`true`,接下来就跳过更新。如果你尝试做上述这些更新,不管怎样,你的游戏都会崩溃,因为在游戏中将不会更新或绘制一个 `fire` 对象。
启动你的游戏,尝试挑战你的武器。
### 检测碰撞
如果你玩使用新投掷技巧的游戏,你可能会注意到,你可以投掷对象,但是它却不会对你的敌人有任何影响。
如果你玩使用新投掷技巧的游戏,你可能会注意到,你可以投掷对象,但是它却不会对你的敌人有任何影响。
原因是你的敌人没有被查到碰撞事故。一名敌人可能会被你的投掷对象所击中,但是敌人却从来不知道被击中了。
你已经在你的 `Player` 类中完成了碰撞检测,这非常类似。在你的 `Enemy` 类中,添加一个新的 `update` 函数:
原因是你的敌人没有被查到碰撞事故。一名敌人可能会被你的投掷物品所击中,但是敌人却从来不知道被击中了。
你已经在你的 `Player` 类中完成了碰撞检测,这非常类似。在你的 `Enemy` 类中,添加一个新的 `update` 函数:
```
def update(self,firepower, enemy_list):
@ -169,8 +160,7 @@ firepower = pygame.sprite.Group()
代码很简单。每个敌人对象都检查并看看它自己是否被 `firepower` 精灵组的成员所击中。如果它被击中,那么敌人就会从敌人组中移除和消失。
为集成这些功能到你的游戏之中,在主循环中调用位于新触发语句块中的函数:
为集成这些功能到你的游戏之中,在主循环中调用位于新触发语句块中的函数:
```
if fire.firing: # 上下文
@ -181,14 +171,13 @@ firepower = pygame.sprite.Group()
你现在可以尝试一下你的游戏了,大多数的事情都如预期般的那样工作。不过,这里仍然有一个问题,那就是投掷的方向。
### 更改投掷技巧的方向
### 更改投掷机制的方向
当前,你英雄的火球只会向右移动。这是因为 `Throwable` 类的 `update` 函数将像素添加到火球的位置,在 Pygame 中,在 X 轴上一个较大的数字意味着向屏幕的右侧移动。当你的英雄转向另一个方向时,你可能希望它投掷的火球也抛向左侧。
到目前为止,你已经知道如何实现这一点,至少在技术上是这样的。然而,最简单的解决方案却是使用一个变量,在一定程度上对你来说可能是一种新的方法。一般来说,你可以 "设置一个标记" ( 有时也被称为 "转刀" ) 来标明你的英雄所面向的方向。在你做完后,你就可以检查这个变量来得知火球是向左移动还是向右移动。
首先,在你的 `Player` 类中创建一个新的变量来代表你的游戏所面向的方向。因为我的游戏天然地面向右侧,由此我把面向右侧作为默认值:
到目前为止,你已经知道如何实现这一点,至少在技术上是这样的。然而,最简单的解决方案却是使用一个变量,在一定程度上对你来说可能是一种新的方法。一般来说,你可以“设置一个标记”(有时也被称为“翻转一个位”)来标明你的英雄所面向的方向。在你做完后,你就可以检查这个变量来得知火球是向左移动还是向右移动。
首先,在你的 `Player` 类中创建一个新的变量来代表你的游戏所面向的方向。因为我的游戏天然地面向右侧,由此我把面向右侧作为默认值:
```
self.score = 0
@ -196,8 +185,7 @@ firepower = pygame.sprite.Group()
self.is_jumping = True
```
当这个变量是 `True` 时,你的英雄精灵是面向右侧的。当玩家每次更改英雄的方向时,变量也必需重新设置,因此,在你的主循环中相关的 `keyup` 事件中这样做:
当这个变量是 `True` 时,你的英雄精灵是面向右侧的。当玩家每次更改英雄的方向时,变量也必须重新设置,因此,在你的主循环中相关的 `keyup` 事件中这样做:
```
if event.type == pygame.KEYUP:
@ -209,8 +197,7 @@ firepower = pygame.sprite.Group()
player.facing_right = True # 添加这行
```
最后,更改你的 `Throwable` 类的 `update` 函数,以检测英雄是否面向右侧,并恰当地添加或减去来自火球位置的像素:
最后,更改你的 `Throwable` 类的 `update` 函数,以检测英雄是否面向右侧,并恰当地添加或减去来自火球位置的像素:
```
if self.rect.y < worldy:
@ -225,13 +212,10 @@ firepower = pygame.sprite.Group()
![Python 平台类使用投掷能力][15]
(Seth Kenlon, [CC BY-SA 4.0][16])
作为一项额外的挑战,当彻底打败敌人时,尝试增加你玩家的得分。
### 完整的代码
```
#!/usr/bin/env python3
# 作者: Seth Kenlon
@ -656,7 +640,7 @@ via: https://opensource.com/article/20/9/add-throwing-python-game
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@ -665,17 +649,17 @@ via: https://opensource.com/article/20/9/add-throwing-python-game
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/game_pawn_grid_linux.png?itok=4gERzRkg (Gaming on a grid with penguin pawns)
[2]: https://www.python.org/
[3]: https://www.pygame.org/news
[4]: https://opensource.com/article/17/10/python-101
[5]: https://opensource.com/article/17/12/game-framework-python
[6]: https://opensource.com/article/17/12/game-python-add-a-player
[7]: https://opensource.com/article/17/12/game-python-moving-player
[8]: https://opensource.com/article/18/5/pygame-enemy
[9]: https://opensource.com/article/18/7/put-platforms-python-game
[10]: https://opensource.com/article/19/11/simulate-gravity-python
[11]: https://opensource.com/article/19/12/jumping-python-platformer-game
[12]: https://opensource.com/article/19/12/python-platformer-game-run
[13]: https://opensource.com/article/19/12/loot-python-platformer-game
[14]: https://opensource.com/article/20/1/add-scorekeeping-your-python-game
[4]: https://linux.cn/article-9071-1.html
[5]: https://linux.cn/article-10850-1.html
[6]: https://linux.cn/article-10858-1.html
[7]: https://linux.cn/article-10874-1.html
[8]: https://linux.cn/article-10883-1.html
[9]: https://linux.cn/article-10902-1.html
[10]: https://linux.cn/article-11780-1.html
[11]: https://linux.cn/article-11790-1.html
[12]: https://linux.cn/article-11819-1.html
[13]: https://linux.cn/article-11828-1.html
[14]: https://linux.cn/article-11839-1.html
[15]: https://opensource.com/sites/default/files/uploads/pygame-throw.jpg (Python platformer with throwing capability)
[16]: https://creativecommons.org/licenses/by-sa/4.0/
[17]: http://www.gnu.org/licenses/\>