Game Development

Creating interactive digital experiences and video games.

1. Game Loop (Pygame)

1. Game Loop (Pygame) is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

2. Collision Detection (AABB & Circle)

2. Collision Detection (AABB & Circle) is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

3. Entity Component System (ECS)

3. Entity Component System (ECS) is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Design principles, analysis methods, standards and codes, and real-world case studies.

4. Procedural Dungeon Generation

4. Procedural Dungeon Generation is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

5. Steering Behaviors (Autonomous Agents)

5. Steering Behaviors (Autonomous Agents) is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

6. Game State Management

6. Game State Management is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

7. Shader Programming (GLSL)

7. Shader Programming (GLSL) is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Syntax and semantics, best practices, debugging techniques, and project-based application.

8. Audio System โ€” Sound Manager

8. Audio System โ€” Sound Manager is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Design principles, analysis methods, standards and codes, and real-world case studies.

9. Tile-Based Level System

9. Tile-Based Level System is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Design principles, analysis methods, standards and codes, and real-world case studies.

10. Unity C# โ€” Player Controller

10. Unity C# โ€” Player Controller is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Game Engine Architecture

Game Engine Architecture is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Popular Game Engines

Popular Game Engines is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Game Physics

Game Physics is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Artificial Intelligence in Games

Artificial Intelligence in Games is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Game Design Patterns

Game Design Patterns is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Design principles, analysis methods, standards and codes, and real-world case studies.

Rendering Techniques

Rendering Techniques is a clinical topic covering pathophysiology, diagnosis, evidence-based treatment, and patient care.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Multiplayer Game Development

Multiplayer Game Development is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Syntax and semantics, best practices, debugging techniques, and project-based application.

Game Optimization

Game Optimization is a core technology topic with practical implementations, complexity analysis, and real-world applications.

Key points: Core principles, practical applications, and advanced concepts that build deep understanding.

Key Code Examples

1. Game Loop (Pygame)

import pygame import sys from dataclasses import dataclass, field from typing import List import time pygame.init() # Display setup SCREEN_WIDTH, SCREEN_HEIGHT = 800, 600 FPS = 60 screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("EduVerse Game") clock = pygame.time.Clock() @dataclass class Vector2: x: float = 0.0 y: float = 0.0 def __add__(self, other): return Vector2(self.x + other.x, self.y + other.y) def __mul__(self, scalar): return Vector2(self.x * scalar, self.y * scalar) @dataclass class GameObject: """Base class for all game objects.""" position: Vector2 = field(default_factory=Vector2) velocity: Vector2 = field(default_factory=Vector2) acceleration: Vector2 = field(default_factory=Vector2) width: int = 32 height: int = 32 color: tuple = (255, 255, 255) mass: float = 1.0 @property def rect(self): return pygame.Rect(self.position.x, self.position.y, self.width, self.height) def update(self, dt: float): """Update physics.""" self.velocity = self.velocity + self.acceleration * dt self.position = self.position + self.velocity * dt def draw(self, surface): pygame.draw.rect(surface, self.color, self.rect) class Player(GameObject): def __init__(self): super().__init__(position=Vector2(400, 300), width=32, height=32, color=(0, 128, 255)) self.speed = 300 # pixels per second self.jump_force = 500 self.on_ground = False def handle_input(self, keys): """Process keyboard input.""" if keys[pygame.K_LEFT] or keys[pygame.K_a]: self.velocity.x = -self.speed elif keys[pygame.K_RIGHT] or keys[pygame.K_d]: self.velocity.x = self.speed else: self.velocity.x = 0 if (keys[pygame.K_SPACE] or keys[pygame.K_UP]) and self.on_ground: self.velocity.y = -self.jump_force self.on_ground = False class Game: """Main game class managing the game loop.""" def __init__(self): self.running = True self.game_objects: List[GameObject] = [] self.player = Player() self.gravity = Vector2(0, 800) # pixels per second^2 self.score = 0 self.font = pygame.font.Font(None, 36) def handle_events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.running = False def update(self, dt: float): keys = pygame.key.get_pressed() self.player.handle_input(keys) # Apply gravity self.player.acceleration = self.gravity # Update all objects for obj in self.game_objects: obj.update(dt) self.player.update(dt) # Ground collision if self.player.position.y >= SCREEN_HEIGHT - 64: self.player.position.y = SCREEN_HEIGHT - 64 self.player.velocity.y = 0 self.player.on_ground = True # Boundary checks self.player.position.x = max(0, min(SCREEN_WIDTH - 32, self.player.position.x)) def draw(self): screen.fill((30, 30, 30)) # Dark background for obj in self.game_objects: obj.draw(screen) self.player.draw(screen) # Draw HUD score_text = self.font.render(f"Score: {self.score}", True, (255, 255, 255)) screen.blit(score_text, (10, 10)) pygame.display.flip() def run(self): """Main game loop with fixed timestep.""" previous_time = time.time() while self.running: current_time = time.time() dt = min(current_time - previous_time, 0.1) # Cap at 100ms previous_time = current_time self.handle_events() self.update(dt) self.draw() clock.tick(FPS) pygame.quit() sys.exit() # Run game if __name__ == "__main__": game = Game() game.run()

2. Collision Detection (AABB & Circle)

