【发布时间】: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