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?
map
is_traversable
is always false 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.