import math from dataclasses import dataclass from typing import Optional @dataclass class AABB: """Axis-Aligned Bounding Box.""" x: float y: float width: float height: float @property def left(self): return self.x @property def right(self): return self.x + self.width @property def top(self): return self.y @property def bottom(self): return self.y + self.height @property def center(self): return (self.x + self.width/2, self.y + self.height/2) @dataclass class Circle: cx: float cy: float radius: float def aabb_collision(a: AABB, b: AABB) -> bool: """Check if two AABBs overlap.""" return (a.left < b.right and a.right > b.left and a.top < b.bottom and a.bottom > b.top) def circle_collision(a: Circle, b: Circle) -> bool: """Check if two circles overlap.""" dx = a.cx - b.cx dy = a.cy - b.cy dist_sq = dx*dx + dy*dy radius_sum = a.radius + b.radius return dist_sq < radius_sum * radius_sum def circle_aabb_collision(circle: Circle, box: AABB) -> bool: """Check if a circle overlaps with an AABB.""" # Find closest point on box to circle center closest_x = max(box.left, min(circle.cx, box.right)) closest_y = max(box.top, min(circle.cy, box.bottom)) # Distance from circle center to closest point dx = circle.cx - closest_x dy = circle.cy - closest_y return (dx*dx + dy*dy) < (circle.radius * circle.radius) def resolve_aabb_collision(a: AABB, b: AABB) -> Optional[tuple]: """Calculate minimum translation vector to separate AABBs.""" a_cx, a_cy = a.center b_cx, b_cy = b.center # Overlap on each axis overlap_x = (a.width + b.width) / 2 - abs(a_cx - b_cx) overlap_y = (a.height + b.height) / 2 - abs(a_cy - b_cy) if overlap_x <= 0 or overlap_y <= 0: return None # No collision # Resolve along axis of least penetration if overlap_x < overlap_y: direction = 1 if a_cx < b_cx else -1 return (overlap_x * direction, 0) else: direction = 1 if a_cy < b_cy else -1 return (0, overlap_y * direction) # Example usage player = AABB(100, 100, 32, 32) enemy = AABB(120, 110, 32, 32) print(aabb_collision(player, enemy)) # True ball = Circle(50, 50, 10) wall = AABB(55, 40, 20, 20) print(circle_aabb_collision(ball, wall)) # True mtv = resolve_aabb_collision(player, enemy) print(f"Push player by: {mtv}")

3. Entity Component System (ECS)

from dataclasses import dataclass, field from typing import Dict, List, Type, TypeVar, Set import uuid T = TypeVar('T') # ===== Components (pure data) ===== @dataclass class Position: x: float = 0.0 y: float = 0.0 @dataclass class Velocity: vx: float = 0.0 vy: float = 0.0 @dataclass class Health: current: int = 100 maximum: int = 100 @property def is_alive(self): return self.current > 0 @property def percent(self): return self.current / self.maximum * 100 @dataclass class Renderable: sprite: str = "default.png" layer: int = 0 color: tuple = (255, 255, 255) @dataclass class Collider: radius: float = 16.0 is_trigger: bool = False # ===== Entity (just an ID) ===== class Entity: _next_id = 0 def __init__(self): self.id = Entity._next_id Entity._next_id += 1 def __hash__(self): return self.id def __eq__(self, other): return isinstance(other, Entity) and self.id == other.id # ===== ECS World ===== class World: def __init__(self): self.entities: Set[Entity] = set() self.components: Dict[Type, Dict[Entity, any]] = {} self.systems: List[System] = [] def create_entity(self, *components) -> Entity: entity = Entity() self.entities.add(entity) for component in components: self.add_component(entity, component) return entity def add_component(self, entity: Entity, component): comp_type = type(component) if comp_type not in self.components: self.components[comp_type] = {} self.components[comp_type][entity] = component def remove_component(self, entity: Entity, comp_type: Type): if comp_type in self.components: self.components[comp_type].pop(entity, None) def get_component(self, entity: Entity, comp_type: Type[T]) -> T: return self.components.get(comp_type, {}).get(entity) def query(self, *component_types: Type) -> List[tuple]: """Get all entities with specified components.""" if not component_types: return [] # Start with entities having the first component result = set(self.components.get(component_types[0], {}).keys()) # Intersect with remaining component types for comp_type in component_types[1:]: result &= set(self.components.get(comp_type, {}).keys()) # Return entities with their components return [(entity, *[self.get_component(entity, ct) for ct in component_types]) for entity in result] def add_system(self, system): system.world = self self.systems.append(system) def update(self, dt: float): for system in self.systems: system.update(dt) # ===== Systems ===== class MovementSystem: def __init__(self): self.world = None def update(self, dt: float): for entity, pos, vel in self.world.query(Position, Velocity): pos.x += vel.vx * dt pos.y += vel.vy * dt class HealthSystem: def __init__(self): self.world = None def update(self, dt: float): dead = [] for entity, health in self.world.query(Health): if not health.is_alive: dead.append(entity) for entity in dead: print(f"Entity {entity.id} died!") self.world.entities.discard(entity) # Usage world = World() world.add_system(MovementSystem()) world.add_system(HealthSystem()) # Create entities player = world.create_entity( Position(x=0, y=0), Velocity(vx=100, vy=0), Health(current=100, maximum=100), Renderable(sprite="player.png") ) enemy = world.create_entity( Position(x=200, y=0), Velocity(vx=-50, vy=0), Health(current=50, maximum=50), Collider(radius=20) ) # Game loop import time for _ in range(60): # 60 frames world.update(dt=1/60) pos = world.get_component(player, Position) print(f"Player position: ({pos.x:.1f}, {pos.y:.1f})")

4. Procedural Dungeon Generation

