首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用pytmx、pygame在精确的时间启动动画对象

使用pytmx、pygame在精确的时间启动动画对象
EN

Stack Overflow用户
提问于 2021-07-14 03:41:50
回答 1查看 28关注 0票数 1

我遇到了麻烦,我正试图在我的游戏中打开大门。我正在使用pygame和pytmx,我已经建立了一个用房间制作的关卡,在每个房间我都有一个使用pytmx的渲染器,我想要实现的是在0级的例子中,玩家必须移动到一扇门打开它并进入1级,我的目标是当玩家敲门时启动并绘制动画。

我试着让我的门对象(他的父类是pygame Sprite类)更新,它已经起作用了,当然对象被修改和显示了,但是瓦片地图对象也在地图的后面,所以我试着不在瓦片地图中初始化我的对象,但如果这样的话门根本不会有任何变化。然后我试着修改瓦片对象图像并重新加载我的渲染,但仍然不能工作,你们中的任何人有什么想法吗?

下面是代码的一些部分,可以让您更好地理解

代码语言:javascript
复制
"""
This is a test of using the pytmx library with Tiled.
"""
import pygame
import pytmx


class Renderer(object):
    """
    This object renders tile maps from Tiled
    """
    def __init__(self, filename):
        tm = pytmx.load_pygame(filename, pixelalpha=True)
        self.object_images = []
        self.size = tm.width * tm.tilewidth, tm.height * tm.tileheight
        self.tmx_data = tm
        self.map_surface = self.make_map()
        self.current_frame = 0

    def render(self, surface):

        tw = self.tmx_data.tilewidth
        th = self.tmx_data.tileheight
        
        print(self.tmx_data.tile_properties.items())

        if self.tmx_data.background_color:
            surface.fill(self.tmx_data.background_color)

        for layer in self.tmx_data.layers:
            if isinstance(layer, pytmx.TiledTileLayer):
                for x, y, image in layer.tiles():
                    if image:
                        surface.blit(image.convert_alpha() , (x * tw, y * th))

            elif isinstance(layer, pytmx.TiledObjectGroup):
                for object in layer:
                    if object.image:
                        surface.blit(object.image.convert_alpha() , (object.x, object.y))

            elif isinstance(layer, pytmx.TiledImageLayer):
                if image:
                    surface.blit(image , (0, 0))

    def make_map(self):
        temp_surface = pygame.Surface(self.size)
        self.render(temp_surface)
        return temp_surface
    
    def reload(self):
        self.map_surface = self.make_map()
    
    def update_object_image(self, object_id, surface):
            pass
    
    def get_layer(self, layer_name):
        return self.tmx_data.get_layer_by_name(layer_name)
代码语言:javascript
复制
class Room:
    def __init__(self, room_image, level_options):
        self.renderer = Renderer(room_image)
        self.surface = self.renderer.map_surface
        self.rect = self.surface.get_rect()
        self.level_options = level_options
        
        self.obstacles = pygame.sprite.Group()
        self.doors = pygame.sprite.Group()
        
        self.load_obstacles()
        self.load_doors()
        
    def load_obstacles(self):
        obstacles = self.level_options['obstacle_layers']
        for obstacle in obstacles:
            try:
                items = self.renderer.get_layer(obstacle)
                for x, y, image in items.tiles():
                    self.obstacles.add(Obstacle(x, y, image, SPRITE_SIZE))
            except ValueError:
                return
            
    def load_doors(self):
        doors = self.renderer.get_layer(self.level_options['door_layer'])
        
        if isinstance(doors, pytmx.TiledTileLayer):
            for x, y, image in doors.tiles():
                if image:
                    self.doors.add(Door(self, x, y, image, SPRITE_SIZE, self.level_options['open_door_actions']))

        elif isinstance(doors, pytmx.TiledObjectGroup):
            for object in doors:
                self.doors.add(Door(self, object.x, object.y, object.image, SPRITE_SIZE, self.level_options['open_door_actions'], object))
            
    def update_doors(self):
        for door in self.doors:
            if door.object:
                door.update()
                #self.renderer.update_object_image(door.object.id, door.image)
            
