---
author: Seth Kenlon
category: 软件开发
comments_data: []
count:
  commentnum: 0
  favtimes: 0
  likes: 0
  sharetimes: 0
  viewnum: 3697
date: '2020-01-25 22:07:00'
editorchoice: false
excerpt: 使用 Pygame 模块来使你的 Python 平台开启侧滚效果，来让你的玩家自由奔跑。
fromurl: https://opensource.com/article/19/12/python-platformer-game-run
id: 11819
islctt: true
largepic: /images/p/202001/25/220636x5mabbl47xvtsk55.jpg
permalink: /article-11819-1.html
pic: /images/p/202001/25/220636x5mabbl47xvtsk55.jpg.thumb.jpg
related:
- displayorder: 0
  raid: 11790
- displayorder: 0
  raid: 11828
reviewer: wxy
selector: lujun9972
summary: 使用 Pygame 模块来使你的 Python 平台开启侧滚效果，来让你的玩家自由奔跑。
tags:
- Pygame
thumb: false
title: 使你的 Python 游戏玩家能够向前和向后跑
titlepic: true
translator: robsean
updated: '2020-01-25 22:07:00'
---


> 
> 使用 Pygame 模块来使你的 Python 平台开启侧滚效果，来让你的玩家自由奔跑。
> 
> 
> 


![](/images/p/202001/25/220636x5mabbl47xvtsk55.jpg)


这是仍在进行中的关于使用 Pygame 模块来在 Python 3 中在创建电脑游戏的第九部分。先前的文章是：


* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程](/article-9071-1.html)
* [使用 Python 和 Pygame 模块构建一个游戏框架](/article-10850-1.html)
* [如何在你的 Python 游戏中添加一个玩家](/article-10858-1.html)
* [用 Pygame 使你的游戏角色移动起来](/article-10874-1.html)
* [如何向你的 Python 游戏中添加一个敌人](/article-10883-1.html)
* [在 Pygame 游戏中放置平台](/article-10902-1.html)
* [在你的 Python 游戏中模拟引力](/article-11780-1.html)
* [为你的 Python 平台类游戏添加跳跃功能](/article-11790-1.html)