import random import numpy as np from typing import List, Tuple from enum import IntEnum class Tile(IntEnum): WALL = 0 FLOOR = 1 DOOR = 2 CHEST = 3 ENEMY = 4 PLAYER = 5 class DungeonGenerator: """Procedural dungeon generation using BSP (Binary Space Partition).""" def __init__(self, width=60, height=40, min_room_size=5): self.width = width self.height = height self.min_room_size = min_room_size self.grid = np.full((height, width), Tile.WALL, dtype=int) self.rooms: List[Tuple[int, int, int, int]] = [] # x, y, w, h self.doors: List[Tuple[int, int]] = [] def generate(self, num_rooms=10, seed=None) -> np.ndarray: """Generate a dungeon with rooms and corridors.""" if seed is not None: random.seed(seed) # BSP partitioning self._split_bsp(0, 0, self.width, self.height, depth=0, max_depth=4) # Connect rooms with corridors self._connect_rooms() # Place features self._place_features() return self.grid def _split_bsp(self, x, y, w, h, depth, max_depth): """Recursively split space using BSP.""" if depth >= max_depth or w < self.min_room_size * 2 or h < self.min_room_size * 2: self._create_room(x, y, w, h) return # Choose split direction (horizontal or vertical) if w > h: split = random.randint(self.min_room_size, w - self.min_room_size) self._split_bsp(x, y, split, h, depth+1, max_depth) self._split_bsp(x+split, y, w-split, h, depth+1, max_depth) else: split = random.randint(self.min_room_size, h - self.min_room_size) self._split_bsp(x, y, w, split, depth+1, max_depth) self._split_bsp(x, y+split, w, h-split, depth+1, max_depth) def _create_room(self, x, y, w, h): """Create a room within the given bounds.""" # Shrink to ensure walls around room room_w = random.randint(self.min_room_size, w-2) room_h = random.randint(self.min_room_size, h-2) room_x = x + random.randint(1, max(1, w - room_w - 1)) room_y = y + random.randint(1, max(1, h - room_h - 1)) # Carve room self.grid[room_y:room_y+room_h, room_x:room_x+room_w] = Tile.FLOOR self.rooms.append((room_x, room_y, room_w, room_h)) def _connect_rooms(self): """Connect rooms with L-shaped corridors.""" for i in range(len(self.rooms) - 1): x1 = self.rooms[i][0] + self.rooms[i][2] // 2 y1 = self.rooms[i][1] + self.rooms[i][3] // 2 x2 = self.rooms[i+1][0] + self.rooms[i+1][2] // 2 y2 = self.rooms[i+1][1] + self.rooms[i+1][3] // 2 # L-shaped corridor if random.random() < 0.5: self._carve_h_corridor(x1, x2, y1) self._carve_v_corridor(y1, y2, x2) else: self._carve_v_corridor(y1, y2, x1) self._carve_h_corridor(x1, x2, y2) def _carve_h_corridor(self, x1, x2, y): for x in range(min(x1, x2), max(x1, x2) + 1): if 0 <= x < self.width and 0 <= y < self.height: self.grid[y][x] = Tile.FLOOR def _carve_v_corridor(self, y1, y2, x): for y in range(min(y1, y2), max(y1, y2) + 1): if 0 <= y < self.height and 0 <= x < self.width: self.grid[y][x] = Tile.FLOOR def _place_features(self): """Place player, enemies, and chests.""" if not self.rooms: return # Player in first room r = self.rooms[0] px = r[0] + r[2] // 2 py = r[1] + r[3] // 2 self.grid[py][px] = Tile.PLAYER # Enemies and chests in other rooms for room in self.rooms[1:]: rx = room[0] + random.randint(0, room[2]-1) ry = room[1] + random.randint(0, room[3]-1) if self.grid[ry][rx] == Tile.FLOOR: if random.random() < 0.5: self.grid[ry][rx] = Tile.ENEMY else: self.grid[ry][rx] = Tile.CHEST def display(self): """ASCII display of the dungeon.""" chars = {Tile.WALL: '#', Tile.FLOOR: '.', Tile.DOOR: '+', Tile.CHEST: '$', Tile.ENEMY: 'E', Tile.PLAYER: '@'} for row in self.grid: print(''.join(chars[Tile(cell)] for cell in row)) # Generate and display dungeon generator = DungeonGenerator(width=60, height=20) dungeon = generator.generate(num_rooms=8, seed=42) generator.display()

5. Steering Behaviors (Autonomous Agents)

import math import random from dataclasses import dataclass from typing import List @dataclass class Vector2: x: float y: float def __add__(self, other): return Vector2(self.x+other.x, self.y+other.y) def __sub__(self, other): return Vector2(self.x-other.x, self.y-other.y) def __mul__(self, s): return Vector2(self.x*s, self.y*s) @property def magnitude(self): return math.sqrt(self.x**2 + self.y**2) @property def normalized(self): mag = self.magnitude if mag == 0: return Vector2(0, 0) return Vector2(self.x/mag, self.y/mag) def limit(self, max_mag): if self.magnitude > max_mag: return self.normalized * max_mag return self class Boid: """Autonomous agent for flocking behavior.""" def __init__(self, x, y): self.position = Vector2(x, y) self.velocity = Vector2(random.uniform(-1, 1), random.uniform(-1, 1)) self.acceleration = Vector2(0, 0) self.max_speed = 4.0 self.max_force = 0.1 self.perception_radius = 50 def apply_force(self, force: Vector2): self.acceleration = self.acceleration + force def seek(self, target: Vector2, weight=1.0) -> Vector2: """Steer towards target position.""" desired = target - self.position desired = desired.normalized * self.max_speed steer = desired - self.velocity return steer.limit(self.max_force) * weight def flee(self, target: Vector2, weight=1.0) -> Vector2: """Steer away from target.""" return self.seek(target, -weight) def arrive(self, target: Vector2, slowing_radius=100, weight=1.0) -> Vector2: """Seek target but slow down when close.""" diff = target - self.position dist = diff.magnitude if dist < slowing_radius: speed = self.max_speed * (dist / slowing_radius) else: speed = self.max_speed desired = diff.normalized * speed steer = desired - self.velocity return steer.limit(self.max_force) * weight def separate(self, boids: List['Boid'], weight=1.5) -> Vector2: """Avoid crowding neighbors.""" steer = Vector2(0, 0) count = 0 for other in boids: if other is self: continue d = (self.position - other.position).magnitude if 0 < d < self.perception_radius: diff = (self.position - other.position).normalized / d steer = steer + diff count += 1 if count > 0: steer = steer * (1.0 / count) steer = steer.normalized * self.max_speed steer = steer - self.velocity return steer.limit(self.max_force) * weight return steer def align(self, boids: List['Boid'], weight=1.0) -> Vector2: """Match velocity of neighbors.""" avg = Vector2(0, 0) count = 0 for other in boids: if other is self: continue if (other.position - self.position).magnitude < self.perception_radius: avg = avg + other.velocity count += 1 if count > 0: avg = avg * (1.0 / count) avg = avg.normalized * self.max_speed steer = avg - self.velocity return steer.limit(self.max_force) * weight return avg def cohesion(self, boids: List['Boid'], weight=1.0) -> Vector2: """Move toward center of neighbors.""" center = Vector2(0, 0) count = 0 for other in boids: if other is self: continue if (other.position - self.position).magnitude < self.perception_radius: center = center + other.position count += 1 if count > 0: center = center * (1.0 / count) return self.seek(center, weight) return center def update(self, dt=1.0): self.velocity = (self.velocity + self.acceleration * dt).limit(self.max_speed) self.position = self.position + self.velocity * dt self.acceleration = Vector2(0, 0) def draw(self, surface): angle = math.atan2(self.velocity.y, self.velocity.x) # Draw triangle pointing in movement direction tip = self.position + Vector2(math.cos(angle)*10, math.sin(angle)*10) left = self.position + Vector2(math.cos(angle+2.5)*7, math.sin(angle+2.5)*7) right = self.position + Vector2(math.cos(angle-2.5)*7, math.sin(angle-2.5)*7) # pygame.draw.polygon(surface, (0, 150, 255), [tip, left, right])

6. Game State Management

