0

I tried to create a camera for my platformer using this tutorial and I can't get it work. It's probably (hopefully) something really easy to fix because I'm new to programming.

This is what it should do.

enter image description here

Instead it's just acting as if there is no camera implemented at all. The player sprite moves around the screen that's visible.

This is my code, if you want the entire thing so you can run it, I'd be happy to provide it:

class Camera(object):
    def __init__(self, camera_func, width, height):
        self.camera_func = camera_func
        self.state = pygame.Rect(0, 0, width, height)

    def apply(self, target):
        return target.rect.move(self.state.topleft)

    def update(self, target):
        self.state = self.camera_func(self.state, target.rect)

def complex_camera(camera, target_rect):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    l, t, _, _ = -l+HALF_WIDTH, -t+HALF_HEIGHT, w, h

    l = min(0, l)                           # stop scrolling at the left edge
    l = max(-(camera.width-SCREEN_WIDTH), l) # stop scrolling at the right edge
    t = max(-(camera.height-SCREEN_HEIGHT), t) # stop scrolling at the bottom
    t = min(0, t)                           # stop scrolling at the top
    return Rect(l, t, w, h)

    return Rect(l, t, w, h)

class Sprite(pygame.sprite.Sprite):
    def __init__(self,img):
        pygame.sprite.Sprite.__init__(self)

class Player(Sprite):
    def __init__(self,x,y,width,height):
        self.dx = 0
        self.dy = 0
        self.onGround = False
        self.image = pygame.image.load('robotStanding_sprite.png')
        self.rect = pygame.Rect(x,y,width,height)

    def update(self):
        self.rect.x += self.dx
        self.collide(self.dx,0,terrain_list)
        self.rect.y += self.dy
        self.collide(0,self.dy,terrain_list)

        if moving_right: self.dx = SPEED
        if moving_left: self.dx = -SPEED
        if not(moving_left or moving_right): self.dx = 0

        if moving_up:
            self.dy = -SPEED
            self.onGround = False
        elif not moving_up: self.dy = SPEED

        if self.rect.y >= LOWER_BOUNDARY-GROUND_LEVEL_HEIGHT-ROBOT_HEIGHT:
            self.rect.y = LOWER_BOUNDARY-GROUND_LEVEL_HEIGHT-ROBOT_HEIGHT
            self.onGround = True

    def collide(self,xvel,yvel,blocks):
        for block in blocks:
            if pygame.sprite.collide_rect(player,block):
                if xvel > 0: self.rect.right = block.rect.left
                if xvel < 0: self.rect.left = block.rect.right

                if yvel > 0:
                    self.rect.bottom = block.rect.top
                    self.onGround = True

class Terrain(Sprite):
    def __init__(self,img,x,y,width,height):
        self.image = pygame.image.load(img)
        self.rect = pygame.Rect(x,y,width,height)

    def addBlock(img,x,y,width,height):
        block = Terrain(img,x,y,width,height)
        terrain_list.append(block)

pygame.init()

size = [700,500]
screen = pygame.display.set_mode(size)


LEFT_BOUNDARY = 0
RIGHT_BOUNDARY = size[0]
UPPER_BOUNDARY = 0
LOWER_BOUNDARY = size[1]
HALF_WIDTH = size[0] / 2
HALF_HEIGHT = size[1] / 2
TILE_SIZE = 20
ROBOT_HEIGHT = 2*TILE_SIZE
ROBOT_WIDTH = 25
GROUND_HEIGHT = 100
GROUND_LEVEL_HEIGHT = 4*TILE_SIZE
GROUND_WIDTH = 3000
BLOCK_HEIGHT = 500
BLOCK_WIDTH = 160
SCREEN_WIDTH = 24*TILE_SIZE
SCREEN_HEIGHT = 35*TILE_SIZE

terrain_list = []

player = Player(17*TILE_SIZE,19*TILE_SIZE,ROBOT_WIDTH,ROBOT_HEIGHT)
Terrain.addBlock('ground.fw.png',
    0*TILE_SIZE,21*TILE_SIZE,GROUND_WIDTH,GROUND_HEIGHT)
Terrain.addBlock('block1.fw.png',
    -5*TILE_SIZE,0*TILE_SIZE,BLOCK_WIDTH,BLOCK_HEIGHT) # LEFT WALL
Terrain.addBlock('block1.fw.png',
    24*TILE_SIZE,16*TILE_SIZE,BLOCK_WIDTH,BLOCK_HEIGHT)
Terrain.addBlock('block1.fw.png',
    32*TILE_SIZE,20*TILE_SIZE,BLOCK_WIDTH,BLOCK_HEIGHT)
Terrain.addBlock('block1.fw.png',
    40*TILE_SIZE,12*TILE_SIZE,BLOCK_WIDTH,BLOCK_HEIGHT)

# CREATE CAMERA -----------------------------------------------------------
camera = Camera(complex_camera, 24*TILE_SIZE, 3000)


done = False
while not done:
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            done = True

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_d: moving_right = True
            if event.key == pygame.K_a: moving_left = True
            if event.key == pygame.K_w:
                if player.onGround:
                    moving_up = True
            if event.key == pygame.K_DOWN: moving_down = True

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_d: moving_right = False
            if event.key == pygame.K_a: moving_left = False
            if event.key == pygame.K_w: moving_up = False

    screen.fill(SKY_BLUE)
    camera.update(player)
    player.update()
    screen.blit(player.image,player.rect)
    for block in terrain_list:
        screen.blit(block.image,camera.apply(block))


     # DRAW TILE LINES -----------------------------------------------------
    if draw_tiles:
        x = 0
        y = 0
        for i in range(RIGHT_BOUNDARY // 2):
            pygame.draw.line(screen,BLACK,
                [x,UPPER_BOUNDARY],[x,LOWER_BOUNDARY])
            pygame.draw.line(screen,BLACK,
                [LEFT_BOUNDARY,y],[RIGHT_BOUNDARY,y])
            x += TILE_SIZE
            y += TILE_SIZE
        # tile test
        pygame.draw.rect(screen,BLACK,
            (34*TILE_SIZE,24*TILE_SIZE,TILE_SIZE,TILE_SIZE))

    pygame.display.flip()
    clock.tick(60)
pygame.quit()
Community
  • 1
  • 1
Alexdr5398
  • 51
  • 1
  • 6

1 Answers1

0

Camera.apply(target) should probably be doing something that involves self.state instead of target.rect.move(1,1).

japreiss
  • 11,111
  • 2
  • 40
  • 77
  • The tutorial said it should be self.state.topleft, but I tried that before and got the error: 'NoneType' object has no attribute 'topleft' – Alexdr5398 Apr 04 '14 at 20:57
  • so `self.state` is `None` instead of a `pygame.Rect`. But you set it to a `pygame.Rect` in the `Camera` constructor. So somewhere along the line it is getting replaced with a `None`. Maybe you should put debugging `print` statements everywhere that touches `Camera.state` and figure out what is going on. – japreiss Apr 04 '14 at 21:02
  • It runs now, but won't keep the player in the center of the screen and the all the terrain blocks moved up to about half the screen. The terrain blocks also move when I move the player, so it's an improvement I guess. – Alexdr5398 Apr 04 '14 at 21:21