What an engine gets you: 1. The boring stuff: setup, loading, input, audio, animation, drawing 2. The hard stuff: transformation matrices, collision detection, picking 3. The performance stuff: optimizations for rendering + GC
Secret item #4! 1. The boring stuff: setup, loading, input, audio, animation, drawing 2. The hard stuff: transformation matrices, collision detection, picking 3. The performance stuff: optimizations for rendering + GC 4. Code Organization and abstractions
Everything in its place... An Uber-container for your game Modules for base and custom functionality Components for reusable, mix-and-match functionality Classes for binding things together Events to decouple the various pieces Scenes for setting up levels and screens Stages with Tile maps for instances and groups of objects Game State objects for tracking global state
Independent of the Genre/Tech Quintus is designed to solve organizational spaghetti-code related problems
The other features Self-contained - a single file, no dependencies (<20k .gz/Min) Full scene graph, with rotation, scaling and child objects. Mobile first-ish - Works well on iOS, Android 4+, (Android 2+ supported) Broad-phase + SAT-based collision detection with directional responses Web Audio + HTML5 Audio Fallback A test suite (partial) A 10,000 word guide A jQuery-like set syntax for manipulating groups of objects. Set up for extensibility and swapping pieces out.
What does it look like? var Q = Quintus() .include("Sprites, Scenes, Anim, 2D, Input") .setup({ width: 500, height: 500 }) .controls() Q.Sprite.extend("Player",{ init: function(p) { this._super(p, { asset: "player.png" }); this.add("2d, platformerControls"); } }); Q.Sprite.extend("Platform", { init: function(p) { this._super(p, { asset: "platform.png" }); } }); Q.scene("level1",function(stage) { stage.insert(new Q.Platform({ x: 50, y: 100 })); stage.insert(new Q.Platform({ x: 200, y: 200 })); stage.insert(new Q.Player({ x: 50, y: 0 })); }); Q.load("player.png, platform.png",function() { Q.stageScene("level1"); });
More complete platformer var Q = Quintus() .include("Sprites, Scenes, Input, 2D, Touch, UI") .setup({ maximize: true }) .controls().touch() Q.Sprite.extend("Player",{ init: function(p) { this._super(p, { sheet: "player", x: 410, y: 90 }); this.add('2d, platformerControls'); this.on("hit.sprite",function(collision) { if(collision.obj.isA("Tower")) { Q.stageScene("endGame",1, { label: "You Won!" }); this.destroy(); } }); } }); Q.Sprite.extend("Tower", { init: function(p) { this._super(p, { sheet: 'tower' }); } }); Q.Sprite.extend("Enemy",{ init: function(p) { this._super(p, { sheet: 'enemy', vx: 100 }); this.add('2d, aiBounce'); this.on("bump.left,bump.right,bump.bottom",function(collision) { if(collision.obj.isA("Player")) { Q.stageScene("endGame",1, { label: "You Died" }); collision.obj.destroy(); } }); this.on("bump.top",function(collision) { if(collision.obj.isA("Player")) { this.destroy(); collision.obj.p.vy = -300; } }); } }); Q.scene("level1",function(stage) { stage.collisionLayer(new Q.TileLayer({ dataAsset: 'level.json', sheet: 'tiles' })); var player = stage.insert(new Q.Player()); stage.add("viewport").follow(player); stage.insert(new Q.Enemy({ x: 700, y: 0 })); stage.insert(new Q.Enemy({ x: 800, y: 0 })); stage.insert(new Q.Tower({ x: 180, y: 50 })); }); Q.scene('endGame',function(stage) { var box = stage.insert(new Q.UI.Container({ x: Q.width/2, y: Q.height/2, fill: "rgba(0,0,0,0.5)" })); var button = box.insert(new Q.UI.Button({ x: 0, y: 0, fill: "#CCCCCC", label: "Play Again" })) var label = box.insert(new Q.UI.Text({x:10, y: -10 - button.p.h, label: stage.options.label })); button.on("click",function() { Q.clearStages(); Q.stageScene('level1'); }); box.fit(20); }); Q.load("sprites.png, sprites.json, level.json, tiles.png", function() { Q.sheet("tiles","tiles.png", { tilew: 32, tileh: 32 }); Q.compileSheets("sprites.png","sprites.json"); Q.stageScene("level1"); });