from typing import Dict, Callable, Any from enum import Enum, auto import copy class GameState(Enum): LOADING = auto() MAIN_MENU = auto() PLAYING = auto() PAUSED = auto() GAME_OVER = auto() SETTINGS = auto() class GameStateMachine: """Hierarchical game state manager.""" def __init__(self): self.current_state: GameState = GameState.LOADING self.previous_state: GameState = None self.state_data: Dict[GameState, Any] = {} self.transitions: Dict[tuple, Callable] = {} self.global_data: Dict[str, Any] = {} # Define valid transitions self._setup_transitions() def _setup_transitions(self): """Define allowed state transitions.""" valid = { GameState.LOADING: [GameState.MAIN_MENU], GameState.MAIN_MENU: [GameState.PLAYING, GameState.SETTINGS], GameState.PLAYING: [GameState.PAUSED, GameState.GAME_OVER], GameState.PAUSED: [GameState.PLAYING, GameState.MAIN_MENU], GameState.GAME_OVER: [GameState.MAIN_MENU, GameState.PLAYING], GameState.SETTINGS: [GameState.MAIN_MENU], } for from_state, to_states in valid.items(): for to_state in to_states: self.transitions[(from_state, to_state)] = None def can_transition(self, new_state: GameState) -> bool: """Check if transition is valid.""" return (self.current_state, new_state) in self.transitions def transition(self, new_state: GameState, data: Any = None): """Change to a new state.""" if not self.can_transition(new_state): raise ValueError( f"Invalid transition: {self.current_state.name} -> {new_state.name}" ) # Save current state data self.state_data[self.current_state] = self._capture_state() self.previous_state = self.current_state self.current_state = new_state # Restore new state data if exists if new_state in self.state_data: self._restore_state(self.state_data[new_state]) print(f"State: {self.previous_state.name} -> {new_state.name}") return self def _capture_state(self) -> dict: """Capture current state for restoration.""" return copy.deepcopy(self.global_data) def _restore_state(self, data: dict): """Restore state from saved data.""" self.global_data = copy.deepcopy(data) def update(self, dt: float): """Update current state.""" handler = getattr(self, f'_update_{self.current_state.name.lower()}', None) if handler: handler(dt) def _update_playing(self, dt): """Update gameplay.""" pass def _update_paused(self, dt): """Update pause menu.""" pass # Usage gsm = GameStateMachine() gsm.transition(GameState.MAIN_MENU) gsm.global_data["player_health"] = 100 gsm.transition(GameState.PLAYING) # Player takes damage gsm.global_data["player_health"] -= 20 print(f"Health: {gsm.global_data['player_health']}") gsm.transition(GameState.PAUSED) gsm.transition(GameState.PLAYING)

7. Shader Programming (GLSL)

// vertex_shader.glsl #version 330 core layout(location = 0) in vec3 aPosition; layout(location = 1) in vec2 aTexCoord; layout(location = 2) in vec3 aNormal; uniform mat4 uModel; uniform mat4 uView; uniform mat4 uProjection; uniform float uTime; out vec2 vTexCoord; out vec3 vNormal; out vec3 vWorldPos; void main() { vec4 worldPos = uModel * vec4(aPosition, 1.0); vWorldPos = worldPos.xyz; vTexCoord = aTexCoord; vNormal = mat3(uModel) * aNormal; gl_Position = uProjection * uView * worldPos; } // fragment_shader.glsl #version 330 core in vec2 vTexCoord; in vec3 vNormal; in vec3 vWorldPos; uniform sampler2D uTexture; uniform vec3 uLightPos; uniform vec3 uCameraPos; uniform float uTime; out vec4 FragColor; void main() { // Ambient float ambientStrength = 0.3; vec3 ambient = ambientStrength * vec3(1.0, 1.0, 1.0); // Diffuse vec3 lightDir = normalize(uLightPos - vWorldPos); float diff = max(dot(vNormal, lightDir), 0.0); vec3 diffuse = diff * vec3(1.0, 0.95, 0.8); // Specular vec3 viewDir = normalize(uCameraPos - vWorldPos); vec3 reflectDir = reflect(-lightDir, vNormal); float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0); vec3 specular = 0.5 * spec * vec3(1.0); // Texture vec4 texColor = texture(uTexture, vTexCoord); // Animated glow effect float glow = sin(uTime * 2.0 + vWorldPos.x) * 0.1 + 0.9; vec3 result = (ambient + diffuse + specular) * texColor.rgb * glow; FragColor = vec4(result, texColor.a); } // Python code to compile and use shaders (Pygame/ModernGL) import moderngl def create_shader_program(ctx, vertex_src, fragment_src): prog = ctx.program( vertex_shader=vertex_src, fragment_shader=fragment_src, ) return prog

8. Audio System โ€” Sound Manager

import pygame import os from typing import Dict, Optional from enum import Enum, auto class SoundType(Enum): SFX = auto() MUSIC = auto() VOICE = auto() class AudioManager: """Centralized audio management system.""" def __init__(self, sfx_volume=0.7, music_volume=0.5): pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=512) self.sounds: Dict[str, pygame.mixer.Sound] = {} self.current_music: Optional[str] = None self.music_paused = False # Channels for different sound types self.channels = { SoundType.SFX: pygame.mixer.Channel(0), SoundType.MUSIC: pygame.mixer.Channel(1), SoundType.VOICE: pygame.mixer.Channel(2), } self.set_sfx_volume(sfx_volume) self.set_music_volume(music_volume) def load_sound(self, name: str, filepath: str, sound_type=SoundType.SFX): """Preload a sound effect.""" if os.path.exists(filepath): self.sounds[name] = pygame.mixer.Sound(filepath) self.sounds[name].set_volume( 0.7 if sound_type == SoundType.SFX else 0.5 ) print(f"Loaded sound: {name}") def play_sfx(self, name: str, loops=0, maxtime=0, fade_ms=0): """Play a one-shot sound effect.""" if name in self.sounds: channel = self.channels[SoundType.SFX] channel.play(self.sounds[name], loops=loops, maxtime=maxtime, fade_ms=fade_ms) def play_music(self, filepath: str, loops=-1, fade_in_ms=1000): """Play background music with smooth transition.""" if self.current_music == filepath: return # Fade out current music if pygame.mixer.music.get_busy(): pygame.mixer.music.fadeout(500) pygame.time.wait(500) pygame.mixer.music.load(filepath) pygame.mixer.music.set_volume(0.5) pygame.mixer.music.play(loops=loops, fade_ms=fade_in_ms) self.current_music = filepath self.music_paused = False def pause_music(self): if pygame.mixer.music.get_busy() and not self.music_paused: pygame.mixer.music.pause() self.music_paused = True def resume_music(self): if self.music_paused: pygame.mixer.music.unpause() self.music_paused = False def stop_music(self, fade_out_ms=500): pygame.mixer.music.fadeout(fade_out_ms) self.current_music = None def set_sfx_volume(self, volume: float): self.channels[SoundType.SFX].set_volume(max(0.0, min(1.0, volume))) def set_music_volume(self, volume: float): pygame.mixer.music.set_volume(max(0.0, min(1.0, volume))) # Usage audio = AudioManager() audio.load_sound("jump", "assets/sounds/jump.wav") audio.load_sound("explosion", "assets/sounds/explosion.wav") audio.play_music("assets/music/level1.ogg") # In game events: # audio.play_sfx("jump") # audio.play_sfx("explosion", fade_ms=50)

