代码之家  ›  专栏  ›  技术社区  ›  K. Groot

为什么我在pygame中的玩家角色有时会出现在瓷砖后面,但仍然在移动?

  •  3
  • K. Groot  · 技术社区  · 7 年前

    The first start up, player invisible in top left

    First tile found where player is visible

    我的主要:

    import pygame as pg
    import sys
    from os import path
    from settings import *
    from sprites import *
    from tilemap import *
    
    class Game:
    def __init__(self):
        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__)
        img_folder = path.join(game_folder, 'img')
        self.map = Map(path.join(game_folder, 'map.txt'))
        self.player_img = pg.image.load(path.join(img_folder, PLAYER)).convert_alpha()
        self.floor_img = pg.image.load(path.join(img_folder, FLOOR)).convert()
        self.wall_img = pg.image.load(path.join(img_folder, WALL)).convert()
        self.water_img = pg.image.load(path.join(img_folder, WATER)).convert()
        self.goal_img = pg.image.load(path.join(img_folder, GOAL)).convert()
    
    def new(self):
        # initialize all variables and do all the setup for a new game
        self.all_sprites = pg.sprite.Group()
        self.walls = pg.sprite.Group()
        self.floors = pg.sprite.Group()
        self.water = pg.sprite.Group()
        self.goal = pg.sprite.Group()
        for row, tiles in enumerate(self.map.data):
            for col, tile in enumerate(tiles):
                if tile == 'X':
                    Wall(self, col, row)
                if tile == 'W':
                    Water(self, col, row)
                if tile == '.':
                    Floor(self, col, row)
                if tile == 'G':
                    Goal(self, col, row)
                if tile == 'P':
                    self.player = Player(self, col, row)
                    Floor(self, col, row)
    
        self.camera = Camera(self.map.width, self.map.height)
    
    def run(self):
        # game loop - set self.playing = False to end the game
        self.playing = True
        while self.playing:
            self.dt = self.clock.tick(FPS) / 1000
            self.events()
            self.draw()
            self.update()
    
    def quit(self):
        pg.quit()
        sys.exit()
    
    def update(self):
        # update portion of the game loop
        self.all_sprites.update()
        self.camera.update(self.player)
    
    def draw(self):
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        pg.display.flip()
    
    def events(self):
        # catch all events here
        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()
                if event.key == pg.K_LEFT:
                    self.player.move(dx=-1)
                if event.key == pg.K_RIGHT:
                    self.player.move(dx=1)
                if event.key == pg.K_UP:
                    self.player.move(dy=-1)
                if event.key == pg.K_DOWN:
                    self.player.move(dy=1)
    
    # create the game object
    g = Game()
    while True:
    g.new()
    g.run()
    

    我的设置:

    DARKGREY = (40, 40, 40)
    
    # game settings
    WIDTH = 1280   # 16 * 64 or 32 * 32 or 64 * 16
    HEIGHT = 720  # 16 * 48 or 32 * 24 or 64 * 12
    FPS = 60
    TITLE = "Code Avontuur"
    BGCOLOR = DARKGREY
    
    TILESIZE = 100
    GRIDWIDTH = WIDTH / TILESIZE
    GRIDHEIGHT = HEIGHT / TILESIZE
    
    PLAYER = 'player.png'
    WALL = 'wall.jpg'
    FLOOR = 'floor.jpg'
    WATER = 'water.jpg'
    GOAL = 'goal.jpg'
    

    XXXXXXXXXXXXXXXX
    XP.....X.....XWX
    XXX.XX.XXX.XXXXX
    XXX..X.XX..XXXXX
    XXXX...X..XXXXXX
    XWWWX.XX.XXWWWWX
    XXXXX....XXXXXXX
    XXXXXXXX......GX
    XXXXXXXXXXXXXXXX
    

    我的精灵:

    import pygame as pg
    from PIL import Image
    from settings import *
    
    class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = game.player_img
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
    
    def move(self, dx=0, dy=0):
        if not self.collide(dx, dy):
            self.x += dx
            self.y += dy
    
    def collide(self, dx=0, dy=0):
        for wall in self.game.walls:
            if wall.x == self.x + dx and wall.y == self.y + dy:
                return True
        for water in self.game.water:
            if water.x == self.x +dx and water.y == self.y +dy:
                return True
        return False
    
    def update(self):
        self.rect.x = self.x * TILESIZE
        self.rect.y = self.y * TILESIZE
    
    class Wall(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.walls
        pg.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 * TILESIZE
        self.rect.y = y * TILESIZE
    
    class Water(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.water
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = game.water_img
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x * TILESIZE
        self.rect.y = y * TILESIZE
    
    class Floor(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.floors
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = game.floor_img
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x * TILESIZE
        self.rect.y = y * TILESIZE
    
    class Goal(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.goal
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = game.goal_img
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x * TILESIZE
        self.rect.y = y * TILESIZE
    

    我的地图处理程序:

    import pygame as pg
    from settings import *
    
    class Map:
    def __init__(self, filename):
        self.data = []
        with open(filename, 'rt') as f:
            for line in f:
                self.data.append(line.strip())
    
        self.tilewidth = len(self.data[0])
        self.tileheight = len(self.data)
        self.width = self.tilewidth * TILESIZE
        self.height = self.tileheight * TILESIZE
    
    class Camera:
    def __init__(self, width, height):
        self.camera = pg.Rect(0, 0, width, height)
        self.width = width
        self.height = height
    
    def apply(self, entity):
        return entity.rect.move(self.camera.topleft)
    
    def update(self, target):
        x = -target.rect.x + int(WIDTH / 2)
        y = -target.rect.y + int(HEIGHT / 2)
    
        #Limit scrolling off map
        x = min(0, x)
        y = min(0, y)
        x = max(-(self.width - WIDTH), x)
        y = max(-(self.height - HEIGHT), y)
        self.camera = pg.Rect(x, y, self.width, self.height)
    

    1 回复  |  直到 7 年前
        1
  •  4
  •   sloth    7 年前

    您的问题是绘制精灵的顺序。

    Group LayeredUpdates

    然后给你的精灵一个 _layer

    Here's 一个例子。


    更改您的 Game 类别:

    ...
    def new(self):
        # initialize all variables and do all the setup for a new game
        self.all_sprites = pg.sprite.LayeredUpdates() # <<--- change here
        self.walls = pg.sprite.Group()
        self.floors = pg.sprite.Group()
        self.water = pg.sprite.Group()
        self.goal = pg.sprite.Group()
        ...
    

    更改您的 Player 类别:

    class Player(pg.sprite.Sprite):
        def __init__(self, game, x, y):
            self.groups = game.all_sprites
            pg.sprite.Sprite.__init__(self, self.groups)
            self.game = game
            self.image = game.player_img
            self.rect = self.image.get_rect()
            self.x = x
            self.y = y
            self._layer = 1 # <<--- add this line
    

    编辑:

    由于实际上并不使用组进行绘制,因此可以保持简单 只需更改绘图功能,按层对精灵进行排序:

    for sprite in sorted(self.all_sprites, lambda i, s: s._layer):
        ...
    

    或者对于Python 3:

    for sprite in sorted(self.all_sprites, key=lambda s: s._layer):
        ...
    

    layer _图层