class Wall(pygame.sprite.Sprite):
    def __init__(self, x, y, image, sprite_size):
        pygame.sprite.Sprite.__init__(self)
        self.rect = pygame.Rect(x * sprite_size,y * sprite_size, sprite_size, sprite_size)
        self.image = image 
    
class Obstacle(pygame.sprite.Sprite):
    def __init__(self, x, y, image, sprite_size):
        pygame.sprite.Sprite.__init__(self)
        self.rect = pygame.Rect(x * sprite_size,y * sprite_size, sprite_size, sprite_size)
        self.image = image 
        
class Door(pygame.sprite.Sprite):
    def __init__(self, parent, x, y, image, sprite_size, open_actions, object = None):
        self.parent = parent
        pygame.sprite.Sprite.__init__(self)
        
        self.object = object
        
        if self.object:
            self.rect = pygame.Rect(x ,y, self.object.width, self.object.height)
            self.current_index = 0
            self.load_animations()
        else:
            self.rect = pygame.Rect(x * sprite_size,y * sprite_size, sprite_size, sprite_size)
            
        self.image = image 
        self.open_actions = open_actions
        self.last_updated = 0
        self.is_open = False
        self.is_activated = False
        
    def load_animations(self):
        self.animations = []
        filename = os.path.join(os.getcwd(), IMAGES_FOLDER, 'maps', 'animations', self.object.animated_image)
        spritesheet = Spritesheet(filename, self.object.width, self.object.height)
        
        for i in range(spritesheet.data['columns']):
            self.animations.append(spritesheet.parse_sprite(i)) 
            
        self.image = self.animations[self.current_index]
        
    def open_animation(self):
        if self.is_open:
            return
        
        if not self.object or not self.is_activated or not self.animations:
            return
        
        self.image = self.animations[self.current_index]
        
        if self.current_index == len(self.animations) - 1:
            self.is_open = True
        
                
    def update(self):
        if self.is_open:
            if self.object:
                self.image = self.animations[-1]
                
        if self.is_activated:
            if self.object:
                now = pygame.time.get_ticks()
                
                if now - self.last_updated > 200:
                    self.last_updated = now
                    self.current_index = (self.current_index + 1) % len(self.animations)
                    self.image = self.animations[self.current_index]
            
        if not self.is_open:
            self.image = self.animations[0]
        
    def check_doors_state(self, player):
        if 'any' in self.open_actions:
            self.is_activated = True
        
        for action in player.actions:
            if action in self.open_actions:
                self.is_activated = True

所以现在我想要做的是使用一个动画的瓦片对象并从tmx数据中启动动画,但我甚至不知道如何在第一次渲染时启动动画。

提前感谢您的回答。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-14 06:37:51

所以我找到了一个解决方案,我不是试图改变和重新加载对象瓦片,我只是将我的游戏精灵分组,修改我的瓦片的生成和渲染。

修改的类:

代码语言:javascript
复制
class Room:
    def __init__(self, level, room_image, level_options):
        self.level = level
        self.renderer = Renderer(room_image)
        self.surface = self.renderer.map_surface
        self.tmx_data = self.renderer.tmx_data
        self.rect = self.surface.get_rect()
        self.level_options = level_options
        
        self.walls = pygame.sprite.Group()
        self.doors = pygame.sprite.Group()
        
        #self.load_walls()
        #self.load_doors()
        
    def load_walls(self):
        walls = self.renderer.get_layer(self.level_options['wall_layer'])
        
        if isinstance(walls, pytmx.TiledObjectGroup):
            for object in walls:
                self.walls.add(Wall(object.x, object.y, object, SPRITE_SIZE))
    
            
    def load_doors(self):
        doors = self.renderer.get_layer(self.level_options['door_layer'])
        
        if isinstance(doors, pytmx.TiledTileLayer):
            for x, y, image in doors.tiles():
                if image:
                    self.doors.add(Door(self, x, y, image, SPRITE_SIZE, self.level_options['open_door_actions']))

        elif isinstance(doors, pytmx.TiledObjectGroup):
            for object in doors:
                self.doors.add(Door(self, object.x, object.y, object.image, SPRITE_SIZE, self.level_options['open_door_actions'], object))
    
    def update(self):
        self.doors.update()
        
    def draw(self, display, camera = None):
        self.doors.draw(self.surface)
        
        if not camera:
            display.blit(self.surface, self.rect)
        else:
            display.blit(self.surface, (self.rect.x - camera.offset.x, self.rect.y - camera.offset.y))
    
    def get_opening_actions(self):
        return self.level_options['open_door_actions']
            
        
            