9. Tile-Based Level System

import json from dataclasses import dataclass, field from typing import Dict, List, Optional from enum import IntEnum class TileType(IntEnum): EMPTY = 0 GROUND = 1 WALL = 2 WATER = 3 LAVA = 4 COIN = 5 SPIKE = 6 CHEST = 7 @dataclass class Tile: type: TileType = TileType.EMPTY walkable: bool = True deadly: bool = False collectible: bool = False sprite_id: str = "" @dataclass class TileLayer: name: str width: int height: int tiles: List[List[Tile]] = field(default_factory=list) visible: bool = True opacity: float = 1.0 def __post_init__(self): if not self.tiles: self.tiles = [[Tile() for _ in range(self.width)] for _ in range(self.height)] def get_tile(self, x: int, y: int) -> Optional[Tile]: if 0 <= x < self.width and 0 <= y < self.height: return self.tiles[y][x] return None def set_tile(self, x: int, y: int, tile: Tile): if 0 <= x < self.width and 0 <= y < self.height: self.tiles[y][x] = tile @dataclass class Level: name: str tile_width: int = 32 tile_height: int = 32 layers: List[TileLayer] = field(default_factory=list) entities: List[dict] = field(default_factory=list) player_start: tuple = (2, 2) @property def pixel_width(self): if self.layers: return self.layers[0].width * self.tile_width return 0 @property def pixel_height(self): if self.layers: return self.layers[0].height * self.tile_height return 0 def is_walkable(self, tile_x: int, tile_y: int) -> bool: """Check if a tile position is walkable.""" for layer in self.layers: tile = layer.get_tile(tile_x, tile_y) if tile and not tile.walkable: return False return True def save(self, filepath: str): """Save level to JSON.""" data = { "name": self.name, "tileWidth": self.tile_width, "tileHeight": self.tile_height, "playerStart": self.player_start, "layers": [], "entities": self.entities, } for layer in self.layers: layer_data = { "name": layer.name, "width": layer.width, "height": layer.height, "visible": layer.visible, "tiles": [[tile.type for tile in row] for row in layer.tiles] } data["layers"].append(layer_data) with open(filepath, 'w') as f: json.dump(data, f, indent=2) @classmethod def load(cls, filepath: str) -> 'Level': """Load level from JSON.""" with open(filepath, 'r') as f: data = json.load(f) level = cls( name=data["name"], tile_width=data["tileWidth"], tile_height=data["tileHeight"], player_start=tuple(data["playerStart"]), entities=data.get("entities", []), ) for layer_data in data["layers"]: layer = TileLayer( name=layer_data["name"], width=layer_data["width"], height=layer_data["height"], visible=layer_data["visible"], ) for y, row in enumerate(layer_data["tiles"]): for x, tile_type in enumerate(row): layer.tiles[y][x] = Tile(type=TileType(tile_type)) level.layers.append(layer) return level # Usage level = Level(name="Forest Level", tile_width=32, tile_height=32) ground = TileLayer(name="Ground", width=30, height=20) decoration = TileLayer(name="Decoration", width=30, height=20) # Set ground tiles for x in range(30): for y in range(15, 20): ground.set_tile(x, y, Tile(type=TileType.GROUND, walkable=True)) # Add some walls for x in range(10, 20): decoration.set_tile(x, 10, Tile(type=TileType.WALL, walkable=False)) level.layers = [ground, decoration] level.player_start = (2, 14) level.save("levels/forest_level.json")

10. Unity C# โ€” Player Controller

