栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

在pygame中将滚动添加到平台游戏

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在pygame中将滚动添加到平台游戏

绘制实体时,你需要将偏移量应用于实体的位置。我们称这个偏移量为

a camera
,因为这是我们想要达到的效果。

首先,我们无法使用

drawSprite
群组的功能,因为
Sprite不
需要知道其位置
(rect)
并非要在屏幕上绘制的位置(最后,我们ll对该
Group
类进行子类化,并重新实现它draw以了解摄像头,但让我们开始慢一点)。

让我们从创建一个

Camera
类开始,以保存要应用于实体位置的偏移量的状态:

class Camera(object):    def __init__(self, camera_func, width, height):        self.camera_func = camera_func        self.state = Rect(0, 0, width, height)    def apply(self, target):        return target.rect.move(self.state.topleft)    def update(self, target):        self.state = self.camera_func(self.state, target.rect)

这里要注意一些事情:

我们需要存储摄像机的位置以及水平的宽度和高度(以像素为单位)(因为我们要停止在水平边缘进行滚动)。我曾经使用

a Rect
来存储所有这些信息,但是你可以轻松地使用一些字段。

使用

Rect
派上用场的
apply
功能。在这里我们重新计算实体在屏幕上的位置以应用滚动。

每个主循环迭代一次,我们需要更新摄影机的位置,因此有了

update
功能。它只是通过调用
camera_func
函数来改变状态,这将为我们完成所有艰苦的工作。我们稍后实施。

让我们创建一个摄影机的实例:

for row in level:    ...total_level_width  = len(level[0])*32 # calculate size of level in pixelstotal_level_height = len(level)*32    # maybe make 32 an constantcamera = Camera(*to_be_implemented*, total_level_width, total_level_height)entities.add(player)... 

并更改我们的主循环:

# draw backgroundfor y in range(32):    ...camera.update(player) # camera follows player. Note that we could also follow any other sprite# update player, draw everything elseplayer.update(up, down, left, right, running, platforms)for e in entities:    # apply the offset to each entity.    # call this for everything that should scroll,    # which is basically everything other than GUI/HUD/UI    screen.blit(e.image, camera.apply(e)) pygame.display.update()

我们的摄像头课程已经非常灵活,但是非常简单。它可以使用不同种类的滚动(通过提供不同的

camera_func
功能),并且可以跟随任何变态的精灵,而不仅仅是播放器。你甚至可以在运行时更改此设置。

现在用于实施

camera_func
。一种简单的方法是将播放器(或我们要跟随的任何实体)居中放在屏幕上,实现很简单:

def simple_camera(camera, target_rect):    l, t, _, _ = target_rect # l = left,  t = top    _, _, w, h = camera      # w = width, h = height    return Rect(-l+HALF_WIDTH, -t+HALF_HEIGHT, w, h)

我们只是将放在位置target,然后加上一半的总屏幕尺寸。你可以通过以下方式创建相机来尝试:

camera = Camera(simple_camera, total_level_width, total_level_height)

到目前为止,一切都很好。但是也许我们不想看到关卡外面的黑色背景?怎么样:

def complex_camera(camera, target_rect):    # we want to center target_rect    x = -target_rect.center[0] + WIN_WIDTH/2     y = -target_rect.center[1] + WIN_HEIGHT/2    # move the camera. Let's use some vectors so we can easily substract/multiply    camera.topleft += (pygame.Vector2((x, y)) - pygame.Vector2(camera.topleft)) * 0.06 # add some smoothness coolnes    # set max/min x/y so we don't see stuff outside the world    camera.x = max(-(camera.width-WIN_WIDTH), min(0, camera.x))    camera.y = max(-(camera.height-WIN_HEIGHT), min(0, camera.y))    return camera

在这里,我们仅使用min/ max函数以确保我们不会向外滚动。

像这样创建相机来尝试一下:

camera = Camera(complex_camera, total_level_width, total_level_height)

我们的最终滚动效果有点动画:

在此处输入图片说明