class Wall(pygame.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.walls
        pygame.sprite.Sprite.__init__(self, self.groups)
        
        self.game = game
        self.image = game.wall_img
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x * SPRITE_SIZE
        self.rect.y = y * SPRITE_SIZE
        
class Obstacle(pygame.sprite.Sprite):
    def __init__(self, game, x, y, w, h):
        self.groups = game.walls
        pygame.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.rect = pygame.Rect(x, y, w, h)
        self.hit_rect = self.rect
        self.x = x
        self.y = y
        self.rect.x = x
        self.rect.y = y
        
class Door(pygame.sprite.Sprite):
    def __init__(self, game, x, y, w, h, open_actions, animated_image):
        self.groups = game.all_sprites, game.doors
        pygame.sprite.Sprite.__init__(self, self.groups)
        
        
        self.game = game
        self.rect = pygame.Rect(x ,y, w, h)
        self.current_index = 0
        self.animated_image = animated_image
        
        self.load_animations()
        
        self.open_actions = open_actions
        self.last_updated = 0
        self.is_open = False
        self.is_activated = False
        
    def load_animations(self):
        self.animations = []
        filename = os.path.join(os.getcwd(), IMAGES_FOLDER, 'maps', 'animations', self.animated_image)
        spritesheet = Spritesheet(filename, self.rect.width, self.rect.height)
        
        for i in range(spritesheet.data['columns']):
            self.animations.append(spritesheet.parse_sprite(i)) 
            
        self.image = self.animations[self.current_index]
        
    def open_animation(self):
        if self.is_open:
            return
        
        if not self.is_activated or not self.animations:
            return
        
        now = pygame.time.get_ticks()
        if now - self.last_updated > 15:
            self.last_updated = now
            self.current_index = (self.current_index + 1) % len(self.animations)
            
        self.image = self.animations[self.current_index]
        
        if self.current_index == len(self.animations) - 1:
            self.current_index = -1
            self.is_open = True
        
                
    def update(self):
        if not self.is_open:
            self.image = self.animations[0]
            
        if self.is_open:
            self.image = self.animations[-1]
                
            
        
    def check_doors_state(self, player):
        if 'any' in self.open_actions:
            self.is_activated = True
        
        for action in player.actions:
            if action in self.open_actions:
                self.is_activated = True

精灵组生成,更新和渲染添加(在我的游戏类中):

代码语言:javascript
复制
    def new(self, level = 0):
        # initialize all variables and do all the setup for a new game
        self.all_sprites = pygame.sprite.Group()
        self.walls = pygame.sprite.Group()
        self.doors = pygame.sprite.Group()
        self.mobs = pygame.sprite.Group()

        ## LOAD LEVEL
        self.level = Level(level)
        self.room = self.level.current_room
        
        for tile_object in self.room.tmx_data.objects:
            if tile_object.name == 'player':
                self.player = Player(self, tile_object.x, tile_object.y)
            
            if tile_object.name == 'obstacle':
                Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height)
            
            if tile_object.name == 'wall':
                Wall(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height)
                
            if tile_object.name == 'door':
                Door(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height, self.room.get_opening_actions(), tile_object.animated_image)
代码语言:javascript
复制
    def update(self):
        self.all_sprites.update()

    def draw(self):
        
        self.window.fill((0, 0, 0))
        
        ## DISPLAY MAP
        self.level.draw_room(self.window, self.camera)
        
        ## DISPLAY SPRITES
        for sprite in self.all_sprites:
            self.window.blit(sprite.image, (sprite.rect.x - self.camera.offset.x, sprite.rect.y - self.camera.offset.y))

        ## REFRESH SCREEN
        pygame.display.flip()

这是结果(我正在为玩家^^开发更好的hitbox ) door opening when player getting close to it

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68368499

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档