using UnityEngine; [RequireComponent(typeof(CharacterController))] public class PlayerController : MonoBehaviour { [Header("Movement Settings")] [SerializeField] private float moveSpeed = 5f; [SerializeField] private float sprintSpeed = 8f; [SerializeField] private float rotationSpeed = 720f; [SerializeField] private float jumpForce = 8f; [SerializeField] private float gravity = -20f; [Header("Ground Check")] [SerializeField] private Transform groundCheck; [SerializeField] private float groundDistance = 0.2f; [SerializeField] private LayerMask groundMask; // Components private CharacterController controller; private Camera mainCamera; // State private Vector3 velocity; private bool isGrounded; private bool isSprinting; // Animation private Animator animator; private static readonly int SpeedHash = Animator.StringToHash("Speed"); private static readonly int IsGroundedHash = Animator.StringToHash("IsGrounded"); private static readonly int JumpHash = Animator.StringToHash("Jump"); private void Awake() { controller = GetComponent(); animator = GetComponent(); mainCamera = Camera.main; Cursor.lockState = CursorLockMode.Locked; } private void Update() { HandleGroundCheck(); HandleMovement(); HandleJump(); ApplyGravity(); UpdateAnimation(); } private void HandleGroundCheck() { isGrounded = Physics.CheckSphere( groundCheck.position, groundDistance, groundMask); if (isGrounded && velocity.y < 0) { velocity.y = -2f; // Small downward force to keep grounded } } private void HandleMovement() { float horizontal = Input.GetAxisRaw("Horizontal"); float vertical = Input.GetAxisRaw("Vertical"); // Camera-relative movement Vector3 camForward = mainCamera.transform.forward; Vector3 camRight = mainCamera.transform.right; camForward.y = 0; camRight.y = 0; camForward.Normalize(); camRight.Normalize(); Vector3 moveDir = (camForward * vertical + camRight * horizontal).normalized; isSprinting = Input.GetKey(KeyCode.LeftShift); float speed = isSprinting ? sprintSpeed : moveSpeed; controller.Move(moveDir * speed * Time.deltaTime); // Rotate player to face movement direction if (moveDir.magnitude > 0.1f) { Quaternion targetRotation = Quaternion.LookRotation(moveDir); transform.rotation = Quaternion.RotateTowards( transform.rotation, targetRotation, rotationSpeed * Time.deltaTime); } } private void HandleJump() { if (Input.GetButtonDown("Jump") && isGrounded) { velocity.y = Mathf.Sqrt(jumpForce * -2f * gravity); animator.SetTrigger(JumpHash); } } private void ApplyGravity() { velocity.y += gravity * Time.deltaTime; controller.Move(velocity * Time.deltaTime); } private void UpdateAnimation() { float speed = new Vector2(controller.velocity.x, controller.velocity.z).magnitude; animator.SetFloat(SpeedHash, speed); animator.SetBool(IsGroundedHash, isGrounded); } }

Core Concepts

Game Engine Architecture

Definition:
A software framework that provides tools and systems for building games efficiently.

  • Rendering Engine:
    2D/3D graphics, shaders, lighting
  • Physics Engine:
    Collision detection, rigid body dynamics
  • Audio Engine:
    Sound effects, music, spatial audio
  • Input System:
    Keyboard, mouse, gamepad, touch
  • Scene Management:
    Level loading, entity management
  • Scripting:
    Game logic, AI, UI scripting

Popular Game Engines

  • Unity:
    C#, cross-platform, massive asset store โ€” most popular for indie/AA
  • Unreal Engine:
    C++, Blueprints, AAA graphics โ€” high-end 3D games
  • Godot:
    GDScript/C#, open-source, lightweight โ€” growing fast
  • GameMaker:
    GML, 2D-focused โ€” great for beginners
  • Pygame:
    Python, 2D โ€” educational and prototyping

Game Physics

Rigid Body Dynamics:
Objects with mass, velocity, and forces (gravity, friction, impulse).

Collision Detection:
Broad phase (BVH, spatial hash) + narrow phase (SAT, GJK algorithms).

Common Algorithms:
Verlet integration, impulse-based resolution, raycasting.

Artificial Intelligence in Games

  • State Machines:
    Simple AI with discrete states (idle, patrol, chase, attack)
  • Behavior Trees:
    Hierarchical decision-making for complex NPCs
  • Pathfinding:
    A*, navigation meshes, dynamic obstacle avoidance
  • Flocking:
    Boids algorithm for crowd/swarm behavior
  • GOAP:
    Goal-Oriented Action Planning โ€” dynamic decision making
  • Machine Learning:
    Neural networks for NPC behavior, procedural content

Game Design Patterns

  • Game Loop:
    Input โ†’ Update โ†’ Render cycle running at 30-60 FPS
  • Entity Component System:
    Composition over inheritance for game objects
  • Object Pool:
    Reuse objects instead of creating/destroying (performance)
  • State Pattern:
    Game states (menu, playing, paused) managed cleanly
  • Observer Pattern:
    Event system for decoupled communication
  • Command Pattern:
    Input handling, undo system, replay system

Rendering Techniques

  • Forward Rendering:
    Traditional, per-object lighting โ€” simple but limited lights
  • Deferred Rendering:
    G-buffer, many lights โ€” AAA games
  • 2D Tilemap:
    Grid-based rendering for pixel art games
  • Particle Systems:
    Fire, smoke, magic effects โ€” GPU-accelerated
  • Post-Processing:
    Bloom, motion blur, color grading โ€” screen-space effects

Multiplayer Game Development

Network Models:

  • Client-Server:
    Authoritative server โ€” most common for competitive games
  • Peer-to-Peer:
    Direct connection between players โ€” simpler but less secure
  • Listen Server:
    One player hosts โ€” common in co-op

Key Challenges:
Latency, prediction, reconciliation, cheating prevention

Game Optimization

  • Performance:
    Profile first, optimize bottlenecks โ€” CPU vs GPU vs memory
  • Draw Calls:
    Batch sprites, use atlases, LOD (Level of Detail)
  • Memory:
    Object pooling, asset streaming, garbage collection management
  • Loading:
    Async loading, level streaming, preloading assets

Worked Examples

Example 1: Build a Complete Pong Game

Problem:
Create a Pong game with paddles, ball physics, scoring, and AI opponent.

import pygame pygame.init() W, H = 800, 600 screen = pygame.display.set_mode((W, H)) clock = pygame.time.Clock() font = pygame.font.Font(None, 74) # Paddle class class Paddle: def __init__(self, x, y, is_ai=False): self.rect = pygame.Rect(x, y, 15, 100) self.speed = 7 self.score = 0 self.is_ai = is_ai def move(self, direction): self.rect.y += direction * self.speed self.rect.clamp_ip(screen.get_rect()) def ai_move(self, ball): # Simple AI: track ball with maximum speed if ball.rect.centery < self.rect.centery: self.move(-1) elif ball.rect.centery > self.rect.centery: self.move(1) # Ball class class Ball: def __init__(self): self.rect = pygame.Rect(W//2, H//2, 15, 15) self.vx = 5 * random.choice([-1, 1]) self.vy = 5 * random.choice([-1, 1]) def update(self, paddle1, paddle2): self.rect.x += self.vx self.rect.y += self.vy # Bounce off top/bottom if self.rect.top <= 0 or self.rect.bottom >= H: self.vy = -self.vy # Bounce off paddles if self.rect.colliderect(paddle1.rect) and self.vx < 0: self.vx = -self.vx * 1.05 # Speed up slightly offset = (self.rect.centery - paddle1.rect.centery) / 50 self.vy += offset * 3 if self.rect.colliderect(paddle2.rect) and self.vx > 0: self.vx = -self.vx * 1.05 offset = (self.rect.centery - paddle2.rect.centery) / 50 self.vy += offset * 3 # Score if self.rect.left <= 0: paddle2.score += 1 self.reset() elif self.rect.right >= W: paddle1.score += 1 self.reset() def reset(self): self.rect.center = (W//2, H//2) self.vx = 5 * random.choice([-1, 1]) self.vy = 5 * random.choice([-1, 1]) # Game setup paddle1 = Paddle(30, H//2 - 50) paddle2 = Paddle(W-45, H//2 - 50, is_ai=True) ball = Ball() # Main loop running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False keys = pygame.key.get_pressed() if keys[pygame.K_w]: paddle1.move(-1) if keys[pygame.K_s]: paddle1.move(1) paddle2.ai_move(ball) ball.update(paddle1, paddle2) screen.fill((0, 0, 0)) pygame.draw.rect(screen, (255,255,255), paddle1.rect) pygame.draw.rect(screen, (255,255,255), paddle2.rect) pygame.draw.ellipse(screen, (255,255,255), ball.rect) pygame.draw.aaline(screen, (255,255,255), (W//2, 0), (W//2, H)) score_text = font.render(f"{paddle1.score} - {paddle2.score}", True, (255,255,255)) screen.blit(score_text, (W//2 - score_text.get_width()//2, 20)) pygame.display.flip() clock.tick(60) pygame.quit()

Example 2: Implement A* for Game Pathfinding

Problem:
Create an A* pathfinding system for an RTS game where units navigate around obstacles.

Solution:

  • Grid-based map with walkable/non-walkable tiles
  • 8-directional movement (including diagonals)
  • Diagonal cost = โˆš2 โ‰ˆ 1.414, orthogonal cost = 1
  • Heuristic: Octile distance (optimal for 8-directional grids)
  • Smooth path by removing unnecessary waypoints
f(n) = g(n) + h(n) g(n) = cost from start to node n h(n) = octile distance = max(dx, dy) + (โˆš2 - 1) ร— min(dx, dy)

Example 3: Object Pool Pattern

Problem:
Optimize bullet management in a shooter game that spawns thousands of bullets.

Solution:
Pre-allocate bullet objects and reuse them instead of creating/destroying constantly.

class BulletPool: def __init__(self, size=100): self.pool = [Bullet() for _ in range(size)] self.active = set() self.available = set(self.pool) def spawn(self, x, y, vx, vy): if not self.available: return None # Pool exhausted bullet = self.available.pop() bullet.activate(x, y, vx, vy) self.active.add(bullet) return bullet def update(self, dt): for bullet in list(self.active): bullet.update(dt) if bullet.is_expired(): bullet.deactivate() self.active.remove(bullet) self.available.add(bullet) def draw(self, surface): for bullet in self.active: bullet.draw(surface) # Performance: ~10x faster than creating new objects each time

Example 4: Implement Game Save System

Problem:
Design a save system that serializes game state to disk with versioning.

Solution:

  • JSON format:
    Human-readable, easy to debug
  • Save slots:
    Multiple save slots with metadata (timestamp, level, screenshot)
  • Auto-save:
    Periodic background saves
  • Migration:
    Version field allows loading old saves with upgrade logic

Example 5: Particle System

Problem:
Create a fire particle system with realistic behavior.

Solution:

  • Emitter spawns 50 particles/second
  • Each particle: position, velocity, lifetime, size, color
  • Particles rise (negative gravity) with random spread
  • Color transitions: white โ†’ yellow โ†’ orange โ†’ red โ†’ gray โ†’ transparent
  • Lifetime: 1-3 seconds with random variance
  • GPU-accelerated using point sprites or instanced rendering

Practice Problems

Problem 1: Implement Spatial Hash for Collision

Create a spatial hash grid for efficient collision detection with many objects.

class SpatialHash: def __init__(self, cell_size=64): self.cell_size = cell_size self.grid = {} def _hash(self, x, y): return (int(x // self.cell_size), int(y // self.cell_size)) def insert(self, obj): min_cell = self._hash(obj.x, obj.y) max_cell = self._hash(obj.x + obj.width, obj.y + obj.height) for cx in range(min_cell[0], max_cell[0] + 1): for cy in range(min_cell[1], max_cell[1] + 1): key = (cx, cy) if key not in self.grid: self.grid[key] = set() self.grid[key].add(obj) def query(self, x, y, width, height): min_cell = self._hash(x, y) max_cell = self._hash(x + width, y + height) results = set() for cx in range(min_cell[0], max_cell[0] + 1): for cy in range(min_cell[1], max_cell[1] + 1): key = (cx, cy) if key in self.grid: results |= self.grid[key] return results

Problem 2: Implement Quadtree

Build a quadtree for 2D spatial partitioning.

class Quadtree: def __init__(self, boundary, capacity=4): self.boundary = boundary # (x, y, w, h) self.capacity = capacity self.objects = [] self.divided = False def insert(self, obj): if not self._contains(self.boundary, obj): return False if len(self.objects) < self.capacity: self.objects.append(obj) return True if not self.divided: self._subdivide() return (self.nw.insert(obj) or self.ne.insert(obj) or self.sw.insert(obj) or self.se.insert(obj)) def _subdivide(self): x, y, w, h = self.boundary hw, hh = w/2, h/2 self.nw = Quadtree((x, y, hw, hh), self.capacity) self.ne = Quadtree((x+hw, y, hw, hh), self.capacity) self.sw = Quadtree((x, y+hh, hw, hh), self.capacity) self.se = Quadtree((x+hw, y+hh, hw, hh), self.capacity) self.divided = True

Problem 3: Implement Game Timer

Create a timer system supporting countdown, stopwatch, and cooldown mechanics.

class GameTimer: def __init__(self): self.timers = {} def add_cooldown(self, name, duration): self.timers[name] = { 'type': 'cooldown', 'duration': duration, 'start': time.time() } def is_ready(self, name): if name not in self.timers: return True timer = self.timers[name] if time.time() - timer['start'] >= timer['duration']: return True return False def get_remaining(self, name): if name not in self.timers: return 0 timer = self.timers[name] elapsed = time.time() - timer['start'] return max(0, timer['duration'] - elapsed) def trigger(self, name): if self.is_ready(name): self.timers[name]['start'] = time.time() return True return False

Problem 4: Behavior Tree for NPC AI

Implement a simple behavior tree for an enemy NPC with patrol, chase, and attack behaviors.

class Node: def tick(self, blackboard): return False class Selector(Node): def __init__(self, children): self.children = children def tick(self, bb): for child in self.children: if child.tick(bb): return True return False class Sequence(Node): def __init__(self, children): self.children = children def tick(self, bb): for child in self.children: if not child.tick(bb): return False return True # Build tree: Enemy AI tree = Selector([ Sequence([ # Attack behavior IsPlayerInRange(radius=50), Attack() ]), Sequence([ # Chase behavior IsPlayerInRange(radius=200), ChasePlayer() ]), Patrol() # Default: patrol ])

Problem 5: Implement Object Pooling

Create an object pool for efficiently managing frequently created/destroyed game objects.

class ObjectPool: def __init__(self, factory, initial_size=10): self._factory = factory self._available = [factory() for _ in range(initial_size)] self._in_use = set() self._all = set(self._available) def acquire(self): if not self._available: obj = self._factory() self._all.add(obj) else: obj = self._available.pop() self._in_use.add(obj) return obj def release(self, obj): if obj in self._in_use: obj.reset() self._in_use.remove(obj) self._available.append(obj) @property def active_count(self): return len(self._in_use) @property def total_count(self): return len(self._all)

Problem 6: Implement Screen Shake

Add a camera screen shake effect to a 2D game.

import random import math class ScreenShake: def __init__(self, max_offset=20, decay=0.9): self.max_offset = max_offset self.decay = decay self.offset = (0, 0) self.trauma = 0 def shake(self, intensity=1.0): self.trauma = min(1.0, self.trauma + intensity) def update(self, dt): self.trauma = max(0, self.trauma - dt * 1.5) shake_amount = self.trauma ** 2 * self.max_offset self.offset = ( random.uniform(-1, 1) * shake_amount, random.uniform(-1, 1) * shake_amount ) return self.offset

Problem 7: Implement Dialogue System

Create a branching dialogue system for an RPG.

@dataclass class DialogueNode: speaker: str text: str choices: List['DialogueChoice'] = field(default_factory=list) next_node: Optional[str] = None conditions: dict = field(default_factory=dict) effects: dict = field(default_factory=dict) @dataclass class DialogueChoice: text: str next_node: str conditions: dict = field(default_factory=dict) class DialogueSystem: def __init__(self, dialogue_data): self.nodes = {k: DialogueNode(**v) for k, v in dialogue_data.items()} self.variables = {} self.current_node = None def start(self, start_node): self.current_node = start_node def advance(self, choice_index=None): node = self.nodes[self.current_node] if choice_index is not None: node = self.nodes[node.choices[choice_index].next_node] elif node.next_node: node = self.nodes[node.next_node] else: return None # End of dialogue self.current_node = node return node

Problem 8: Procedural Terrain Generation

Generate terrain heightmaps using Perlin noise.

import numpy as np import random def generate_perlin_noise(width, height, octaves=6, persistence=0.5, scale=1.0): """Generate 2D Perlin noise for terrain.""" noise = np.zeros((height, width)) amplitude = 1.0 frequency = scale for o in range(octaves): # Generate base gradient grid grid_w = int(frequency) + 2 grid_h = int(frequency) + 2 gradients = np.random.uniform(-1, 1, (grid_h, grid_w, 2)) for y in range(height): for x in range(width): gx, gy = x * frequency / width, y * frequency / height # Smooth interpolation noise[y, x] += _interpolate(gx, gy, gradients) * amplitude amplitude *= persistence frequency *= 2 # Normalize to [0, 1] noise = (noise - noise.min()) / (noise.max() - noise.min()) return noise def _interpolate(x, y, gradients): x0, y0 = int(x), int(y) fx, fy = x - x0, y - y0 # Smoothstep fx = fx * fx * (3 - 2 * fx) fy = fy * fy * (3 - 2 * fy) # Bilinear interpolation return gradients[y0, x0, 0] # Simplified

Problem 9: Implement HUD System

Create a heads-up display with health bars, ammo counter, and minimap.

class HUD: def __init__(self, screen_width, screen_height): self.elements = [] def add_health_bar(self, x, y, width=200, height=20): bar = HealthBar(x, y, width, height) self.elements.append(bar) def add_ammo_counter(self, x, y, font_size=36): ammo = TextElement(x, y, "Ammo: 30/120", font_size) self.elements.append(ammo) def add_minimap(self, x, y, size=150, world_size=2000): minimap = Minimap(x, y, size, world_size) self.elements.append(minimap) def draw(self, surface): for element in self.elements: element.draw(surface) def update(self, game_state): for element in self.elements: element.update(game_state)

Problem 10: Implement Raycasting Engine

Create a simple raycasting 3D engine (Wolfenstein 3D style).

import pygame import math class Raycaster: def __init__(self, screen, map_data): self.screen = screen self.map = map_data self.width, self.height = map_data.shape def cast_ray(self, px, py, angle): """DDA raycasting algorithm.""" sin_a = math.sin(angle) cos_a = math.cos(angle) # DDA algorithm map_x, map_y = int(px), int(py) delta_dist_x = abs(1 / cos_a) if cos_a != 0 else 1e30 delta_dist_y = abs(1 / sin_a) if sin_a != 0 else 1e30 # Step direction step_x = 1 if cos_a > 0 else -1 step_y = 1 if sin_a > 0 else -1 side_dist_x = (map_x + 1 - px) * delta_dist_x if cos_a > 0 else (px - map_x) * delta_dist_x side_dist_y = (map_y + 1 - py) * delta_dist_y if sin_a > 0 else (py - map_y) * delta_dist_y # Walk until hitting wall for _ in range(100): if side_dist_x < side_dist_y: side_dist_x += delta_dist_x map_x += step_x side = 0 else: side_dist_y += delta_dist_y map_y += step_y side = 1 if self.map[map_y, map_x] > 0: break # Calculate distance if side == 0: dist = (map_x - px + (1 - step_x) / 2) / cos_a else: dist = (map_y - py + (1 - step_y) / 2) / sin_a return max(dist, 0.01), side def render(self, player_x, player_y, player_angle): num_rays = self.screen.get_width() for i in range(num_rays): ray_angle = player_angle - math.pi/3 + (math.pi/3) * i / (num_rays/2) dist, side = self.cast_ray(player_x, player_y, ray_angle) # Fix fisheye corrected_dist = dist * math.cos(ray_angle - player_angle) # Wall height wall_height = min(int(self.screen.get_height() / corrected_dist), self.screen.get_height()) # Color based on distance and side shade = max(50, min(255, int(255 / corrected_dist))) color = (shade, shade, shade) if side == 0 else (shade//2, shade//2, shade//2) x = i y_start = (self.screen.get_height() - wall_height) // 2 pygame.draw.line(self.screen, color, (x, y_start), (x, y_start + wall_height))

๐Ÿ“š Related Subjects

๐Ÿ“š Related Subjects