在这一系列关于使用 [Pygame](https://www.pygame.org/news) 模块来在 [Python 3](https://www.python.org/) 中创建电脑游戏的先前文章中，你已经设计了你的关卡设计布局，但是你的关卡的一些部分可能已近超出你的屏幕的可视区域。在平台类游戏中，这个问题的普遍解决方案是，像术语“<ruby> 侧滚 <rt>  side-scroller </rt></ruby>”表明的一样，滚动。


滚动的关键是当玩家精灵接近屏的幕边缘时，使在玩家精灵周围的平台移动。这样给予一种错觉，屏幕是一个在游戏世界中穿梭追拍的摄像机。


这个滚动技巧需要两个在屏幕边缘的绝对区域，在绝对区域内的点处，在世界滚动期间，你的化身静止不动。


### 在侧滚动条中放置卷轴


如果你希望你的玩家能够后退，你需要一个触发点来向前和向后。这两个点仅仅是两个变量。设置它们各个距各个屏幕边缘大约 100 或 200 像素。在你的设置部分中创建变量。在下面的代码中，前两行用于上下文说明，所以仅需要添加这行后的代码：



```
player_list.add(player)
steps = 10
forwardX  = 600
backwardX = 230
```

在主循环中，查看你的玩家精灵是否在 `forwardx` 或 `backwardx` 滚动点处。如果是这样，向左或向右移动使用的平台，取决于世界是向前或向后移动。在下面的代码中，代码的最后三行仅供你参考：



```
        # scroll the world forward
        if player.rect.x >= forwardx:
                scroll = player.rect.x - forwardx
                player.rect.x = forwardx
                for p in plat_list:
                        p.rect.x -= scroll

        # scroll the world backward
        if player.rect.x <= backwardx:
                scroll = backwardx - player.rect.x
                player.rect.x = backwardx
                for p in plat_list:
                        p.rect.x += scroll

        ## scrolling code above
    world.blit(backdrop, backdropbox)
    player.gravity() # check gravity
    player.update()
```

启动你的游戏，并尝试它。


![Scrolling the world in Pygame](/images/p/202001/25/220744t1lg1nz1htuh564x.jpg "Scrolling the world in Pygame")


滚动像预期的一样工作，但是你可能注意到一个发生的小问题，当你滚动你的玩家和非玩家精灵周围的世界时：敌人精灵不随同世界滚动。除非你要你的敌人精灵要无休止地追逐你的玩家，你需要修改敌人代码，以便当你的玩家快速撤退时，敌人被留在后面。


### 敌人卷轴


在你的主循环中，你必须对卷轴平台为你的敌人的位置的应用相同的规则。因为你的游戏世界将（很可能）有不止一个敌人在其中，该规则应该被应用于你的敌人列表，而不是一个单独的敌人精灵。这是分组类似元素到列表中的优点之一。


前两行用于上下文注释，所以只需添加这两行后面的代码到你的主循环中：



```
    # scroll the world forward
    if player.rect.x >= forwardx:
        scroll = player.rect.x - forwardx
        player.rect.x = forwardx
        for p in plat_list:
            p.rect.x -= scroll
        for e in enemy_list:
            e.rect.x -= scroll
```

来滚向另一个方向：



```
    # scroll the world backward
    if player.rect.x <= backwardx:
        scroll = backwardx - player.rect.x
        player.rect.x = backwardx
        for p in plat_list:
            p.rect.x += scroll
        for e in enemy_list:
            e.rect.x += scroll
```

再次启动游戏，看看发生什么。


这里是到目前为止你已经为这个 Python 平台所写所有的代码：



```
#!/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
# add jumping
# add scrolling

# 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.collide_delta = 0
        self.jump_delta = 6
        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 jump(self,platform_list):
        self.jump_delta = 0

    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
       
    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)

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.collide_delta = 0 # stop jumping
            self.movey = 0
            if self.rect.y > p.rect.y:
                self.rect.y = p.rect.y+ty
            else:
                self.rect.y = p.rect.y-ty
           
        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.movey = 0
            self.rect.y = worldy-ty-ty
            self.collide_delta = 0 # stop jumping
            if self.rect.y > g.rect.y:
                self.health -=1
                print(self.health)
               
        if self.collide_delta < 6 and self.jump_delta < 6:
            self.jump_delta = 6*2
            self.movey -= 33  # how high to jump
            self.collide_delta += 6
            self.jump_delta    += 6
           
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.movey = 0
        #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

        self.movey += 3.2
       
        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

        if not self.rect.y >= worldy-ty-ty:
            self.rect.y += self.movey

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.movey = 0
            if self.rect.y > p.rect.y:
                self.rect.y = p.rect.y+ty
            else:
                self.rect.y = p.rect.y-ty

        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.rect.y = worldy-ty-ty

       
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
forwardx = 600
backwardx = 230

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'):
                player.jump(plat_list)

            if event.key == ord('q'):
                pygame.quit()
                sys.exit()
                main = False

    # scroll the world forward
    if player.rect.x >= forwardx:
        scroll = player.rect.x - forwardx
        player.rect.x = forwardx
        for p in plat_list:
            p.rect.x -= scroll
        for e in enemy_list:
            e.rect.x -= scroll
               
    # scroll the world backward
    if player.rect.x <= backwardx:
        scroll = backwardx - player.rect.x
        player.rect.x = backwardx
        for p in plat_list:
            p.rect.x += scroll
        for e in enemy_list:
            e.rect.x += scroll

    world.blit(backdrop, backdropbox)
    player.gravity() # check 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
    for e in enemy_list:
        e.move()
    pygame.display.flip()
    clock.tick(fps)
```



---


via: <https://opensource.com/article/19/12/python-platformer-game-run>


作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[robsean](https://github.com/robsean) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出