Trying to make a top down shooter on pygame and having trouble trying to figure out how to scroll the map when the player moves

Question:

I am currently trying to make a top down shooter game, but I am having a bit of trouble trying to figure out how to move the map when the character moves (Up, down, left, and right). I want the map to always fill the screen but when the character moves the map will move with it. I have looked online trying to find some solutions but having a hard time trying to implement it into my own program.

import pygame
pygame.display.set_caption("TEST")

clock = pygame.time.Clock()

class Player():

  def __init__(self,x,y):
    self.Image = pygame.image.load("myAvatar.png").convert()

    self.rect  = self.Image.get_rect(topleft = (x,y))

  def getX(self):
    return self.rect.x

  def getY(self):
    return self.rect.y

  def handle_keys(self,screenHeight,screenWidth):
      key = pygame.key.get_pressed()
      dist = 1 

      if key[pygame.K_DOWN]: 
          self.rect.y += dist
          if self.rect.y > screenHeight:
            self.rect.y = screenHeight
    
      elif key[pygame.K_UP]: 
          self.rect.y -= dist
          if self.rect.y < 0:
            self.rect.y = 0  
      if key[pygame.K_RIGHT]: 
          self.rect.x += dist
          if self.rect.x > screenWidth:
            self.rect.x = screenWidth
      elif key[pygame.K_LEFT]: 
          self.rect.x -= dist
          if self.rect.x < 0:
            self.rect.x = 0 

  def draw(self, game_window,screenX,screenY):
    self.Image = pygame.transform.scale(self.Image,(20,20))
    game_window.blit(self.Image, (screenX, screenY))


class Map():
  def __init__(self):
    self.Image = pygame.image.load("testbackground.jpg").convert()
    self.rect = self.Image.get_rect()
    self.rect.x = 0
    self.rect.y = 0

  def getX(self):
    return self.rect.x

  def getY(self):
    return self.rect.y

  def setX(self,newX):
    self.rect.x = newX
  
  def setY(self,newY):
    self.rect.y = newY

  def draw(self, game_window,screenX,screenY):
    self.Image = pygame.transform.scale(self.Image,(800,800))
    game_window.blit(self.Image,(screenX, screenY))


class Enemy():

  def __init__ (self,x,y):
    self.Image = pygame.image.load("WC.jpg").convert()
    self.rect  = self.Image.get_rect(topleft = (x,y))

  def draw(self, game_window):
    self.Image = pygame.transform.scale(self.Image,(20,20))
    game_window.blit(self.Image, (self.rect.x, self.rect.y))


pygame.init()

clock = pygame.time.Clock()
screenWidth = 400
screenHeight = 400
game_window = pygame.display.set_mode((screenWidth,screenHeight))
player = Player(200,200)
map = Map()
enemy = Enemy(250,250)
leave = False
while not leave:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      pygame.quit() 
      running = False

  playerX = player.getX()
  playerY = player.getY()

  mapX = map.getX()
  mapY = map.getY()

  screenX = playerX - (screenWidth/2)
  if screenX < 0:
    screenX = 0
  if screenX > (mapX - screenWidth):
    screenX = (mapX - screenWidth)

  screenY = playerY - (screenHeight/2)
  if screenY < 0:
    screenY = 0
  if screenY > (mapY - screenHeight):
    screenY = (mapY - screenHeight)
  
  player.handle_keys(screenHeight,screenWidth)

  map.draw(game_window,screenX,screenY)
  enemy.draw(game_window)
  player.draw(game_window,screenX,screenY)
  pygame.display.update()
  pygame.display.flip()
  clock.tick(60)


pygame.quit()
quit()
Asked By: Shay

||

Answers:

You can move the camera like in this question:

Basically, every sprite has a position, and is drawn on the screen like this:

pos_on_the_screen = (posX - cameraX, posY - cameraY)

Then, the camera follows the player like this:

width, height = sceen_size
camera_pos = (player.posX - width / 2, player.posY - height / 2)

In this case, the player stays in the center of the screen.


If you want the camera to follow the player, but you don’t want the player to be constantly in the center (it could move a little bit, but not exit the screen), you can use this method:

width, height = screen_size
if cameraX - playerX > 2 * width / 3: # player exits to the right
    cameraX = playerX - 2 * width / 3
elif cameraX - playerX < width / 3: # player exits to the left
    cameraX = playerX - width / 3
if cameraY - playerY > 2 * height / 3: # player exits to the bottom
    cameraY = playerY - 2 * height / 3
elif cameraY - playerY < height / 3: # player exits to the top
    cameraY = playerY - height / 3

In this example, the player never goes out of this space:

You can also use a more compact form:

width, height = screen_size
cameraX = min(max(cameraX, playerX - 2 * width / 3), playerX - width / 3)
cameraY = min(max(cameraY, playerY - 2 * height / 3), playerY - height / 3)

Example:

https://github.com/d-002/camera-scrolling

Answered By: D_00
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.