再次是完整的代码。注意我更改了一些内容:

  • 级别更大,并拥有更多平台
  • 使用python 3
  • 使用精灵组来处理相机
  • 重构了一些重复的代码
  • 由于Vector2 / 3现在很稳定,因此请使用它们来简化数学运算
  • 摆脱丑陋的事件处理代码,
    pygame.key.get_pressed
    而改用
 #! /usr/bin/pythonimport pygamefrom pygame import *SCREEN_SIZE = pygame.Rect((0, 0, 800, 640))TILE_SIZE = 32 GRAVITY = pygame.Vector2((0, 0.3))class CameraAwareLayeredUpdates(pygame.sprite.LayeredUpdates):    def __init__(self, target, world_size):        super().__init__()        self.target = target        self.cam = pygame.Vector2(0, 0)        self.world_size = world_size        if self.target: self.add(target)    def update(self, *args):        super().update(*args)        if self.target: x = -self.target.rect.center[0] + SCREEN_SIZE.width/2 y = -self.target.rect.center[1] + SCREEN_SIZE.height/2 self.cam += (pygame.Vector2((x, y)) - self.cam) * 0.05 self.cam.x = max(-(self.world_size.width-SCREEN_SIZE.width), min(0, self.cam.x)) self.cam.y = max(-(self.world_size.height-SCREEN_SIZE.height), min(0, self.cam.y))    def draw(self, surface):        spritedict = self.spritedict        surface_blit = surface.blit        dirty = self.lostsprites        self.lostsprites = []        dirty_append = dirty.append        init_rect = self._init_rect        for spr in self.sprites(): rec = spritedict[spr] newrect = surface_blit(spr.image, spr.rect.move(self.cam)) if rec is init_rect:     dirty_append(newrect) else:     if newrect.colliderect(rec):         dirty_append(newrect.union(rec))     else:         dirty_append(newrect)         dirty_append(rec) spritedict[spr] = newrect        return dirty def main():    pygame.init()    screen = pygame.display.set_mode(SCREEN_SIZE.size)    pygame.display.set_caption("Use arrows to move!")    timer = pygame.time.Clock()    level = [        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",        "P         P",        "P         P",        "P         P",        "P         PPPPPPPPPPPP",        "P         P",        "P         P",        "P         P",        "P    PPPPPPPP        P",        "P         P",        "P    PPPPPPP         P",        "P      PPPPPP        P",        "P         P",        "P         PPPPPPP    P",        "P         P",        "P          PPPPPP    P",        "P         P",        "P   PPPPPPPPPPP      P",        "P         P",        "P      PPPPPPPPPPP   P",        "P         P",        "P         P",        "P         P",        "P         P",        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]    platforms = pygame.sprite.Group()    player = Player(platforms, (TILE_SIZE, TILE_SIZE))    level_width  = len(level[0])*TILE_SIZE    level_height = len(level)*TILE_SIZE    entities = CameraAwareLayeredUpdates(player, pygame.Rect(0, 0, level_width, level_height))    # build the level    x = y = 0    for row in level:        for col in row: if col == "P":     Platform((x, y), platforms, entities) if col == "E":     ExitBlock((x, y), platforms, entities) x += TILE_SIZE        y += TILE_SIZE        x = 0    while 1:        for e in pygame.event.get(): if e.type == QUIT:      return if e.type == KEYDOWN and e.key == K_ESCAPE:     return        entities.update()        screen.fill((0, 0, 0))        entities.draw(screen)        pygame.display.update()        timer.tick(60)class Entity(pygame.sprite.Sprite):    def __init__(self, color, pos, *groups):        super().__init__(*groups)        self.image = Surface((TILE_SIZE, TILE_SIZE))        self.image.fill(color)        self.rect = self.image.get_rect(topleft=pos)class Player(Entity):    def __init__(self, platforms, pos, *groups):        super().__init__(Color("#0000FF"), pos)        self.vel = pygame.Vector2((0, 0))        self.onGround = False        self.platforms = platforms        self.speed = 8        self.jump_strength = 10    def update(self):        pressed = pygame.key.get_pressed()        up = pressed[K_UP]        left = pressed[K_LEFT]        right = pressed[K_RIGHT]        running = pressed[K_SPACE]        if up: # only jump if on the ground if self.onGround: self.vel.y = -self.jump_strength        if left: self.vel.x = -self.speed        if right: self.vel.x = self.speed        if running: self.vel.x *= 1.5        if not self.onGround: # only accelerate with gravity if in the air self.vel += GRAVITY # max falling speed if self.vel.y > 100: self.vel.y = 100        print(self.vel.y)        if not(left or right): self.vel.x = 0        # increment in x direction        self.rect.left += self.vel.x        # do x-axis collisions        self.collide(self.vel.x, 0, self.platforms)        # increment in y direction        self.rect.top += self.vel.y        # assuming we're in the air        self.onGround = False;        # do y-axis collisions        self.collide(0, self.vel.y, self.platforms)    def collide(self, xvel, yvel, platforms):        for p in platforms: if pygame.sprite.collide_rect(self, p):     if isinstance(p, ExitBlock):         pygame.event.post(pygame.event.Event(QUIT))     if xvel > 0:         self.rect.right = p.rect.left     if xvel < 0:         self.rect.left = p.rect.right     if yvel > 0:         self.rect.bottom = p.rect.top         self.onGround = True         self.yvel = 0     if yvel < 0:         self.rect.top = p.rect.bottomclass Platform(Entity):    def __init__(self, pos, *groups):        super().__init__(Color("#DDDDDD"), pos, *groups)class ExitBlock(Platform):    def __init__(self, pos, *groups):        super().__init__(Color("#0033FF"), pos, *groups)if __name__ == "__main__":    main()


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/414829.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号