type3games-engine
Version:
Modulární herní engine pro 2D hry v JavaScriptu
979 lines (841 loc) • 24.8 kB
Markdown
# Type3Games Engine Documentation
## Overview
Type3Games Engine is a modular 2D game engine written in JavaScript. It provides a robust foundation for creating 2D games with features like physics, rendering, event handling, and level loading. The engine is designed with a component-based architecture focusing on modularity and extensibility.
## Technical Architecture
### Module Structure
```
engine.js - Main entry point and module exports
coretools/ - Core utilities and systems
├── vector.js - Vector mathematics
├── hitbox.js - Collision detection
├── controls.js - Input handling
└── event.js - Event management
blocks/ - Block type implementations
├── block.js - Base block class
├── movingBlock.js - Moving block implementation
├── eventBlock.js - Event-emitting block
└── eventMovingBlock.js - Combined moving and event block
entities/ - Game entities
├── entity.js - Base entity class
└── player.js - Player implementation
```
### Import/Export Structure
The engine uses ES6 modules with named exports from `engine.js`:
```javascript
export {
LevelLoader, Player, Entity, GameLoop,
Sprite, Render, Block, Physic,
MovingBlock, EventBlock, EventMovingBlock
};
```
## Core Components
### 1. Game Loop (`GameLoop`)
The central component that manages the game's update and render cycle.
#### Constructor Parameters
```javascript
{
physic: PhysicSystem, // Physics system instance
render: RenderSystem, // Render system instance
fps: number // Target frames per second (default: 60)
}
```
#### Properties
- `isRunning: boolean` - Current running state
- `frameDuration: number` - Milliseconds between frames (calculated from fps)
- `deltaTime: number` - Time between frames in seconds
- `ended: boolean` - Whether the game loop has ended
#### Methods
- `start()` - Starts the game loop
- `stop()` - Stops the game loop
- `step()` - Executes a single frame update
- `addFunction(fn: Function)` - Adds a function to be called each frame
- `destroy()` - Cleans up and stops the game loop
#### Update Sequence
1. Execute custom functions
2. Emit `Frame` event with deltaTime
3. Update physics
4. Render frame
5. Calculate FPS metrics (if enabled)
#### Events
- `Frame(deltaTime: number)` - Emitted each frame with time elapsed
- Timing is managed using `performance.now()` for precision
- Uses `setTimeout` for frame timing with half frame duration offset
### 2. Rendering System (`Render`)
Handles all visual aspects of the game using HTML5 Canvas.
#### Constructor Parameters
```javascript
{
width?: number, // Canvas width (default: window.innerWidth)
height?: number, // Canvas height (default: window.innerHeight)
scale?: number, // Rendering scale factor
background?: number[], // RGB background color [r,g,b] (default: [250,250,250])
camera?: Vector, // Initial camera position
cameraMinX?: number, // Minimum X camera bound
cameraMinY?: number, // Minimum Y camera bound
cameraMaxX?: number, // Maximum X camera bound
cameraMaxY?: number, // Maximum Y camera bound
debug?: boolean // Enable debug visualization
}
```
#### Core Features
- **Canvas Management**
- Automatically creates and appends canvas to document
- Handles canvas scaling and viewport adjustments
- CSS reset for full-screen display
- **Camera System**
```javascript
setCameraBoundres(maxX: number, maxY: number)
cameraFolow(vector: Vector)
```
- Smooth camera following
- Boundary constraints
- Scale-aware positioning
- **Sprite Management**
```javascript
addSprite(sprite: Sprite)
makeSprite(x: number, y: number, imageSrc: string, width: number, height: number)
```
- Automatic sprite registration
- Visibility culling
- Scale-aware rendering
- **Debug Visualization**
- Hitbox outlines (red)
- Line width: 0.1 units
- Camera bounds indication
#### Rendering Pipeline
1. Clear canvas with background color
2. Apply camera transformation
3. Apply scale transformation
4. Render all loaded sprites
5. Draw debug information (if enabled)
6. Emit HUD render event
#### Events
- `RenderHUD(ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement)`
- Emitted after main rendering
- Provides context for HUD drawing
- Uses reset transformation matrix
### 3. Physics System (`Physic`)
Manages physical interactions and simulation between game objects.
#### System Components
```javascript
class Physic {
blocks: Block[] // Static collision objects
entities: Entity[] // Dynamic physics objects
updatable: Object[] // Objects requiring updates
ended: boolean // System state flag
}
```
#### Entity Physics Properties
- Position (Vector)
- Velocity (Vector)
- Acceleration (Vector)
- Gravity (Vector, default: 0, 500)
- Ground state detection
- Collision response
#### Collision Detection
- Hierarchical checking:
1. Entity-Block collisions
2. Ground sensor checks
3. Precise hitbox intersection
- Collision Response Types:
```javascript
// Direction vectors for collision
LEFT: Vector(-1, 0)
RIGHT: Vector(1, 0)
TOP: Vector(0, -1)
BOTTOM: Vector(0, 1)
```
#### Update Cycle
1. Update all updatable objects
2. Update entity physics
- Apply gravity
- Update velocities
- Apply friction
3. Check and resolve collisions
4. Update ground states
5. Reset acceleration
#### Registration Methods
```javascript
addBlock(block: Block) // Add static collision object
addEntity(entity: Entity) // Add dynamic physics object
addUpdatable(obj: Object) // Add updateable object
```
#### Physics Parameters
- Default gravity: `new Vector(0, 500)`
- Collision offset: 1 unit
- Ground sensor height: 1 unit
- Friction range: 0-1 (default: 0.99)
### 4. Level System (`LevelLoader`)
Manages level loading, object instantiation, and level progression.
#### Constructor Parameters
```javascript
{
settings?: Object, // Default level settings
pathPrefix?: string, // Path prefix for assets
levelList?: string[] // Array of level names
}
```
#### Level JSON Structure
```javascript
{
name?: string, // Level name (default: filename)
settings: {
grid: {
size: number // Grid cell size
},
render: {
scale: number, // Render scale
background: number[] // RGB background color
},
// Object type definitions
[key: string]: {
type: string, // Object type identifier
settings: { // Type-specific settings
imageSrc: string,
width: number,
height: number,
[key: string]: any
}
}
},
grid: (string|string[])[][] // Level layout matrix
}
```
#### Object Type Mappings
```javascript
const TYPE_MAP = {
'block': Block,
'player': Player,
'entity': Entity,
'sprite': Sprite,
'movingBlock': MovingBlock,
'eventBlock': EventBlock,
'eventMovingBlock': EventMovingBlock
}
```
#### Level Loading Process
1. Parse JSON configuration
2. Convert Vector properties
3. Process grid layout
4. Create game objects
5. Set camera bounds
6. Initialize game loop
#### Asset Management
- Automatic path resolution
- Image preloading
- Resource loading tracking
- Load completion detection
#### Events
```javascript
LevelLoading(level: Object) // Level start loading
LevelJSONLoaded(url: string) // JSON loaded
DefaultSettingsJSONLoaded(url: string) // Default settings loaded
LevelListMissing() // No level list
CurrentLevelNotSet() // No current level
CurrentLevelNotFound(levelName: string) // Level not in list
NoMoreLevels() // End of levels
End() // Level ending
```
#### Level Progression
- Sequential level loading
- Automatic level transitions
- Level list management
- End-game detection
### 5. Core Tools
#### Event System (`Event`)
Global event management system for game-wide communication.
```javascript
const Event = {
// Internal storage
listeners: { [event: string]: Map<number, Function> },
id: number,
index: Map<number, string>,
// Methods
on(event: string, callback: Function): number
off(id: number): void
emit(event: string, ...args: any[]): void
}
```
**Usage Example:**
```javascript
// Register listener
const id = Event.on("collision", (data) => {
console.log(`Collision: ${data.entity} with ${data.block}`);
});
// Emit event
Event.emit("collision", { entity: player, block: wall });
// Remove listener
Event.off(id);
```
#### Vector System (`Vector`)
Comprehensive 2D vector mathematics implementation.
```javascript
class Vector {
x: number
y: number
// Instance Methods
get mag(): number // Vector magnitude
add(vector: Vector): Vector // Add vector
sub(vector: Vector): Vector // Subtract vector
mult(scalar: number): Vector // Multiply by scalar
multTogether(vector: Vector): Vector // Component-wise multiply
div(scalar: number): Vector // Divide by scalar
normalize(): Vector // Normalize to unit vector
setMag(newMag: number): Vector // Set magnitude
copy(): Vector // Create copy
// Static Methods
static add(vecA: Vector, vecB: Vector): Vector
static sub(vecA: Vector, vecB: Vector): Vector
static mult(vecA: Vector, scalar: number): Vector
static multTogether(vecA: Vector, vecB: Vector): Vector
static div(vecA: Vector, scalar: number): Vector
static dot(vecA: Vector, vecB: Vector): number
static equal(vecA: Vector, vecB: Vector): boolean
}
```
#### Controls System (`Control`)
Sophisticated input handling system with recording capabilities.
```javascript
class Control {
// Binding Types
bind(name: string, key: string, callback: Function) // Continuous
bindOnce(name: string, key: string, callback: Function) // Single press
bindRelease(name: string, key: string, callback: Function) // On release
bindReleaseOnce(name: string, key: string, callback: Function)
bindWithReleaseTick(name: string, key: string, callback: Function)
// Recording System
startRecording(): void
stopRecording(): RecordedEvent[]
startPlayback(events: RecordedEvent[]): void
stopPlayback(): void
// State Management
update(): void
pause(): void
unpause(): void
// Configuration
setBinding(name: string, type: string, key: string, callback: Function)
updateBinding(name: string, newCallback: Function)
updateBindingKey(name: string, newKey: string)
exportBindings(): BindingConfig
}
interface RecordedEvent {
type: "keydown" | "keyup"
key: string
frame: number
}
```
#### Hitbox System (`Hitbox`)
Efficient collision detection system.
```javascript
class Hitbox {
offset1: Vector // Top-left offset
offset2: Vector // Width and height
position: Vector // World position
constructor(
corner1: Vector, // Top-left corner
corner2: Vector, // Dimensions
position?: Vector // World position (default: 0,0)
)
// Methods
updatePosition(position: Vector): void
isColliding(hitbox: Hitbox): boolean
// Collision Algorithm
// Returns true if rectangles overlap:
// !(right1 < left2 || right2 < left1 || bottom1 < top2 || bottom2 < top1)
}
```
## Game Objects
### 1. Sprites (`Sprite`)
Base class for all visual objects.
```javascript
class Sprite {
constructor(options: {
x: number, // X position
y: number, // Y position
imageSrc: string, // Image URL
width: number, // Sprite width
height: number, // Sprite height
render?: Render, // Render system
onLoadCallback?: Function // Load completion callback
})
// Properties
position: Vector // World position
width: number // Sprite width
height: number // Sprite height
image: HTMLImageElement // Sprite image
loaded: boolean // Image load state
}
```
### 2. Entities (`Entity`)
Physics-enabled game objects.
```javascript
class Entity extends Sprite {
constructor(config: {
x: number,
y: number,
imageSrc: string,
width: number,
height: number,
render: Render,
physic: Physic,
gravity?: Vector,
collisionOffset?: number,
onLoadCallback?: Function
})
// Physics Properties
velocity: Vector
acceleration: Vector
gravity: Vector
onGround: boolean
touching: Block[]
passableOnGround: boolean[]
// Collision
hitbox: Hitbox
groundSensor: Hitbox
// Methods
update(deltaTime: number): void
afterUpdate(deltaTime: number): void
addVelocity(velocity: Vector): void
addAcceleration(acceleration: Vector): void
checkCollision(block: Block): boolean
onCollision(block: Block): void
checkSensor(block: Block): boolean
}
```
### 3. Blocks
#### Basic Block (`Block`)
Foundation for solid game objects.
```javascript
class Block extends Sprite {
constructor({
x: number,
y: number,
imageSrc: string,
width: number,
height: number,
render: Render,
physic: Physic,
friction?: number, // Default: 0.99
onLoadCallback?: Function
})
// Properties
hitbox: Hitbox
friction: number
// Methods
onCollision(entity: Entity, direction: Vector): void
touching(entity: Entity): void
}
```
#### Moving Block (`MovingBlock`)
Blocks that move along a defined path.
```javascript
class MovingBlock extends Block {
constructor(config: {
startx: number,
starty: number,
endx: number,
endy: number,
routeTime: number, // Time to complete path
imageSrc: string,
width: number,
height: number,
render: Render,
physic: Physic,
friction?: number,
onLoadCallback?: Function
})
// Movement
velocity: Vector
start: Vector
end: Vector
routeTime: number
exeptedError: number // Position tolerance
// Methods
update(deltaTime: number): void
touching(entity: Entity): void
onCollision(entity: Entity, direction: Vector): void
}
```
#### Event Block (`EventBlock`)
Event-emitting blocks.
```javascript
class EventBlock extends Block {
constructor(obj: {
onCollisionEvent?: string, // Default: "defaultOnColisionEvent"
touchingEvent?: string, // Default: "defaultTouchingEvent"
// ... Block parameters
})
onCollision(entity: Entity, direction: Vector): void
touching(entity: Entity): void
}
```
#### Event Moving Block (`EventMovingBlock`)
Combined moving and event-emitting blocks.
```javascript
class EventMovingBlock extends MovingBlock {
constructor(obj: {
onCollisionEvent?: string,
touchingEvent?: string,
// ... MovingBlock parameters
})
}
```
### 4. Player (`Player`)
Player-controlled game entity.
```javascript
class Player extends Entity {
constructor(input: {
onClickAcceleration: number,
inAirAccelerationDrag: number,
maxXSpeed: number,
maxBoost: number,
jumpAcceleration: number,
callBackMap?: Object,
// ... Entity parameters
})
// Controls
controls: Control
// Movement Parameters
onClickAcceleration: number
inAirAccelerationDrag: number
maxXSpeed: number
maxBoost: number
jumpAcceleration: number
dragCorectionAplied: boolean
// Methods
left(This: Player): void // Left movement
right(This: Player): void // Right movement
jump(This: Player): void // Jump action
down(This: Player): void // Downward movement
// Events Emitted
"MaxSpeedReached" - When reaching max speed
}
```
Key Features:
- Air/ground movement differentiation
- Friction-aware velocity adjustments
- Speed limiting and boost mechanics
- Ground state detection
- Recording/playback support
## Level Creation Guide
### Level JSON Schema
```typescript
interface LevelJSON {
name?: string; // Optional level name
settings: { // Corrected spelling
grid: {
size: number; // Grid cell size in pixels
};
render: {
scale: number; // Render scaling factor
background: [number, number, number]; // RGB values
debug?: boolean; // Enable debug visualization
};
// Object type definitions
[key: string]: {
type: "player" | "block" | "sprite" | "movingBlock" | "eventBlock" | "eventMovingBlock";
settings: ObjectSettings;
};
};
grid: (string | string[])[][]; // Level layout matrix
}
interface ObjectSettings {
// Common properties
imageSrc: string; // Path to sprite image
width: number; // Object width
height: number; // Object height
// Physics properties
friction?: number; // Block friction (0-1)
routeTime?: number; // Moving block path time
// Player-specific
onClickAcceleration?: number;
jumpAcceleration?: number;
inAirDrag?: number;
inAirAccelerationDrag?: number;
gravity?: {
x: number;
y: number;
};
maxXSpeed?: number;
maxBoost?: number;
collisionOffset?: number;
// Event properties
onCollisionEvent?: string;
touchingEvent?: string;
}
```
### Grid Layout Specification
#### Basic Syntax
```javascript
"grid": [
["b","p", "", "m", "e"], // Row 0
["b", "b", "", "", ""], // Row 1
["b", "", "","", ""] // Row 2
]
```
#### Object Type Keys
- `p` - Player spawn point
- `b` - Static block
- `s` - Static sprite
- `m` - Moving block
- `e` - Event block
- `E` - Event moving block
- `""` - Empty space
#### Moving Block Format
```javascript
["m", "2"] // Moving block with target point "2"
```
First element is the block type, second is the target point identifier.
#### Complete Example
```javascript
{
"settings": {
"grid": { "size": 32 },
"p": {
"type": "player",
"settings": {
"imageSrc": "./player.png",
"width": 30,
"height": 30,
"onClickAcceleration": 200,
"jumpAcceleration": 110,
"inAirDrag": 1,
"gravity": { "x": 0, "y": 300 },
"maxXSpeed": 640,
"maxBoost": 1200,
"collisionOffset": 1
}
},
"b": {
"type": "block",
"settings": {
"width": 32,
"height": 32,
"imageSrc": "./block.png",
"friction": 0.9
}
}
},
"grid": [
["b","p", "", ["m","2"], ""],
["b", "b", "", "2", "e"],
["b", "b", "b", "b", "b"]
]
}
```
## Implementation Guide
### Basic Setup
```javascript
import { LevelLoader, Event } from "./engine.js";
// Initialize with level sequence
const loader = new LevelLoader({
levelList: ["level1", "level2"],
pathPrefix: "./levels/", // Optional asset path prefix
settings: { // Optional default settings
grid: { size: 32 },
render: {
scale: 2,
background: [240, 240, 240]
}
}
});
// Load first level
loader.loadJSON("level1.json");
```
### Event Handling System
```javascript
// Core game events
Event.on("LevelLoading", (level) => {
console.log("Loading level:", level.name);
});
Event.on("Frame", (deltaTime) => {
// Update game logic
});
Event.on("RenderHUD", (ctx, canvas) => {
// Draw HUD elements
ctx.fillStyle = 'white';
ctx.fillText(`Score: ${score}`, 10, 20);
});
// Physics events
Event.on("EntityCollision", ({entity, block, position}) => {
// Handle collision logic
});
// Level progression
Event.on("NoMoreLevels", () => {
// Handle game completion
});
// Custom events
Event.on("PowerupCollected", (data) => {
// Handle powerup effects
});
```
### Custom Block Creation
```javascript
class CustomBlock extends Block {
constructor(config) {
super(config);
this.customProperty = config.customProperty;
}
onCollision(entity, direction) {
super.onCollision(entity, direction);
// Custom collision behavior
Event.emit("CustomBlockHit", {
entity: entity,
block: this
});
}
}
```
## Performance Optimization
### 1. Rendering Optimization
```javascript
// Efficient sprite batching
class RenderBatch {
constructor(maxSprites = 1000) {
this.sprites = new Array(maxSprites);
this.count = 0;
}
add(sprite) {
if (this.count < this.sprites.length) {
this.sprites[this.count++] = sprite;
}
}
render(ctx) {
// Sort by texture to minimize state changes
this.sprites.sort((a, b) => a.image.src.localeCompare(b.image.src));
// Batch render
let currentTexture = null;
for (let i = 0; i < this.count; i++) {
const sprite = this.sprites[i];
if (sprite.image !== currentTexture) {
currentTexture = sprite.image;
}
ctx.drawImage(sprite.image,
sprite.position.x,
sprite.position.y,
sprite.width,
sprite.height);
}
}
}
```
### 2. Physics Optimization
```javascript
// Spatial partitioning
class SpatialGrid {
constructor(cellSize) {
this.cellSize = cellSize;
this.grid = new Map();
}
getCell(x, y) {
const cellX = Math.floor(x / this.cellSize);
const cellY = Math.floor(y / this.cellSize);
return `${cellX},${cellY}`;
}
insert(entity) {
const cell = this.getCell(entity.position.x, entity.position.y);
if (!this.grid.has(cell)) {
this.grid.set(cell, []);
}
this.grid.get(cell).push(entity);
}
getPotentialCollisions(entity) {
const cell = this.getCell(entity.position.x, entity.position.y);
return this.grid.get(cell) || [];
}
}
```
### 3. Event System Optimization
```javascript
// Event batching
class EventBatcher {
constructor(batchTime = 16) { // ~1 frame
this.batchTime = batchTime;
this.eventQueue = new Map();
this.lastFlush = performance.now();
}
queueEvent(eventName, data) {
if (!this.eventQueue.has(eventName)) {
this.eventQueue.set(eventName, []);
}
this.eventQueue.get(eventName).push(data);
const now = performance.now();
if (now - this.lastFlush >= this.batchTime) {
this.flush();
}
}
flush() {
for (const [eventName, events] of this.eventQueue) {
Event.emit(eventName, events);
}
this.eventQueue.clear();
this.lastFlush = performance.now();
}
}
```
### 4. Memory Management
```javascript
class ResourceManager {
constructor() {
this.resources = new Map();
this.referenceCount = new Map();
}
load(key, resource) {
if (!this.resources.has(key)) {
this.resources.set(key, resource);
this.referenceCount.set(key, 0);
}
this.referenceCount.set(key, this.referenceCount.get(key) + 1);
}
unload(key) {
const count = this.referenceCount.get(key) - 1;
if (count <= 0) {
this.resources.delete(key);
this.referenceCount.delete(key);
} else {
this.referenceCount.set(key, count);
}
}
}
```
## Technical Limitations
### 1. Threading Model
- Single-threaded JavaScript execution
- Main thread handles all calculations
- No Web Worker support currently
```javascript
// Current synchronous update model
update(deltaTime) {
this.physics.update(deltaTime);
this.entities.forEach(e => e.update(deltaTime));
this.render.render();
}
```
### 2. Rendering System
- HTML5 Canvas API only
- No WebGL acceleration
- Limited to 2D contexts
```javascript
// Current rendering initialization
this.ctx = this.canvas.getContext("2d");
// No support for:
// this.ctx = this.canvas.getContext("webgl");
```
### 3. Collision System
- Axis-Aligned Bounding Box (AABB) only
- No support for rotated rectangles
- No polygon collision support
```javascript
// Current collision check
isColliding(hitbox) {
return !(
(this.position.x + this.offset2.x < hitbox.position.x + hitbox.offset1.x) ||
(hitbox.position.x + hitbox.offset2.x < this.position.x + this.offset1.x) ||
(this.position.y + this.offset2.y < hitbox.position.y + hitbox.offset1.y) ||
(hitbox.position.y + hitbox.offset2.y < this.position.y + this.offset1.y)
);
}
```
## Future Development
Planned features and improvements will be documented in future releases. Please refer to the changelog for current features and updates.
Please refer to the changelog for version-specific changes and updates.