title: How do I add a camera with a sprite grid in pygame?
body: <p><strong>I have seen <a href="https://stackoverflow.com/questions/14354171/add-scrolling-to-a-platformer-in-pygame">this answer</a>, and am still trying to add this answer. This IS NOT a duplicate.</strong></p>
  <p>I have a 20x20 grid, and the screen size is 800x640. The screen cannot see the full grid, and I want it to be able to via a scrolling camera.</p>
  <p>However, I am not sure how I would even implement this.</p>
  <p>The way my code works is that, in the main loop, <code>player.update()</code> is called to update the player's position and collision, and then an <code>update()</code> function is called, which redraws all sprites in the grid (to show any changes).</p>
  <p>Code:</p>
  <pre><code>import pygame
  from pygame.locals import *
  import os
  import random
  import time
  pygame.init()
  W, Height = 800, 640
  
  screen = pygame.display.set_mode((W,Height))
  
  SCREEN_SIZE = pygame.Rect((0,0,W,Height))
  TILE_SIZE = 48
  
  t0 = time.time()
  font = pygame.font.SysFont(None, 24)
  print(&quot;Time needed to create fonts: &quot; + str(time.time() - t0))
  
  vec = pygame.math.Vector2
  
  # USER CAN MODIFY
  ACC = 0.5
  FRIC = -0.12
  FPS = 60
  
  clock = pygame.time.Clock()
  
  class BlueBlock(pygame.sprite.Sprite):
    def __init__(self, x, y):
      super(BlueBlock, self).__init__()
      self.surf = pygame.Surface((48,48))
      self.surf.fill((0,191,255))
      self.rect = self.surf.get_rect()
      self.original_surface = self.surf
      self.hover_surface = self.original_surface.copy()
      pygame.draw.rect(self.hover_surface, (255, 255, 0), self.hover_surface.get_rect(), 6)
      self.surf = self.original_surface
      self.rect = self.surf.get_rect(center = (x, y))
      self.hover = False
      self.mouse_pos = None
      self.count = 0
      
    def update(self):
      if player.mode == &quot;build&quot;:
        mouse_pos = pygame.mouse.get_pos()
        self.hover = self.rect.collidepoint(mouse_pos)
        self.surf = self.hover_surface if self.hover else self.original_surface
        if self.hover and mouse_pos == self.mouse_pos:
          self.count += 1
        if self.count &gt; 10:
          self.image = pygame.Surface((48,48))
          self.image.fill((255,255,255))
  
  class textureblock(pygame.sprite.Sprite):
    def __init__(self, imagefile, x, y, type):
      super(textureblock, self).__init__()
        
      self.imagefile = imagefile
      self.original_image = pygame.image.load(imagefile).convert_alpha()
      self.original_image = pygame.transform.scale(self.original_image, (48,48))
      self.hover_image = self.original_image.copy()
      pygame.draw.rect(self.hover_image, (255, 255, 0), self.hover_image.get_rect(), 6)
      self.image = self.original_image 
      self.rect = self.image.get_rect(center = (x, y))
      self.hover = False
      self.mouse_pos = None
      self.count = 0
      self.type = type
  
    def update(self):
      if player.mode == &quot;build&quot;:
        pygame.draw.rect(self.hover_image, (255,0,0), self.hover_image.get_rect(), 6)
      elif player.mode == &quot;destroy&quot;:
        pygame.draw.rect(self.hover_image, (255, 255,0), self.hover_image.get_rect(), 6)
      mouse_pos = pygame.mouse.get_pos()
      self.hover = self.rect.collidepoint(mouse_pos)
      self.image = self.hover_image if self.hover else self.original_image
      if self.hover and mouse_pos == self.mouse_pos and player.mode == &quot;destroy&quot;:
        self.count += 1
        if self.count &gt; 10:
          self.image = pygame.Surface((48,48))
          self.image.fill((0,191,255))
  
          item = Item(self.imagefile, self.rect.x, self.rect.y, self.type)
          
          items.add(item)
          self.remove(blocks)
        
      else:
        self.count = 0
      self.mouse_pos = mouse_pos
    
  class Player(pygame.sprite.Sprite):
    def __init__(self):
      super(Player, self).__init__()
      self.surf = pygame.Surface((40,40))
      self.surf.fill((255,0,0))
      self.rect = self.surf.get_rect()
      self.pos = vec(0,144) # Position
      self.vel = vec(0,0) # Velocity
      self.acc = vec(0,0) # Acceleration 
      self.inventory = {} # Items can be added
      self.mode = &quot;destroy&quot; # Mode. Probably will be changed later
      self.selected_item = None # Selected item
  
    def move(self, pressed_keys):
      self.acc = vec(0,0.5)
      if pressed_keys[K_LEFT]:
        self.acc.x = -ACC
        
      if pressed_keys[K_RIGHT]:
        self.acc.x = ACC
      
      self.acc.x += self.vel.x * FRIC
      self.vel += self.acc
      self.pos.x += self.vel.x + 0.5 * self.acc.x
      self.rect.midbottom = self.pos
  
      hit_side = False
      for entity in blocks:
          if self.rect.colliderect(entity.rect):
  
              # move left and hit the block on the right
              if self.vel.x &lt; 0 and self.rect.right &gt; entity.rect.right:
                  self.rect.left = entity.rect.right
                  self.pos.x = self.rect.centerx
                  hit_side = True
  
              # move right and hit the block on the left
              if self.vel.x &gt; 0 and self.rect.left &lt; entity.rect.left:
                  self.rect.right = entity.rect.left
                  self.pos.x = self.rect.centerx
                  hit_side = True
  
      if hit_side:
          self.vel.x = 0
          self.acc.x = 0
  
    def update(self):
      self.acc = vec(0,0.5)
      if pressed_keys[K_LEFT]:
        self.acc.x = -ACC
        
      if pressed_keys[K_RIGHT]:
        self.acc.x = ACC
      
      self.acc.x += self.vel.x * FRIC
      self.vel += self.acc
      self.pos.x += self.vel.x + 0.5 * self.acc.x
      self.rect.midbottom = self.pos
  
      hit_side = False
      for entity in blocks:
          if self.rect.colliderect(entity.rect):
  
              # move left and hit the block on the right
              if self.vel.x &lt; 0 and self.rect.right &gt; entity.rect.right:
                  self.rect.left = entity.rect.right
                  self.pos.x = self.rect.centerx
                  hit_side = True
  
              # move right and hit the block on the left
              if self.vel.x &gt; 0 and self.rect.left &lt; entity.rect.left:
                  self.rect.right = entity.rect.left
                  self.pos.x = self.rect.centerx
                  hit_side = True
  
      if hit_side:
          self.vel.x = 0
          self.acc.x = 0
      hits = pygame.sprite.spritecollide(self, blocks, False)
  
      self.pos.y += self.vel.y + 0.5 * self.acc.y
      self.rect.midbottom = self.pos
  
      for entity in blocks:
          if self.rect.colliderect(entity.rect):
              if self.vel.y &gt; 0:
                  self.rect.bottom = entity.rect.top
                  self.pos.y = self.rect.bottom
                  self.vel.y = 0
      if self.vel.y &gt; 0:
        if hits: 
          self.pos.y = hits[0].rect.top + 1
          self.vel.y = 0
  
    def jump(self):
      self.vel.y = -15
  
  # Item class - Spawned when a player breaks a block.
  class Item(pygame.sprite.Sprite):
    def __init__(self, image, x, y, type):
      super(Item, self).__init__()
      self.image = pygame.image.load(image).convert_alpha()
      self.image = pygame.transform.scale(self.image, (24,24))
      self.rect = self.image.get_rect()
      
      self.pos = vec(x, y)
      self.vel = vec(0,0)
      self.acc = vec(0,0)
      self.type = type
  
    def move(self):
      self.acc = vec(0,0.5)
      
      self.acc.x += self.vel.x * FRIC
      self.vel += self.acc
      self.pos.x += self.vel.x + 0.5 * self.acc.x
      self.rect.midbottom = self.pos
  
      hit_side = False
      for entity in blocks:
          if self.rect.colliderect(entity.rect):
  
              # move left and hit the block on the right
              if self.vel.x &lt; 0 and self.rect.right &gt; entity.rect.right:
                  self.rect.left = entity.rect.right
                  self.pos.x = self.rect.centerx
                  hit_side = True
  
              # move right and hit the block on the left
              if self.vel.x &gt; 0 and self.rect.left &lt; entity.rect.left:
                  self.rect.right = entity.rect.left
                  self.pos.x = self.rect.centerx
                  hit_side = True
  
      if hit_side:
          self.vel.x = 0
          self.acc.x = 0
  
    def update(self):
      hits = pygame.sprite.spritecollide(self, blocks, False)
  
      self.pos.y += self.vel.y + 0.5 * self.acc.y
      self.rect.midbottom = self.pos
  
      for entity in blocks:
          if self.rect.colliderect(entity.rect):
              if self.vel.y &gt; 0:
                  self.rect.bottom = entity.rect.top
                  self.pos.y = self.rect.bottom
                  self.vel.y = 0
      if self.vel.y &gt; 0:
        if hits: 
          self.pos.y = hits[0].rect.top + 1
          self.vel.y = 0
  
      # Now we check if we hit the Player
      if self.rect.colliderect(player.rect):
        # Attempt to check the player inventory
        if self.type not in player.inventory.keys():
          
          player.inventory[self.type] = 1
          self.kill()
        else:
          
          player.inventory.update({self.type: player.inventory.get(self.type) + 1})
          self.kill()
         
  player = Player()
  blueblock = BlueBlock(0,0)
  
  running = True
  
  all_sprites = pygame.sprite.Group()
  blocks = pygame.sprite.Group()
  items = pygame.sprite.Group()
  miscBlocks = pygame.sprite.Group()
  
  def drawGraph(graph, start):
    y = start
    x = 0
    for item in graph:
      if item == &quot;O&quot;:
        spr = BlueBlock(x, y)
        spr.rect.x = x
        spr.rect.y = y
        all_sprites.add(spr)
        miscBlocks.add(spr)
        screen.blit(spr.surf, spr.rect)
        x += 48
      elif item == &quot;G&quot;:
        spr = textureblock(&quot;media/Grass.jpeg&quot;, x, y, &quot;Grass&quot;)
        spr.rect.x = x
        spr.rect.y = y
        all_sprites.add(spr)
        blocks.add(spr)
        screen.blit(spr.image, spr.rect)
        x += 48
        
      elif item == &quot;S&quot;:
        spr = textureblock(&quot;media/Stone.png&quot;,x,y, &quot;Stone&quot;)
        spr.rect.x = x
        spr.rect.y = y
        all_sprites.add(spr)
        blocks.add(spr)
        screen.blit(spr.image, spr.rect)
        x += 48
      elif item == &quot;C&quot;:
        spr = textureblock(&quot;media/Coal.jpeg&quot;,x,y, &quot;Coal&quot;)
        spr.rect.x = x
        spr.rect.y = y
        all_sprites.add(spr)
        blocks.add(spr)
        screen.blit(spr.image, spr.rect)
        x += 48
      elif item == &quot;NL&quot;:
        y += 48
        x = 0
      else:
        print(&quot;Item not found: &quot; + item)
    print(&quot;[Debug] Generation finished. Amount of blocks: &quot; + str(len(blocks.sprites())))
  
  def randomGen(graph):
    print(&quot;[Debug] Begin randomGen...&quot;)
    # We assume the user has not done anything with the graph, so we add the sky and grass
    for i in range(20):
      newgraph.append('O')
    newgraph.append('NL')
    
    for i in range(20):
      newgraph.append('O')
    newgraph.append('NL')
    for i in range(20):
      newgraph.append('O')
    newgraph.append('NL')
    for i in range(20):
      newgraph.append('O')
    newgraph.append('NL')
    for i in range(20):
      newgraph.append('O')
    newgraph.append('NL')
    for i in range(20):
      newgraph.append('G')
    newgraph.append('NL')
  
    # Next begins the random ore gen
    
    for i in range(20):
      x = 0
      for i in range(20):
        # Chance of coal - 1 in 15
        iscoal = random.randint(1,15)
        
        if iscoal == 6:
          graph.append(&quot;C&quot;)
         
        else:
          graph.append(&quot;S&quot;)
        x += 48
      graph.append('NL')
    print(&quot;[Debug] randomGen finished. Block Stats: %s air blocks, %s grass blocks, %s stone blocks, %s coal blocks, and %s newlines.&quot; % (str(graph.count('O')), str(graph.count('G')), str(graph.count('S')), str(graph.count('C')), str(graph.count('NL'))))
  
  newgraph = []
  randomGen(newgraph)
  
  all_sprites.add(player)
  
  def update():
    for entity in all_sprites:
      try:
        screen.blit(entity.surf, entity.rect)
      except:
        screen.blit(entity.image, entity.rect)
    screen.blit(player.surf, player.rect)
    for entity in blocks:
      screen.blit(entity.image, entity.rect)
    for entity in items:
      screen.blit(entity.image, entity.rect)
    pygame.display.update()
  
  drawGraph(newgraph, 0)
  
  # Calculate the size of the level
  level_width = 0
  for i in newgraph:
    if i != &quot;NL&quot;:
      level_width += 1
    elif i == &quot;NL&quot;:
      break
  level_width = level_width * TILE_SIZE
  
  level_height = (newgraph.count(&quot;NL&quot;)-1)*TILE_SIZE
  
  print(&quot;[Debug] Calculated level width and height: %s and %s&quot; % (str(level_width), str(level_height)))
  
  while running:
    for event in pygame.event.get():
      if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_SPACE:
          player.jump()
        if event.key == pygame.K_ESCAPE:
          running = False
          pygame.quit()
        if event.key == pygame.K_e:
          if len(player.inventory) == 0:
            print(&quot;Player Inventory: Empty&quot;)
          else:
            print(&quot;Player Inventory: &quot; + str(player.inventory).replace(&quot;{&quot;, &quot;&quot;).replace(&quot;}&quot;,&quot;&quot;).replace(&quot;:&quot;, &quot; x&quot;).replace(&quot;'&quot;,&quot;&quot;))
        if event.key == pygame.K_b:
          if player.mode == &quot;build&quot;:
            player.mode = &quot;destroy&quot;
          elif player.mode == &quot;destroy&quot;:
            player.mode = &quot;build&quot;
          print(&quot;Changed player mode to &quot; + player.mode)
        if event.key == pygame.K_1:
          
          player.selected_item = list(player.inventory)[0]
          print(&quot;Item: &quot; + list(player.inventory)[0])
      if event.type == pygame.MOUSEBUTTONDOWN:
        x,y = event.pos
      if event.type == pygame.QUIT:
        running = False
        pygame.quit()
        
    miscBlocks.update()
    blocks.update()
    blocks.draw(screen)
    
    pressed_keys = pygame.key.get_pressed()
    for entity in items:
      entity.move()
    # Commented out because it lagged everything.
  
    items.update()
    player.update()
    update()
    
    img1 = font.render(&quot;FPS: &quot; + str(clock.get_fps()), True, (255,255,0))
    img2 = font.render(&quot;Mode: &quot; + player.mode, True, (255,0,0))
    try:
      img3 = font.render(&quot;Selected Item: &quot; + player.selected_item, True, (0,255,0))
    except Exception:
      img3 = font.render(&quot;Selected Item: None&quot;, True, (0,255,0))
  
    screen.blit(img1, (0,0))
    screen.blit(img2, (0,24))
    screen.blit(img3, (0,48))
    
    pygame.display.update()
    clock.tick(60)
  </code></pre>