【问题标题】:Player sprite not behind isometric tiles玩家精灵不在等距图块后面
【发布时间】:2022-11-05 17:11:06
【问题描述】:

我目前正在尝试学习如何在游戏环境中使用等距地图。我正在使用 Tiled Map Editor 创建地图,并使用 PyTMX 和 Pygame 来读取和使用信息。我目前正在分层制作地图并将它们视为大精灵。这样我可以使用

'''

pygame.sprites.LayerUpdates

'''

这样做可以让我按顺序渲染:

地面

播放器

墙壁

但是,这给了我下图中显示的问题:

我已经在互联网上研究了解决方案,但我一直空白!我不确定是否应该在游戏开始时渲染一次图层,然后每帧对图层进行 blitting,或者我应该渲染一次地面层,因为那将是最低层(玩家精灵将始终打开该层的顶部),然后每帧渲染墙壁层,并检查播放器是在特定图块的前面还是后面,(我怀疑这可能需要大量处理)。

我已经包含了用于主​​游戏循环、精灵类和 TiledMap 阅读器的代码。我从互联网上学到的非常标准的东西。

class Game:
    def __init__(self):
        pg.mixer.pre_init(44100, -16, 1, 2048)
        pg.init()
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        pg.key.set_repeat(500, 100)
        self.load_data()
    
    def load_data(self):
        game_folder = path.dirname(__file__)
        self.map_folder = path.join(game_folder, 'maps')
        img_folder = path.join(game_folder, 'img')
        self.player_img = pg.image.load(path.join(img_folder,PLAYER_IMG)).convert_alpha()
        self.player_img = pg.transform.scale(self.player_img, PLAYER_SCALE)

    def new(self):
        self.all_sprites = pg.sprite.LayeredUpdates()
        self.wall_sprites = pg.sprite.Group()
        self.map = TiledMap(path.join(self.map_folder, LEVEL_MAPS), self)
        self.ground_map = Ground(self, self.map)
        self.wall_map = Walls(self, self.map)
        self.camera = Camera(self.ground_map.rect.width, self.ground_map.rect.height)
        for tile_object in self.map.tmxdata.objects:
            if tile_object.name == 'player':
                origin_x = ((self.map.width / 2))# - self.tilewidth / 2)
                tile_x = tile_object.x / self.map.tileheight
                tile_y = tile_object.y / self.map.tileheight
            
                offset = vec((tile_x - tile_y) * self.map.tilewidth / 2 + origin_x,
                             (tile_x + tile_y) * self.map.tileheight / 2)
                self.player = Player(self, offset.x, offset.y)
    
    def run(self):
        self.playing = True
        while self.playing:
            self.dt = self.clock.tick(FPS) / 1000
            self.update()
            self.events()
            self.draw()

    def update(self):
        self.all_sprites.update()
        self.camera.update(self.player)

    def draw(self):
        self.screen.fill(BLACK)
        pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        pg.display.flip()

    def quit(self):
        pg.quit()
        sys.exit()
    
    def events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.quit()
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    self.quit()
g = Game()

def main():
    while True:
        g.new()
        g.run()

if __name__ == '__main__':
    main()

精灵类

def isometric_render(layer, tiled_map):
    temp_surface = pg.Surface((tiled_map.width, tiled_map.height))
    current_layer = tiled_map.tmxdata.get_layer_by_name(layer)
    ti = tiled_map.tmxdata.get_tile_image_by_gid           
    if isinstance(current_layer, pytmx.TiledTileLayer):
        for x, y, gid in current_layer:
            if gid != 0:
                starting_x = ((tiled_map.width / 2) - tiled_map.tilewidth / 2)
                offset = vec(((x - y) * tiled_map.tilewidth / 2) + starting_x,
                             ((x + y) * tiled_map.tileheight / 2) - 370)
                tile = ti(gid)                
                if tile:
                    temp_surface.blit(tile, (offset.x, offset.y))
    return temp_surface

class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self._layer = PLAYER_LAYER
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = self.game.player_img
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)
        self.vel = vec(0, 0)
        self.pos = vec(x, y)
        self.rot = 0

class Ground(pg.sprite.Sprite):
    def __init__(self, game, tiled_map):
        self._layer = GROUND_LAYER
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = isometric_render('Ground', tiled_map)
        self.rect = self.image.get_rect()
        
class Walls(pg.sprite.Sprite):
    def __init__(self, game, tiled_map):
        self._layer = WALL_LAYER
        self.groups = game.all_sprites, game.wall_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = isometric_render('Walls', tiled_map)
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()

TiledMap 类

class TiledMap:
    def __init__(self, filename, game):
        tm = pytmx.load_pygame(filename, pixelalpha=True)
        self.tilewidth = tm.tilewidth
        self.tileheight = tm.tileheight
        self.game = game
        self.width = tm.width * tm.tilewidth
        self.height = tm.height * tm.tileheight
        self.tmxdata = tm

这是我的 GitHub 页面的链接,您可以在其中查看完整代码 Isometric Map loading practice GitHub Link

我希望这是有道理的,我只编程了大约一年,所以我的术语还没有达到标准。任何代码 sn-ps、教程链接或一般建议将不胜感激。

【问题讨论】:

  • 在绘制对象之前,您必须按对象的 y 坐标以相反的顺序对对象进行排序。
  • 谢谢兔子。我是否必须在 draw() 方法中的每一帧都渲染地图,或者我可以像在游戏类的 new() 方法中那样只做一次吗?

标签: python pygame tiled isometric pytmx


【解决方案1】:

您必须以正确的顺序绘制对象:

  1. 绘制等轴测图

  2. 按对象的较低 y 坐标对对象(玩家、楼梯等)进行排序,并从下到上渲染它们

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 2014-01-16
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    相关资源
    最近更新 更多