Merge pull request #1 from LCTT/master

sync from origin repository
This commit is contained in:
qianmingtian 2020-01-13 23:20:23 +08:00 committed by GitHub
commit 1fc6e1fa75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 491 additions and 498 deletions

View File

@ -0,0 +1,395 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11780-1.html)
[#]: subject: (Simulate gravity in your Python game)
[#]: via: (https://opensource.com/article/19/11/simulate-gravity-python)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
在你的 Python 游戏中模拟引力
======
> 学习如何使用 Python 的 Pygame 模块编程电脑游戏,并开始操作引力。
![](https://img.linux.net.cn/data/attachment/album/202001/13/223923k6t4zmvvmo6tfmmg.png)
真实的世界充满了运动和生活。物理学使得真实的生活如此忙碌和动态。物理学是物质在空间中运动的方式。既然一个电脑游戏世界没有物质,它也就没有物理学规律,使用游戏程序员不得不*模拟*物理学。
从大多数电脑游戏来说,这里基本上仅有两个方面的物理学是重要的:引力和碰撞。
当你[添加一个敌人][2]到你的游戏中时,你实现了一些碰撞检测,但是这篇文章要添加更多的东西,因为引力需要碰撞检测。想想为什么引力可能涉及碰撞。如果你不能想到任何原因,不要担心 —— 它会随着你开发示例代码工作而且显然。
在真实世界中的引力是有质量的物体来相互吸引的倾向性。物体(质量)越大,它施加越大的引力作用。在电脑游戏物理学中,你不必创建质量足够大的物体来证明引力的正确;你可以在电脑游戏世界本身中仅编程一个物体落向假设的最大的对象的倾向。
### 添加一个引力函数
记住你的玩家已经有了一个决定动作的属性。使用这个属性来将玩家精灵拉向屏幕底部。
在 Pygame 中,较高的数字更接近屏幕的底部边缘。
在真实的世界中,引力影响一切。然而,在平台游戏中,引力是有选择性的 —— 如果你添加引力到你的整个游戏世界,你的所有平台都将掉到地上。反之,你可以仅添加引力到你的玩家和敌人精灵中。
首先,在你的 `Player` 类中添加一个 `gravity` 函数:
```
    def gravity(self):
        self.movey += 3.2 # 玩家掉落的多快
```
这是一个简单的函数。首先,不管你的玩家是否想运动,你设置你的玩家垂直运动。也就是说,你已经编程你的玩家总是在下降。这基本上就是引力。
为使引力函数生效你必须在你的主循环中调用它。这样当每一个处理循环时Python 都应用下落运动到你的玩家。
在这代码中,添加第一行到你的循环中:
```
    player.gravity() # 检查引力
    player.update()
```
启动你的游戏来看看会发生什么。要注意,因为它发生的很快:你是玩家从天空上下落,马上掉出了你的游戏屏幕。
你的引力模拟是工作的,但是,也许太好了。
作为一次试验,尝试更改你玩家下落的速度。
### 给引力添加一个地板
你的游戏没有办法发现你的角色掉落出世界的问题。在一些游戏中,如果一个玩家掉落出世界,该精灵被删除,并在某个新的位置重生。在另一些游戏中,玩家会丢失分数或一条生命。当一个玩家掉落出世界时,不管你想发生什么,你必须能够侦测出玩家何时消失在屏幕外。
在 Python 中,要检查一个条件,你可以使用一个 `if` 语句。
你必需查看你玩家**是否**正在掉落,以及你的玩家掉落的程度。如果你的玩家掉落到屏幕的底部,那么你可以做*一些事情*。简化一下,设置玩家精灵的位置为底部边缘上方 20 像素。
使你的 `gravity` 函数看起来像这样:
```
    def gravity(self):
        self.movey += 3.2 # 玩家掉落的多快
       
        if self.rect.y > worldy and self.movey >= 0:
            self.movey = 0
            self.rect.y = worldy-ty
```
然后,启动你的游戏。你的精灵仍然下落,但是它停在屏幕的底部。不过,你也许不能*看到*你在地面层之上的精灵。一个简单的解决方法是,在精灵碰撞游戏世界的底部后,通过添加另一个 `-ty` 到它的新 Y 位置,从而使你的精灵弹跳到更高处:
```
    def gravity(self):
        self.movey += 3.2 # 玩家掉落的多快
       
        if self.rect.y > worldy and self.movey >= 0:
            self.movey = 0
            self.rect.y = worldy-ty-ty
```
现在你的玩家在屏幕底部弹跳,恰好在你地面精灵上面。
你的玩家真正需要的是反抗引力的方法。引力问题是,你不能反抗它,除非你有一些东西来推开引力作用。因此,在接下来的文章中,你将添加地面和平台碰撞以及跳跃能力。在这期间,尝试应用引力到敌人精灵。
到目前为止,这里是全部的代码:
```
#!/usr/bin/env python3
# draw a world
# add a player and player control
# add player movement
# add enemy and basic collision
# add platform
# add gravity
# GNU All-Permissive License
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved. This file is offered as-is,
# without any warranty.
import pygame
import sys
import os
'''
Objects
'''
class Platform(pygame.sprite.Sprite):
# x location, y location, img width, img height, img file
def __init__(self,xloc,yloc,imgw,imgh,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img)).convert()
self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.y = yloc
self.rect.x = xloc
class Player(pygame.sprite.Sprite):
'''
Spawn a player
'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
self.score = 1
self.images = []
for i in range(1,9):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(ALPHA)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def gravity(self):
self.movey += 3.2 # how fast player falls
if self.rect.y > worldy and self.movey >= 0:
self.movey = 0
self.rect.y = worldy-ty-ty
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey += y
def update(self):
'''
Update sprite position
'''
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[(self.frame//ani)+4]
# collisions
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in enemy_hit_list:
self.health -= 1
print(self.health)
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
for g in ground_hit_list:
self.health -= 1
print(self.health)
class Enemy(pygame.sprite.Sprite):
'''
Spawn an enemy
'''
def __init__(self,x,y,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img))
#self.image.convert_alpha()
#self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.counter = 0
def move(self):
'''
enemy movement
'''
distance = 80
speed = 8
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
class Level():
def bad(lvl,eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
enemy_list = pygame.sprite.Group() # create enemy group
enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return enemy_list
def loot(lvl,lloc):
print(lvl)
def ground(lvl,gloc,tx,ty):
ground_list = pygame.sprite.Group()
i=0
if lvl == 1:
while i < len(gloc):
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
ground_list.add(ground)
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return ground_list
def platform(lvl,tx,ty):
plat_list = pygame.sprite.Group()
ploc = []
i=0
if lvl == 1:
ploc.append((0,worldy-ty-128,3))
ploc.append((300,worldy-ty-256,3))
ploc.append((500,worldy-ty-128,4))
while i < len(ploc):
j=0
while j <= ploc[i][2]:
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
plat_list.add(plat)
j=j+1
print('run' + str(i) + str(ploc[i]))
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return plat_list
'''
Setup
'''
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
i=0
while i <= (worldx/tx)+tx:
gloc.append(i*tx)
i=i+1
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
'''
Main loop
'''
while main == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
print("LEFT")
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
print("RIGHT")
player.control(steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
print('jump')
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
print('jump')
if event.key == ord('q'):
pygame.quit()
sys.exit()
main = False
world.blit(backdrop, backdropbox)
player.gravity() # check gravity
player.update()
player_list.draw(world)
enemy_list.draw(world)
ground_list.draw(world)
plat_list.draw(world)
for e in enemy_list:
e.move()
pygame.display.flip()
clock.tick(fps)
```
* * *
这是仍在进行中的关于使用 [Pygame][4] 模块来在 [Python 3][3] 在创建电脑游戏的第七部分。先前的文章是:
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][5]
* [使用 Python 和 Pygame 模块构建一个游戏框架][6]
* [如何在你的 Python 游戏中添加一个玩家][7]
* [用 Pygame 使你的游戏角色移动起来][8]
* [如何向你的 Python 游戏中添加一个敌人][2]
* [在 Pygame 游戏中放置平台][9]
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/11/simulate-gravity-python
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/space_stars_cosmic.jpg?itok=bE94WtN- (Cosmic stars in outer space)
[2]: https://linux.cn/article-10883-1.html
[3]: https://www.python.org/
[4]: https://www.pygame.org
[5]: https://linux.cn/article-9071-1.html
[6]: https://linux.cn/article-10850-1.html
[7]: https://linux.cn/article-10858-1.html
[8]: https://linux.cn/article-10874-1.html
[9]: https://linux.cn/article-10902-1.html

View File

@ -1,8 +1,8 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-11779-1.html)
[#]: subject: (PaperWM: tiled window management for GNOME)
[#]: via: (https://jvns.ca/blog/2020/01/05/paperwm/)
[#]: author: (Julia Evans https://jvns.ca/)
@ -10,13 +10,15 @@
PaperWMGNOME 下的平铺窗口管理
======
当我开始在个人计算机上使用 Linux 时,令我兴奋的第一件事就是轻巧的窗口管理器,这主要是因为当时我的笔记本电脑只有有 32MB 的内存,且没有其他可使用的内存。
![](https://img.linux.net.cn/data/attachment/album/202001/13/212936hsk572f4jrsj2jsh.jpg)
接着我开始接触 [xmonad][1] 之类的平铺窗口管理器!我可以用键盘管理窗口了!它们太快了!我可以通过编写 Haskell 程序来配置 xmonad我可以用各种有趣的方式自定义所有内容例如使用 [dmenu][2] 作为启动器)!这些年来,我用过 34 个不同的平铺窗口管理器,它们很有趣
当我开始在个人计算机上使用 Linux 时,首先令我兴奋的就是轻巧的窗口管理器,这主要是因为当时我的笔记本电脑只有有 32MB 的内存,其它的都运行不了了
大约 6 年前,我觉得配置平铺窗口管理器对我来说不再是一件有趣的事情,因此转而使用 Ubuntu 桌面环境 Gnome。 (现在,我的笔记本电脑中的内存增加了 500 倍,这要快得多 :)
接着我开始接触 [xmonad][1] 之类的平铺窗口管理器!我可以用键盘管理窗口了!它们是如此之快!我可以通过编写 Haskell 程序来配置 xmonad我可以用各种有趣的方式自定义所有内容例如使用 [dmenu][2] 作为启动器)!这些年来,我用过 3、4 个不同的平铺窗口管理器,它们都很有趣。
我使用 Gnome 已有很长时间了,但是我仍然有点想念平铺窗口管理器。六个月前,一个朋友告诉我有关 [PaperWM][3] 的消息,它使你可以在 Gnome中 平铺窗口!我立即安装了它,并从那时起我一直在使用它。
大约 6 年前,我觉得配置平铺窗口管理器对我来说不再是一件有趣的事情,因此转而使用 Ubuntu 桌面环境 Gnome。现在我的笔记本电脑中的内存增加了 500 倍,这要快得多 :)
我使用 Gnome 已有很长时间了,但是我仍然有点想念平铺窗口管理器。六个月前,一个朋友告诉我有关 [PaperWM][3] 的消息,它使你可以在 Gnome 中平铺窗口!我立即安装了它,并从那时起我一直在使用它。
### PaperWMGnome 下的平铺窗口管理
@ -26,7 +28,7 @@ PaperWMGNOME 下的平铺窗口管理
### “Paper” 表示你的所有窗户都在一行中
PaperWM 的主要想是将所有窗口排成一行,这实际上与传统的平铺窗口管理器大不相同,在传统的平铺窗口管理器中,你可以按任意方式平铺窗口。这是我写这篇博客时在几个窗口之间切换/调整大小的 gif 图像(有一个浏览器和两个终端窗口):
PaperWM 的主要想是将所有窗口排成一行,这实际上与传统的平铺窗口管理器大不相同,在传统的平铺窗口管理器中,你可以按任意方式平铺窗口。这是我写这篇博客时在几个窗口之间切换/调整大小的 gif 图像(有一个浏览器和两个终端窗口):
![][4]
@ -38,16 +40,14 @@ PaperWM 的 Github README 链接了此视频:<http://10gui.com/video/>,它
还有很多其他功能,但这是我使用的功能:
* 在窗口之间左右移动(`Super + ,`, `Super + .`
  * 按顺序向左/向右移动窗口(`Super+Shift+,``Super+Shift+.`
  * 全屏显示窗口(`Super + f`
  * 缩小窗口(`Super + r`
* 在窗口之间左右移动(`Super + ,`、`Super + .`
* 按顺序向左/向右移动窗口(`Super+Shift+,`、`Super+Shift+.`
* 全屏显示窗口(`Super + f`
* 缩小窗口(`Super + r`
### 我喜欢不需要配置的工具
我在笔记本上使用 PaperWM 已经6个月了我真的很喜欢它即使它是可配置通过编写 Javascript 配置文件),我也非常欣赏它,它自带我想要的功能,我无需研究如何去配置。
我在笔记本上使用 PaperWM 已经 6 个月了,我真的很喜欢它!即使它是可配置(通过编写 Javascript 配置文件),我也非常欣赏它,它自带我想要的功能,我无需研究如何去配置。
[fish shell][5] 是另一个类似的令人愉悦的工具,我基本上没有配置 fish除了设置环境变量等我真的很喜欢它的默认功能。
@ -58,7 +58,7 @@ via: https://jvns.ca/blog/2020/01/05/paperwm/
作者:[Julia Evans][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,401 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (Simulate gravity in your Python game)
[#]: via: (https://opensource.com/article/19/11/simulate-gravity-python)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
在你的 Python 游戏中模拟引力
======
学习如何使用 Python 的 Pygame 模块编程电脑游戏,并开始操作引力。
![Cosmic stars in outer space][1]
真实的世界充满了运动和生活。物理学使得真实的生活如此忙碌和动态。物理学是物质在空间中运动的方式。既然一个电脑游戏世界没有物质,它也就没有物理学规律,使用游戏程序员不得不 _模拟_ 物理学。
从大多数电脑游戏来说,这里基本上仅有物理学的两个方向是重要的:引力和碰撞。
当你[添加一个敌人][2]到你的游戏中时,你实现了一下碰撞检测,但是这篇文章添加更多的东西,因为引力需要碰撞检测。想想为什么引力可能涉及碰撞。如果你不能想到任何原因,不要担心—当你通过示例代码工作时,它将变得明显。
引力在真实世界中的是有质量的物体来相互吸引的趋势。物体(质量)越大,它施加越大的引力作用。在电脑游戏物理学中,你不必创建质量足够大的物体来证明引力的正确;你可以在电脑游戏世界本身中仅编程一个物体落向假设的最大的对象的倾向。
### 添加一个引力函数
记住你的玩家已经有一个属性来决定动作。使用这个属性来将玩家精灵拉向屏幕底部。
在 Pygame 中,较高的数字更接近屏幕的底部边缘。
在真实的世界中,引力影响一切。然而,在平台中,引力是有选择性的—如果你添加引力到你的整个游戏世界,你所有平台都将掉到地上。作为替换,你仅添加引力到你的玩家和敌人精灵中。
首先,在你的 **Player** 类中添加一个 **引力** 函数:
```
    def gravity(self):
        self.movey += 3.2 # how fast player falls
```
这是一个简单的函数。首先,不管你的玩家是否想运动,你设置你的玩家垂直运动。也就是说,你已经编程你的玩家总是在下降。这基本上就是引力。
为使引力函数生效你必需在你的主循环中调用它。这样当每一个时钟滴答作响时Python 应用下落运动到你玩家。
在这代码中,添加第一行到你的循环中:
```
    player.gravity() # check gravity
    player.update()
```
启动你的游戏来看看会发生什么。注意,因为它快速地发生:你是玩家从天空上下落,恰好从你的游戏屏幕落下。
你的引力模拟是工作的,但是,也许太好了。
作为一次试验,尝试更改你玩家下落的速度。
### 添加一个地板到引力
你的游戏没有办法发现你的角色掉落出世界的问题。在一些游戏中,如果一个玩家掉落出世界,该精灵被删除,并在新的位置重生。在其它的游戏中,玩家丢失分数或一条生命。当一个玩家掉落出世界时,不管你想发生什么,你必需能够侦测出玩家何时消失在屏幕外。
在 Python 中,要检查一个条件,你可以使用一个 **if** 语句。
你必需查看你玩家**是否**正在掉落,以及你的玩家掉落到什么程度。如果你的玩家掉落到屏幕的底部,那么你可以做 _一些事情_ 。 为保持事情简单设置玩家精灵的位置为底部边缘上方20像素。
使你的 **引力** 函数看起来像这样:
```
    def gravity(self):
        self.movey += 3.2 # how fast player falls
       
        if self.rect.y > worldy and self.movey >= 0:
            self.movey = 0
            self.rect.y = worldy-ty
```
然后,启动你的游戏。你的精灵仍然下落,但是它停在屏幕的底部。不过,你也许不能 _看到_ 你在地面层下的精灵。一个简单的解决方法是,在精灵碰撞游戏世界的底部后,通过添加另一个 **-ty** 到它的新 Y 位置,从而使你的精灵弹跳更高:
```
    def gravity(self):
        self.movey += 3.2 # how fast player falls
       
        if self.rect.y > worldy and self.movey >= 0:
            self.movey = 0
            self.rect.y = worldy-ty-ty
```
现在你的玩家在屏幕底部弹跳,恰好在你地面层精灵的后面。
你的玩家真正需要的是反抗引力的方法。引力问题是,你不能反抗它,除非你有一些东西来推开引力作用。因此,在接下来的文章中,你将添加地面和平台碰撞以及跳跃能力。在这期间,尝试应用引力到敌人精灵。
到目前为止,这里是全部的代码:
```
#!/usr/bin/env python3
# draw a world
# add a player and player control
# add player movement
# add enemy and basic collision
# add platform
# add gravity
# GNU All-Permissive License
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.  This file is offered as-is,
# without any warranty.
import pygame
import sys
import os
'''
Objects
'''
class Platform(pygame.sprite.Sprite):
    # x location, y location, img width, img height, img file    
    def __init__(self,xloc,yloc,imgw,imgh,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images',img)).convert()
        self.image.convert_alpha()
        self.rect = self.image.get_rect()
        self.rect.y = yloc
        self.rect.x = xloc
class Player(pygame.sprite.Sprite):
    '''
    Spawn a player
    '''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.movex = 0
        self.movey = 0
        self.frame = 0
        self.health = 10
        self.score = 1
        self.images = []
        for i in range(1,9):
            img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
            img.convert_alpha()
            img.set_colorkey(ALPHA)
            self.images.append(img)
            self.image = self.images[0]
            self.rect  = self.image.get_rect()
    def gravity(self):
        self.movey += 3.2 # how fast player falls
       
        if self.rect.y > worldy and self.movey >= 0:
            self.movey = 0
            self.rect.y = worldy-ty-ty
       
    def control(self,x,y):
        '''
        control player movement
        '''
        self.movex += x
        self.movey += y
       
    def update(self):
        '''
        Update sprite position
        '''
        self.rect.x = self.rect.x + self.movex
        self.rect.y = self.rect.y + self.movey
        # moving left
        if self.movex < 0:
            self.frame += 1
            if self.frame > ani*3:
                self.frame = 0
            self.image = self.images[self.frame//ani]
        # moving right
        if self.movex > 0:
            self.frame += 1
            if self.frame > ani*3:
                self.frame = 0
            self.image = self.images[(self.frame//ani)+4]
        # collisions
        enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
        for enemy in enemy_hit_list:
            self.health -= 1
            print(self.health)
        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.health -= 1
            print(self.health)
class Enemy(pygame.sprite.Sprite):
    '''
    Spawn an enemy
    '''
    def __init__(self,x,y,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images',img))
        #self.image.convert_alpha()
        #self.image.set_colorkey(ALPHA)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.counter = 0
       
    def move(self):
        '''
        enemy movement
        '''
        distance = 80
        speed = 8
        if self.counter >= 0 and self.counter <= distance:
            self.rect.x += speed
        elif self.counter >= distance and self.counter <= distance*2:
            self.rect.x -= speed
        else:
            self.counter = 0
        self.counter += 1
class Level():
    def bad(lvl,eloc):
        if lvl == 1:
            enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
            enemy_list = pygame.sprite.Group() # create enemy group
            enemy_list.add(enemy)              # add enemy to group
           
        if lvl == 2:
            print("Level " + str(lvl) )
        return enemy_list
    def loot(lvl,lloc):
        print(lvl)
    def ground(lvl,gloc,tx,ty):
        ground_list = pygame.sprite.Group()
        i=0
        if lvl == 1:
            while i < len(gloc):
                ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
                ground_list.add(ground)
                i=i+1
        if lvl == 2:
            print("Level " + str(lvl) )
        return ground_list
    def platform(lvl,tx,ty):
        plat_list = pygame.sprite.Group()
        ploc = []
        i=0
        if lvl == 1:
            ploc.append((0,worldy-ty-128,3))
            ploc.append((300,worldy-ty-256,3))
            ploc.append((500,worldy-ty-128,4))
            while i < len(ploc):
                j=0
                while j <= ploc[i][2]:
                    plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
                    plat_list.add(plat)
                    j=j+1
                print('run' + str(i) + str(ploc[i]))
                i=i+1
        if lvl == 2:
            print("Level " + str(lvl) )
        return plat_list
'''
Setup
'''
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4  # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE  = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
i=0
while i <= (worldx/tx)+tx:
    gloc.append(i*tx)
    i=i+1
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
'''
Main loop
'''
while main == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit(); sys.exit()
            main = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                print("LEFT")
                player.control(-steps,0)
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                print("RIGHT")
                player.control(steps,0)
            if event.key == pygame.K_UP or event.key == ord('w'):
                print('jump')
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                player.control(steps,0)
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                player.control(-steps,0)
            if event.key == pygame.K_UP or event.key == ord('w'):
                print('jump')
            if event.key == ord('q'):
                pygame.quit()
                sys.exit()
                main = False
    world.blit(backdrop, backdropbox)
    player.gravity() # check gravity
    player.update()
    player_list.draw(world)
    enemy_list.draw(world)
    ground_list.draw(world)
    plat_list.draw(world)
    for e in enemy_list:
        e.move()
    pygame.display.flip()
    clock.tick(fps)
```
* * *
这是仍在进行中的关于使用 [Pygame][4] 模块来在 [Python 3][3] 在创建电脑游戏的第七部分。先前的文章是:
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][5]
* [使用 Python 和 Pygame 模块构建一个游戏框架][6]
* [如何在你的 Python 游戏中添加一个玩家][7]
* [用 Pygame 使你的游戏角色移动起来][8]
* [如何向你的 Python 游戏中添加一个敌人][2]
* [在 Pygame 游戏中放置平台][9]
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/11/simulate-gravity-python
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/space_stars_cosmic.jpg?itok=bE94WtN- (Cosmic stars in outer space)
[2]: https://opensource.com/article/18/5/pygame-enemy
[3]: https://www.python.org/
[4]: https://www.pygame.org
[5]: https://opensource.com/article/17/10/python-101
[6]: https://opensource.com/article/17/12/game-framework-python
[7]: https://opensource.com/article/17/12/game-python-add-a-player
[8]: https://opensource.com/article/17/12/game-python-moving-player
[9]: https://opensource.com/article/18/7/put-platforms-python-game

View File

@ -7,28 +7,27 @@
[#]: via: (https://opensource.com/article/19/12/jumping-python-platformer-game)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
Add jumping to your Python platformer game
为你的 Python 平台类游戏添加跳跃功能
======
Learn how to fight gravity with jumping in this installment on
programming video games with Python's Pygame module.
![Arcade games][1]
在本期使用 Python Pygame 模块编写视频游戏中,学会如何使用跳跃来对抗重力。
![游戏厅中的游戏][1]
In the [previous article][2] in this series, you simulated gravity, but now you need to give your player a way to fight against gravity by jumping.
在本系列的 [前一篇文章][2] 中,你已经模拟了重力。但现在,你需要赋予你的角色跳跃的能力来对抗重力。
A jump is a temporary reprieve from gravity. For a few moments, you jump _up_ instead of falling down, the way gravity is pulling you. But once you hit the peak of your jump, gravity kicks in again and pulls you back down to earth.
跳跃是对重力作用的暂时延缓。在这一小段时间里你是向_上_跳而不是被重力拉着向下落。但你一旦到达了跳跃的最高点重力就会重新发挥作用将你拉回地面。
In code, this translates to variables. First, you must establish variables for the player sprite so that Python can track whether or not the sprite is jumping. Once the player sprite is jumping, then gravity is applied to the player sprite again, pulling it back down to the nearest object.
在代码中,跳跃被表示为变量。首先,你需要为玩家对象建立一个变量,使得 Python 能够跟踪对象是否正在跳跃中。一旦玩家对象开始跳跃,他就会再次受到重力的作用,并被拉回最近的物体。
### Setting jump state variables
### 设置跳跃状态变量
You must add two new variables to your Player class:
你需要为你的 Player 类添加两个新变量:
* One to track whether your player is jumping or not, determined by whether or not your player sprite is standing on solid ground
* One to bring the player back down to the ground
* 一个是为了跟踪你的角色是否正在跳跃中,可通过你的玩家对象是否站在坚实的地面来确定
* 一个是为了将玩家带回地面
Add these variables to your **Player** class. In the following code, the lines above the comment are for context, so just add the final two lines:
将如下两个变量添加到你的 **Player** 类中。在下方的代码中,注释前的部分用于提示上下文,因此只需要添加最后两行:
```
@ -36,20 +35,20 @@ Add these variables to your **Player** class. In the following code, the lines a
                self.movey = 0
                self.frame = 0
                self.health = 10
                # gravity variables here
                # 此处是重力相关变量
                self.collide_delta = 0
                self.jump_delta = 6
```
The first variable (**collide_delta**) is set to 0 because, in its natural state, the player sprite is not in a mid-jump. The other variable (**jump_delta**) is set to 6 to prevent the sprite from bouncing (actually, jumping) when it first lands in the game world. When you've finished this article's examples, try setting it to 0 to see what happens.
第一个变量 **collide_delta** 被设为 0 是因为在正常状态下,玩家对象没有处在跳跃中的状态。另一个变量 **jump_delta** 被设为 6是为了防止对象在第一次进入游戏世界时就发生反弹实际上就是跳跃。当你完成了本篇文章的示例尝试把该变量设为 0 看看会发生什么。
### Colliding mid-jump
### 跳跃中的碰撞
If you jump on a trampoline, your jumps are pretty impressive. But what would happen if you jumped into a wall? (Don't try it to find out!) Your jump, no matter how impressively it started, would end very quickly when you collide with something much larger and much more solid than you.
如果你是跳到一个蹦床上,那你的跳跃一定非常优美。但是如果你是跳向一面墙会发生什么呢?(千万不要去尝试!)不管你的起跳多么令人印象深刻,当你撞到比你更大更硬的物体时,你都会立马停下。(译注:原理参考动量守恒定律)
To mimic this in your video game, you must set the **self.collide_delta** variable to 0 whenever your player sprite collides with something, like the ground. If **self.collide_delta** is anything other than 0, then your player is jumping, and your player can't jump when it hits a wall or the ground.
为了在你的视频游戏中模拟这一点,你需要在你的玩家对象与地面等东西发生碰撞时,将 **self.collide_delta** 变量设为 0。如果你的 **self.collide_delta** 不是 0 而是其它的什么值,那么你的玩家就会发生跳跃,并且当你的玩家与墙或者地面发生碰撞时无法跳跃。
In the **update** function of your **Player** class, modify the ground collision block to look like this:
在你的 **Player** 类的 **update** 方法中,将地面碰撞相关代码块修改为如下所示:
```
@ -57,54 +56,54 @@ In the **update** function of your **Player** class, modify the ground collision
        for g in ground_hit_list:
            self.movey = 0
            self.rect.y = worldy-ty-ty
            self.collide_delta = 0 # stop jumping
            self.collide_delta = 0 # 停止跳跃
            if self.rect.y &gt; g.rect.y:
                self.health -=1
                print(self.health)
```
This code block checks for collisions happening between the ground sprites and the player sprite. In the event of a collision, it sets the Y-position of the player to a value equal to the height of the game window (**worldy**) minus the height of a tile minus the height of another tile (so that the player sprite appears to be standing on top of the ground and not in the middle of it). It also sets **self.collide_delta** to 0 so that the program is aware that the player is not in mid-jump. Additionally, it sets **self.movey** to 0 so that the program is aware that the player is not being pulled by gravity (it's a quirk of game physics that you don't need to continue to pull your player toward earth once the player has been grounded).
这段代码块检查了地面对象和玩家对象之间发生的碰撞。当发生碰撞时,它会将玩家 Y 方向的坐标值设置为游戏窗口的高度减去一个瓷贴的高度再减去另一个瓷贴的高度。以此保证了玩家对象是站在地面**上**,而不是嵌在地面里。同时它也将 **self.collide_delta** 设为 0使得程序能够知道玩家未处在跳跃中。除此之外它将 **self.movey** 设为 0使得程序能够知道玩家当前未受到重力的牵引作用这是游戏物理引擎的奇怪之处一旦玩家落地也就没有必要继续将玩家拉向地面
The **if** statement detects whether the player has descended _below_ the level of the ground; if so, it deducts health points as a penalty. This assumes that you want your player to lose health points for falling off the world. That's not strictly necessary; it's just a common convention in platformers. More than likely, you want this event to trigger something, though, or else your real-world player will be stuck playing a game with a sprite that's fallen off the screen. An easy recovery is to set **self.rect.y** to 0 again so that when the player sprite falls off the world, it respawns at the top of the world and falls back onto solid ground.
此处 **if** 语句用来检测玩家是否已经落到地面之_下_如果是那就扣除一点生命值作为惩罚。此处假定了你希望当你的玩家落到地图之外时失去生命值。这个设定不是必需的它只是平台类游戏的一种惯例。更有可能的是你希望这个事件能够触发另一些事件或者说是一种能够让你的现实世界玩家沉迷于让对象掉到屏幕之外的东西。一种简单的恢复方式是在玩家对象掉落到地图之外时**self.rect.y** 重新设置为 0这样它就会在地图上方重新生成并落到坚实的地面上。
### Hitting the ground
### 撞向地面
Your simulated gravity wants your player's Y-axis movement to be 0 or more. To create a jump, write code that sends your player sprite off solid ground and into the air.
模拟的重力使你玩家的 Y 坐标不断增大(译注:此处原文中为 0但在 Pygame 中越靠下方 Y 坐标应越大)。要实现跳跃,完成如下代码使你的玩家对象离开地面,飞向空中。
In the **update** function of your **Player** class, add a temporary reprieve from gravity:
在你的 **Player** 类的 **update** 方法中,添加如下代码来暂时延缓重力的作用:
```
        if self.collide_delta &lt; 6 and self.jump_delta &lt; 6:
            self.jump_delta = 6*2
            self.movey -= 33  # how high to jump
            self.movey -= 33  # 跳跃的高度
            self.collide_delta += 6
            self.jump_delta    += 6
```
According to this code, a jump sends the player sprite 33 pixels into the air. It's _negative_ 33 because a lower number in Pygame means it's closer to the top of the screen.
根据此代码所示,跳跃使玩家对象向空中移动了 33 个像素。此处是_负_ 33 是因为在 Pygame 中,越小的数代表距离屏幕顶端越近。
This event is conditional, though. It only happens if **self.collide_delta** is less than 6 (its default value established in the **init** function of your **Player** sprite) and if **self.jump_delta** is less than 6. This condition prevents the player from triggering another jump until it collides with a platform. In other words, it prevents mid-air jumps.
不过此事件视条件而定,只有当 **self.collide_delta** 小于 6缺省值定义在你 **Player** 类的 **init** 方法中)并且 **self.jump_delta** 也于 6 的时候才会发生。此条件能够保证直到玩家碰到一个平台,才能触发另一次跳跃。换言之,它能够阻止空中二段跳。
You don't have to prevent mid-air jumps, or you can allow for mid-air jumps under special conditions; for instance, if a player obtains a special loot item, then you could grant it the ability to perform mid-air jumps until the next time it is hit by an enemy.
在某些特殊条件下,你可能不想阻止空中二段跳,或者说你允许玩家进行空中二段跳。举个栗子,如果玩家获得了某个战利品,那么在他被敌人攻击到之前,都能够拥有空中二段跳的能力。
When you've finished this article's examples, try setting **self.collide_delta** and **self.jump_delta** to 0 for a 100% chance to jump in mid-air.
当你完成本篇文章中的示例,尝试将 **self.collide_delta****self.jump_delta** 设置为 0从而获得百分之百的几率触发空中二段跳。
### Landing on a platform
### 在平台上着陆
So far, you've defined an anti-gravity condition for when the player sprite hits the ground, but the game code keeps platforms and the ground in separate lists. (As with so many choices made in this article, that's not strictly necessary, and you can experiment with treating the ground as just another platform.) To enable a player sprite to stand on top of a platform, you must detect a collision between the player sprite and a platform sprite and then perform the same actions as you did for a ground collision. Place this code into your **update** function:
目前你已经定义了再玩家对象摔落地面时的抵抗重力条件,但此时你的游戏代码仍保持平台与地面置于不同的列表中(就像本文中做的很多其他选择一样,这个设定并不是必需的,你可以尝试将地面作为另一种平台)。为了允许玩家对象站在平台之上,你必须像检测地面碰撞一样,检测玩家对象与平台对象之间的碰撞。将如下代码放于你的 **update** 方法中:
```
        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.collide_delta = 0 # stop jumping
            self.collide_delta = 0 # 跳跃结束
            self.movey = 0
```
There's one additional concern, though: platforms hang in the air, meaning the player can interact with them by approaching them from either the top or the bottom.
但此处还有一点需要考虑:平台悬在空中,也就意味着玩家可以通过从上面或者从下面接触平台来与之互动。
It's up to you how you want the platforms to react to your player. It's not uncommon to block a player from accessing a platform from below. Add this code to the above code block to treat platforms as a sort of ceiling or pergola, such that the player sprite can jump onto a platform as long as it jumps higher than the platform's topside, but obstructs the player when it tries to jump from beneath:
确定平台如何与玩家互动取决于你,阻止玩家从下方到达平台也并不稀奇。将如下代码加到上方的代码块中,使得平台表现得像天花板或者说是藤架。只有在玩家对象跳得比平台上沿更高时才能跳到平台上,但会阻止玩家从平台下方跳上来:
```
@ -114,17 +113,17 @@ It's up to you how you want the platforms to react to your player. It's not unco
                self.rect.y = p.rect.y-ty
```
The first clause of this **if** statement blocks the player from accessing a platform when the player sprite is directly under the platform. It does this by detecting that the player sprite's position is greater (in Pygame, that means lower on the screen, from top to bottom), and then sets the player sprite's new Y position to its current Y position plus the height of a tile, effectively keeping the player one tile's height away from ever passing through a platform from beneath it.
此处 **if** 语句代码块的第一个子句阻止玩家对象从平台正下方跳到平台上。如果它检测到玩家对象的坐标比平台更大(在 Pygame 中,坐标更大意味着在屏幕的更下方),那么将玩家对象新的 Y 坐标设置为当前平台的 Y 坐标加上一个瓷贴的高度。实际效果就是保证玩家对象距离平台一个瓷贴的高度,防止其从下方穿过平台。
The **else** clause does the opposite. If the program is running this code, then the player sprite's Y position is _not_ greater than the platforms, meaning that the player sprite is falling from the sky (either because it has been freshly spawned there or because the player has jumped). In this event, the player sprite's position is set to the position of the platform minus one tile's height (because, remember, in Pygame, lower numbers mean something is higher up on the screen). This keeps the player on top of the platform unless it jumps or walks off of it.
**else** 子句做了相反的事情。当程序运行到此处时,如果玩家对象的 Y 坐标_不_比平台的更大意味着玩家对象是从空中落下不论是由于玩家刚刚从此处生成或者是玩家执行了跳跃。在这种情况下玩家对象的 Y 坐标被设为平台的 Y 坐标减去一个瓷贴的高度(切记,在 Pygame 中更小的 Y 坐标代表在屏幕上的更高处。这样就能保证玩家在平台_上_除非他从平台上跳下来或者走下来。
You can experiment with other ways of dealing with sprite and platform interaction. For instance, maybe the player is assumed to be "in front" of the platforms and can seamlessly jump through them to stand on top of one. Or a platform could slow a player's leap but not block it entirely. You can even mix and match by grouping platforms into different lists.
你也可以尝试其他的方式来处理玩家与平台之间的互动。举个栗子,也许玩家对象被设定为处在平台的“前面”,他能够无障碍地跳跃穿过平台并站在上面。或者你可以设计一种平台会减缓而又不完全阻止玩家的跳跃过程。甚至你可以通过将不同平台分到不同列表中来混合搭配使用。
### Triggering a jump
### 触发一次跳跃
Your code now simulates all the necessary jump conditions, but it still lacks a jump trigger. Your player sprite's **self.jump_delta** is set to 6 initially, and the jump update code is triggered only when it's less than 6.
目前为此,你的代码已经模拟了所有必需的跳跃条件,但仍缺少一个跳跃触发器。你的玩家对象的 **self.jump_delta** 初始值被设置为 6只有当它比 6 小时才会触发更新跳跃的代码。
To trigger a new setting for the jumping variable, create a **jump** function in your **Player** class that sets the **self.jump_delta** to less than 6, causing gravity to be temporarily reprieved by sending your player sprite 33 pixels into the air:
为跳跃变量设置一个新的设置方法,在你的 **Player** 类中创建一个 **jump** 方法,并将 **self.jump_delta** 设为小于 6 的值。通过使玩家对象向空中移动 33 个像素,来暂时减缓重力的作用。
```
@ -132,17 +131,17 @@ To trigger a new setting for the jumping variable, create a **jump** function in
        self.jump_delta = 0
```
That's all the **jump** function requires, believe it or not. The rest happens in the **update** function, and you've already written that code.
不管你相信与否,这就是 **jump** 方法的全部。剩余的部分在 **update** 方法中,你已经在前面实现了相关代码。
There's one last thing to do before jumping is functional in your game. If you can't think of what it is, try playing your game to see how jumping works for you.
要使你游戏中的跳跃功能生效,还有最后一件事情要做。如果你想不起来是什么,运行游戏并观察跳跃是如何生效的。
The problem is that nothing in your main loop is calling the **jump** function. You made a placeholder keypress for it early on, but right now, all the jump key does is print **jump** to the terminal.
问题就在于你的主循环中没有调用 **jump** 方法。先前你已经为该方法创建了一个按键占位符,现在,跳跃键所做的就是将 **jump** 打印到终端。
### Calling the jump function
### 调用 jump 方法
In your main loop, change the result of the Up arrow from printing a debug statement to calling the **jump** function.
在你的主循环中将_上_方向键的效果从打印一条调试语句改为调用 **jump** 方法。
Notice that the **jump** function, like the **update** function, needs to know about collisions, so you have to tell it which **plat_list** to use.
注意此处,与 **update** 方法类似,**jump** 方法也需要检测碰撞,因此你需要告诉它使用哪个 **plat_list**
```
@ -150,13 +149,13 @@ Notice that the **jump** function, like the **update** function, needs to know a
                player.jump(plat_list)
```
If you would rather use the Spacebar for jumping, set the key to **pygame.K_SPACE** instead of **pygame.K_UP**. Alternately, you can use both (as separate **if** statements) so that the player has a choice.
如果你倾向于使用空格键作为跳跃键,使用 **pygame.K_SPACE** 替代 **pygame.K_UP** 作为按键。另一种选择,你可以同时使用两种方式(使用单独的 **if** 语句),给玩家多一种选择。
Try your game now. In the next article, you'll make your world scroll.
现在来尝试你的游戏吧!在下一篇文章中,你将让你的游戏卷动起来。
![Pygame platformer][3]
![Pygame 平台类游戏][3]
Here's all the code so far:
以下是目前为止的所有代码:
```
@ -184,7 +183,7 @@ Objects
'''
class Platform(pygame.sprite.Sprite):
    # x location, y location, img width, img height, img file    
# x 坐标y 坐标,图像宽度,图像高度,图像文件
    def __init__(self,xloc,yloc,imgw,imgh,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images',img)).convert()
@ -195,7 +194,7 @@ class Platform(pygame.sprite.Sprite):
class Player(pygame.sprite.Sprite):
    '''
    Spawn a player
    生成一个玩家
    '''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
@ -227,34 +226,34 @@ class Player(pygame.sprite.Sprite):
       
    def control(self,x,y):
        '''
        control player movement
        控制玩家移动
        '''
        self.movex += x
        self.movey += y
       
    def update(self):
        '''
        Update sprite position
        更新对象位置
        '''
       
        self.rect.x = self.rect.x + self.movex
        self.rect.y = self.rect.y + self.movey
        # moving left
        # 向左移动
        if self.movex &lt; 0:
            self.frame += 1
            if self.frame &gt; ani*3:
                self.frame = 0
            self.image = self.images[self.frame//ani]
        # moving right
        # 向右移动
        if self.movex &gt; 0:
            self.frame += 1
            if self.frame &gt; ani*3:
                self.frame = 0
            self.image = self.images[(self.frame//ani)+4]
        # collisions
        # 碰撞
        enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
        for enemy in enemy_hit_list:
            self.health -= 1
@ -286,7 +285,7 @@ class Player(pygame.sprite.Sprite):
           
class Enemy(pygame.sprite.Sprite):
    '''
    Spawn an enemy
    生成一个敌人
    '''
    def __init__(self,x,y,img):
        pygame.sprite.Sprite.__init__(self)
@ -302,7 +301,7 @@ class Enemy(pygame.sprite.Sprite):
               
    def move(self):
        '''
        enemy movement
        敌人移动
        '''
        distance = 80
        speed = 8
@ -337,9 +336,9 @@ class Enemy(pygame.sprite.Sprite):
class Level():
    def bad(lvl,eloc):
        if lvl == 1:
            enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
            enemy_list = pygame.sprite.Group() # create enemy group
            enemy_list.add(enemy)              # add enemy to group
            enemy = Enemy(eloc[0],eloc[1],'yeti.png') # 生成敌人
            enemy_list = pygame.sprite.Group() # 创建敌人组
            enemy_list.add(enemy)              # 将敌人添加到敌人组
           
        if lvl == 2:
            print("Level " + str(lvl) )
@ -392,8 +391,8 @@ Setup
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4  # animation cycles
fps = 40 # 帧率
ani = 4  # 动画循环
clock = pygame.time.Clock()
pygame.init()
main = True
@ -406,7 +405,7 @@ ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player = Player() # 生成玩家
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
@ -418,8 +417,8 @@ eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
tx = 64 # 瓷贴尺寸
ty = 64 # 瓷贴尺寸
i=0
while i &lt;= (worldx/tx)+tx:
@ -431,7 +430,7 @@ ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
'''
Main loop
主循环
'''
while main == True:
    for event in pygame.event.get():
@ -464,26 +463,26 @@ while main == True:
#    world.fill(BLACK)
    world.blit(backdrop, backdropbox)
    player.gravity() # check gravity
    player.gravity() # 检查重力
    player.update()
    player_list.draw(world) #refresh player position
    enemy_list.draw(world)  # refresh enemies
    ground_list.draw(world)  # refresh enemies
    plat_list.draw(world)   # refresh platforms
    player_list.draw(world) # 刷新玩家位置
    enemy_list.draw(world)  # 刷新敌人
    ground_list.draw(world)  # 刷新地面
    plat_list.draw(world)   # 刷新平台
    for e in enemy_list:
        e.move()
    pygame.display.flip()
    clock.tick(fps)
```
This is the 7th installment in an ongoing series about creating video games in [Python 3][4] using the [Pygame][5] module. Previous articles are:
本期是使用 [Pygame][5] 模块在 [Python 3][4] 中创建视频游戏连载系列的第 7 期。往期文章为:
* [Learn how to program in Python by building a simple dice game][6]
* [Build a game framework with Python using the Pygame module][7]
* [How to add a player to your Python game][8]
* [Using Pygame to move your game character around][9]
* [What's a hero without a villain? How to add one to your Python game][10]
* [Simulate gravity in your Python game][2]
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][6]
* [使用 Python 和 Pygame 模块构建一个游戏框架][7]
* [如何在你的 Python 游戏中添加一个玩家][8]
* [用 Pygame 使你的游戏角色移动起来][9]
* [如何向你的 Python 游戏中添加一个敌人][10]
* [在你的 Python 游戏中模拟重力][2]
@ -493,7 +492,7 @@ via: https://opensource.com/article/19/12/jumping-python-platformer-game
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
译者:[cycoe](https://github.com/cycoe)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出