├── .gitignore ├── GPL-LICENSE.txt ├── Gruntfile.js ├── MIT-LICENSE.txt ├── README.md ├── SpecRunner.html ├── examples ├── assets │ ├── sprites │ │ ├── enemy01.png │ │ ├── player01.png │ │ ├── player02.png │ │ ├── player03.png │ │ └── tower01.png │ └── tiles │ │ ├── tiles00.png │ │ ├── tiles01.png │ │ └── tiles02.png ├── audio │ ├── audio.js │ ├── audio │ │ ├── 14564__noisecollector__yamaha-a6.mp3 │ │ ├── 14564__noisecollector__yamaha-a6.ogg │ │ ├── 14565__noisecollector__yamaha-a7.mp3 │ │ ├── 14565__noisecollector__yamaha-a7.ogg │ │ ├── 14567__noisecollector__yamaha-am.mp3 │ │ ├── 14567__noisecollector__yamaha-am.ogg │ │ ├── 16287__ltibbits__kick-high-vol.mp3 │ │ ├── 16287__ltibbits__kick-high-vol.ogg │ │ ├── 16292__ltibbits__rim1-snare.mp3 │ │ ├── 16292__ltibbits__rim1-snare.ogg │ │ ├── 16295__ltibbits__rim4-tom-16.mp3 │ │ ├── 16295__ltibbits__rim4-tom-16.ogg │ │ ├── _readme_and_license1.txt │ │ ├── _readme_and_license2.txt │ │ └── raw │ └── index.html ├── ball │ ├── ball.js │ └── index.html ├── breakout │ ├── README.md │ ├── audio │ │ ├── brickDeath.mp3 │ │ ├── brickDeath.ogg │ │ ├── brickDeath.wav │ │ ├── countdownBlip.mp3 │ │ ├── countdownBlip.ogg │ │ ├── countdownBlip.wav │ │ ├── powerdown.mp3 │ │ ├── powerdown.ogg │ │ ├── powerdown.wav │ │ ├── powerup.mp3 │ │ ├── powerup.ogg │ │ ├── powerup.wav │ │ ├── recover.mp3 │ │ ├── recover.ogg │ │ └── recover.wav │ ├── data │ │ ├── bg.tmx │ │ └── sprites.json │ ├── images │ │ ├── bg_prerendered.png │ │ ├── logo.png │ │ └── tiles.png │ ├── index.html │ └── javascripts │ │ ├── breakout-levels.js │ │ ├── breakout-scenes.js │ │ ├── breakout-sprites.js │ │ ├── breakout-ui.js │ │ └── breakout.js ├── cannon │ ├── cannon.js │ └── index.html ├── collision │ ├── collision.js │ └── index.html ├── disasteroids │ ├── disasteroids.js │ └── index.html ├── platformer.png ├── platformer │ ├── data │ │ ├── level.json │ │ └── sprites.json │ ├── images │ │ ├── background-wall.png │ │ ├── sprites.png │ │ └── tiles.png │ ├── index.html │ └── platformer.js ├── platformer_full │ ├── README.md │ ├── assets │ │ ├── player │ │ │ ├── player01.png │ │ │ ├── player02.png │ │ │ ├── player03.png │ │ │ ├── player04.png │ │ │ ├── player05.png │ │ │ ├── player06.png │ │ │ ├── player07.png │ │ │ ├── player08.png │ │ │ ├── player09.png │ │ │ ├── player10.png │ │ │ ├── player11.png │ │ │ ├── player12.png │ │ │ ├── player13.png │ │ │ ├── player14.png │ │ │ ├── player15.png │ │ │ ├── player16.png │ │ │ ├── player17.png │ │ │ └── player18.png │ │ ├── style.css │ │ └── style.scss │ ├── audio │ │ ├── coin.mp3 │ │ ├── coin.ogg │ │ ├── coin.wav │ │ ├── fire.mp3 │ │ ├── fire.ogg │ │ ├── fire.wav │ │ ├── heart.mp3 │ │ ├── heart.ogg │ │ ├── heart.wav │ │ ├── hit.mp3 │ │ ├── hit.ogg │ │ ├── hit.wav │ │ ├── jump.mp3 │ │ ├── jump.ogg │ │ └── jump.wav │ ├── data │ │ ├── collectables.json │ │ ├── doors.json │ │ ├── enemies.json │ │ ├── level1.tmx │ │ └── player.json │ ├── images │ │ ├── bg.png │ │ ├── bg_castle.png │ │ ├── collectables.png │ │ ├── doors.png │ │ ├── enemies.png │ │ ├── player.png │ │ └── tiles.png │ ├── index.html │ └── platformer.js ├── platformer_tmx │ ├── data │ │ ├── level1.json │ │ ├── level1.tmx │ │ └── sprites.json │ ├── images │ │ ├── background-wall.png │ │ ├── sprites.png │ │ └── tiles.png │ ├── index.html │ └── platformer.js ├── platforms │ ├── data │ │ └── sprites.json │ ├── images │ │ ├── background-wall.png │ │ └── sprites.png │ ├── index.html │ └── platforms.js ├── runner │ ├── data │ │ ├── crates.json │ │ └── player.json │ ├── images │ │ ├── background-floor.png │ │ ├── background-wall.png │ │ ├── crates.png │ │ └── player.png │ ├── index.html │ └── runner.js ├── server │ ├── .gitignore │ ├── app.js │ └── package.json ├── sprite │ ├── images │ │ ├── enemy.png │ │ └── sprites.png │ ├── index.html │ └── sprite.js ├── touch │ ├── images │ │ ├── enemy.png │ │ └── sprites.png │ ├── index.html │ └── touch.js ├── tower_man │ ├── data │ │ ├── level.json │ │ └── sprites.json │ ├── images │ │ ├── background-wall.png │ │ ├── sprites.png │ │ └── tiles.png │ ├── index.html │ └── tower_man.js ├── tween │ ├── images │ │ └── enemy01.png │ ├── index.html │ └── tween.js └── ui │ ├── data │ ├── level.json │ └── sprites.json │ ├── images │ ├── enemy.png │ ├── sprites.png │ └── tiles.png │ ├── index.html │ └── ui.js ├── extra ├── README.md ├── quintus_dom.js ├── quintus_physics.js └── quintus_svg.js ├── lib ├── quintus.js ├── quintus_2d.js ├── quintus_anim.js ├── quintus_audio.js ├── quintus_input.js ├── quintus_scenes.js ├── quintus_sprites.js ├── quintus_tmx.js ├── quintus_touch.js └── quintus_ui.js ├── package.json ├── specs ├── data │ └── blockbreak.json ├── fixtures │ ├── samples │ │ └── QuintusSprites │ │ │ ├── blank.png │ │ │ ├── should-be-able-to-draw-sprites.png │ │ │ ├── sprite-asset-should-be-able-to-draw-its-bounding-box.png │ │ │ ├── sprite-asset-should-be-able-to-draw-itself-at-an-angle.png │ │ │ ├── sprite-asset-should-be-able-to-draw-itself.png │ │ │ ├── sprite-asset-should-be-able-to-scale-itself.png │ │ │ ├── sprite-sheet-should-be-able-to-draw-its-bounding-box.png │ │ │ ├── sprite-sheet-should-be-able-to-draw-itself-at-an-angle.png │ │ │ ├── sprite-sheet-should-be-able-to-draw-itself.png │ │ │ └── sprite-sheet-should-be-able-to-scale-itself.png │ └── sprites.js ├── images │ └── blockbreak.png ├── lib │ ├── imagediff.js │ └── jasmine-1.2.0 │ │ ├── MIT.LICENSE │ │ ├── jasmine-html.js │ │ ├── jasmine.css │ │ └── jasmine.js └── spec │ ├── QuintusSceneSpec.js │ ├── QuintusSpec.js │ ├── QuintusSpritesSpec.js │ └── SpecHelper.js └── vendor ├── Box2dWeb-2.1.a.3.js └── stats.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | node_modules/ 3 | .DS_Store 4 | dist/ 5 | docs/ 6 | doc/ 7 | bin/ 8 | s3.json 9 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:false*/ 2 | module.exports = function(grunt) { 3 | 'use strict'; 4 | 5 | // Project configuration. 6 | grunt.initConfig({ 7 | pkg: grunt.file.readJSON('package.json'), 8 | jasmine: { 9 | all: { 10 | src: 'lib/*.js', 11 | options: { 12 | specs: 'specs/spec/*.js', 13 | helpers: ['specs/lib/imagediff.js', 'specs/fixtures/*.js'] 14 | }, 15 | errorReporting: true 16 | } 17 | }, 18 | concat: { 19 | dist: { 20 | src: ["lib/quintus.js","lib/*.js"], 21 | dest: 'dist/quintus-all.js' 22 | } 23 | }, 24 | uglify: { 25 | options: { 26 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + 27 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 28 | ' * <%= pkg.homepage %>\n' + 29 | ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + 30 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n' 31 | }, 32 | dist: { 33 | files: { 34 | 'dist/quintus-all.min.js': ['dist/quintus-all.js'] 35 | } 36 | } 37 | }, 38 | watch: { 39 | files: '', 40 | tasks: 'lint qunit' 41 | }, 42 | exec: { 43 | gzip: { 44 | cmd: [ 45 | "gzip dist/quintus-all.js", 46 | "mv dist/quintus-all.js.gz dist/quintus-all.js", 47 | "gzip dist/quintus-all.min.js", 48 | "mv dist/quintus-all.min.js.gz dist/quintus-all.min.js" 49 | ].join("&&") 50 | }, 51 | 52 | // Until grunt docco works again... 53 | docco: { 54 | cmd: "./node_modules/docco/bin/docco -o ./docs examples/*/*.js examples/*/javascripts/*.js" 55 | } 56 | }, 57 | 58 | jshint: { 59 | options: { 60 | curly: true, 61 | eqeqeq: true, 62 | immed: true, 63 | latedef: true, 64 | newcap: true, 65 | noarg: true, 66 | sub: true, 67 | undef: true, 68 | boss: true, 69 | eqnull: true, 70 | browser: true, 71 | globals: { 72 | "alert": true 73 | }, 74 | }, 75 | globals: {}, 76 | all: ['lib/**/*.js'] 77 | }, 78 | 79 | 80 | yuidoc: { 81 | pkg: grunt.file.readJSON('package.json'), 82 | api: { 83 | name: '<%= pkg.name %>', 84 | description: '<%= pkg.description %>', 85 | version: '<%= pkg.version %>', 86 | url: '<%= pkg.homepage %>', 87 | options: { 88 | paths: './lib/', 89 | outdir: './doc/' 90 | } 91 | } 92 | } 93 | }); 94 | 95 | // Default task. 96 | grunt.registerTask('default', ['jshint:all','jasmine','concat:dist','uglify:dist']); 97 | grunt.registerTask("docs", [ 'yuidoc:api', 'exec:docco' ]); 98 | grunt.registerTask('release', ['jshint:all','jasmine','concat:dist','uglify:dist','exec:gzip','s3-copy']); 99 | grunt.loadNpmTasks('grunt-contrib-concat'); 100 | grunt.loadNpmTasks('grunt-contrib-jshint'); 101 | grunt.loadNpmTasks('grunt-contrib-uglify'); 102 | grunt.loadNpmTasks('grunt-contrib-jasmine'); 103 | grunt.loadNpmTasks('grunt-exec'); 104 | grunt.loadNpmTasks('grunt-contrib-yuidoc'); 105 | 106 | grunt.registerTask('s3-copy',function() { 107 | var AWS = require("aws-sdk"), 108 | fs = require('fs'), 109 | pjson = require('./package.json'), 110 | s3Config = require("./s3.json"), 111 | done = this.async(); 112 | 113 | AWS.config.loadFromPath("./s3.json"); 114 | var s3 = new AWS.S3(); 115 | 116 | var filePath = "v" + pjson.version + "/"; 117 | 118 | var allData = fs.readFileSync("dist/quintus-all.js"); 119 | var minData = fs.readFileSync('dist/quintus-all.min.js'); 120 | 121 | function s3Opts(key,data) { 122 | return { 123 | Bucket: s3Config.bucket, 124 | Key: filePath + key, 125 | Body: data, 126 | ACL: "public-read", 127 | ContentEncoding: "gzip", 128 | ContentType: "application/x-javascript" 129 | } 130 | 131 | } 132 | 133 | s3.client.putObject(s3Opts('quintus-all.js',allData), 134 | function() { 135 | s3.client.putObject(s3Opts('quintus-all.min.js',minData), done) }); 136 | }); 137 | 138 | 139 | }; 140 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Cykod LLC, http://coderdeck.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /SpecRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Quintus Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /examples/assets/sprites/enemy01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/sprites/enemy01.png -------------------------------------------------------------------------------- /examples/assets/sprites/player01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/sprites/player01.png -------------------------------------------------------------------------------- /examples/assets/sprites/player02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/sprites/player02.png -------------------------------------------------------------------------------- /examples/assets/sprites/player03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/sprites/player03.png -------------------------------------------------------------------------------- /examples/assets/sprites/tower01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/sprites/tower01.png -------------------------------------------------------------------------------- /examples/assets/tiles/tiles00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/tiles/tiles00.png -------------------------------------------------------------------------------- /examples/assets/tiles/tiles01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/tiles/tiles01.png -------------------------------------------------------------------------------- /examples/assets/tiles/tiles02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/assets/tiles/tiles02.png -------------------------------------------------------------------------------- /examples/audio/audio.js: -------------------------------------------------------------------------------- 1 | // # Quintus Audio Example 2 | // 3 | // [Run the example](../quintus/examples/audio/index.html) 4 | // 5 | // This example demonstrates the Quintus audio library 6 | window.addEventListener('load',function(e) { 7 | 8 | // Set up a Quintus Instance 9 | var Q = window.Q = Quintus() 10 | .include("Audio, Sprites, Scenes, Touch, UI") 11 | .setup() 12 | .touch(); 13 | 14 | function goHTML5Audio() { 15 | Q.assets = {}; 16 | Q.audio.enableHTML5Sound(); 17 | loadAssetsAndGo(); 18 | } 19 | 20 | function goWebAudio() { 21 | Q.assets = []; 22 | Q.audio.enableWebAudioSound(); 23 | loadAssetsAndGo(); 24 | } 25 | 26 | Q.scene("selector",function(stage) { 27 | var container = stage.insert(new Q.UI.Container({ 28 | w: "0%", 29 | y: 50 30 | })); 31 | 32 | 33 | if(Q.hasWebAudio) { 34 | var web = stage.insert(new Q.UI.Button({ 35 | label: "Web Audio", 36 | align: "center", 37 | fill: "#CCC", 38 | highlight: "#999" 39 | },goWebAudio),container); 40 | } else { 41 | stage.insert(new Q.UI.Text({ 42 | label: "Web Audio\nnot supported", 43 | align: "center", 44 | }), container); 45 | } 46 | 47 | var html5 = stage.insert(new Q.UI.Button({ 48 | label: "HTML5 Audio", 49 | align: "center", 50 | fill: "#CCC", 51 | highlight: "#999", 52 | y: 80, 53 | }, goHTML5Audio),container); 54 | 55 | 56 | if(Q.touchDevice) { 57 | stage.insert(new Q.UI.Text({ 58 | label: "HTML5 Audio\nnot well\nsupported\non Mobile", 59 | align: "center", 60 | y: 200 61 | }), container); 62 | } 63 | 64 | container.fit(20); 65 | }); 66 | 67 | Q.scene("loading",function(stage) { 68 | stage.insert(new Q.UI.Text({ 69 | label: "Loading...", 70 | x: Q.width/2, 71 | y: Q.height/2 72 | })); 73 | }); 74 | 75 | Q.scene("play",function(stage) { 76 | sounds = ["Guitar 1", "Guitar 2", "Guitar 3", "Kick", "Snare", "TomTom"]; 77 | 78 | stage.insert(new Q.UI.Text({ 79 | label: "No Loop", 80 | x: Q.width/4, 81 | y: 20 82 | })); 83 | 84 | stage.insert(new Q.UI.Text({ 85 | label: "Loop", 86 | x: 3*Q.width/4, 87 | y: 20 88 | })); 89 | 90 | 91 | for(var x=0;x<2;x++) { 92 | for(var i=0;i 2 | 3 | 4 | 5 | Quintus Audio Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/ball/ball.js: -------------------------------------------------------------------------------- 1 | // # Quintus moving ball example 2 | // 3 | // [Run the example](../quintus/examples/ball/index.html) 4 | // 5 | // This is one of the simplest possible examples of using 6 | // Quintus that doesn't use the scene/stage functionality, 7 | // but rather just creates a single sprite and steps and 8 | // draws that sprite 9 | // 10 | // The goal of the example is to demonstrate the modularity 11 | // of the engine and the ability to only include the components 12 | // you actually need. 13 | 14 | 15 | // Wait for the load event to start the game. 16 | window.addEventListener("load",function() { 17 | 18 | // Create an instance of the engine, including only 19 | // the `Sprites` module, and then call setup to create a 20 | // canvas element on the page. If you already have a 21 | // canvas element in your page, you can pass the element 22 | // or it's id as the first parameter to set up as well. 23 | var Q = window.Q = Quintus().include("Sprites").setup({ width: 400, height: 400 }); 24 | 25 | // The `MovingSprite` class is a descendant of the base `Sprite` class, 26 | // all it does is add in a step method to Sprite that runs the standard 27 | // 2D motion equations using properties vx, vy for the velocity and ax, ay 28 | // to calculate the new x and y positions. 29 | Q.MovingSprite.extend("Ball",{ 30 | // Sprites by default expect either a `sheet` or an `asset` property 31 | // to draw themselves, but by overriding the draw method you can draw a 32 | // shape directly on the canvas instead. 33 | draw: function(ctx) { 34 | ctx.fillStyle = "black"; 35 | ctx.beginPath(); 36 | ctx.arc(-this.p.cx, 37 | -this.p.cy, 38 | this.p.w/2,0,Math.PI*2); 39 | ctx.fill(); 40 | 41 | } 42 | }); 43 | 44 | // Create a new instance of the `Ball` Sprite, 45 | // passing in the size, position, velocity, and 46 | // acceleration 47 | var ball = window.ball = new Q.Ball({ w: 20, h: 20, 48 | x: 30, y: 300, 49 | vx: 30, vy: -100, 50 | ax: 0, ay: 30 }); 51 | 52 | // You can start the game loop directly by 53 | // calling `gameLoop` with a callback and Quintus 54 | // will set up a requestAnimationFrame powered game loop 55 | // for you. Most examples don't call `gameLoop` directly as 56 | // calling `stageScene` will start a game loop that takes care 57 | // of clearing the canvas and updating and drawing all the stages 58 | // for you. 59 | Q.gameLoop(function(dt) { 60 | // Clear the canvas 61 | Q.clear(); 62 | 63 | // Move the ball `dt` forward in time 64 | ball.update(dt); 65 | 66 | // Render the ball onto the canvas context. 67 | ball.render(Q.ctx); 68 | }); 69 | 70 | 71 | // ## Possible Experimentations: 72 | // 73 | // 1. Try adding multiple balls of different positions and sizes 74 | // and looping over them manually in game loop 75 | // 2. Change the clear color of the canvas 76 | // 3. Add in the `Scenes` module and create and stage a scene. 77 | }); 78 | -------------------------------------------------------------------------------- /examples/ball/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quintus Ball Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/breakout/README.md: -------------------------------------------------------------------------------- 1 | ## Breakouts 2 | 3 | This is the Quintus implementation of [city41](https://github.com/city41)'s [Breakouts](https://github.com/city41/breakouts) project. It uses MIT licensed art, data and audio assets from that project.# Breakouts -- Quintus 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/breakout/audio/brickDeath.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/brickDeath.mp3 -------------------------------------------------------------------------------- /examples/breakout/audio/brickDeath.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/brickDeath.ogg -------------------------------------------------------------------------------- /examples/breakout/audio/brickDeath.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/brickDeath.wav -------------------------------------------------------------------------------- /examples/breakout/audio/countdownBlip.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/countdownBlip.mp3 -------------------------------------------------------------------------------- /examples/breakout/audio/countdownBlip.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/countdownBlip.ogg -------------------------------------------------------------------------------- /examples/breakout/audio/countdownBlip.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/countdownBlip.wav -------------------------------------------------------------------------------- /examples/breakout/audio/powerdown.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/powerdown.mp3 -------------------------------------------------------------------------------- /examples/breakout/audio/powerdown.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/powerdown.ogg -------------------------------------------------------------------------------- /examples/breakout/audio/powerdown.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/powerdown.wav -------------------------------------------------------------------------------- /examples/breakout/audio/powerup.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/powerup.mp3 -------------------------------------------------------------------------------- /examples/breakout/audio/powerup.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/powerup.ogg -------------------------------------------------------------------------------- /examples/breakout/audio/powerup.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/powerup.wav -------------------------------------------------------------------------------- /examples/breakout/audio/recover.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/recover.mp3 -------------------------------------------------------------------------------- /examples/breakout/audio/recover.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/recover.ogg -------------------------------------------------------------------------------- /examples/breakout/audio/recover.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/audio/recover.wav -------------------------------------------------------------------------------- /examples/breakout/data/sprites.json: -------------------------------------------------------------------------------- 1 | { 2 | "tiles" : { "tilew": 16, "tileh": 16, "sx": 0, "sy": 0, "w": 192, "h": 144}, 3 | "block1": { "tilew": 32, "tileh": 16, "sx": 0, "sy": 0, "w": 160, "h": 16 }, 4 | "block2": { "tilew": 32, "tileh": 16, "sx": 0, "sy": 16, "w": 160, "h": 16 }, 5 | "block3": { "tilew": 32, "tileh": 16, "sx": 0, "sy": 32, "w": 160, "h": 16 }, 6 | "block4": { "tilew": 32, "tileh": 16, "sx": 0, "sy": 48, "w": 160, "h": 16 }, 7 | "paddlelg":{ "tilew": 48, "tileh": 16, "sx": 0, "sy": 64, "w": 48, "h": 16 }, 8 | "ball": { "tilew": 16, "tileh": 16, "sx":48, "sy": 64, "w": 80, "h": 16 }, 9 | "paddlesm":{ "tilew": 32, "tileh": 16, "sx": 0, "sy": 80, "w": 32, "h": 16 }, 10 | "count": { "tilew": 32, "tileh": 48, "sx": 0, "sy": 96, "w": 96, "h": 48 }, 11 | "powerup": { "tilew": 16, "tileh": 16, "sx":96, "sy": 96, "w": 96, "h": 16 }, 12 | "powerdown":{ "tilew": 16, "tileh": 16, "sx":112, "sy": 96, "w": 96, "h": 16 } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /examples/breakout/images/bg_prerendered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/images/bg_prerendered.png -------------------------------------------------------------------------------- /examples/breakout/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/images/logo.png -------------------------------------------------------------------------------- /examples/breakout/images/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/breakout/images/tiles.png -------------------------------------------------------------------------------- /examples/breakout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Breakout - Quintus 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/breakout/javascripts/breakout-levels.js: -------------------------------------------------------------------------------- 1 | ;Quintus.BreakoutLevels = function(Q) { 2 | 3 | var b = 4; // red 4 | var r = 3; // blue 5 | var o = 2; // orange 6 | var g = 1; // green 7 | var X = 0; // null 8 | 9 | Q.assets['level1'] = [ 10 | [X,X,g,o,g,X,X], 11 | [o,b,g,g,g,b,o], 12 | [X,b,b,b,b,b,X] 13 | ]; 14 | 15 | Q.assets['level2'] = [ 16 | [X,g,o,g,o,g,X], 17 | [X,b,b,b,b,b,X], 18 | [g,b,r,b,r,b,g], 19 | [g,b,b,b,b,b,g], 20 | [g,b,X,X,X,b,g], 21 | [X,b,b,b,b,b,X] 22 | ]; 23 | 24 | Q.assets['level3'] = [ 25 | [X,b,X,g,X,b,X], 26 | [b,X,b,o,b,X,b], 27 | [b,g,b,o,b,g,b], 28 | [b,X,b,o,b,X,b], 29 | [X,b,X,X,X,b,X], 30 | [r,X,r,X,r,X,r] 31 | ]; 32 | 33 | Q.assets['level4'] = [ 34 | [r,g,o,b,r,g,o], 35 | [b,X,X,X,X,X,X], 36 | [o,X,o,b,r,g,o], 37 | [g,X,g,X,X,X,b], 38 | [r,X,r,X,r,X,r], 39 | [b,X,b,o,g,X,g], 40 | [o,X,X,X,X,X,o], 41 | [g,r,b,o,g,r,b] 42 | ]; 43 | 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /examples/breakout/javascripts/breakout-scenes.js: -------------------------------------------------------------------------------- 1 | ;Quintus.BreakoutScenes = function(Q) { 2 | 3 | Q.scene("title",function(stage) { 4 | Q.state.set("level",0); 5 | 6 | // Clear the hud out 7 | Q.clearStage(1); 8 | 9 | var bg = stage.insert(new Q.Background({ type: Q.SPRITE_UI })); 10 | bg.on("touch",function() { Q.stageScene("level1"); }); 11 | 12 | stage.insert(new Q.Title()); 13 | 14 | var verb = Q.touchDevice ? 'Tap': 'Click'; 15 | 16 | stage.insert(new Q.UI.Text({ 17 | label: verb + " to start", 18 | align: 'center', 19 | x: Q.width/2, 20 | y: 280, 21 | weight: "normal", 22 | size: 20 23 | })); 24 | 25 | 26 | stage.insert(new Q.UI.Text({ 27 | label: "during the game: use L/R arrow\nkeys to skip levels", 28 | align: 'center', 29 | x: Q.width/2, 30 | y: 370, 31 | weight: "normal", 32 | size: 20 33 | })); 34 | }); 35 | 36 | Q.scene("gameOver",function(stage) { 37 | 38 | var bg = stage.insert(new Q.Background({ type: Q.SPRITE_UI })); 39 | bg.on("touch",function() { Q.stageScene("title"); }); 40 | 41 | stage.insert(new Q.Title()); 42 | 43 | stage.insert(new Q.UI.Text({ 44 | label: "Game Over!", 45 | align: 'center', 46 | x: Q.width/2, 47 | y: 350, 48 | weight: "normal", 49 | size: 20 50 | })); 51 | 52 | }); 53 | 54 | Q.scene("winner",function(stage) { 55 | 56 | var bg = stage.insert(new Q.Background({ type: Q.SPRITE_UI })); 57 | bg.on("touch",function() { Q.stageScene("title"); }); 58 | 59 | stage.insert(new Q.Title()); 60 | 61 | stage.insert(new Q.UI.Text({ 62 | label: "You Win!", 63 | align: 'center', 64 | x: Q.width/2, 65 | y: 350, 66 | weight: "normal", 67 | size: 20 68 | })); 69 | 70 | }); 71 | 72 | Q.scene("hud",function(stage) { 73 | stage.insert(new Q.Score()); 74 | stage.insert(new Q.Lives()); 75 | stage.insert(new Q.Level()); 76 | }, { stage: 1 }); 77 | 78 | function setupLevel(levelAsset,stage) { 79 | 80 | if(Q.useTiles) { 81 | stage.collisionLayer(new Q.GameTiles()); 82 | } else { 83 | stage.insert(new Q.Background()); 84 | } 85 | 86 | stage.insert(new Q.BlockTracker({ data: Q.asset(levelAsset) })); 87 | 88 | stage.insert(new Q.Ball({ x: 50, y: 100 })); 89 | stage.insert(new Q.Countdown()); 90 | stage.insert(new Q.Paddle()); 91 | 92 | } 93 | 94 | Q.scene("level1",function(stage) { 95 | // Set up the game state 96 | Q.state.reset({ score: 0, lives: 3, level: 1 }); 97 | 98 | // Add the hud in 99 | Q.stageScene("hud"); 100 | 101 | // Call the helper methods to get the 102 | // level all set up with blocks, a ball and a paddle 103 | setupLevel("level1",stage); 104 | 105 | // Set up a listener for when the stage is complete 106 | // to load the next level 107 | stage.on("complete",function() { Q.stageScene("level2"); }); 108 | }); 109 | 110 | Q.scene("level2",function(stage) { 111 | Q.state.set("level",2); 112 | setupLevel("level2",stage); 113 | stage.on("complete",function() { Q.stageScene("level3"); }); 114 | }); 115 | 116 | Q.scene("level3",function(stage) { 117 | Q.state.set("level",3); 118 | setupLevel("level3",stage); 119 | stage.on("complete",function() { Q.stageScene("level4"); }); 120 | }); 121 | 122 | Q.scene("level4",function(stage) { 123 | Q.state.set("level",4); 124 | setupLevel("level4",stage); 125 | stage.on("complete",function() { Q.stageScene("winner"); }); 126 | }); 127 | 128 | // Level Skipping 129 | Q.input.on('left',function() { 130 | var level = Q.state.get("level"); 131 | 132 | if(level > 1) { 133 | Q.stageScene('level' + (level-1)); 134 | } else { 135 | Q.stageScene('title'); 136 | } 137 | }); 138 | 139 | Q.input.on('right',function() { 140 | var level = Q.state.get("level") || 0; 141 | 142 | if(level < 4) { 143 | Q.stageScene('level' + (level+1)); 144 | } else { 145 | Q.stageScene('winner'); 146 | } 147 | }); 148 | }; 149 | 150 | -------------------------------------------------------------------------------- /examples/breakout/javascripts/breakout-sprites.js: -------------------------------------------------------------------------------- 1 | ;Quintus.BreakoutSprites = function(Q) { 2 | 3 | Q.gravityY = 0; 4 | Q.gravityX = 0; 5 | 6 | Q.TileLayer.extend("GameTiles",{ 7 | init: function(p) { 8 | this._super({ 9 | dataAsset: "bg.tmx", 10 | sheet: 'tiles', 11 | tileW: 16, 12 | tileH: 16, 13 | blockTileW: 21, 14 | blockTileH: 27 15 | }); 16 | }, 17 | 18 | // Override the load method to load the bg.tmx file, 19 | // then pass the data array to the original implementation 20 | load: function(dataAsset) { 21 | var parser = new DOMParser(), 22 | doc = parser.parseFromString(Q.asset(dataAsset), "application/xml"); 23 | 24 | var layer = doc.getElementsByTagName("layer")[0], 25 | width = parseInt(layer.getAttribute("width")), 26 | height = parseInt(layer.getAttribute("height")); 27 | 28 | var data = [], 29 | tiles = layer.getElementsByTagName("tile"), 30 | idx = 0; 31 | for(var y = 0;y < height;y++) { 32 | data[y] = []; 33 | for(var x = 0;x < width;x++) { 34 | var tile = tiles[idx]; 35 | data[y].push(parseInt(tile.getAttribute("gid")-1)); 36 | idx++; 37 | } 38 | } 39 | 40 | this._super(data); 41 | }, 42 | 43 | collidableTile: function(tileNum) { 44 | return tileNum != 23; 45 | } 46 | 47 | }); 48 | 49 | Q.Sprite.extend("BlockTracker",{ 50 | init: function(p) { 51 | this._super(p, { 52 | x: Q.width/2, 53 | y: 64, 54 | scale: 0.1 55 | }); 56 | 57 | this.add("tween"); 58 | 59 | this.animate({ scale: 1 },1.5, Q.Easing.Quadratic.InOut); 60 | 61 | this.on("inserted",this,"setupBlocks"); 62 | }, 63 | 64 | setupBlocks: function() { 65 | Q._each(this.p.data,function(row,y) { 66 | Q._each(row,function(block,x) { 67 | if(block) { 68 | // Add onto the stage, with this as the 69 | // container 70 | this.stage.insert(new Q.Block({ 71 | num: block, 72 | x: 32 * x - (row.length / 2 - 0.5) * 32, 73 | y: 16 * y 74 | }), this); 75 | } 76 | 77 | },this); 78 | },this); 79 | }, 80 | 81 | step: function(dt) { 82 | if(this.children.length == 0) { 83 | this.stage.trigger("complete"); 84 | } 85 | } 86 | }); 87 | 88 | 89 | Q.Sprite.extend("Ball", { 90 | init: function(p) { 91 | this._super({ 92 | sheet:"ball", 93 | sprite: "ball", 94 | speed: 200, 95 | collisionMask: Q.SPRITE_DEFAULT, 96 | vx: 0, 97 | vy: 0, 98 | x: 50, 99 | y: 250 100 | },p); 101 | 102 | this.add("animation"); 103 | this.play("default"); 104 | 105 | // Wait til we are inserted, then listen for events on the stage 106 | this.on("inserted"); 107 | this.on("hit",this,"collide"); 108 | 109 | }, 110 | 111 | inserted: function() { 112 | this.stage.on("start",this,"start"); 113 | }, 114 | 115 | collide: function(col) { 116 | if(col.obj.isA("Paddle")) { 117 | var dx = (this.p.x - col.obj.p.x) / col.obj.p.w * 2.5; 118 | 119 | if(col.normalY <= 0) { 120 | this.p.vy = -this.p.speed; 121 | } 122 | this.p.vx = dx * this.p.speed; 123 | } else { 124 | 125 | 126 | if(col.normalY < -0.3) { 127 | this.p.vy = -Math.abs(this.p.vy); 128 | } 129 | if(col.normalY > 0.3) { 130 | this.p.vy = Math.abs(this.p.vy); 131 | } 132 | 133 | if(col.normalX < -0.3) { 134 | this.p.vx = -Math.abs(this.p.vx); 135 | } 136 | if(col.normalX > 0.3) { 137 | this.p.vx = Math.abs(this.p.vx); 138 | } 139 | 140 | if(col.obj.isA("Block")) { 141 | Q.audio.play("brickDeath.ogg"); 142 | col.obj.play("hit",2); 143 | } 144 | } 145 | this.p.x -= col.separate[0]; 146 | this.p.y -= col.separate[1]; 147 | 148 | }, 149 | 150 | start:function() { 151 | this.p.vy = this.p.speed; 152 | this.p.vx = this.p.speed; 153 | 154 | }, 155 | 156 | step: function(dt) { 157 | this.p.x += this.p.vx * dt; 158 | this.p.y += this.p.vy * dt; 159 | 160 | this.stage.collide(this); 161 | 162 | if(!Q.useTiles) { 163 | if(this.p.x < 24) { this.p.vx = Math.abs(this.p.vx); } 164 | if(this.p.x > Q.width - 24) { this.p.vx = -Math.abs(this.p.vx); } 165 | 166 | if(this.p.y < 24) { this.p.vy = Math.abs(this.p.vy); } 167 | } 168 | 169 | if(this.p.y > Q.height) { 170 | this.destroy(); // Remove the ball if it's off the screen 171 | } 172 | } 173 | }); 174 | 175 | Q.Sprite.extend("Block", { 176 | init: function(p) { 177 | this._super({ 178 | sheet: "block" + p.num, 179 | sprite: "block" 180 | },p); 181 | 182 | this.add("animation"); 183 | this.play("appear"); 184 | this.on("destroy"); // will just call destroy 185 | }, 186 | 187 | destroyed: function() { 188 | Q.state.inc("score",100); 189 | 190 | var rand = Math.round(Math.random()*7); 191 | 192 | if(rand == 1 && Q("Powerdown").length == 0) { 193 | this.stage.insert(new Q.Powerdown({ x: this.c.x, 194 | y: this.c.y })); 195 | 196 | } else if(rand == 2 && Q("Powerup").length == 0) { 197 | this.stage.insert(new Q.Powerup({ x: this.c.x, 198 | y: this.c.y })); 199 | 200 | } 201 | } 202 | }); 203 | 204 | 205 | Q.Sprite.extend("Paddle", { 206 | init: function(p) { 207 | this._super({ 208 | sheet: "paddlelg", 209 | type: Q.SPRITE_DEFAULT | Q.SPRITE_FRIENDLY, 210 | y: 376, 211 | x: 0, 212 | powerdown: 0 213 | },p); 214 | 215 | this.on("powerdown"); 216 | this.on("powerup"); 217 | }, 218 | 219 | step: function(dt) { 220 | this.p.x = Q.inputs['mouseX']; 221 | 222 | if(Q("Ball").length == 0) { 223 | Q.state.dec("lives",1); 224 | if(Q.state.get("lives") == 0) { 225 | Q.stageScene("gameOver"); 226 | } else { 227 | this.stage.insert(new Q.Ball()); 228 | this.stage.insert(new Q.Countdown()); 229 | } 230 | } 231 | 232 | if(this.p.powerdown > 0) { 233 | this.p.powerdown -= dt; 234 | if(this.p.powerdown <= 0) { 235 | Q.audio.play("recover.ogg"); 236 | this.sheet("paddlelg",true); 237 | } 238 | } 239 | }, 240 | 241 | powerup: function() { 242 | var ball = this.stage.insert(new Q.Ball()); 243 | ball.start(); 244 | }, 245 | 246 | powerdown: function() { 247 | this.sheet("paddlesm",true); 248 | this.p.powerdown = 10; 249 | } 250 | 251 | }); 252 | 253 | 254 | Q.Sprite.extend("Powerdown", { 255 | init: function(p) { 256 | this._super({ 257 | sheet: "powerdown", 258 | type: Q.SPRITE_POWERUP, 259 | collisionMask: Q.SPRITE_FRIENDLY, 260 | vy: 100 261 | },p); 262 | 263 | this.add("2d") 264 | this.on("hit") 265 | }, 266 | 267 | hit: function() { 268 | this.destroy(); 269 | Q.audio.play("powerdown.ogg"); 270 | Q("Paddle").trigger("powerdown"); 271 | }, 272 | 273 | step: function(dt) { 274 | if(this.p.y > Q.height) this.destroy(); 275 | } 276 | }); 277 | 278 | Q.Sprite.extend("Powerup", { 279 | init: function(p) { 280 | this._super({ 281 | sheet: "powerup", 282 | type: Q.SPRITE_POWERUP, 283 | collisionMask: Q.SPRITE_FRIENDLY, 284 | vy: 100 285 | },p); 286 | 287 | this.add("2d") 288 | this.on("hit") 289 | }, 290 | 291 | hit: function() { 292 | this.destroy(); 293 | Q.audio.play("powerup.ogg"); 294 | Q("Paddle").trigger("powerup"); 295 | }, 296 | 297 | step: function(dt) { 298 | if(this.p.y > Q.height) this.destroy(); 299 | } 300 | }); 301 | 302 | 303 | Q.Sprite.extend("Countdown", { 304 | init: function(p) { 305 | 306 | this._super({ 307 | sheet: "count", 308 | sprite: "countdown", 309 | x: Q.width/2, 310 | y: 200 311 | },p); 312 | 313 | this.add("animation").play("countdown"); 314 | 315 | // Listen for a frame change to play sounds 316 | this.on("animFrame"); 317 | 318 | // When our animation is over, trigger a "start" event on the stage 319 | this.on("start"); 320 | 321 | Q.audio.play("countdownBlip.ogg"); 322 | }, 323 | 324 | animFrame: function(){ 325 | Q.audio.play("countdownBlip.ogg"); 326 | }, 327 | 328 | start: function() { 329 | this.stage.trigger("start"); 330 | this.destroy(); 331 | } 332 | }); 333 | 334 | 335 | }; 336 | 337 | 338 | -------------------------------------------------------------------------------- /examples/breakout/javascripts/breakout-ui.js: -------------------------------------------------------------------------------- 1 | ;Quintus.BreakoutUI = function(Q) { 2 | 3 | Q.Sprite.extend("Title", { 4 | init: function(p) { 5 | this._super({ 6 | y: 150, 7 | x: Q.width/2, 8 | asset: "logo.png" 9 | }); 10 | 11 | } 12 | }); 13 | 14 | Q.Sprite.extend("Background",{ 15 | init: function(p) { 16 | this._super(p,{ 17 | x: Q.width/2, 18 | y: Q.height/2, 19 | asset: 'bg_prerendered.png', 20 | type: 0 21 | }); 22 | } 23 | }); 24 | 25 | Q.UI.Text.extend("Level",{ 26 | init: function() { 27 | this._super({ 28 | label: "level: 1", 29 | align: "right", 30 | level: 1, 31 | x: Q.width - 70, 32 | y: Q.height - 10, 33 | weight: "normal", 34 | size:18 35 | }); 36 | 37 | Q.state.on("change.level",this,"level"); 38 | }, 39 | 40 | level: function(lvl) { 41 | this.p.label = "level: " + lvl; 42 | } 43 | }); 44 | 45 | Q.UI.Text.extend("Lives",{ 46 | init: function() { 47 | this._super({ 48 | label: "lives: 3", 49 | align: "left", 50 | x: 70, 51 | y: Q.height - 10, 52 | weight: "normal", 53 | size:18 54 | }); 55 | 56 | Q.state.on("change.lives",this,"lives"); 57 | }, 58 | 59 | lives: function(lives) { 60 | this.p.label = "lives: " + lives; 61 | } 62 | }); 63 | 64 | Q.UI.Text.extend("Score",{ 65 | init: function() { 66 | this._super({ 67 | label: "score: 0", 68 | align: "center", 69 | x: Q.width/2, 70 | y: Q.height - 10, 71 | weight: "normal", 72 | size:18 73 | }); 74 | 75 | Q.state.on("change.score",this,"score"); 76 | }, 77 | 78 | score: function(score) { 79 | this.p.label = "score: " + score; 80 | } 81 | }); 82 | 83 | 84 | }; 85 | -------------------------------------------------------------------------------- /examples/breakout/javascripts/breakout.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load',function() { 2 | 3 | var Q = Quintus().include("Sprites, Scenes, Input, Anim, 2D, Audio, Touch, UI") 4 | .include("BreakoutUI, BreakoutSprites, BreakoutScenes, BreakoutLevels") 5 | .enableSound() 6 | .setup({ width: 320, height: 416, downsampleWidth: 640, downsampleHeight: 832 }) 7 | .touch(); 8 | 9 | Q.input.mouseControls(); 10 | Q.input.keyboardControls(); 11 | 12 | 13 | Q.load([ 14 | // Images 15 | "bg_prerendered.png","tiles.png","logo.png", 16 | // Audio 17 | "brickDeath.ogg", "countdownBlip.ogg","powerdown.ogg", 18 | "powerup.ogg", "recover.ogg", 19 | // Data 20 | "bg.tmx", "sprites.json" 21 | ],function() { 22 | Q.useTiles = window.location.href.indexOf('usetiles') > -1; 23 | 24 | // Set up all the sprite sheets 25 | Q.compileSheets("tiles.png","sprites.json"); 26 | 27 | 28 | // Now add in the animations for the various sprites 29 | Q.animations("ball", { default: { frames: [0,1,2,3,4], rate: 1/4 } }); 30 | Q.animations("countdown", { 31 | countdown: { frames: [ 0,1,2 ], rate: 1.5, trigger: "start", loop: false } 32 | }); 33 | 34 | Q.animations("block", { 35 | appear: { frames: [ 4,3,2,1,0], rate: 1/3, loop: false }, 36 | hit: { frames: [ 1,2,3,4], rate: 1/4, loop: false, trigger: "destroy" } 37 | }); 38 | 39 | // Go Time 40 | Q.stageScene("title"); 41 | }); 42 | 43 | window.Q = Q; 44 | 45 | },true); 46 | -------------------------------------------------------------------------------- /examples/cannon/cannon.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load',function(e) { 2 | var Q = window.Q = Quintus() 3 | .include('Input,Sprites,Scenes,SVG,Physics') 4 | .svgOnly() 5 | .setup('quintus',{ maximize: true }); 6 | 7 | 8 | Q.Sprite.extend('CannonBall',{ 9 | init: function(props) { 10 | this._super({ 11 | shape: 'circle', 12 | color: 'red', 13 | r: 8, 14 | restitution: 0.5, 15 | density: 4, 16 | x: props.dx * 50 + 10, 17 | y: props.dy * 50 + 210, 18 | seconds: 5 19 | }); 20 | this.add('physics'); 21 | this.on('step',this,'countdown'); 22 | }, 23 | 24 | countdown: function(dt) { 25 | this.p.seconds -= dt; 26 | if(this.p.seconds < 0) { 27 | this.destroy(); 28 | } else if(this.p.seconds < 1) { 29 | this.set({ "fill-opacity": this.p.seconds }); 30 | } 31 | } 32 | }); 33 | 34 | Q.Sprite.extend('Cannon',{ 35 | init: function(props) { 36 | this._super({ 37 | shape:'polygon', 38 | color: 'black', 39 | points: [[ 0,0 ], [0,-5], [5,-10], [8, -11], [40, -11], 40 | [ 40, 11], [8, 11], [5, 10], [0, 5] ], 41 | x: 10, 42 | y: 210 43 | }); 44 | }, 45 | 46 | fire: function() { 47 | var dx = Math.cos(this.p.angle / 180 * Math.PI), 48 | dy = Math.sin(this.p.angle / 180 * Math.PI), 49 | ball = new Q.CannonBall({ dx: dx, dy: dy, angle: this.p.angle }); 50 | Q.stage().insert(ball); 51 | ball.physics.velocity(dx*400,dy*400); 52 | } 53 | }); 54 | 55 | var targetCount = 0; 56 | Q.Sprite.extend('Target',{ 57 | init: function(props) { 58 | this._super( Q._extend(props,{ 59 | shape: 'circle', 60 | color: 'pink', 61 | r: 8 62 | })); 63 | targetCount++; 64 | this.add('physics'); 65 | this.on('contact',this,'checkHit'); 66 | }, 67 | 68 | checkHit: function(sprite) { 69 | if(sprite instanceof Q.CannonBall) { 70 | targetCount--; 71 | this.destroy(); 72 | if(targetCount == 0) { Q.stageScene('level'); } 73 | } 74 | } 75 | }); 76 | 77 | 78 | 79 | 80 | Q.scene('level',new Q.Scene(function(stage) { 81 | targetCount = 0; 82 | stage.add("world"); 83 | stage.insert(new Q.Sprite({ 84 | x: 250, y: 250, w: 700, h: 50, type:"static" 85 | })) 86 | 87 | stage.insert(new Q.Sprite({ w: 10, h:50, x: 500, y: 200 })); 88 | stage.insert(new Q.Sprite({ w: 10, h:50, x: 550, y: 200 })); 89 | stage.insert(new Q.Sprite({ w: 70, h:10, x: 525, y: 170 })); 90 | stage.insert(new Q.Sprite({ w: 10, h:50, x: 500, y: 130 })); 91 | stage.insert(new Q.Sprite({ w: 10, h:50, x: 550, y: 130 })); 92 | stage.insert(new Q.Sprite({ w: 70, h:10, x: 525, y: 110 })); 93 | 94 | stage.insert(new Q.Sprite({ 95 | points: [[ 0,0 ], [ 50, -50 ],[150, -50],[200,0]], 96 | x: 200, 97 | y: 225, 98 | type:'static', 99 | shape: 'polygon' 100 | })); 101 | 102 | stage.insert(new Q.Sprite({ w: 50, h:50, x: 300, y: 150 })); 103 | stage.insert(new Q.Sprite({ w: 25, h:25, x: 300, y: 115 })); 104 | 105 | stage.each(function() { this.add("physics"); }); 106 | 107 | stage.insert(new Q.Target({ x: 525, y: 90 })); 108 | stage.insert(new Q.Target({ x: 300, y: 90 })); 109 | stage.insert(new Q.Sprite({ w: 30, h:30, x: 10, y: 210, 110 | color: 'blue' })); 111 | 112 | stage.cannon = stage.insert(new Q.Cannon()); 113 | stage.viewport(600,400); 114 | stage.centerOn(300,100); 115 | 116 | })); 117 | Q.stageScene("level"); 118 | var cannonMove=function(e) { 119 | var stage = Q.stage(0), 120 | cannon = stage.cannon, 121 | touch = e.changedTouches ? 122 | e.changedTouches[0] : e, 123 | point = stage.browserToWorld(touch.pageX,touch.pageY); 124 | 125 | var angle = Math.atan2(point.y - cannon.p.y, 126 | point.x - cannon.p.x); 127 | cannon.p.angle = angle * 180 / Math.PI; 128 | e.preventDefault(); 129 | }; 130 | Q._each(["touchstart","mousemove","touchmove"],function(evt) { 131 | Q.wrapper.addEventListener(evt,cannonMove); 132 | },this); 133 | 134 | var canonFire=function(e) { 135 | Q.stage(0).cannon.fire(); 136 | e.preventDefault(); 137 | } 138 | Q._each(["touchend","mouseup"],function(evt) { 139 | Q.wrapper.addEventListener(evt,canonFire); 140 | }); 141 | 142 | 143 | }); 144 | 145 | -------------------------------------------------------------------------------- /examples/cannon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Canon 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/collision/collision.js: -------------------------------------------------------------------------------- 1 | // # Quintus SAT Collision detection example 2 | // 3 | // [Run the example](../quintus/examples/collision/index.html) 4 | // 5 | // This example creates a number of random convex shapes to 6 | // exercise the SAT-based (Separating-axis-theorem) collision 7 | // detection. The Shapes also rotate at different speeds and scale 8 | // themselves up and down. 9 | // 10 | // Most of the code isn't particularly interesting, the main piece 11 | // of Quintus-specific collision stuff is tucked away at the bottom of 12 | // the step method. 13 | // 14 | window.addEventListener('load',function(e) { 15 | 16 | 17 | // Set up a standard Quintus instance with only the 18 | // Sprites and Scene module (for the stage support) loaded. 19 | var Q = window.Q = Quintus().include("Sprites, Scenes") 20 | .setup({ width: 960, height: 512 }); 21 | 22 | // Sprite class for the randomly generated pulsating / rotating shape, 23 | // The most of the init code isn't particularly useful - it just 24 | // generates random convex shapes with anywhere from 3 to 7 points. 25 | // 26 | // 27 | Q.Sprite.extend("RandomShape", { 28 | init: function(p) { 29 | var angle = Math.random()*2*Math.PI, 30 | numPoints = 3 + Math.floor(Math.random()*5), 31 | minX = 0, maxX = 0, 32 | minY = 0, maxY = 0, 33 | curX, curY; 34 | 35 | p = p || {}; 36 | 37 | p.points = []; 38 | 39 | var startAmount = 40; 40 | 41 | for(var i = 0;i < numPoints;i++) { 42 | curX = Math.floor(Math.cos(angle)*startAmount); 43 | curY = Math.floor(Math.sin(angle)*startAmount); 44 | 45 | if(curX < minX) minX = curX; 46 | if(curX > maxX) maxX = curX; 47 | 48 | if(curY < minY) minY = curY; 49 | if(curY > maxY) maxY = curY; 50 | 51 | p.points.push([curX,curY]); 52 | 53 | startAmount += Math.floor(Math.random()*10); 54 | angle += (Math.PI * 2) / (numPoints+1); 55 | }; 56 | 57 | maxX += 30; 58 | minX -= 30; 59 | maxY += 30; 60 | minY -= 30; 61 | 62 | p.w = maxX - minX; 63 | p.h = maxY - minY; 64 | 65 | for(var i = 0;i < numPoints;i++) { 66 | p.points[i][0] -= minX + p.w/2; 67 | p.points[i][1] -= minY + p.h/2; 68 | } 69 | 70 | 71 | p.x = Math.random()*Q.width; 72 | p.y = Math.random()*Q.height; 73 | p.cx = p.w/2; 74 | p.cy = p.h/2; 75 | p.type = 1; 76 | 77 | p.dx = 1; 78 | p.dy = 1; 79 | p.speed = Math.random() * 20 + 30; 80 | p.omega = Math.random() * 40 - 20; 81 | p.scaleOffset = 0; 82 | p.scaleSpeed = Math.random(); 83 | p.scaleAmount = 0.70 * Math.random(); 84 | 85 | this._super(p); 86 | }, 87 | 88 | step: function(dt) { 89 | var p = this.p; 90 | 91 | p.x += p.dx * p.speed * dt; 92 | p.y += p.dy * p.speed * dt; 93 | 94 | if(p.x < 0) { 95 | p.x = 0; 96 | p.dx = 1; 97 | } else if(p.x > Q.width - p.w) { 98 | p.dx = -1; 99 | p.x = Q.width - p.w; 100 | } 101 | 102 | if(p.y < 0) { 103 | p.y = 0; 104 | p.dy = 1; 105 | } else if(p.y > Q.height - p.h) { 106 | p.dy = -1; 107 | p.y = Q.height - p.h; 108 | } 109 | 110 | p.angle += dt * p.omega; 111 | 112 | p.scaleOffset += dt; 113 | p.scale = 1 + Math.sin(p.scaleOffset * p.scaleSpeed) * p.scaleAmount; 114 | 115 | // ### Checking for collisions. 116 | // This code actually runs detection for the object and moves it away 117 | // from any collisions. There's a loop in there so that the object will 118 | // move away from up to 3 collisions per frame. 119 | // 120 | // In order to work with collision detection, at minimum a sprite must have a width `w`, 121 | // a height `h`, a horizontal location `x` and a vertical location `y`. From this 122 | // the system will auto-generate a convex set of points in the shape of a square. 123 | // If you want a collision shape of a different size, you'll need to add a `points` 124 | // property that is an array of arrays of the form [ [ x0,y0 ], [x1, y1] ] that 125 | // creates a convex shape. 126 | // 127 | // The search method simply returns the first collision it hits, whether 128 | // it be in the collision layer or with another sprite. This method is called 129 | // on the `stage` stage object. You can also call the collide method which is 130 | // used primarily to trigger `hit` callbacks in lieu of returning the collision. 131 | // 132 | // Most of the time you won't need to worry about this directly as adding 133 | // the `2d` component to your class will handle it for you automatically. 134 | var maxCol = 3, collided = false; 135 | p.hit = false; 136 | while((collided = this.stage.search(this)) && maxCol > 0) { 137 | 138 | if(collided) { 139 | p.hit = true; 140 | this.p.x -= collided.separate[0]; 141 | this.p.y -= collided.separate[1]; 142 | } 143 | maxCol--; 144 | } 145 | } 146 | }); 147 | 148 | // Number of shapes to add to the page 149 | var numShapes = 5; 150 | 151 | // Scene that actually adds shapes onto the stage 152 | Q.scene("start",new Q.Scene(function(stage) { 153 | var shapesLeft = numShapes; 154 | while(shapesLeft-- > 0) { 155 | stage.insert(new Q.RandomShape()); 156 | } 157 | })); 158 | 159 | // Finally call `stageScene` to start the show 160 | Q.stageScene("start"); 161 | 162 | // Render the elements 163 | // Turning Q.debug and Q.debugFill on will render 164 | // the sprites' collision meshes, which is all we want 165 | // in this situation, otherwise nothing would get rendered 166 | Q.debug = true; 167 | Q.debugFill = true; 168 | 169 | // ## Possible Experimentations: 170 | // 171 | // 1. Try staging the `start` scene on multiple stages (e.g. add Q.stageScene("start",1)), notice 172 | // the shapes only collide with other shapes on their own stage 173 | // 2. Add in a check to the draw method that looks at the currently active stage 174 | // (stored in Q.activeStage) to determine the color of the shapes 175 | // 3. Using the collision.normalX and collision.normalY values of each collision, adjust the 176 | // velocity of colliding shapes to bounce off each other more normally 177 | // 4. Turn this into a game of asteroids. 178 | 179 | 180 | }); 181 | -------------------------------------------------------------------------------- /examples/collision/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quintus SAT Collision Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/disasteroids/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Disasteroids 8 | Platformer Example 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/platformer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer.png -------------------------------------------------------------------------------- /examples/platformer/data/level.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], 3 | [ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], 4 | [ 1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], 5 | [ 1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,1,1], 6 | [ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,2,1,1], 7 | [ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,2,1,1], 8 | [ 1,1,1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,1], 9 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 10 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 11 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 12 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 13 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 14 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 15 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] 16 | ] 17 | -------------------------------------------------------------------------------- /examples/platformer/data/sprites.json: -------------------------------------------------------------------------------- 1 | {"player":{"sx":0,"sy":0,"cols":1,"tilew":30,"tileh":30,"frames":1},"enemy":{"sx":0,"sy":31,"cols":1,"tilew":30,"tileh":24,"frames":1},"tower":{"sx":0,"sy":56,"cols":1,"tilew":30,"tileh":30,"frames":1}} 2 | -------------------------------------------------------------------------------- /examples/platformer/images/background-wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer/images/background-wall.png -------------------------------------------------------------------------------- /examples/platformer/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer/images/sprites.png -------------------------------------------------------------------------------- /examples/platformer/images/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer/images/tiles.png -------------------------------------------------------------------------------- /examples/platformer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Platformer Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/platformer/platformer.js: -------------------------------------------------------------------------------- 1 | // # Quintus platformer example 2 | // 3 | // [Run the example](../quintus/examples/platformer/index.html) 4 | // WARNING: this game must be run from a non-file:// url 5 | // as it loads a level json file. 6 | // 7 | // This is the example from the website homepage, it consists 8 | // a simple, non-animated platformer with some enemies and a 9 | // target for the player. 10 | window.addEventListener("load",function() { 11 | 12 | // Set up an instance of the Quintus engine and include 13 | // the Sprites, Scenes, Input and 2D module. The 2D module 14 | // includes the `TileLayer` class as well as the `2d` componet. 15 | var Q = window.Q = Quintus() 16 | .include("Sprites, Scenes, Input, 2D, Anim, Touch, UI") 17 | // Maximize this game to whatever the size of the browser is 18 | .setup({ maximize: true }) 19 | // And turn on default input controls and touch input (for UI) 20 | .controls().touch() 21 | 22 | // ## Player Sprite 23 | // The very basic player sprite, this is just a normal sprite 24 | // using the player sprite sheet with default controls added to it. 25 | Q.Sprite.extend("Player",{ 26 | 27 | // the init constructor is called on creation 28 | init: function(p) { 29 | 30 | // You can call the parent's constructor with this._super(..) 31 | this._super(p, { 32 | sheet: "player", // Setting a sprite sheet sets sprite width and height 33 | x: 410, // You can also set additional properties that can 34 | y: 90 // be overridden on object creation 35 | }); 36 | 37 | // Add in pre-made components to get up and running quickly 38 | // The `2d` component adds in default 2d collision detection 39 | // and kinetics (velocity, gravity) 40 | // The `platformerControls` makes the player controllable by the 41 | // default input actions (left, right to move, up or action to jump) 42 | // It also checks to make sure the player is on a horizontal surface before 43 | // letting them jump. 44 | this.add('2d, platformerControls'); 45 | 46 | // Write event handlers to respond hook into behaviors. 47 | // hit.sprite is called everytime the player collides with a sprite 48 | this.on("hit.sprite",function(collision) { 49 | 50 | // Check the collision, if it's the Tower, you win! 51 | if(collision.obj.isA("Tower")) { 52 | Q.stageScene("endGame",1, { label: "You Won!" }); 53 | this.destroy(); 54 | } 55 | }); 56 | 57 | } 58 | 59 | }); 60 | 61 | 62 | // ## Tower Sprite 63 | // Sprites can be simple, the Tower sprite just sets a custom sprite sheet 64 | Q.Sprite.extend("Tower", { 65 | init: function(p) { 66 | this._super(p, { sheet: 'tower' }); 67 | } 68 | }); 69 | 70 | // ## Enemy Sprite 71 | // Create the Enemy class to add in some baddies 72 | Q.Sprite.extend("Enemy",{ 73 | init: function(p) { 74 | this._super(p, { sheet: 'enemy', vx: 100 }); 75 | 76 | // Enemies use the Bounce AI to change direction 77 | // whenver they run into something. 78 | this.add('2d, aiBounce'); 79 | 80 | // Listen for a sprite collision, if it's the player, 81 | // end the game unless the enemy is hit on top 82 | this.on("bump.left,bump.right,bump.bottom",function(collision) { 83 | if(collision.obj.isA("Player")) { 84 | Q.stageScene("endGame",1, { label: "You Died" }); 85 | collision.obj.destroy(); 86 | } 87 | }); 88 | 89 | // If the enemy gets hit on the top, destroy it 90 | // and give the user a "hop" 91 | this.on("bump.top",function(collision) { 92 | if(collision.obj.isA("Player")) { 93 | this.destroy(); 94 | collision.obj.p.vy = -300; 95 | } 96 | }); 97 | } 98 | }); 99 | 100 | // ## Level1 scene 101 | // Create a new scene called level 1 102 | Q.scene("level1",function(stage) { 103 | 104 | // Add in a repeater for a little parallax action 105 | stage.insert(new Q.Repeater({ asset: "background-wall.png", speedX: 0.5, speedY: 0.5 })); 106 | 107 | // Add in a tile layer, and make it the collision layer 108 | stage.collisionLayer(new Q.TileLayer({ 109 | dataAsset: 'level.json', 110 | sheet: 'tiles' })); 111 | 112 | 113 | // Create the player and add them to the stage 114 | var player = stage.insert(new Q.Player()); 115 | 116 | // Give the stage a moveable viewport and tell it 117 | // to follow the player. 118 | stage.add("viewport").follow(player); 119 | 120 | // Add in a couple of enemies 121 | stage.insert(new Q.Enemy({ x: 700, y: 0 })); 122 | stage.insert(new Q.Enemy({ x: 800, y: 0 })); 123 | 124 | // Finally add in the tower goal 125 | stage.insert(new Q.Tower({ x: 180, y: 50 })); 126 | }); 127 | 128 | // To display a game over / game won popup box, 129 | // create a endGame scene that takes in a `label` option 130 | // to control the displayed message. 131 | Q.scene('endGame',function(stage) { 132 | var container = stage.insert(new Q.UI.Container({ 133 | x: Q.width/2, y: Q.height/2, fill: "rgba(0,0,0,0.5)" 134 | })); 135 | 136 | var button = container.insert(new Q.UI.Button({ x: 0, y: 0, fill: "#CCCCCC", 137 | label: "Play Again" })) 138 | var label = container.insert(new Q.UI.Text({x:10, y: -10 - button.p.h, 139 | label: stage.options.label })); 140 | // When the button is clicked, clear all the stages 141 | // and restart the game. 142 | button.on("click",function() { 143 | Q.clearStages(); 144 | Q.stageScene('level1'); 145 | }); 146 | 147 | // Expand the container to visibily fit it's contents 148 | // (with a padding of 20 pixels) 149 | container.fit(20); 150 | }); 151 | 152 | // ## Asset Loading and Game Launch 153 | // Q.load can be called at any time to load additional assets 154 | // assets that are already loaded will be skipped 155 | // The callback will be triggered when everything is loaded 156 | Q.load("sprites.png, sprites.json, level.json, tiles.png, background-wall.png", function() { 157 | // Sprites sheets can be created manually 158 | Q.sheet("tiles","tiles.png", { tilew: 32, tileh: 32 }); 159 | 160 | // Or from a .json asset that defines sprite locations 161 | Q.compileSheets("sprites.png","sprites.json"); 162 | 163 | // Finally, call stageScene to run the game 164 | Q.stageScene("level1"); 165 | }); 166 | 167 | // ## Possible Experimentations: 168 | // 169 | // The are lots of things to try out here. 170 | // 171 | // 1. Modify level.json to change the level around and add in some more enemies. 172 | // 2. Add in a second level by creating a level2.json and a level2 scene that gets 173 | // loaded after level 1 is complete. 174 | // 3. Add in a title screen 175 | // 4. Add in a hud and points for jumping on enemies. 176 | // 5. Add in a `Repeater` behind the TileLayer to create a paralax scrolling effect. 177 | 178 | }); 179 | -------------------------------------------------------------------------------- /examples/platformer_full/README.md: -------------------------------------------------------------------------------- 1 | Sound effects created using http://www.bfxr.net/ 2 | -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player01.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player02.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player03.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player04.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player05.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player06.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player07.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player08.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player09.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player10.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player11.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player12.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player13.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player14.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player15.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player16.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player17.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/player/player18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/assets/player/player18.png -------------------------------------------------------------------------------- /examples/platformer_full/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0px; 3 | margin: 0px; } 4 | body #loading { 5 | margin: 50px auto; 6 | max-width: 1024px; 7 | position: fixed; 8 | width: 100%; 9 | height: 100%; 10 | text-align: center; } 11 | body #loading #loading_container { 12 | position: relative; 13 | margin: 0 auto; 14 | width: 50%; 15 | height: 40px; 16 | background: #aaccff; 17 | -moz-border-radius: 25px; 18 | -webkit-border-radius: 25px; 19 | border-radius: 25px; 20 | padding: 10px; 21 | -webkit-box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3); 22 | -moz-box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3); 23 | box-shadow: inset 0 -1px 1px rgba(255, 255, 255, 0.3); } 24 | body #loading #loading_container #loading_progress { 25 | display: block; 26 | height: 100%; 27 | width: 0; 28 | color: white; 29 | -webkit-border-top-right-radius: 8px; 30 | -webkit-border-bottom-right-radius: 8px; 31 | -moz-border-radius-topright: 8px; 32 | -moz-border-radius-bottomright: 8px; 33 | border-top-right-radius: 8px; 34 | border-bottom-right-radius: 8px; 35 | -webkit-border-top-left-radius: 20px; 36 | -webkit-border-bottom-left-radius: 20px; 37 | -moz-border-radius-topleft: 20px; 38 | -moz-border-radius-bottomleft: 20px; 39 | border-top-left-radius: 20px; 40 | border-bottom-left-radius: 20px; 41 | background-color: #2bc253; 42 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #2bc253), color-stop(1, #54f054)); 43 | background-image: -webkit-linear-gradient(center bottom, #2bc253 37%, #54f054 69%); 44 | background-image: -moz-linear-gradient(center bottom, #2bc253 37%, #54f054 69%); 45 | background-image: -ms-linear-gradient(center bottom, #2bc253 37%, #54f054 69%); 46 | background-image: -o-linear-gradient(center bottom, #2bc253 37%, #54f054 69%); 47 | -webkit-box-shadow: inset 0 2px 9px rgba(255, 255, 255, 0.3), inset 0 -2px 6px rgba(0, 0, 0, 0.4); 48 | -moz-box-shadow: inset 0 2px 9px rgba(255, 255, 255, 0.3), inset 0 -2px 6px rgba(0, 0, 0, 0.4); 49 | position: relative; 50 | overflow: hidden; } 51 | body #loading #loading_container #loading_progress span { 52 | position: absolute; 53 | left: 0; 54 | height: 100%; 55 | width: 100%; 56 | top: 25%; 57 | display: block; 58 | font-family: sans-serif; } 59 | -------------------------------------------------------------------------------- /examples/platformer_full/assets/style.scss: -------------------------------------------------------------------------------- 1 | body { 2 | padding:0px; 3 | margin:0px; 4 | #loading { 5 | margin: 50px auto; 6 | max-width: 1024px; 7 | position: fixed; 8 | width: 100%; 9 | height: 100%; 10 | text-align: center; 11 | 12 | #loading_container { 13 | position: relative; 14 | margin:0 auto; 15 | width: 50%; 16 | height: 40px; 17 | background: #aaccff; 18 | -moz-border-radius: 25px; 19 | -webkit-border-radius: 25px; 20 | border-radius: 25px; 21 | padding: 10px; 22 | -webkit-box-shadow: inset 0 -1px 1px rgba(255,255,255,0.3); 23 | -moz-box-shadow : inset 0 -1px 1px rgba(255,255,255,0.3); 24 | box-shadow : inset 0 -1px 1px rgba(255,255,255,0.3); 25 | 26 | #loading_progress { 27 | display: block; 28 | height: 100%; 29 | width: 0; 30 | color: white; 31 | span { 32 | position: absolute; 33 | left: 0; 34 | height: 100%; 35 | width: 100%; 36 | top: 25%; 37 | display:block; 38 | font-family: sans-serif; 39 | } 40 | -webkit-border-top-right-radius: 8px; 41 | -webkit-border-bottom-right-radius: 8px; 42 | -moz-border-radius-topright: 8px; 43 | -moz-border-radius-bottomright: 8px; 44 | border-top-right-radius: 8px; 45 | border-bottom-right-radius: 8px; 46 | -webkit-border-top-left-radius: 20px; 47 | -webkit-border-bottom-left-radius: 20px; 48 | -moz-border-radius-topleft: 20px; 49 | -moz-border-radius-bottomleft: 20px; 50 | border-top-left-radius: 20px; 51 | border-bottom-left-radius: 20px; 52 | background-color: rgb(43,194,83); 53 | background-image: -webkit-gradient( 54 | linear, 55 | left bottom, 56 | left top, 57 | color-stop(0, rgb(43,194,83)), 58 | color-stop(1, rgb(84,240,84)) 59 | ); 60 | background-image: -webkit-linear-gradient( 61 | center bottom, 62 | rgb(43,194,83) 37%, 63 | rgb(84,240,84) 69% 64 | ); 65 | background-image: -moz-linear-gradient( 66 | center bottom, 67 | rgb(43,194,83) 37%, 68 | rgb(84,240,84) 69% 69 | ); 70 | background-image: -ms-linear-gradient( 71 | center bottom, 72 | rgb(43,194,83) 37%, 73 | rgb(84,240,84) 69% 74 | ); 75 | background-image: -o-linear-gradient( 76 | center bottom, 77 | rgb(43,194,83) 37%, 78 | rgb(84,240,84) 69% 79 | ); 80 | -webkit-box-shadow: 81 | inset 0 2px 9px rgba(255,255,255,0.3), 82 | inset 0 -2px 6px rgba(0,0,0,0.4); 83 | -moz-box-shadow: 84 | inset 0 2px 9px rgba(255,255,255,0.3), 85 | inset 0 -2px 6px rgba(0,0,0,0.4); 86 | position: relative; 87 | overflow: hidden; 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/platformer_full/audio/coin.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/coin.mp3 -------------------------------------------------------------------------------- /examples/platformer_full/audio/coin.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/coin.ogg -------------------------------------------------------------------------------- /examples/platformer_full/audio/coin.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/coin.wav -------------------------------------------------------------------------------- /examples/platformer_full/audio/fire.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/fire.mp3 -------------------------------------------------------------------------------- /examples/platformer_full/audio/fire.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/fire.ogg -------------------------------------------------------------------------------- /examples/platformer_full/audio/fire.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/fire.wav -------------------------------------------------------------------------------- /examples/platformer_full/audio/heart.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/heart.mp3 -------------------------------------------------------------------------------- /examples/platformer_full/audio/heart.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/heart.ogg -------------------------------------------------------------------------------- /examples/platformer_full/audio/heart.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/heart.wav -------------------------------------------------------------------------------- /examples/platformer_full/audio/hit.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/hit.mp3 -------------------------------------------------------------------------------- /examples/platformer_full/audio/hit.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/hit.ogg -------------------------------------------------------------------------------- /examples/platformer_full/audio/hit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/hit.wav -------------------------------------------------------------------------------- /examples/platformer_full/audio/jump.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/jump.mp3 -------------------------------------------------------------------------------- /examples/platformer_full/audio/jump.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/jump.ogg -------------------------------------------------------------------------------- /examples/platformer_full/audio/jump.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/audio/jump.wav -------------------------------------------------------------------------------- /examples/platformer_full/data/collectables.json: -------------------------------------------------------------------------------- 1 | { 2 | "coin_gold":{"sx":72,"sy":0,"cols":1,"spacingX":2,"spacingY":2,"tilew":70,"tileh":70,"frames":1}, 3 | "gem_red":{"sx":360,"sy":0,"cols":1,"spacingX":2,"spacingY":2,"tilew":70,"tileh":70,"frames":1}, 4 | "gem_yellow":{"sx":432,"sy":0,"cols":1,"spacingX":2,"spacingY":2,"tilew":70,"tileh":70,"frames":1}, 5 | "heart":{"sx":862,"sy":0,"cols":1,"spacingX":2,"spacingY":2,"tilew":70,"tileh":70,"frames":1} 6 | } 7 | -------------------------------------------------------------------------------- /examples/platformer_full/data/doors.json: -------------------------------------------------------------------------------- 1 | { 2 | "door_closed":{"sx":70,"sy":0,"cols":1,"tilew":70,"tileh":110,"frames":1}, 3 | "door_open":{"sx":0,"sy":0,"cols":1,"tilew":70,"tileh":110,"frames":1} 4 | } 5 | -------------------------------------------------------------------------------- /examples/platformer_full/data/enemies.json: -------------------------------------------------------------------------------- 1 | { 2 | "snail":{"sx":0,"sy":32,"cols":1,"tilew":72,"tileh":42,"frames":3,"rows":3,"spacingY":32}, 3 | "slime":{"sx":72,"sy":32,"cols":1,"tilew":72,"tileh":42,"frames":3,"rows":3,"spacingY":32}, 4 | "fly":{"sx":144,"sy":32,"cols":1,"tilew":72,"tileh":42,"frames":3,"rows":3,"spacingY":32} 5 | } 6 | -------------------------------------------------------------------------------- /examples/platformer_full/data/player.json: -------------------------------------------------------------------------------- 1 | {"player":{"sx":0,"sy":1,"cols":18,"tilew":72,"tileh":97,"frames":18}} 2 | -------------------------------------------------------------------------------- /examples/platformer_full/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/bg.png -------------------------------------------------------------------------------- /examples/platformer_full/images/bg_castle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/bg_castle.png -------------------------------------------------------------------------------- /examples/platformer_full/images/collectables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/collectables.png -------------------------------------------------------------------------------- /examples/platformer_full/images/doors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/doors.png -------------------------------------------------------------------------------- /examples/platformer_full/images/enemies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/enemies.png -------------------------------------------------------------------------------- /examples/platformer_full/images/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/player.png -------------------------------------------------------------------------------- /examples/platformer_full/images/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_full/images/tiles.png -------------------------------------------------------------------------------- /examples/platformer_full/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Full-featured platformer example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 |
loading...
26 |
27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /examples/platformer_tmx/data/sprites.json: -------------------------------------------------------------------------------- 1 | {"player":{"sx":0,"sy":0,"cols":1,"tilew":30,"tileh":30,"frames":1},"enemy":{"sx":0,"sy":33,"cols":1,"tilew":30,"tileh":24,"frames":1},"tower":{"sx":0,"sy":60,"cols":1,"tilew":30,"tileh":30,"frames":1}} 2 | -------------------------------------------------------------------------------- /examples/platformer_tmx/images/background-wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_tmx/images/background-wall.png -------------------------------------------------------------------------------- /examples/platformer_tmx/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_tmx/images/sprites.png -------------------------------------------------------------------------------- /examples/platformer_tmx/images/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platformer_tmx/images/tiles.png -------------------------------------------------------------------------------- /examples/platformer_tmx/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Platformer TMX Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/platformer_tmx/platformer.js: -------------------------------------------------------------------------------- 1 | // # Quintus platformer example 2 | // 3 | // [Run the example](../quintus/examples/platformer/index.html) 4 | // WARNING: this game must be run from a non-file:// url 5 | // as it loads a level json file. 6 | // 7 | // This is the example from the website homepage, it consists 8 | // a simple, non-animated platformer with some enemies and a 9 | // target for the player. 10 | window.addEventListener("load",function() { 11 | 12 | // Set up an instance of the Quintus engine and include 13 | // the Sprites, Scenes, Input and 2D module. The 2D module 14 | // includes the `TileLayer` class as well as the `2d` componet. 15 | var Q = window.Q = Quintus() 16 | .include("Sprites, Scenes, Input, 2D, Anim, Touch, UI, TMX") 17 | // Maximize this game to whatever the size of the browser is 18 | .setup({ maximize: true }) 19 | // And turn on default input controls and touch input (for UI) 20 | .controls().touch() 21 | 22 | // ## Player Sprite 23 | // The very basic player sprite, this is just a normal sprite 24 | // using the player sprite sheet with default controls added to it. 25 | Q.Sprite.extend("Player",{ 26 | 27 | // the init constructor is called on creation 28 | init: function(p) { 29 | 30 | // You can call the parent's constructor with this._super(..) 31 | this._super(p, { 32 | sheet: "player", // Setting a sprite sheet sets sprite width and height 33 | jumpSpeed: -400, 34 | speed: 300 35 | }); 36 | 37 | this.add('2d, platformerControls'); 38 | 39 | this.on("hit.sprite",function(collision) { 40 | 41 | if(collision.obj.isA("Tower")) { 42 | Q.stageScene("endGame",1, { label: "You Won!" }); 43 | this.destroy(); 44 | } 45 | }); 46 | } 47 | }); 48 | 49 | 50 | // ## Tower Sprite 51 | // Sprites can be simple, the Tower sprite just sets a custom sprite sheet 52 | Q.Sprite.extend("Tower", { 53 | init: function(p) { 54 | this._super(p, { sheet: 'tower' }); 55 | } 56 | }); 57 | 58 | // ## Enemy Sprite 59 | // Create the Enemy class to add in some baddies 60 | Q.Sprite.extend("Enemy",{ 61 | init: function(p) { 62 | this._super(p, { sheet: 'enemy', vx: 100, visibleOnly: true }); 63 | 64 | this.add('2d, aiBounce'); 65 | 66 | this.on("bump.left,bump.right,bump.bottom",function(collision) { 67 | if(collision.obj.isA("Player")) { 68 | Q.stageScene("endGame",1, { label: "You Died" }); 69 | collision.obj.destroy(); 70 | } 71 | }); 72 | 73 | this.on("bump.top",function(collision) { 74 | if(collision.obj.isA("Player")) { 75 | this.destroy(); 76 | collision.obj.p.vy = -300; 77 | } 78 | }); 79 | } 80 | }); 81 | 82 | // ## Level1 scene 83 | // Create a new scene called level 1 84 | Q.scene("level1",function(stage) { 85 | Q.stageTMX("level1.tmx",stage); 86 | stage.add("viewport").follow(Q("Player").first()); 87 | }); 88 | 89 | 90 | Q.scene('endGame',function(stage) { 91 | var container = stage.insert(new Q.UI.Container({ 92 | x: Q.width/2, y: Q.height/2, fill: "rgba(0,0,0,0.5)" 93 | })); 94 | 95 | var button = container.insert(new Q.UI.Button({ x: 0, y: 0, fill: "#CCCCCC", 96 | label: "Play Again" })) 97 | var label = container.insert(new Q.UI.Text({x:10, y: -10 - button.p.h, 98 | label: stage.options.label })); 99 | button.on("click",function() { 100 | Q.clearStages(); 101 | Q.stageScene('level1'); 102 | }); 103 | 104 | container.fit(20); 105 | }); 106 | 107 | 108 | // Load one or more TMX files 109 | // and load all the assets referenced in them 110 | Q.loadTMX("level1.tmx, sprites.json", function() { 111 | Q.compileSheets("sprites.png","sprites.json"); 112 | Q.stageScene("level1"); 113 | }); 114 | 115 | // ## Possible Experimentations: 116 | // 117 | // The are lots of things to try out here. 118 | // 119 | // 1. Modify level.json to change the level around and add in some more enemies. 120 | // 2. Add in a second level by creating a level2.json and a level2 scene that gets 121 | // loaded after level 1 is complete. 122 | // 3. Add in a title screen 123 | // 4. Add in a hud and points for jumping on enemies. 124 | // 5. Add in a `Repeater` behind the TileLayer to create a paralax scrolling effect. 125 | 126 | }); 127 | -------------------------------------------------------------------------------- /examples/platforms/data/sprites.json: -------------------------------------------------------------------------------- 1 | {"player":{"sx":0,"sy":0,"cols":1,"tilew":30,"tileh":30,"frames":1},"enemy":{"sx":0,"sy":30,"cols":1,"tilew":30,"tileh":24,"frames":1},"tower":{"sx":0,"sy":54,"cols":1,"tilew":30,"tileh":30,"frames":1}} -------------------------------------------------------------------------------- /examples/platforms/images/background-wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platforms/images/background-wall.png -------------------------------------------------------------------------------- /examples/platforms/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/platforms/images/sprites.png -------------------------------------------------------------------------------- /examples/platforms/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Platformer Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/platforms/platforms.js: -------------------------------------------------------------------------------- 1 | // # Quintus platforms example 2 | // 3 | // [Run the example](../quintus/examples/platforms/index.html) 4 | // WARNING: this game must be run from a non-file:// url 5 | // as it loads a level json file. 6 | // 7 | // This example uses convex polygons as structures for the 8 | // player to jump across 9 | window.addEventListener("load",function() { 10 | 11 | // Set up an instance of the Quintus engine and include 12 | // the Sprites, Scenes, Input and 2D module. The 2D module 13 | // includes the `TileLayer` class as well as the `2d` componet. 14 | var Q = window.Q = Quintus() 15 | .include("Sprites, Scenes, Input, 2D, Anim, Touch, UI") 16 | // Maximize this game to whatever the size of the browser is 17 | .setup({ maximize: true }) 18 | // And turn on default input controls and touch input (for UI) 19 | .controls().touch() 20 | 21 | // ## Player Sprite 22 | // The very basic player sprite, this is just a normal sprite 23 | // using the player sprite sheet with default controls added to it. 24 | Q.Sprite.extend("Player",{ 25 | 26 | // the init constructor is called on creation 27 | init: function(p) { 28 | 29 | // You can call the parent's constructor with this._super(..) 30 | this._super(p, { 31 | sheet: "player", // Setting a sprite sheet sets sprite width and height 32 | x: 0, // You can also set additional properties that can 33 | y: -100 // be overridden on object creation 34 | }); 35 | 36 | this.add('2d, platformerControls'); 37 | 38 | // Write event handlers to respond hook into behaviors. 39 | // hit.sprite is called everytime the player collides with a sprite 40 | this.on("hit.sprite",function(collision) { 41 | 42 | // Check the collision, if it's the Tower, you win! 43 | if(collision.obj.isA("Tower")) { 44 | Q.stageScene("endGame",1, { label: "You Won!" }); 45 | this.destroy(); 46 | } 47 | }); 48 | }, 49 | 50 | step: function(dt) { 51 | if(this.p.y > 200) { 52 | Q.stageScene("endGame",1, { label: "You Fell!" }); 53 | } 54 | 55 | if(this.p.vy > 600) { this.p.vy = 600; } 56 | 57 | } 58 | 59 | }); 60 | 61 | 62 | // ## Tower Sprite 63 | // Sprites can be simple, the Tower sprite just sets a custom sprite sheet 64 | Q.Sprite.extend("Tower", { 65 | init: function(p) { 66 | this._super(p, { sheet: 'tower' }); 67 | } 68 | }); 69 | 70 | 71 | Q.Sprite.extend("Block", { 72 | init: function(p) { 73 | this._super(p); 74 | }, 75 | 76 | draw: function(ctx) { 77 | if(!this.p.points) { 78 | Q._generatePoints(this); 79 | } 80 | 81 | ctx.beginPath(); 82 | ctx.fillStyle = this.p.hit ? "blue" : "red"; 83 | ctx.strokeStyle = "#000000"; 84 | ctx.fillStyle = "rgba(0,0,0,0.5)"; 85 | ctx.moveTo(this.p.points[0][0],this.p.points[0][1]); 86 | for(var i=0;i 2 | 3 | 4 | 5 | 6 | 7 | Platformer Example 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/runner/runner.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load",function() { 2 | 3 | var Q = window.Q = Quintus() 4 | .include("Sprites, Scenes, Input, 2D, Anim, Touch, UI") 5 | .setup({ maximize: true }) 6 | .controls().touch() 7 | 8 | var SPRITE_BOX = 1; 9 | 10 | Q.gravityY = 2000; 11 | 12 | Q.Sprite.extend("Player",{ 13 | 14 | init: function(p) { 15 | 16 | this._super(p,{ 17 | sheet: "player", 18 | sprite: "player", 19 | collisionMask: SPRITE_BOX, 20 | x: 40, 21 | y: 555, 22 | standingPoints: [ [ -16, 44], [ -23, 35 ], [-23,-48], [23,-48], [23, 35 ], [ 16, 44 ]], 23 | duckingPoints : [ [ -16, 44], [ -23, 35 ], [-23,-10], [23,-10], [23, 35 ], [ 16, 44 ]], 24 | speed: 500, 25 | jump: -700 26 | }); 27 | 28 | this.p.points = this.p.standingPoints; 29 | 30 | this.add("2d, animation"); 31 | }, 32 | 33 | step: function(dt) { 34 | this.p.vx += (this.p.speed - this.p.vx)/4; 35 | 36 | if(this.p.y > 555) { 37 | this.p.y = 555; 38 | this.p.landed = 1; 39 | this.p.vy = 0; 40 | } else { 41 | this.p.landed = 0; 42 | } 43 | 44 | if(Q.inputs['up'] && this.p.landed > 0) { 45 | this.p.vy = this.p.jump; 46 | } 47 | 48 | this.p.points = this.p.standingPoints; 49 | if(this.p.landed) { 50 | if(Q.inputs['down']) { 51 | this.play("duck_right"); 52 | this.p.points = this.p.duckingPoints; 53 | } else { 54 | this.play("walk_right"); 55 | } 56 | } else { 57 | this.play("jump_right"); 58 | } 59 | 60 | this.stage.viewport.centerOn(this.p.x + 300, 400 ); 61 | 62 | } 63 | }); 64 | 65 | Q.Sprite.extend("Box",{ 66 | init: function() { 67 | 68 | var levels = [ 565, 540, 500, 450 ]; 69 | 70 | var player = Q("Player").first(); 71 | this._super({ 72 | x: player.p.x + Q.width + 50, 73 | y: levels[Math.floor(Math.random() * 3)], 74 | frame: Math.random() < 0.5 ? 1 : 0, 75 | scale: 2, 76 | type: SPRITE_BOX, 77 | sheet: "crates", 78 | vx: -600 + 200 * Math.random(), 79 | vy: 0, 80 | ay: 0, 81 | theta: (300 * Math.random() + 200) * (Math.random() < 0.5 ? 1 : -1) 82 | }); 83 | 84 | 85 | this.on("hit"); 86 | }, 87 | 88 | step: function(dt) { 89 | this.p.x += this.p.vx * dt; 90 | 91 | 92 | this.p.vy += this.p.ay * dt; 93 | this.p.y += this.p.vy * dt; 94 | if(this.p.y != 565) { 95 | this.p.angle += this.p.theta * dt; 96 | } 97 | 98 | if(this.p.y > 800) { this.destroy(); } 99 | 100 | }, 101 | 102 | hit: function() { 103 | this.p.type = 0; 104 | this.p.collisionMask = Q.SPRITE_NONE; 105 | this.p.vx = 200; 106 | this.p.ay = 400; 107 | this.p.vy = -300; 108 | this.p.opacity = 0.5; 109 | } 110 | 111 | 112 | }); 113 | 114 | Q.GameObject.extend("BoxThrower",{ 115 | init: function() { 116 | this.p = { 117 | launchDelay: 0.75, 118 | launchRandom: 1, 119 | launch: 2 120 | } 121 | }, 122 | 123 | update: function(dt) { 124 | this.p.launch -= dt; 125 | 126 | if(this.p.launch < 0) { 127 | this.stage.insert(new Q.Box()); 128 | this.p.launch = this.p.launchDelay + this.p.launchRandom * Math.random(); 129 | } 130 | } 131 | 132 | }); 133 | 134 | 135 | Q.scene("level1",function(stage) { 136 | 137 | stage.insert(new Q.Repeater({ asset: "background-wall.png", 138 | speedX: 0.5 })); 139 | 140 | stage.insert(new Q.Repeater({ asset: "background-floor.png", 141 | repeatY: false, 142 | speedX: 1.0, 143 | y: 300 })); 144 | 145 | stage.insert(new Q.BoxThrower()); 146 | 147 | stage.insert(new Q.Player()); 148 | stage.add("viewport"); 149 | 150 | }); 151 | 152 | Q.load("player.json, player.png, background-wall.png, background-floor.png, crates.png, crates.json", function() { 153 | Q.compileSheets("player.png","player.json"); 154 | Q.compileSheets("crates.png","crates.json"); 155 | Q.animations("player", { 156 | walk_right: { frames: [0,1,2,3,4,5,6,7,8,9,10], rate: 1/15, flip: false, loop: true }, 157 | jump_right: { frames: [13], rate: 1/10, flip: false }, 158 | stand_right: { frames:[14], rate: 1/10, flip: false }, 159 | duck_right: { frames: [15], rate: 1/10, flip: false }, 160 | }); 161 | Q.stageScene("level1"); 162 | 163 | }); 164 | 165 | 166 | }); 167 | -------------------------------------------------------------------------------- /examples/server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /examples/server/app.js: -------------------------------------------------------------------------------- 1 | var Quintus = require("../../lib/quintus.js"); 2 | 3 | require("../../lib/quintus_sprites.js")(Quintus); 4 | require("../../lib/quintus_scenes.js")(Quintus); 5 | 6 | var Q = Quintus().include("Sprites, Scenes"); 7 | 8 | 9 | Q.Sprite.extend("Box", { 10 | step: function(dt) { 11 | console.log("p"); 12 | } 13 | }); 14 | 15 | 16 | 17 | Q.scene("level1",function(stage) { 18 | stage.insert(new Q.Box({ x: 10, y: 50 })); 19 | }); 20 | 21 | 22 | Q.gameLoop(Q.stageStepLoop); 23 | Q.stageScene("level1"); 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quintus-server-example", 3 | "version": "0.0.1", 4 | "description": "Quintus Multi-user server example", 5 | "dependencies": { 6 | "express": "^4.10.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/sprite/images/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/sprite/images/enemy.png -------------------------------------------------------------------------------- /examples/sprite/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/sprite/images/sprites.png -------------------------------------------------------------------------------- /examples/sprite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quintus Basic Sprite Manipulation Example 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/sprite/sprite.js: -------------------------------------------------------------------------------- 1 | // # Quintus Basic Sprite Example 2 | // 3 | // [Run the example](../quintus/examples/sprite/index.html) 4 | // 5 | // This example creates two simple sprites to test basic collision detection 6 | // with regards to rotation, scaling and movement. 7 | // 8 | // Use the arrows keys to rotate and scale the top sprite and 9 | // Z or Space to move the sprite up. X resets the position. 10 | // 11 | window.addEventListener('load',function(e) { 12 | 13 | 14 | // Set up a standard Quintus instance with only the 15 | // Sprites and Scene module (for the stage support) loaded. 16 | var Q = window.Q = Quintus().include("Sprites, Scenes, 2D, Input") 17 | .setup({ width: 1000, height: 600 }); 18 | 19 | // Draw vertical lines at every 100 pixels for visual indicators 20 | function drawLines(ctx) { 21 | ctx.save(); 22 | ctx.strokeStyle = '#FFFFFF'; 23 | for(var x = 0;x < 1000;x+=100) { 24 | ctx.beginPath(); 25 | ctx.moveTo(x,0); 26 | ctx.lineTo(x,600); 27 | ctx.stroke(); 28 | } 29 | ctx.restore(); 30 | } 31 | 32 | // Create a simple scene that adds two shapes on the page 33 | Q.scene("start",function(stage) { 34 | 35 | // A basic sprite shape a asset as the image 36 | var sprite1 = new Q.Sprite({ x: 500, y: 100, asset: 'enemy.png', 37 | angle: 0, collisionMask: 1, scale: 1}); 38 | sprite1.p.points = [ 39 | [ -150, -120 ], 40 | [ 150, -120 ], 41 | [ 150, 60 ], 42 | [ 90, 120 ], 43 | [ -90, 120 ], 44 | [ -150, 60 ] 45 | ]; 46 | stage.insert(sprite1); 47 | // Add the 2D component for collision detection and gravity. 48 | sprite1.add('2d') 49 | 50 | sprite1.on('step',function() { 51 | 52 | }); 53 | 54 | // A red platform for the other sprite to land on 55 | var sprite2 = new Q.Sprite({ x: 500, y: 600, w: 300, h: 200 }); 56 | sprite2.draw= function(ctx) { 57 | ctx.fillStyle = '#FF0000'; 58 | ctx.fillRect(-this.p.cx,-this.p.cy,this.p.w,this.p.h); 59 | }; 60 | stage.insert(sprite2); 61 | 62 | // Bind the basic inputs to different behaviors of sprite1 63 | Q.input.on('up',stage,function(e) { 64 | sprite1.p.scale -= 0.1; 65 | }); 66 | 67 | Q.input.on('down',stage,function(e) { 68 | sprite1.p.scale += 0.1; 69 | }); 70 | 71 | Q.input.on('left',stage,function(e) { 72 | sprite1.p.angle -= 5; 73 | }); 74 | 75 | Q.input.on('right',stage,function(e) { 76 | sprite1.p.angle += 5; 77 | }); 78 | 79 | Q.input.on('fire',stage,function(e) { 80 | sprite1.p.vy = -600; 81 | }); 82 | 83 | Q.input.on('action',stage,function(e) { 84 | sprite1.p.x = 500; 85 | sprite1.p.y = 100; 86 | }); 87 | 88 | 89 | // Draw some lines after each frame 90 | stage.on('postrender',drawLines); 91 | }); 92 | 93 | Q.load('enemy.png',function() { 94 | 95 | // Start the show 96 | Q.stageScene("start"); 97 | 98 | // Turn visual debugging on to see the 99 | // bounding boxes and collision shapes 100 | Q.debug = true; 101 | 102 | // Turn on default keyboard controls 103 | Q.input.keyboardControls(); 104 | }); 105 | 106 | }); 107 | -------------------------------------------------------------------------------- /examples/touch/images/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/touch/images/enemy.png -------------------------------------------------------------------------------- /examples/touch/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/touch/images/sprites.png -------------------------------------------------------------------------------- /examples/touch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quintus Touch and Drag Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/touch/touch.js: -------------------------------------------------------------------------------- 1 | // # Quintus Touch and Drag Example 2 | // 3 | // [Run the example](../quintus/examples/touch/index.html) 4 | // 5 | // This example creates a number of random convex shapes 6 | // and then adds touch and drag support to them. 7 | window.addEventListener('load',function(e) { 8 | 9 | 10 | // Set up a standard Quintus instance with only the 11 | // Sprites and Scene module (for the stage support) loaded. 12 | var Q = window.Q = Quintus().include("Sprites, Scenes, Input, Touch"); 13 | 14 | Q.setup({ maximize: true }) 15 | .touch(Q.SPRITE_ALL); 16 | // Sprite class for the randomly shapes 17 | // 18 | // 19 | Q.Sprite.extend("RandomShape", { 20 | init: function(p) { 21 | // Create a random shape (defined below) 22 | p =this.createShape(p); 23 | 24 | // Initialize the p hash 25 | this._super(p); 26 | 27 | // Listen for a drag events, sent by the 28 | // touch module 29 | this.on("drag"); 30 | this.on("touchEnd"); 31 | }, 32 | 33 | drag: function(touch) { 34 | this.p.dragging = true; 35 | this.p.x = touch.origX + touch.dx; 36 | this.p.y = touch.origY + touch.dy; 37 | }, 38 | 39 | touchEnd: function(touch) { 40 | this.p.dragging = false; 41 | 42 | }, 43 | 44 | createShape: function(p) { 45 | var angle = Math.random()*2*Math.PI, 46 | numPoints = 3 + Math.floor(Math.random()*5), 47 | minX = 0, maxX = 0, 48 | minY = 0, maxY = 0, 49 | curX, curY; 50 | 51 | p = p || {}; 52 | 53 | p.points = []; 54 | 55 | var startAmount = 40; 56 | 57 | for(var i = 0;i < numPoints;i++) { 58 | curX = Math.floor(Math.cos(angle)*startAmount); 59 | curY = Math.floor(Math.sin(angle)*startAmount); 60 | 61 | if(curX < minX) minX = curX; 62 | if(curX > maxX) maxX = curX; 63 | 64 | if(curY < minY) minY = curY; 65 | if(curY > maxY) maxY = curY; 66 | 67 | p.points.push([curX,curY]); 68 | 69 | startAmount += Math.floor(Math.random()*10); 70 | angle += (Math.PI * 2) / (numPoints+1); 71 | }; 72 | 73 | maxX += 30; 74 | minX -= 30; 75 | maxY += 30; 76 | minY -= 30; 77 | 78 | p.w = maxX - minX; 79 | p.h = maxY - minY; 80 | 81 | for(var i = 0;i < numPoints;i++) { 82 | p.points[i][0] -= minX + p.w/2; 83 | p.points[i][1] -= minY + p.h/2; 84 | } 85 | 86 | 87 | p.x = Math.random()*Q.width; 88 | p.y = Math.random()*Q.height; 89 | p.cx = p.w/2; 90 | p.cy = p.h/2; 91 | p.angle = angle; 92 | p.type = 1; 93 | return p; 94 | }, 95 | 96 | // If the mousemove event below sets the 97 | // hit variable, scale this sucker up a bit. 98 | // 99 | // Also move to avoid collisions with any other sprites 100 | step: function(dt) { 101 | if(this.p.over) { 102 | this.p.scale = 1.2; 103 | } else { 104 | this.p.scale = 1.; 105 | } 106 | 107 | var maxCol = 3, collided = false, p = this.p; 108 | p.hit = false; 109 | while((collided = this.stage.search(this)) && maxCol > 0) { 110 | if(collided) { 111 | // If we're dragging, move other objects 112 | // otherwise, move us 113 | if(this.p.dragging) { 114 | collided.obj.p.x += collided.separate[0]; 115 | collided.obj.p.y += collided.separate[1]; 116 | } else { 117 | this.p.x -= collided.separate[0]; 118 | this.p.y -= collided.separate[1]; 119 | } 120 | } 121 | maxCol--; 122 | } 123 | 124 | 125 | } 126 | 127 | 128 | }); 129 | 130 | // Number of shapes to add to the page 131 | var numShapes = 5; 132 | 133 | // Scene that actually adds shapes onto the stage 134 | Q.scene("start",new Q.Scene(function(stage) { 135 | var shapesLeft = numShapes; 136 | while(shapesLeft-- > 0) { 137 | stage.insert(new Q.RandomShape()); 138 | } 139 | })); 140 | 141 | // Finally call `stageScene` to start the show 142 | Q.stageScene("start"); 143 | 144 | // Render the elements 145 | // Turning Q.debug and Q.debugFill on will render 146 | // the sprites' collision meshes, which is all we want 147 | // in this situation, otherwise nothing would get rendered 148 | Q.debug = true; 149 | Q.debugFill = true; 150 | 151 | var currentObj = null; 152 | // Touch events do most of the work for us, but the 153 | // touch system doesn't handle mousemouse events, so lets add 154 | // in an event listener and use `Stage.locate` to highlight 155 | // sprites on desktop. 156 | Q.el.addEventListener('mousemove',function(e) { 157 | var x = e.offsetX || e.layerX, 158 | y = e.offsetY || e.layerY, 159 | stage = Q.stage(); 160 | 161 | // Use the helper methods from the Input Module on Q to 162 | // translate from canvas to stage 163 | var stageX = Q.canvasToStageX(x, stage), 164 | stageY = Q.canvasToStageY(y, stage); 165 | 166 | // Find the first object at that position on the stage 167 | var obj = stage.locate(stageX,stageY); 168 | 169 | 170 | // Set a `hit` property so the step method for the 171 | // sprite can handle scale appropriately 172 | if(currentObj) { currentObj.p.over = false; } 173 | if(obj) { 174 | currentObj = obj; 175 | obj.p.over = true; 176 | } 177 | }); 178 | 179 | }); 180 | 181 | -------------------------------------------------------------------------------- /examples/tower_man/data/level.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 3 | [ 1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1], 4 | [ 1,0,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1], 5 | [ 1,0,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1], 6 | [ 1,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1], 7 | [ 1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1], 8 | [ 1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1], 9 | [ 1,0,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1], 10 | [ 1,1,1,0,1,1,1,0,1,1,0,1,1,0,0,0,0,1,0,1], 11 | [ 1,0,0,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1], 12 | [ 1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1], 13 | [ 1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1], 14 | [ 1,2,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,2,1], 15 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] 16 | ] 17 | -------------------------------------------------------------------------------- /examples/tower_man/data/sprites.json: -------------------------------------------------------------------------------- 1 | {"player":{"sx":0,"sy":0,"cols":1,"tilew":32,"tileh":32,"frames":1},"enemy":{"sx":0,"sy":32,"cols":1,"tilew":32,"tileh":32,"frames":1},"tower":{"sx":0,"sy":64,"cols":1,"tilew":32,"tileh":32,"frames":1},"dot":{"sx":0, "sy":96, "cols":1, "tilew":32, "tileh":32 }} 2 | -------------------------------------------------------------------------------- /examples/tower_man/images/background-wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/tower_man/images/background-wall.png -------------------------------------------------------------------------------- /examples/tower_man/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/tower_man/images/sprites.png -------------------------------------------------------------------------------- /examples/tower_man/images/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/tower_man/images/tiles.png -------------------------------------------------------------------------------- /examples/tower_man/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tower man 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/tower_man/tower_man.js: -------------------------------------------------------------------------------- 1 | 2 | // 1. Wait for the onload even 3 | window.addEventListener("load",function() { 4 | 5 | // Set up a basic Quintus object 6 | // with the necessary modules and controls 7 | var Q = window.Q = Quintus({ development: true }) 8 | .include("Sprites, Scenes, Input, 2D") 9 | .setup({ width: 640, height: 480 }) 10 | .controls(true) 11 | 12 | // Add in the default keyboard controls 13 | // along with joypad controls for touch 14 | Q.input.keyboardControls(); 15 | Q.input.joypadControls(); 16 | 17 | Q.gravityX = 0; 18 | Q.gravityY = 0; 19 | 20 | var SPRITE_PLAYER = 1; 21 | var SPRITE_TILES = 2; 22 | var SPRITE_ENEMY = 4; 23 | var SPRITE_DOT = 8; 24 | 25 | Q.component("towerManControls", { 26 | // default properties to add onto our entity 27 | defaults: { speed: 100, direction: 'up' }, 28 | 29 | // called when the component is added to 30 | // an entity 31 | added: function() { 32 | var p = this.entity.p; 33 | 34 | // add in our default properties 35 | Q._defaults(p,this.defaults); 36 | 37 | // every time our entity steps 38 | // call our step method 39 | this.entity.on("step",this,"step"); 40 | }, 41 | 42 | step: function(dt) { 43 | // grab the entity's properties 44 | // for easy reference 45 | var p = this.entity.p; 46 | 47 | // rotate the player 48 | // based on our velocity 49 | if(p.vx > 0) { 50 | p.angle = 90; 51 | } else if(p.vx < 0) { 52 | p.angle = -90; 53 | } else if(p.vy > 0) { 54 | p.angle = 180; 55 | } else if(p.vy < 0) { 56 | p.angle = 0; 57 | } 58 | 59 | // grab a direction from the input 60 | p.direction = Q.inputs['left'] ? 'left' : 61 | Q.inputs['right'] ? 'right' : 62 | Q.inputs['up'] ? 'up' : 63 | Q.inputs['down'] ? 'down' : p.direction; 64 | 65 | // based on our direction, try to add velocity 66 | // in that direction 67 | switch(p.direction) { 68 | case "left": p.vx = -p.speed; break; 69 | case "right":p.vx = p.speed; break; 70 | case "up": p.vy = -p.speed; break; 71 | case "down": p.vy = p.speed; break; 72 | } 73 | } 74 | }); 75 | 76 | 77 | Q.Sprite.extend("Player", { 78 | init: function(p) { 79 | 80 | this._super(p,{ 81 | sheet:"player", 82 | type: SPRITE_PLAYER, 83 | collisionMask: SPRITE_TILES | SPRITE_ENEMY | SPRITE_DOT 84 | }); 85 | 86 | this.add("2d, towerManControls"); 87 | } 88 | }); 89 | 90 | 91 | // Create the Dot sprite 92 | Q.Sprite.extend("Dot", { 93 | init: function(p) { 94 | this._super(p,{ 95 | sheet: 'dot', 96 | type: SPRITE_DOT, 97 | // Set sensor to true so that it gets notified when it's 98 | // hit, but doesn't trigger collisions itself that cause 99 | // the player to stop or change direction 100 | sensor: true 101 | }); 102 | 103 | this.on("sensor"); 104 | this.on("inserted"); 105 | }, 106 | 107 | // When a dot is hit.. 108 | sensor: function() { 109 | // Destroy it and keep track of how many dots are left 110 | this.destroy(); 111 | this.stage.dotCount--; 112 | // If there are no more dots left, just restart the game 113 | if(this.stage.dotCount == 0) { 114 | Q.stageScene("level1"); 115 | } 116 | }, 117 | 118 | // When a dot is inserted, use it's parent (the stage) 119 | // to keep track of the total number of dots on the stage 120 | inserted: function() { 121 | this.stage.dotCount = this.stage.dotCount || 0 122 | this.stage.dotCount++; 123 | } 124 | }); 125 | 126 | 127 | // Tower is just a dot with a different sheet - use the same 128 | // sensor and counting functionality 129 | Q.Dot.extend("Tower", { 130 | init: function(p) { 131 | this._super(Q._defaults(p,{ 132 | sheet: 'tower' 133 | })); 134 | } 135 | }); 136 | 137 | // Return a x and y location from a row and column 138 | // in our tile map 139 | Q.tilePos = function(col,row) { 140 | return { x: col*32 + 16, y: row*32 + 16 }; 141 | } 142 | 143 | Q.TileLayer.extend("TowerManMap",{ 144 | init: function() { 145 | this._super({ 146 | type: SPRITE_TILES, 147 | dataAsset: 'level.json', 148 | sheet: 'tiles', 149 | }); 150 | 151 | }, 152 | 153 | setup: function() { 154 | // Clone the top level arriw 155 | var tiles = this.p.tiles = this.p.tiles.concat(); 156 | var size = this.p.tileW; 157 | for(var y=0;y 2 | 3 | 4 | 5 | Quintus Tweened Animation Example 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/tween/tween.js: -------------------------------------------------------------------------------- 1 | // # Quintus Tweened Animation Example 2 | // 3 | // [Run the example](../quintus/examples/tween/index.html) 4 | // 5 | // This example shows how to use the tween component to 6 | // play tweened animations in sprites. 7 | window.addEventListener("load",function() { 8 | 9 | // Set up a standard Quintus instance with only the 10 | // Sprites and Scene module (for the stage support) loaded. 11 | var Q = Quintus().include("Sprites, Scenes, Anim").setup({ 12 | width: 320, 13 | height: 320 14 | }); 15 | 16 | // Setup a scene with just one sprite to animate. 17 | Q.scene("scene1",function(stage) { 18 | var sprite = new Q.Sprite({ asset: "enemy01.png", x: 32, y: 32, scale: 1 }); 19 | sprite.add("tween"); 20 | stage.insert(sprite); 21 | 22 | // Using animate()/chain() the value of each property is tweened 23 | // between the current value and the input value. 24 | sprite 25 | .animate({ x: 288, y: 288 }, 2, Q.Easing.Quadratic.InOut, { delay: 1 }) 26 | .chain({ angle: 360 }) 27 | .chain({ angle: 0 }, 1, { callback: function() { console.log("0"); } }) 28 | .chain({ angle: 360 }, 1, { callback: function(){ /*normalization*/ this.p.angle = 0; console.log("Callback"); } }) 29 | .chain({ angle: -360 }) 30 | .chain({ x: 160, y: 160, scale: 4, opacity: 0 }, 1, Q.Easing.Quadratic.In ) 31 | .chain({ x: 160, y: 160, scale: 0.1, opacity: 1 }, 1, Q.Easing.Quadratic.In ); 32 | }); 33 | 34 | Q.load(["enemy01.png"], function() { 35 | Q.stageScene("scene1"); 36 | }); 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /examples/ui/data/level.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], 3 | [ 1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], 4 | [ 1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], 5 | [ 1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,1,1], 6 | [ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,2,1,1], 7 | [ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,2,1,1], 8 | [ 1,1,1,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,1], 9 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 10 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 11 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 12 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 13 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 14 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], 15 | [ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] 16 | ] 17 | -------------------------------------------------------------------------------- /examples/ui/data/sprites.json: -------------------------------------------------------------------------------- 1 | {"player":{"sx":0,"sy":0,"cols":1,"tilew":30,"tileh":30,"frames":1},"enemy":{"sx":0,"sy":30,"cols":1,"tilew":30,"tileh":24,"frames":1},"tower":{"sx":0,"sy":54,"cols":1,"tilew":30,"tileh":30,"frames":1}} -------------------------------------------------------------------------------- /examples/ui/images/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/ui/images/enemy.png -------------------------------------------------------------------------------- /examples/ui/images/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/ui/images/sprites.png -------------------------------------------------------------------------------- /examples/ui/images/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cykod/Quintus/7124c63e90a00888cd5b23fa8f9a46a7a622cd7b/examples/ui/images/tiles.png -------------------------------------------------------------------------------- /examples/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quintus Audio Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/ui/ui.js: -------------------------------------------------------------------------------- 1 | // # Quintus UI Elements example 2 | // 3 | // [Run the example](../quintus/examples/ui/index.html) 4 | // 5 | // This example creates a couple of UI elements 6 | window.addEventListener('load',function(e) { 7 | 8 | // Set up a standard Quintus instance with the 9 | // Sprites, Scene, Touch and UI 10 | var Q = window.Q = Quintus().include("Sprites, Scenes, Touch, UI") 11 | .setup().touch(); 12 | 13 | Q.scene("start",function(stage) { 14 | 15 | // Create a container, which can be used to 16 | // contain other UI elements 17 | // (containers are transparent by default, but 18 | // seeting a fill and/or a border give them an appearance) 19 | var container = stage.insert(new Q.UI.Container({ 20 | fill: "gray", 21 | border: 5, 22 | shadow: 10, 23 | shadowColor: "rgba(0,0,0,0.5)", 24 | y: 50, 25 | x: Q.width/2 26 | })); 27 | 28 | // You can create text labels as well, 29 | // pass a second argument to stage.insert 30 | // to insert elements into containers. 31 | // Elements in containers move relative to 32 | // container so (0,0) is the center of the container 33 | stage.insert(new Q.UI.Text({ 34 | label: "Here's a label\nin a container", 35 | color: "white", 36 | x: 0, 37 | y: 0 38 | }),container); 39 | 40 | // Call container.fit to expand a container 41 | // to fit all the elemnt in it 42 | container.fit(20,20); 43 | 44 | // You can create buttons, which just default 45 | // to text labels and take a second init argument 46 | // which is a on click callback 47 | stage.insert(new Q.UI.Button({ 48 | label: "A Button", 49 | y: 150, 50 | x: Q.width/2 51 | }, function() { 52 | this.p.label = "Pressed"; 53 | })); 54 | 55 | // Buttons inherit from containers and so can 56 | // have fills and borders as well 57 | stage.insert(new Q.UI.Button({ 58 | label: "Another Button", 59 | y: 200, 60 | x: Q.width/2, 61 | fill: "#990000", 62 | border: 5, 63 | shadow: 10, 64 | shadowColor: "rgba(0,0,0,0.5)", 65 | }, function() { 66 | this.p.label = "Pressed"; 67 | })); 68 | 69 | stage.insert(new Q.UI.Text({ 70 | label: "Image below is a\n button using an asset", 71 | color: "black", 72 | align: 'center', 73 | x: Q.width/2, 74 | y: 280 75 | })); 76 | 77 | // Buttons can also have assets or sheets 78 | // and will render themselves as images 79 | stage.insert(new Q.UI.Button({ 80 | asset: 'enemy.png', 81 | x: Q.width/2, 82 | scale: 0.5, 83 | y: 370 84 | }, function() { 85 | this.p.angle += 90; 86 | })); 87 | }); 88 | 89 | 90 | Q.load("enemy.png", function() { 91 | // Finally call `stageScene` to start the show 92 | Q.stageScene("start"); 93 | }); 94 | 95 | }); 96 | 97 | -------------------------------------------------------------------------------- /extra/README.md: -------------------------------------------------------------------------------- 1 | This directory contains additional files that either are part of the Quintus core or aren't quite ready for primetime as well as the API docs in source form. 2 | 3 | Use at your own risk. 4 | -------------------------------------------------------------------------------- /extra/quintus_physics.js: -------------------------------------------------------------------------------- 1 | /*global Quintus:false */ 2 | /*global Box2D:false */ 3 | 4 | 5 | 6 | Quintus.Physics = function(Q) { 7 | var B2d = Q.B2d = { 8 | World: Box2D.Dynamics.b2World, 9 | Vec: Box2D.Common.Math.b2Vec2, 10 | BodyDef: Box2D.Dynamics.b2BodyDef, 11 | Body: Box2D.Dynamics.b2Body, 12 | FixtureDef: Box2D.Dynamics.b2FixtureDef, 13 | Fixture: Box2D.Dynamics.b2Fixture, 14 | PolygonShape: Box2D.Collision.Shapes.b2PolygonShape, 15 | CircleShape: Box2D.Collision.Shapes.b2CircleShape, 16 | Listener: Box2D.Dynamics.b2ContactListener 17 | }; 18 | 19 | var defOpts = Q.PhysicsDefaults = { 20 | gravityX: 0, 21 | gravityY: 9.8, 22 | scale: 30, 23 | velocityIterations: 8, 24 | positionIterations: 3 25 | }; 26 | 27 | Q.component('world',{ 28 | added: function() { 29 | this.opts = Q._extend({},defOpts); 30 | this._gravity = new B2d.Vec(this.opts.gravityX, 31 | this.opts.gravityY); 32 | this._world = new B2d.World(this._gravity, true); 33 | 34 | var physics = this, 35 | boundBegin = function(contact) { physics.beginContact(contact); }, 36 | boundEnd = function(contact) { physics.endContact(contact); }, 37 | boundPostSolve = function(contact,impulse) { physics.postSolve(contact,impulse); }; 38 | 39 | this._listener = new B2d.Listener(); 40 | this._listener.BeginContact = boundBegin; 41 | this._listener.EndContact = boundEnd; 42 | this._listener.PostSolve = boundPostSolve; 43 | this._world.SetContactListener(this._listener); 44 | 45 | this.col = {}; 46 | this.scale = this.opts.scale; 47 | this.entity.on('step',this,'boxStep'); 48 | }, 49 | 50 | setCollisionData: function(contact,impulse) { 51 | var spriteA = contact.GetFixtureA().GetBody().GetUserData(), 52 | spriteB = contact.GetFixtureB().GetBody().GetUserData(); 53 | 54 | this.col["a"] = spriteA; 55 | this.col["b"] = spriteB; 56 | this.col["impulse"] = impulse; 57 | this.col["sprite"] = null; 58 | }, 59 | 60 | beginContact: function(contact) { 61 | this.setCollisionData(contact,null); 62 | this.col.a.trigger("contact",this.col.b); 63 | this.col.b.trigger("contact",this.col.a); 64 | this.entity.trigger("contact",this.col); 65 | }, 66 | 67 | endContact: function(contact) { 68 | this.setCollisionData(contact,null); 69 | this.col.a.trigger("endContact",this.col.b); 70 | this.col.b.trigger("endContact",this.col.a); 71 | this.entity.trigger("endContact",this.col); 72 | }, 73 | 74 | postSolve: function(contact, impulse) { 75 | this.setCollisionData(contact,impulse); 76 | this.col["sprite"] = this.col.b; 77 | this.col.a.trigger("impulse",this.col); 78 | this.col["sprite"] = this.col.a; 79 | this.col.b.trigger("impulse",this.col); 80 | this.entity.trigger("impulse",this.col); 81 | }, 82 | 83 | createBody: function(def) { 84 | return this._world.CreateBody(def); 85 | }, 86 | 87 | destroyBody: function(body) { 88 | return this._world.DestroyBody(body); 89 | }, 90 | 91 | boxStep: function(dt) { 92 | if(dt > 1/20) { dt = 1/20; } 93 | this._world.Step(dt, 94 | this.opts.velocityIterations, 95 | this.opts.positionIterations); 96 | } 97 | }); 98 | 99 | var entityDefaults = Q.PhysicsEntityDefaults = { 100 | density: 1, 101 | friction: 1, 102 | restitution: 0.1 103 | }; 104 | 105 | Q.component('physics',{ 106 | added: function() { 107 | if(this.entity.stage) { 108 | this.inserted(); 109 | } else { 110 | this.entity.on('inserted',this,'inserted'); 111 | } 112 | this.entity.on('step',this,'step'); 113 | this.entity.on('removed',this,'removed'); 114 | }, 115 | 116 | position: function(x,y) { 117 | var stage = this.entity.stage; 118 | this._body.SetAwake(true); 119 | this._body.SetPosition(new B2d.Vec(x / stage.world.scale, 120 | y / stage.world.scale)); 121 | }, 122 | 123 | angle: function(angle) { 124 | this._body.SetAngle(angle / 180 * Math.PI); 125 | }, 126 | 127 | velocity: function(x,y) { 128 | var stage = this.entity.stage; 129 | this._body.SetAwake(true); 130 | this._body.SetLinearVelocity(new B2d.Vec(x / stage.world.scale, 131 | y / stage.world.scale)); 132 | }, 133 | 134 | inserted: function() { 135 | var entity = this.entity, 136 | stage = entity.stage, 137 | scale = stage.world.scale, 138 | p = entity.p, 139 | ops = entityDefaults, 140 | def = this._def = new B2d.BodyDef(), 141 | fixtureDef = this._fixture = new B2d.FixtureDef(); 142 | 143 | def.position.x = p.x / scale; 144 | def.position.y = p.y / scale; 145 | def.type = p.type === 'static' ? 146 | B2d.Body.b2_staticBody : 147 | B2d.Body.b2_dynamicBody; 148 | def.active = true; 149 | 150 | this._body = stage.world.createBody(def); 151 | this._body.SetUserData(entity); 152 | fixtureDef.density = p.density || ops.density; 153 | fixtureDef.friction = p.friction || ops.friction; 154 | fixtureDef.restitution = p.restitution || ops.restitution; 155 | 156 | switch(p.shape) { 157 | case "block": 158 | fixtureDef.shape = new B2d.PolygonShape(); 159 | fixtureDef.shape.SetAsBox(p.w/2/scale, p.h/2/scale); 160 | break; 161 | case "circle": 162 | fixtureDef.shape = new B2d.CircleShape(p.r/scale); 163 | break; 164 | case "polygon": 165 | fixtureDef.shape = new B2d.PolygonShape(); 166 | var pointsObj = Q._map(p.points,function(pt) { 167 | return { x: pt[0] / scale, y: pt[1] / scale }; 168 | }); 169 | fixtureDef.shape.SetAsArray(pointsObj, p.points.length); 170 | break; 171 | } 172 | 173 | this._body.CreateFixture(fixtureDef); 174 | this._body._bbid = p.id; 175 | }, 176 | 177 | removed: function() { 178 | var entity = this.entity, 179 | stage = entity.stage; 180 | stage.world.destroyBody(this._body); 181 | }, 182 | 183 | step: function() { 184 | var p = this.entity.p, 185 | stage = this.entity.stage, 186 | pos = this._body.GetPosition(), 187 | angle = this._body.GetAngle(); 188 | p.x = pos.x * stage.world.scale; 189 | p.y = pos.y * stage.world.scale; 190 | p.angle = angle / Math.PI * 180; 191 | } 192 | }); 193 | 194 | 195 | }; 196 | -------------------------------------------------------------------------------- /extra/quintus_svg.js: -------------------------------------------------------------------------------- 1 | /*global Quintus:false */ 2 | /*global $:false */ 3 | 4 | Quintus.SVG = function(Q) { 5 | var SVG_NS ="http://www.w3.org/2000/svg"; 6 | Q.setupSVG = function(id,options) { 7 | options = options || {}; 8 | id = id || "quintus"; 9 | Q.svg =Q._isString(id) ? document.getElementById(id) : id; 10 | 11 | if(!Q.svg) { 12 | Q.svg = document.createElementNS(SVG_NS,'svg'); 13 | Q.svg.setAttribute('width',320); 14 | Q.svg.setAttribute('height',420); 15 | document.body.appendChild(Q.svg); 16 | } 17 | 18 | if(options.maximize) { 19 | var w = window.innerWidth-1; 20 | var h = window.innerHeight-10; 21 | Q.svg.setAttribute('width',w); 22 | Q.svg.setAttribute('height',h); 23 | } 24 | Q.width = Q.svg.getAttribute('width'); 25 | Q.height = Q.svg.getAttribute('height'); 26 | var parent=Q.svg.parentNode; 27 | var container=document.createElement('div'); 28 | container.setAttribute('id',id+'_container'); 29 | container.style.width=Q.width; 30 | container.style.height=Q.height; 31 | container.style.margin='0 auto'; 32 | container.appendChild(Q.svg); 33 | parent.appendChild(container); 34 | Q.wrapper=container; 35 | 36 | setTimeout(function() { window.scrollTo(0,1); }, 0); 37 | window.addEventListener('orientationchange',function() { 38 | setTimeout(function() { window.scrollTo(0,1); }, 0); 39 | }); 40 | return Q; 41 | }; 42 | 43 | Q.Sprite.extend("SVGSprite",{ 44 | init: function(props) { 45 | this._super(Q._defaults(props,{ 46 | shape: 'block', 47 | color: 'black', 48 | angle: 0, 49 | active: true, 50 | cx: 0, 51 | cy: 0 52 | })); 53 | this.createShape(); 54 | this.svg.sprite = this; 55 | this.rp = {}; 56 | this.setTransform(); 57 | }, 58 | 59 | set: function(attr) { 60 | Q._each(attr,function(value,key) { 61 | this.svg.setAttribute(key,value); 62 | },this); 63 | }, 64 | 65 | createShape: function() { 66 | var p = this.p; 67 | switch(p.shape) { 68 | case 'block': 69 | this.svg = document.createElementNS(SVG_NS,'rect'); 70 | Q._extend(p,{ cx: p.w/2, cy: p.h/2 }); 71 | this.set({ width: p.w, height: p.h }); 72 | break; 73 | case 'circle': 74 | this.svg = document.createElementNS(SVG_NS,'circle'); 75 | this.set({ r: p.r, cx: 0, cy: 0 }); 76 | break; 77 | case 'polygon': 78 | this.svg = document.createElementNS(SVG_NS,'polygon'); 79 | var pts = Q._map(p.points, 80 | function(pt) { 81 | return pt[0] + "," + pt[1]; 82 | }).join(" "); 83 | this.set({ points: pts }); 84 | break; 85 | 86 | } 87 | this.set({ fill: p.color }); 88 | if(p.outline) { 89 | this.set({ 90 | stroke: p.outline, 91 | "stroke-width": p.outlineWidth || 1 92 | }); 93 | } 94 | }, 95 | 96 | setTransform: function() { 97 | var p = this.p; 98 | var rp = this.rp; 99 | if(rp.x !== p.x || 100 | rp.y !== p.y || 101 | rp.angle !== p.angle ) { 102 | var transform = "translate(" + (p.x - p.cx) + "," + 103 | (p.y - p.cy) + ") " + 104 | "rotate(" + p.angle + 105 | "," + p.cx + 106 | "," + p.cy + 107 | ")"; 108 | this.svg.setAttribute('transform',transform); 109 | rp.angle = p.angle; 110 | rp.x = p.x; 111 | rp.y = p.y; 112 | } 113 | }, 114 | render: function(ctx) { 115 | 116 | this.trigger('predraw',ctx); 117 | this.trigger('beforedraw',ctx); 118 | this.draw(ctx); 119 | this.trigger('beforedraw',ctx); 120 | }, 121 | draw: function(ctx) { 122 | }, 123 | 124 | step: function(dt) { 125 | this.trigger('step',dt); 126 | this.setTransform(); 127 | } 128 | }); 129 | 130 | 131 | Q.Stage.extend("SVGStage",{ 132 | init: function(scene) { 133 | this.svg = document.createElementNS(SVG_NS,'svg'); 134 | this.svg.setAttribute('width',Q.width); 135 | this.svg.setAttribute('height',Q.height); 136 | Q.svg.appendChild(this.svg); 137 | 138 | this.viewBox = { x: 0, y: 0, w: Q.width, h: Q.height }; 139 | this._super(scene); 140 | }, 141 | remove:function(itm){ 142 | if(itm.svg) { this.svg.removeChild(itm.svg); } 143 | return this._super(itm); 144 | }, 145 | insert: function(itm) { 146 | if(itm.svg) { this.svg.appendChild(itm.svg); } 147 | return this._super(itm); 148 | }, 149 | 150 | destroy: function() { 151 | Q.svg.removeChild(this.svg); 152 | this._super(); 153 | }, 154 | 155 | viewport: function(w,h) { 156 | this.viewBox.w = w; 157 | this.viewBox.h = h; 158 | if(this.viewBox.cx || this.viewBox.cy) { 159 | this.centerOn(this.viewBox.cx, 160 | this.viewBox.cy); 161 | } else { 162 | this.setViewBox(); 163 | } 164 | }, 165 | 166 | centerOn: function(x,y) { 167 | this.viewBox.cx = x; 168 | this.viewBox.cy = y; 169 | this.viewBox.x = x - this.viewBox.w/2; 170 | this.viewBox.y = y - this.viewBox.h/2; 171 | this.setViewBox(); 172 | }, 173 | 174 | setViewBox: function() { 175 | this.svg.setAttribute('viewBox', 176 | this.viewBox.x + " " + this.viewBox.y + " " + 177 | this.viewBox.w + " " + this.viewBox.h); 178 | }, 179 | 180 | browserToWorld: function(x,y) { 181 | var m = this.svg.getScreenCTM(); 182 | var p = this.svg.createSVGPoint(); 183 | p.x = x; p.y = y; 184 | return p.matrixTransform(m.inverse()); 185 | } 186 | }); 187 | 188 | Q.svgOnly = function() { 189 | Q.Stage = Q.SVGStage; 190 | Q.setup = Q.setupSVG; 191 | Q.Sprite = Q.SVGSprite; 192 | return Q; 193 | }; 194 | 195 | 196 | }; 197 | 198 | -------------------------------------------------------------------------------- /lib/quintus_audio.js: -------------------------------------------------------------------------------- 1 | /*global Quintus:false, AudioContext:false, window:false, module: false */ 2 | 3 | var quintusAudio = function(Quintus) { 4 | "use strict"; 5 | 6 | Quintus.Audio = function(Q) { 7 | 8 | Q.audio = { 9 | channels: [], 10 | channelMax: Q.options.channelMax || 10, 11 | active: {}, 12 | play: function() {} 13 | }; 14 | 15 | 16 | Q.hasWebAudio = (typeof AudioContext !== "undefined") || (typeof webkitAudioContext !== "undefined"); 17 | 18 | if(Q.hasWebAudio) { 19 | if(typeof AudioContext !== "undefined") { 20 | Q.audioContext = new AudioContext(); 21 | } else { 22 | Q.audioContext = new window.webkitAudioContext(); 23 | } 24 | } 25 | 26 | Q.enableSound = function() { 27 | var hasTouch = (typeof window !== "undefined") && !!('ontouchstart' in window); 28 | 29 | if(Q.hasWebAudio) { 30 | Q.audio.enableWebAudioSound(); 31 | } else { 32 | Q.audio.enableHTML5Sound(); 33 | } 34 | return Q; 35 | }; 36 | 37 | Q.audio.enableWebAudioSound = function() { 38 | Q.audio.type = "WebAudio"; 39 | 40 | Q.audio.soundID = 0; 41 | 42 | Q.audio.playingSounds = {}; 43 | 44 | Q.audio.removeSound = function(soundID) { 45 | delete Q.audio.playingSounds[soundID]; 46 | }; 47 | 48 | // Play a single sound, optionally debounced 49 | // to prevent repeated plays in a short time 50 | Q.audio.play = function(s,options) { 51 | var now = new Date().getTime(); 52 | 53 | // See if this audio file is currently being debounced, if 54 | // it is, don't do anything and just return 55 | if(Q.audio.active[s] && Q.audio.active[s] > now) { return; } 56 | 57 | // If any options were passed in, check for a debounce, 58 | // which is the number of milliseconds to debounce this sound 59 | if(options && options['debounce']) { 60 | Q.audio.active[s] = now + options['debounce']; 61 | } else { 62 | delete Q.audio.active[s]; 63 | } 64 | 65 | var soundID = Q.audio.soundID++; 66 | 67 | var source = Q.audioContext.createBufferSource(); 68 | source.buffer = Q.asset(s); 69 | source.connect(Q.audioContext.destination); 70 | if(options && options['loop']) { 71 | source.loop = true; 72 | } else { 73 | setTimeout(function() { 74 | Q.audio.removeSound(soundID); 75 | },source.buffer.duration * 1000); 76 | } 77 | source.assetName = s; 78 | if(source.start) { source.start(0); } else { source.noteOn(0); } 79 | 80 | Q.audio.playingSounds[soundID] = source; 81 | 82 | 83 | }; 84 | 85 | Q.audio.stop = function(s) { 86 | for(var key in Q.audio.playingSounds) { 87 | var snd = Q.audio.playingSounds[key]; 88 | if(!s || s === snd.assetName) { 89 | if(snd.stop) { snd.stop(0); } else { snd.noteOff(0); } 90 | } 91 | } 92 | }; 93 | 94 | }; 95 | 96 | Q.audio.enableHTML5Sound = function() { 97 | Q.audio.type = "HTML5"; 98 | 99 | for (var i=0;i now) { return; } 113 | 114 | // If any options were passed in, check for a debounce, 115 | // which is the number of milliseconds to debounce this sound 116 | if(options && options['debounce']) { 117 | Q.audio.active[s] = now + options['debounce']; 118 | } else { 119 | delete Q.audio.active[s]; 120 | } 121 | 122 | // Find a free audio channel and play the sound 123 | for (var i=0;i= tm)) { 151 | Q.audio.channels[i]['channel'].pause(); 152 | Q.audio.channels[i]['loop'] = false; 153 | } 154 | } 155 | }; 156 | 157 | }; 158 | 159 | }; 160 | 161 | 162 | }; 163 | 164 | if(typeof Quintus === 'undefined') { 165 | module.exports = quintusAudio; 166 | } else { 167 | quintusAudio(Quintus); 168 | } 169 | -------------------------------------------------------------------------------- /lib/quintus_tmx.js: -------------------------------------------------------------------------------- 1 | /*global Quintus:false, module:false */ 2 | 3 | /** 4 | Quintus HTML5 Game Engine - TMX Loader module 5 | 6 | Module responsible for loading Tiled TMX files 7 | 8 | @module Quintus.Input 9 | */ 10 | 11 | 12 | var quintusTMX = function(Quintus) { 13 | "use strict"; 14 | 15 | /** 16 | * Quintus TMX Loading module 17 | * 18 | * @class Quintus.TMX 19 | */ 20 | Quintus.TMX = function(Q) { 21 | 22 | 23 | // Add TMX file loading support to Quintus 24 | Q.assetTypes['tmx'] = 'TMX'; 25 | 26 | // Load a TMX file as a parsed XML DOM 27 | Q.loadAssetTMX = function(key,src,callback,errorCallback) { 28 | 29 | // Piggyback on loadAssetOther's AJAX call 30 | Q.loadAssetOther(key,src,function(key,responseText) { 31 | var parser = new DOMParser(); 32 | var doc = parser.parseFromString(responseText, "application/xml"); 33 | // save the asset as the parsed doc 34 | callback(key,doc); 35 | }, errorCallback); 36 | 37 | }; 38 | 39 | Q._tmxExtractAssetName = function(result) { 40 | var source = result.getAttribute("source"), 41 | sourceParts = source.split("/"); 42 | // only return the last part of the asset string 43 | return sourceParts[sourceParts.length - 1]; 44 | }; 45 | 46 | 47 | Q._tmxExtractSources = function(asset) { 48 | var results = asset.querySelectorAll("[source]"); 49 | return Q._map(results,Q._tmxExtractAssetName); 50 | 51 | }; 52 | 53 | 54 | Q.loadTMX = function(files,callback,options) { 55 | if(Q._isString(files)) { 56 | files = Q._normalizeArg(files); 57 | } 58 | 59 | var tmxFiles = []; 60 | Q._each(files,function(file) { 61 | if(Q._fileExtension(file) === 'tmx') { 62 | tmxFiles.push(file); 63 | } 64 | }); 65 | 66 | var additionalAssets = []; 67 | 68 | Q.load(files,function() { 69 | Q._each(tmxFiles,function(tmxFile) { 70 | var sources = Q._tmxExtractSources(Q.asset(tmxFile)); 71 | additionalAssets = additionalAssets.concat(sources); 72 | }); 73 | 74 | if(additionalAssets.length > 0) { 75 | Q.load(additionalAssets,callback,options); 76 | } else { 77 | callback(); 78 | } 79 | }); 80 | 81 | }; 82 | 83 | 84 | 85 | function attr(elem,atr) { 86 | var value = elem.getAttribute(atr); 87 | return isNaN(value) ? value : +value; 88 | } 89 | 90 | function parseProperties(elem) { 91 | var propElems = elem.querySelectorAll("property"), 92 | props = {}; 93 | 94 | for(var i = 0; i < propElems.length; i++) { 95 | var propElem = propElems[i]; 96 | props[attr(propElem,'name')] = attr(propElem,'value'); 97 | } 98 | return props; 99 | } 100 | 101 | Q._tmxLoadTilesets = function(tilesets, tileProperties) { 102 | var gidMap = []; 103 | 104 | function parsePoint(pt) { 105 | var pts = pt.split(","); 106 | return [ parseFloat(pts[0]), parseFloat(pts[1]) ]; 107 | } 108 | 109 | for(var t = 0; t < tilesets.length;t++) { 110 | var tileset = tilesets[t], 111 | sheetName = attr(tileset,"name"), 112 | gid = attr(tileset,"firstgid"), 113 | assetName = Q._tmxExtractAssetName(tileset.querySelector("image")), 114 | tilesetTileProps = {}, 115 | tilesetProps = { tileW: attr(tileset,"tilewidth"), 116 | tileH: attr(tileset,"tileheight"), 117 | spacingX: attr(tileset,"spacing"), 118 | spacingY: attr(tileset,"spacing") 119 | }; 120 | 121 | var tiles = tileset.querySelectorAll("tile"); 122 | for(var i = 0;i < tiles.length;i++) { 123 | var tile = tiles[i]; 124 | var tileId = attr(tile,"id"); 125 | var tileGid = gid + tileId; 126 | 127 | var properties = parseProperties(tile); 128 | 129 | if(properties.points) { 130 | properties.points = Q._map(properties.points.split(" "),parsePoint); 131 | } 132 | 133 | // save the properties indexed by GID for creating objects 134 | tileProperties[tileGid] = properties; 135 | 136 | // save the properties indexed by tile number for the frame properties 137 | tilesetTileProps[tileId] = properties; 138 | } 139 | tilesetProps.frameProperties = tilesetTileProps; 140 | gidMap.push([ gid, sheetName ]); 141 | Q.sheet(sheetName, assetName, tilesetProps); 142 | 143 | } 144 | return gidMap; 145 | }; 146 | 147 | Q._tmxProcessImageLayer = function(stage,gidMap,tileProperties,layer) { 148 | var assetName = Q._tmxExtractAssetName(layer.querySelector("image")); 149 | var properties = parseProperties(layer); 150 | properties.asset = assetName; 151 | 152 | stage.insert(new Q.Repeater(properties)); 153 | }; 154 | 155 | // get the first entry in the gid map that gives 156 | // a gid offset 157 | Q._lookupGid = function(gid,gidMap) { 158 | var idx = 0; 159 | 160 | while(gidMap[idx+1] && gid >= gidMap[idx+1][0]) { 161 | idx++; 162 | } 163 | return gidMap[idx]; 164 | }; 165 | 166 | Q._tmxProcessTileLayer = function(stage,gidMap,tileProperties,layer) { 167 | var tiles = layer.querySelectorAll("tile"), 168 | width = attr(layer,'width'), 169 | height = attr(layer,'height'); 170 | 171 | 172 | var gidDetails,gidOffset, sheetName; 173 | 174 | var data = [], idx=0; 175 | for(var y=0;yc.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div"); 4 | k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display= 5 | "block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height= 6 | a+"px",m=b,r=0);return b},update:function(){l=this.end()}}}; 7 | --------------------------------------------------------------------------------