CS50 2D - Lecture 4 - Super Mario Bros. (live, unedited)
Watch on YouTube →
Overview
CS50's lecture on Super Mario Bros. introduces 2D game development concepts, focusing on creating virtual worlds using tile maps, 2D animation, procedural level generation, and platformer physics. David J. Malan demonstrates how to implement scrolling with `love.graphics.translate`, animate characters using sprite sheets, and manage entity states with state machines. The lecture also covers game objects, collision detection (point-to-tile for tiles, AABB for game objects), and power-up mechanics, culminating in a demonstration of a functional Mario-like platformer.
Key takeaways
- Tile maps, using IDs to represent game world elements, are fundamental for building 2D levels, enabling efficient collision detection and rendering.
- Character animation is achieved by sequencing frames from a sprite sheet, managed by a state machine that transitions based on player input and game events.
- Procedural level generation, using rules and randomization, allows for dynamic creation of diverse and replayable game worlds.
- Entities (like players and enemies) and Game Objects (like items and blocks) are distinct concepts, with entities having states and behaviors, while game objects are typically static but interactive.
- Collision detection in tile-based games can be optimized by converting pixel coordinates to tile indices (`point_to_tile`) and checking only relevant surrounding tiles.
- State machines provide a structured way to manage complex entity behaviors (e.g., player actions, enemy AI) and decouple logic, making code more organized and maintainable.
Chapters
- CS50 2D is an introduction to 2D game development.
- Lecture 4 focuses on Super Mario Bros. as a case study.
- The goal is to model virtual worlds, moving beyond abstract games like Pong and Flappy Bird.
- Creative Commons assets will be used instead of exact Mario assets.
- Tile maps are used to represent the game world, mapping IDs to drawable tiles.
- 2D animation is introduced, with characters changing poses (e.g., walking, jumping) frame-by-frame.
- Procedural level generation will be used to create levels in code, offering infinite replayability.
- Platformer physics and AI for simple enemies (like a snail) are discussed.
- A volunteer plays a demo of the Super Mario Bros.-like game.
- Demonstrates movement, jumping, interacting with blocks, and hitting enemies (snails).
- Highlights collision detection with terrain and enemies.
- Shows blocks with hidden gems and the death state upon falling.
- Tile maps are similar to Match-3 grids but used for drawing collidable terrain.
- Each tile ID maps to a portion of a texture (quad).
- A 2D array stores tile IDs, defining the level layout.
- The `love.graphics.clear` function is used for background colors.
- Demonstrates drawing static tiles using a simple 2D array.
- Uses 16-pixel tiles with IDs for sky (0) and ground (1).
- Splices a two-tile sprite sheet into frames.
- Iterates through the 2D tile array to draw each tile at calculated screen coordinates.
- Scrolling is achieved using `love.graphics.translate` to offset all drawing operations.
- A camera scroll variable is manipulated, often with delta time.
- Translating by the negative of the camera scroll effectively moves the camera.
- This allows the player to feel like they are moving through a larger world.
- Introduces a player avatar (Mario-like alien) positioned on the ground.
- Uses a sprite sheet with various frames for different actions (standing, walking, jumping).
- Slices the sprite sheet into frames and uses an ID to select the current frame.
- Character X and Y are set to position the avatar, initially near the center.
- Character movement is implemented by updating the character's X position based on input and `character_move_speed`.
- Character One shows movement without camera tracking.
- Character Two demonstrates camera tracking: the camera scroll is set to center the character.
- The camera scroll is calculated as `character.x - virtual_width / 2` to keep the character centered.
- Introduces an `Animation.lua` module for handling sprite animations.
- Animations are defined as sets of frames that play over time with a specified interval.
- Delta time is used to update the animation timer and advance frames.
- Supports flipping sprites horizontally for left/right movement and transitions between idle, walking, and jumping animations.
- Defines 'idle' (single frame) and 'moving' (two frames) animations.
- Updates the current animation based on player input (left/right keys).
- Handles sprite flipping using `love.graphics.scale(-1, 1)` by adjusting the drawing origin to the sprite's center.
- The `animation:update(dt)` function manages frame progression.
- Adds a jump animation (frame 3) to the character's states.
- Jump is triggered by spacebar input only when `dy` is zero (i.e., on the ground).
- Applies gravity (`dy = dy + gravity * dt`) to simulate falling.
- Collision detection with the ground prevents the player from falling indefinitely.
- Procedural generation creates levels dynamically, offering infinite replayability.
- Levels are represented as grids of numbers (tile IDs).
- Rules are applied to place tiles, gaps, pillars, and other features.
- The goal is to create winnable levels without manual design.
- A detailed Creative Commons tile set (by Kenny) is used, featuring various tile types (slopes, rounded corners).
- Toppers are decorative elements drawn on top of specific tiles to add visual variety (e.g., icy, forest themes).
- The tile set and toppers are isolated and programmatically slicable.
- Randomization is applied to tile sets, topper sets, and backgrounds for varied level appearance.
- Demonstrates random selection of tile sets and topper sets.
- Tiles are spliced from the main texture, and toppers are applied based on a 'topper' flag.
- The 'topper' flag is set if `y == 7` during level generation, indicating the top surface of the ground.
- Pressing 'R' regenerates the level with new random combinations.
- Introduces variation by having ground tiles jut up from the baseline.
- A 1-in-5 chance per column to start terrain at `y=4` instead of `y=7`, creating pillars.
- The 'topper' flag is set for the pillar's top tile (`pillar == 4`).
- Relies on pure randomness, sometimes resulting in narrow or grouped pillars.
- Chasms are created by simply not drawing tiles in certain sections of the level.
- A `continue` statement skips tile generation logic based on a random chance (1 in 7).
- This results in gaps where tiles would normally be, leaving sky.
- Potential issues include narrow chasms and visual glitches with toppers.
- Collision detection for tile maps differs from AABB for individual objects.
- Uses a `point_to_tile` function to determine the tile at a given pixel coordinate.
- Checks only relevant surrounding tiles (2-4) based on character's movement direction (left, right, up, down).
- This is more efficient than checking every tile on the map.
- Checks tiles at the character's top-left and bottom-left corners for left collisions.
- Checks tiles at the character's top-right and bottom-right corners for right collisions.
- The `point_to_tile` function converts pixel coordinates to tile indices (adding 1 for Lua's 1-based indexing).
- If collision occurs, the character's position is reset to avoid clipping.
- Entities are objects with position, velocity, width, height, texture, and a state machine.
- Game Objects are interactive but static items (e.g., gems, blocks) that can trigger behaviors.
- Entities use state machines (e.g., idle, walking, jumping) to manage behavior.
- Collision checks differentiate between tiles (`point_to_tile`) and game objects (AABB).
- Player states manage transitions based on input and game conditions.
- Walking state transitions to Idle if no movement keys are pressed.
- Falling state transitions to Walking or Idle upon hitting the ground.
- Death condition: falling below virtual height triggers a reset to the start state.
- Game Objects have properties like `collidable`, `consumable`, `on_collide`, and `on_consume`.
- Gems are consumable game objects that increase score.
- Blocks are collidable game objects that can spawn gems when hit.
- The `GameLevel` class manages entities, objects, and the tile map.
- The `LevelMaker` class generates levels, including placing game objects.
- Static props like bushes are placed as non-collidable game objects.
- Jump blocks are collidable game objects with an `on_collide` function to spawn gems.
- Randomization is applied to object types, positions, and variations.
- Snails are entities with states: Idle, Moving, and Chasing.
- Idle state includes a wait timer before transitioning to Moving or Chasing.
- Chasing state moves the snail towards the player if within a 5-tile radius.
- Moving state selects random directions and has a chance to return to Idle.
- Implement ground collision capping and ensure solid ground beneath the player.
- Use keys and locks (game objects) to unlock the end goal flag, enabling level progression.
- Generate larger levels upon reaching the end and transitioning to the next.
- Introduce ladders for climbing taller pillars (over 4 tiles) and a new 'Ladder Climbing' state.
- Implement a power-up (e.g., a star) that grants temporary invincibility.
- When invincible, the player can touch snails without dying, potentially defeating them.
- Add particle effects for power-up activation and interaction.
- Optional: Add music and implement score-based power-ups.
- Next lecture covers Zelda (Link to the Past) with a top-down perspective.
- Explores 2-axis movement, stenciling, triggers, events, and basic AI for enemies.
- Introduces hurtboxes for attacking and inventory systems for items like boomerangs.
- Focuses on event handling (switches opening doors) and combat mechanics.
- A brief addendum to fix missing slides from a previous lecture (Pong).
- Clarifies the first assignment: implementing basic AI for the right paddle in Pong.
- Player 1 controls their paddle; Player 2 is AI-controlled.
- The AI's behavior and balance are up to the implementer.
- Lecture 1 will cover Flappy Bird, introducing images and the concept of games as illusions.
- Focuses on fake scrolling and infinite scrolling backgrounds.
- Introduces basic procedural generation through random pipe spawning.
- Explores state machines for cleaner game state management and mouse input.
Summary, takeaways, and chapters were generated by AI from the video's transcript and may contain errors. The video belongs to its creator, CS50.