Я создаю 2-мерный мир на основе тайлов для игры - в значительной степени под влиянием Pokemon - используя pygame / python, Tiled для файлов .tmx и библиотеку tmx Ричарда Джонса. Код, который я использую, в основном основан на этой замечательной демонстрации Pallet Town на Python.
Игра работает нормально, однако у меня возникают проблемы с тем, чтобы плитки на карте (например, дома, деревья) перекрывали спрайт игрока, когда было бы разумно, чтобы спрайт игрока исчез за ними. Например: на изображении здесь принципы восприятия глубины говорят нам, что дом на переднем плане должен перекрывать игрок в фоновом режиме, но поскольку карта 2D, нет глубины и, следовательно, нет окклюзии. Я бы хотел добавить глубины, но, поскольку я новичок в pygame (и python в целом), я не понимаю, как рисовать соответствующие объекты переднего плана поверх спрайта.
К счастью, я не одинок в этой проблеме, и существует множество документации о возможных решениях. Например:
Однако этот код обычно не пишется для python, и я не уверен, как его реализовать в моей ситуации. Сортировка / рисование по положению z (или по свойству «глубины») кажется наиболее разумным, но, глядя на библиотеку tmx, я могу найти только упомянутые значения x и y. Добавление спрайта игрока к пустому объектному слою в Tiled также является решением, но я снова не знаю, как это сделать, и все мои попытки приводили к сообщениям об ошибках. (Попытки здесь не описаны, потому что я, честно говоря, не знаю, что делал, и это все равно не сработало.)
Мой текущий код выглядит следующим образом:
class Player(pygame.sprite.Sprite):
def __init__(self, location, collStart, orientation, *groups):
super(Player, self).__init__(*groups)
self.image = pygame.image.load('sprites/player.png')
self.imageDefault = self.image.copy()
self.rect = pygame.Rect(location, (26,26))
self.collider = pygame.Rect(collStart, (13,13))
self.orient = orientation
self.holdTime = 0
self.walking = False
self.dx = 0
self.step = 'rightFoot'
# Set default orientation
self.setSprite()
self.speed = pygame.time.get_ticks() + 50 # slows down walking speed
by .5 sec (current time + 50 ms)
def setSprite(self):
# this function contains information about where to find which sprite
in the sprite sheet, probably not relevant here.
def update(self, dt, game):
key = pygame.key.get_pressed()
if pygame.time.get_ticks() >= self.speed:
self.speed = pygame.time.get_ticks() + 50
# Setting orientation and sprite based on key input, removed the
#code here because it wasn't relevant
#[....]
# Walking mode enabled if a button is held for 0.1 seconds
if self.holdTime >= 100:
self.walking = True
lastRect = self.rect.copy()
lastColl = self.collider.copy() # collider covers the bottom section of the sprite
# Code for walking in the direction the player is facing, not relevant here
#[....]
# Collision detection:
# Reset to the previous rectangle if player collides
# with anything in the foreground layer
if len(game.tilemap.layers['triggers'].collide(self.collider,
'solid')) > 0:
self.rect = lastRect
self.collider = lastColl
# Area entry detection, loads dialog screen from the dialog file:
elif len(game.tilemap.layers['triggers'].collide(self.collider,
'entry')) > 0:
entryCell = game.tilemap.layers['triggers'].find('entry')[0]
game.fadeOut()
run()
pygame.quit()
quit()
return
if self.dx == 16:
# Makes the player appear to take steps w/ different feet, not relevant here
#[....]
# After traversing 32 pixels, the walking animation is done
if self.dx == 32:
self.walking = False
self.setSprite()
self.dx = 0
game.tilemap.set_focus(self.rect.x, self.rect.y)
class Game(object):
def __init__(self, screen):
self.screen = screen
def initArea(self, mapFile):
"""Load maps and initialize sprite layers for each new area"""
self.tilemap = tmx.load(mapFile, screen.get_size())
self.players = tmx.SpriteLayer()
self.objects = tmx.SpriteLayer()
# In case there is no sprite layer for the current map
except KeyError:
pass
else:
self.tilemap.layers.append(self.objects)
# Initializing player sprite
startCell = self.tilemap.layers['triggers'].find('playerStart')[0]
self.player = Player((startCell.px, startCell.py), (startCell.px,
startCell.bottom-4),
startCell['playerStart'], self.players)
self.tilemap.layers.append(self.players)
self.tilemap.set_focus(self.player.rect.x, self.player.rect.y)
def main(self):
clock = pygame.time.Clock()
self.initArea('test tilemap.tmx')
while 1:
dt = clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
self.tilemap.update(dt, self)
screen.fill((0,0,0))
self.tilemap.draw(self.screen)
pygame.display.flip()
Я снова использую библиотеку tmx, которую можно найти здесь. Может там что-то нужно поменять? Надеюсь, кто-нибудь поможет мне разобраться в этом. Это определенно возможно, как показывает этот клон покемона на Python (к сожалению, исходный код недоступен) . Кроме того, впервые пользователь StackOverflow, поэтому дайте мне знать, если я совершаю какие-либо ложные проходы :)