简体   繁体   中英

PyGame: Sprites won't move

I'm making a small game with PyGame where the camera is focused on a sprite that represents a character and the map moves around it when the arrow keys are pressed. The problem is the map does not move. I've had this problem multiple times before and I think I've narrowed it down to what it might be, but I have no idea how actually to solve the problem.

Here's the code:

import sys, pygame
from pygame.locals import *

pygame.init()
size = screen_width, screen_height = 800, 600
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()

game_is_running = True

class Character(object):
    """ Defines player's metadata """
    def __init__(self):
        self.x = 350
        self.y = 250 # at about the center of the screen
        self.dx = 0
        self.dy = 0
        self.width = 50
        self.height = 50
        self.sprite = pygame.image.load("./../Images/main-char-sprite.png") #the pic representing the character
        self.dead_sprite = None #the pic representing the character when dead (doesn't exist yet)

player = Character()


class Map():
    """
    Defines environment.
    Will be drawn around static arrays for now.
    """
    def __init__(self):
        self.wall = pygame.image.load("./../Images/dungeon/wall.jpg")
        self.floor = pygame.image.load("./../Images/dungeon/floor.jpg")
        self.door = pygame.image.load("./../Images/dungeon/door.jpg")
        self.null_tile = pygame.image.load("./../Images/blank.png")

        self.x = 0
        self.y = 0

        self.tile_height = 50
        self.tile_width = 50

        self.center_x = 400
        self.center_y = 300
        #self.center_of_room = (self.center_x, self.center_y)

        self.town = [
            [0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
            [0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ]

    def draw_floor(self): #will use arrays
        for j in range(24): #self.town is 24x24 elements
            for k in range(24):
                if self.town[j][k]==0: 
                    screen.blit(self.null_tile, (j*player.height, k*player.width))
                elif self.town[j][k]==1: 
                    screen.blit(self.wall, (j*player.height, k*player.width))
                elif self.town[j][k]==2: 
                    screen.blit(self.floor, (j*player.height, k*player.width))
                elif self.town[j][k]==3: 
                    screen.blit(self.door, (j*player.height, k*player.width))
                else: 
                    screen.blit(self.null_tile, (j*player.height, k*player.width))

    def is_traversable(self):
    # if where the player is about to walk is not a floor,
    # the land is not traversable and character will not move
        if self.town[(player.x + player.dx)//50][(player.y + player.dy)//50]==2:
            return True
        return False

map = Map()

while game_is_running:
    clock.tick(60)
    key = pygame.key.get_pressed()
    for event in pygame.event.get():
        if event.type == pygame.QUIT or key[K_ESCAPE] or key[K_RETURN]:
            game_is_running = False
        if key[K_UP]:
            player.dy = player.height-(2*player.height) #turns player.height negative
            if map.is_traversable():
                map.y -= player.height
        elif key[K_DOWN]:
            player.dy = player.height
            if map.is_traversable():
                map.y += player.height
        elif key[K_LEFT]:
            player.dx = player.width-(2*player.width)
            if map.is_traversable():
                map.x -= player.width
        elif key[K_RIGHT] and map.is_traversable():
            player.dx = player.width
            if map.is_traversable():
                map.x += player.width
        else: pass  


        """ Drawing routines: """
        screen.fill((0, 0, 0))
        map.draw_floor()
        screen.blit(player.sprite, (player.x, player.y))

        """ Graphics cleanup: """
        pygame.display.update()
        pygame.display.flip()


pygame.quit()
sys.exit()

Based on my past PyGame programs, I've always had problems moving sets of sprites that have been drawn to the screen with for loops, such as what I have done here. Even banal and simple examples fail. What I want to know is why is this, and how can I draw large maps concisely and still have them move? range() makes a list and as far as I know, list elements are mutable, so why isn't the map's position changing?

  1. You have input-state inside event polling input. This causes problems.
  2. you are shadowing the name map
  3. is_traversable is always false
  4. rendering sprites is x = world_x + camera_x and y = world_y + camera_y . Changing camera_x/y ( or think of it as offset ) causes the map to scroll. Yet objects store their position as global coordinates. (Whether that's pixels or tile based)

The modified code is below. You can see it polls up arrow , yet it never prints "true!".

import pygame
from pygame.locals import *

pygame.init()
size = screen_width, screen_height = 800, 600
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()

game_is_running = True

def temp_sprite(color, size=50):
    # gen Surface, since I don't have your sprites
    surf = pygame.Surface([size, size])
    surf.fill(Color(color))
    return surf

class Character(object):
    """ Defines player's metadata """
    def __init__(self):
        self.x = 350
        self.y = 250 # at about the center of the screen
        self.dx = 0
        self.dy = 0
        self.width = 50
        self.height = 50
        #self.sprite = pygame.image.load("./../Images/main-char-sprite.png") #the pic representing the character
        self.sprite = temp_sprite("red")


        self.dead_sprite = None #the pic representing the character when dead (doesn't exist yet)

player = Character()


class Map():
    """
    Defines environment.
    Will be drawn around static arrays for now.
    """
    def __init__(self):
        self.wall = temp_sprite("blue") #pygame.image.load("./../Images/dungeon/wall.jpg")
        self.floor = temp_sprite("green") #pygame.image.load("./../Images/dungeon/floor.jpg")
        self.door = temp_sprite("brown") #pygame.image.load("./../Images/dungeon/door.jpg")
        self.null_tile = temp_sprite("magenta") # pygame.image.load("./../Images/blank.png")

        self.x = 0
        self.y = 0

        self.tile_height = 50
        self.tile_width = 50

        self.center_x = 400
        self.center_y = 300
        #self.center_of_room = (self.center_x, self.center_y)

        self.town = [
            [0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
            [0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0],
            [0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ]

    def draw_floor(self): #will use arrays
        for j in range(24): #self.town is 24x24 elements
            for k in range(24):
                if self.town[j][k]==0:
                    screen.blit(self.null_tile, (gamemap.y + j*player.height, gamemap.x + k*player.width))
                elif self.town[j][k]==1:
                    screen.blit(self.wall, (gamemap.y + j*player.height, gamemap.x + k*player.width))
                elif self.town[j][k]==2:
                    screen.blit(self.floor, (gamemap.y + j*player.height, gamemap.x + k*player.width))
                elif self.town[j][k]==3:
                    screen.blit(self.door, (gamemap.y + j*player.height, gamemap.x + k*player.width))
                else:
                    screen.blit(self.null_tile, (gamemap.y + j*player.height, gamemap.x + k*player.width))

    def is_traversable(self):
    # if where the player is about to walk is not a floor,
    # the land is not traversable and character will not move
        if self.town[(player.x + player.dx)//50][(player.y + player.dy)//50]!=2:
            print "true!"
            return True
        return False

gamemap = Map()

while game_is_running:
    clock.tick(60)

    key = pygame.key.get_pressed()
    for event in pygame.event.get():
        if event.type == pygame.QUIT or key[K_ESCAPE] or key[K_RETURN]:
            game_is_running = False

    if key[K_UP]:
        print '.'
        player.dy = player.height-(2*player.height) #turns player.height negative
        if gamemap.is_traversable():
            gamemap.y -= player.height
    elif key[K_DOWN]:
        player.dy = player.height
        if gamemap.is_traversable():
            gamemap.y += player.height
    elif key[K_LEFT]:
        player.dx = player.width-(2*player.width)
        if gamemap.is_traversable():
            gamemap.x -= player.width
    elif key[K_RIGHT] and gamemap.is_traversable():
        player.dx = player.width
        if gamemap.is_traversable():
            gamemap.x += player.width
    else: pass


    """ Drawing routines: """
    screen.fill((0, 0, 0))
    gamemap.draw_floor()
    screen.blit(player.sprite, (player.x, player.y))

    """ Graphics cleanup: """
    pygame.display.update()
    pygame.display.flip()


pygame.quit()
sys.exit()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM