A tilemap is a 2D grid where each cell holds a small integer (tile ID) that maps to a tile image. This is how almost every 2D game stores its levels β from Super Mario Bros to modern indie games.
What is a Tilemap?
A tilemap is a 2D grid where each cell holds a small integer (tile ID) that maps to a tile image. This is how almost every 2D game stores its levels β from Super Mario Bros to modern indie games.
A tilemap is a 2D grid where each cell holds a small integer (tile ID) that maps to a tile image. This is how almost every 2D game stores its levels β from Super Mario Bros to modern indie games.
Benefits of tilemaps: - Levels are compact β a 100Γ50 map is just 5,000 integers - Easy to serialize (save/load levels as text files) - Efficient rendering β draw only visible tiles (culling) - Reusable assets β 10 tile images can build infinite levels
Culling savings β tiles skipped vs drawn each frame
============================================================
Map size Total Visible Skipped Saved
--------------------------------------------------------
Small (20Γ15) 300 300 0 0%
Medium (50Γ30) 1500 408 1092 73%
Large (100Γ50) 5000 408 4592 92%
Huge (200Γ80) 16000 408 15592 97%
The Camera
The camera represents the viewport into the world. Everything is drawn in world space and converted to screen space for rendering.
class Camera:def__init__(self, view_w, view_h):self.x =0.0# Camera top-left in world spaceself.y =0.0self.zoom =1.0def world_to_screen(self, wx, wy):"""What screen pixel does this world coordinate map to?""" sx = (wx -self.x) *self.zoom sy = (wy -self.y) *self.zoomreturnint(sx), int(sy)def screen_to_world(self, sx, sy):"""What world coordinate is under this screen pixel?""" wx = sx /self.zoom +self.x wy = sy /self.zoom +self.yreturn wx, wydef follow(self, target_x, target_y, dt, world_w, world_h):"""Smooth follow with lerp.""" desired_x = target_x -self.view_w / (2*self.zoom) desired_y = target_y -self.view_h / (2*self.zoom)self.x += (desired_x -self.x) *6.0* dt # Lerp# Clamp to world boundsself.x =max(0, min(self.x, world_w -self.view_w /self.zoom))self.y =max(0, min(self.y, world_h -self.view_h /self.zoom))
Camera Dead Zone
A dead zone is a region around the screen center where the camera doesnβt move. The player can walk freely within the dead zone; the camera only moves when the player hits its edge.
Screen:
ββββββββββββββββββββββββββββββββββββ
β β
β ββββββββββββββββ β
β β DEAD ZONE β β
β β Player β β β camera β
β β moves here β doesn't β
β β freely β move β
β ββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββ
Parallax makes the world feel deep by scrolling different background layers at different speeds.
Layer Speed (% of camera) Perceived depth
βββββ βββββββββββββββββββ βββββββββββββββ
Stars 5% Very far away
Distant mountains 15% Far
Near mountains 25% Medium
Clouds 30β50% Near background
class ParallaxLayer:""" factor = 0.0 β stationary (sky) factor = 1.0 β moves with the world (foreground) """def__init__(self, factor):self.factor = factordef draw(self, surface, camera_x): offset_x =int(camera_x *self.factor)for element inself.elements: screen_x = element.x - offset_x# Seamless horizontal wrap screen_x = screen_x % (WORLD_W + SCREEN_W) - SCREEN_W# Draw at screen_x...
Parallax Scrolling
Camera scrolled 500px to the right
Layer Factor Scrolled Illusion
--------------------------------------------------------
Stars (far) 0.05 25 Stationary
Distant mountains 0.15 75 Very far
Near mountains 0.25 125 Far
Far clouds 0.30 150 Far
Near clouds 0.50 250 Medium
Background trees 0.70 350 Same as world
World objects 1.00 500 Same as world
Tilemaps & Camera β Summary
Tilemap = 2D list of ints β compact, serializable, efficient
Culling: only draw tiles within the viewport β critical for large maps
Camera converts world βοΈ screen coordinates for every object
Smooth follow: lerp toward desired camera position each frame
Dead zone: player moves freely in a central region before camera tracks