Game Engine Structure - Overview
An epic battle of fidelity and features against deadlines and constraints.
Often we try to define lines between things: model, view, controller; engine, game, and data; etc. This can often be blurry (which is totally fine).
Our goal is to try craft an engine with a data-driven architecture, so that it provides a core foundation for the game we think we are going to make and with room to adjust course.
We really want to build up the systems in a way such that they are data driven enough to help support quick iteration of gameplay.
Key Services of an Interactive Real-time Simulation (General)
- A game will use memory for everything: the code, resources like textures and audio, etc.
- Some platforms have less memory than others, or different ways to allocate/deallocate it. Memory that is allocated by the game needs to be deallocated.
- Your target platform will have its own nuances when it comes to device drivers and accessing hardware features, and also just how variables are stored in memory.
- HTML5 removes the hard part of this problem, although leaves us with having to target different vendors and features on either desktop or mobile.
- We always want to build our engine so that gameplay doesn't worry about what platform we are on.
Managing a Game loop
- Drives the game by performing a series of tasks:
- Simple model: Sample Input, Update Game Entities, Render the Scene
- Complex model: Handle Elapsed Time, Sample Input, Update Networking messages, Update Physics Simulation, Update Animation, Update Game Entities, Render the Scene
- Various ways to do game physics: Simple "pinball" style physics, 2D Grid physics, Rigid body dynamics
- Rigid Body Dynamics - Motion (kinematics) of rigid bodies and the forces (dynamics) that cause motion
- Updates the physics world (integration of forces to determine objects' positions)
- Checks for collisions between objects based on their shape (circles, boxes, triangle meshes)
- Resolves collisions so solid objects react believably (moves objects so they do not penetrate, sets velocities based on desired behavior: bouncy ball, heavy brick)
- Stores contact information so gameplay can react to it (deal damage, activate switches)
- Advanced features: Constraints, Raycasting, Triggers, etc
Animation and Rendering System
- We're focusing on Sprite Animation. Others in games are: Skeletal animation, vertex animation, Inverse Kinematics
- Updates the current frame of objects based on their playback speed and other parameters
- Renders textures (or draws lines) based on current playback properties, and object position/rotation (usually driven by physics)
- Storage of Animation Data (texture to use, frames to play, playback speed, etc), can be referenced by name
- Adds ability to play/stop music files
- Adds support for triggering audio sfx, possibly parameterizing them (random pitch for variation)
- Storage of SFX data (audio file(s) to use, configuration parameters like volume, pitch), can be referenced by name
- Typically polls for input, or waits for events
- Stores input values for gameplay code to check against
- Or sends input events to registered handlers
- HUGE undertaking. Has profound design implications for almost all engine components.
- Have to support a variety of network conditions
- Real-time vs. asynchronous
- Server authentication, Client-side prediction, and lots of messaging
- Asset pipeline is an important part of a game engine, especially working with Artists
- Provides a consistent interface for accessing game resources
- Centralize resource loading so gameplay can reference a single loaded instance by ID
- Ability to load and unload resources at run-time (AJAX)
- AJAX calls need to be done through a web server. For local testing we can use something like Mongoose
Game Object System
- Composition of components that we need for an entity in our game world.
- Animation, Physics, AI, and helper functions to manage their relationship
- Common patterns: Event Systems and Components, Composition
- Storage for level data, player objects, enemy objects, dynamic things like bullets or collectables
- Loading and unloading of world data
- Interacts with the renderer to control what's viewable. Could follow an object, or zoom in and out.
- Simple in 2D games; behavior can be very extensive in 3D games
- Math Library (vectors, matrices, quaternions)
- Container Library (linked list, vectors, trees)
- Debug and Profiling Systems (runtime/ingame variable watching, profile sampling)
- Unit Testing
- Visual Effects (particle systems)
- Advanced Rendering Systems (customizable shaders)
- Cinematics / Video playback
- HUD/UI Systems
Our HTML5 Game Engine Framework
Required JS libraries
- JQuery - for easy DOM access
- Underscore - for handy JS utilities
- Modernizr - script file and basic asset loading
- Manages the gameloop, ticking all the subsystems
- Features can be extended through additional modules
Game Object System
- Game Objects, Events, Components
- A Game Object is mostly a utility object that handles the adding and removing of components
- Components add features to a Game Object, such as animation or physics
- Events work great in JS, allows for communication between systems, between objects, or between components
- Manages configuring our render context
- Could support multiple canvases, or off screen canvas
- Loading game assets at run-time
- Date Store for assets, so they can be referenced by resource name instead of filename
- Storage of all instances of game objects in a scene
- Can be extended with a Camera or Physics World
Sprites and Animation
- Utilizes Game Object and Component system
- Draws entire images, or switches through clipped rects from within a single image to do animations
- The biggest weakness of HTML5 in terms of uniform vendor support
- Manages input from Keyboard, Mouse, Touch, Gamepad
- Provides a data abstraction so that the game can connect specific input events to the game's "action" events
- Could be done with Box2D, or with tile checking on a 2D grid
- Part of scene management
- The game engine acts as a client application that communicates with a server application
- Could possibly communicate with other client applications
Dynamic typing - whatever methods and properties the object has determine the valid semantics/usages (versus determining it from inheritence).
We are more concerned with the aspects of an object, rather than what type the object itself is.
Testing for properties/methods can be annoying, so rely on clear code and documentation.
A function that closes-over variables within it's scope, and can be called somewhere else where those variables are not available
A functions returning a functions
Anonymous functions that get passed in as parameters to other functions
Engine systems we don't always need but can add per project. We can drop out one module and replaced with another (Box2D physics for custom physics)
The extend the engine with new features.
Book designated approach, not really much different than just having another sub system except that we include it at run-time.
Instructor Code Notes
- I break apart the code into separate files.
- Several function name changes (limited method overloading, more pedantic naming conventions)
- I limit the use of method overloading - one method with multiple purposes - for code clarity.
- Slightly updated inheritance system with Class.js
- Dynamically generated constructor function name to aid with debugging
- Support for member variables objects to be extended by child classes (eg. .defaults)
- Sprite position now refers to the center of the sprite
- Book made a big mistake not addressing this, but got away with it since he didn't work with both sprites and physics
- Center of sprite now lines up with our physics engine defaults
- Advanced systems would let the user define point-of-origin (center, top-left, bottom-center, etc) per sprite
- All angles are in radians
- Our base Entity has functions for converting local points and vectors into world space (necessary for our scene camera)
- Renamed some sprite parameters to avoid conflicts with physics parameters (eg. .width is just for sprites, .shape_width is for physics, .angle .x .y still works for both)
- Destroying a scene will destroy the sub objects (Did the book actually miss this, or did I just have a bug?)
Engine Proof Milestone - February 6th
You will be presenting your game ran through a local webserver and submitting your code through BitBucket or GitHub.
Asset Management, Sprites, Camera (if needed), Scene Management
Sprite Sheets and Sprite Animation (Animation not necessary if it doesn't fit your game)
Physics (not necessarily Box2D, could be postponed if necessary)
Gameplay Prototype (custom sprite classes, simulation reacts to input)
Other goals should be to establish your engine's API; hopefully avoid any big changes down the road.
Also to keep extending systems (scenes, sprites, etc), testing little bits at a time to drive the development.
Final Milestone - March 13th
You will be presenting your game running online and submitting your code through BitBucket or GitHub
Animation and Physics are both are demonstrable in game
Advanced Gameplay (Game states, interaction between objects, basic AI)
Online systems such as persistent player profiles, leaderboard, achievements, etc.
General polish and professionalism