- on Thu 18 July 2019
After I completed the Revised Python Tutorial and started playing with different ways to procedurally generate street-like maps, I realised that I wanted to change the way the map was rendered — I wanted a scrolling map.
Below, I have detailed the process to get there beginning from a clone of this repo, which is a fork of TStand90's repository roguelike-tutorial-2019.
-
Start by creating a file called 'camera.py' the following code:
class Camera: def __init__(self, x: int, y: int, width: int, height: int, map_width: int, map_height: int): self.x = x self.y = y self.width = width self.height = height self.map_width = map_width self.map_height = map_height def apply(self, x, y): x = x + self.x y = y + self.y return (x, y) def update(self, entity): x = -entity.x + int(self.width / 2) y = -entity.y + int(self.height / 2) # TODO add limits to stop camera near map edges self.x, self.y = (x, y)
-
In 'engine.py' import our new camera class:
from camera import Camera
-
Now create a new camera object and update it with the player's map coordinates. This code should be added after the game map has been created:
camera = Camera( x=0, y=0, width=screen_width, height=screen_height, map_width=map_width, map_height=map_height, ) camera.update(player)
-
We also want to update the camera after the player moves: ... player.move(dx, dy)
camera.update(player) fov_recompute = True ...
-
We need to pass the camera to the render_all() function:
render_all(entities=entities, game_map=game_map, colors=colors, camera=camera)
-
Import the camera class into 'render_functions.py'
-
Change 'render_functions.py' to pass the camera to the draw functions:
def render_all(entities: List[Entity], game_map: GameMap, colors, camera: Camera): # Draw the map game_map.render(colors=colors, camera=camera) # Draw all entities in the list for entity in entities: if game_map.fov[entity.x, entity.y]: entity.draw(camera)
-
In 'entity.py' shift the coordinates at which entities are being drawn.
def draw(self, camera): """ Draw the entity to the terminal """ x, y = camera.apply(self.x, self.y) terminal.printf(x=x, y=y, s=f'[color={self.color}]{self.char}[/color]')
-
Import the camera class into 'game_map.py'
from camera import Camera
-
In 'game_map.py', pass the camera to the render method and shift the coordinates for each x and y on the map before drawing:
def render(self, colors, camera: Camera): for y in range(self.height): for x in range(self.width): wall = self.is_blocked(x, y) visible = self.fov[x, y] x_in_camera, y_in_camera = camera.apply(x, y) if visible: if wall: terminal.printf( x=x_in_camera, y=y_in_camera, s=f'[color={colors.get("light_wall")}]#[/color]', ) else: terminal.printf( x=x_in_camera, y=y_in_camera, s=f'[color={colors.get("light_ground")}].[/color]', ) elif self.explored[x, y]: if wall: terminal.printf( x=x_in_camera, y=y_in_camera, s=f'[color={colors.get("dark_wall")}]#[/color]', ) else: terminal.printf( x=x_in_camera, y=y_in_camera, s=f'[color={colors.get("dark_ground")}].[/color]', ) self.explored |= self.fov
And that's it! Now when you execute 'python engine.py' the player should be in the centre of the game window and the map should scroll as the player moves.