Latest local changes for branching (2).
@@ -0,0 +1,4 @@
|
||||
AddType application/x-web-app-manifest+json .webapp
|
||||
ExpiresByType application/x-web-app-manifest+json "access"
|
||||
AddType text/cache-manifest .appcache
|
||||
ExpiresByType text/cache-manifest "access"
|
||||
@@ -12,8 +12,8 @@ bkcore.hexgl.Gameplay = function(opts)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.startDelay = 1000;
|
||||
this.countDownDelay = 1500;
|
||||
this.startDelay = opts.hud == null ? 0 : 1000;
|
||||
this.countDownDelay = opts.hud == null ? 1000 : 1500;
|
||||
|
||||
this.active = false;
|
||||
this.timer = new bkcore.Timer();
|
||||
@@ -107,7 +107,7 @@ bkcore.hexgl.Gameplay.prototype.simu = function()
|
||||
{
|
||||
this.lapTimes = [92300, 91250, 90365];
|
||||
this.finishTime = this.lapTimes[0]+this.lapTimes[1]+this.lapTimes[2];
|
||||
this.hud != null && this.hud.display("Finish");
|
||||
if(this.hud != null) this.hud.display("Finish");
|
||||
this.step = 100;
|
||||
this.result = this.results.FINISH;
|
||||
this.shipControls.active = false;
|
||||
@@ -128,7 +128,7 @@ bkcore.hexgl.Gameplay.prototype.start = function(opts)
|
||||
if(this.mode == 'replay')
|
||||
{
|
||||
this.cameraControls.mode = this.cameraControls.modes.ORBIT;
|
||||
this.hud != null && this.hud.messageOnly = true;
|
||||
if(this.hud != null) this.hud.messageOnly = true;
|
||||
|
||||
try {
|
||||
var d = localStorage['race-'+this.track.name+'-replay'];
|
||||
@@ -166,12 +166,12 @@ bkcore.hexgl.Gameplay.prototype.end = function(result)
|
||||
|
||||
if(result == this.results.FINISH)
|
||||
{
|
||||
this.hud != null && this.hud.display("Finish");
|
||||
if(this.hud != null) this.hud.display("Finish");
|
||||
this.step = 100;
|
||||
}
|
||||
else if(result == this.results.DESTROYED)
|
||||
{
|
||||
this.hud != null && this.hud.display("Destroyed");
|
||||
if(this.hud != null) this.hud.display("Destroyed");
|
||||
this.step = 100;
|
||||
}
|
||||
}
|
||||
@@ -184,22 +184,22 @@ bkcore.hexgl.Gameplay.prototype.update = function()
|
||||
|
||||
if(this.step == 0 && this.timer.time.elapsed >= this.countDownDelay+this.startDelay)
|
||||
{
|
||||
this.hud != null && this.hud.display("3");
|
||||
if(this.hud != null) this.hud.display("3");
|
||||
this.step = 1;
|
||||
}
|
||||
else if(this.step == 1 && this.timer.time.elapsed >= 2*this.countDownDelay+this.startDelay)
|
||||
{
|
||||
this.hud != null && this.hud.display("2");
|
||||
if(this.hud != null) this.hud.display("2");
|
||||
this.step = 2;
|
||||
}
|
||||
else if(this.step == 2 && this.timer.time.elapsed >= 3*this.countDownDelay+this.startDelay)
|
||||
{
|
||||
this.hud != null && this.hud.display("1");
|
||||
if(this.hud != null) this.hud.display("1");
|
||||
this.step = 3;
|
||||
}
|
||||
else if(this.step == 3 && this.timer.time.elapsed >= 4*this.countDownDelay+this.startDelay)
|
||||
{
|
||||
this.hud != null && this.hud.display("Go", 0.5);
|
||||
if(this.hud != null) this.hud.display("Go", 0.5);
|
||||
this.step = 4;
|
||||
this.timer.start();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ bkcore.hexgl.HexGL = function(opts)
|
||||
|
||||
this.a = window.location.href;
|
||||
|
||||
this.mobile = opts.mobile == undefined ? false : opts.mobile;
|
||||
this.active = true;
|
||||
this.displayHUD = opts.hud == undefined ? true : opts.hud;
|
||||
this.width = opts.width == undefined ? window.innerWidth : opts.width;
|
||||
@@ -34,6 +35,8 @@ bkcore.hexgl.HexGL = function(opts)
|
||||
|
||||
this.mode = opts.mode == undefined ? 'timeattack' : opts.mode;
|
||||
|
||||
this.controlType = opts.controlType == undefined ? 1 : opts.controlType;
|
||||
|
||||
if(this.half)
|
||||
{
|
||||
this.width /= 2;
|
||||
@@ -56,6 +59,10 @@ bkcore.hexgl.HexGL = function(opts)
|
||||
this.containers.main = opts.container == undefined ? document.body : opts.container;
|
||||
this.containers.overlay = opts.overlay == undefined ? document.body : opts.overlay;
|
||||
|
||||
this.gameover = opts.gameover == undefined ? null : opts.gameover;
|
||||
|
||||
this.godmode = opts.godmode == undefined ? false : opts.godmode;
|
||||
|
||||
this.hud = null;
|
||||
|
||||
this.gameplay = null;
|
||||
@@ -86,7 +93,7 @@ bkcore.hexgl.HexGL.prototype.start = function()
|
||||
|
||||
function raf()
|
||||
{
|
||||
requestAnimationFrame( raf );
|
||||
if(self && self.active) requestAnimationFrame( raf );
|
||||
self.update();
|
||||
}
|
||||
|
||||
@@ -104,7 +111,8 @@ bkcore.hexgl.HexGL.prototype.reset = function()
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.restart = function()
|
||||
{
|
||||
this.document.getElementById('finish').style.display = 'none';
|
||||
try{ this.document.getElementById('finish').style.display = 'none'; }
|
||||
catch(e){};
|
||||
this.reset();
|
||||
}
|
||||
|
||||
@@ -122,16 +130,16 @@ bkcore.hexgl.HexGL.prototype.init = function()
|
||||
{
|
||||
this.initHUD();
|
||||
|
||||
this.track.buildMaterials(this.quality);
|
||||
this.track.buildMaterials(this.quality, this.mobile);
|
||||
|
||||
this.track.buildScenes(this, this.quality);
|
||||
this.track.buildScenes(this, this.quality, this.mobile);
|
||||
|
||||
this.initGameComposer();
|
||||
}
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.load = function(opts)
|
||||
{
|
||||
this.track.load(opts, this.quality);
|
||||
this.track.load(opts, this.quality, this.mobile);
|
||||
}
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.initGameplay = function()
|
||||
@@ -156,6 +164,23 @@ bkcore.hexgl.HexGL.prototype.initGameplay = function()
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
|
||||
{
|
||||
this.active = false;
|
||||
|
||||
var tf = bkcore.Timer.msToTimeString(f);
|
||||
var tl = [
|
||||
bkcore.Timer.msToTimeString(l[0]),
|
||||
bkcore.Timer.msToTimeString(l[1]),
|
||||
bkcore.Timer.msToTimeString(l[2])
|
||||
];
|
||||
|
||||
if(this.mobile)
|
||||
{
|
||||
this.gameover.style.display = "block";
|
||||
this.gameover.innerHTML = tf.m + "'" + tf.s + "''" + tf.ms;
|
||||
this.containers.main.style.display = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
var t = this.track;
|
||||
var dc = this.document.getElementById("finish");
|
||||
var ds = this.document.getElementById("finish-state");
|
||||
@@ -171,12 +196,6 @@ bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
|
||||
var sl = this.document.getElementById("lowfps-msg");
|
||||
var d = this.difficulty == 0 ? 'casual' : 'hard';
|
||||
var ts = this.hud.timeSeparators;
|
||||
var tf = bkcore.Timer.msToTimeString(f);
|
||||
var tl = [
|
||||
bkcore.Timer.msToTimeString(l[0]),
|
||||
bkcore.Timer.msToTimeString(l[1]),
|
||||
bkcore.Timer.msToTimeString(l[2])
|
||||
];
|
||||
|
||||
if(this.gameplay.result == this.gameplay.results.FINISH)
|
||||
{
|
||||
@@ -252,12 +271,15 @@ bkcore.hexgl.HexGL.prototype.initRenderer = function()
|
||||
clearColor: 0x000000
|
||||
});
|
||||
|
||||
renderer.physicallyBasedShading = true;
|
||||
renderer.gammaInput = true;
|
||||
renderer.gammaOutput = true;
|
||||
|
||||
renderer.shadowMapEnabled = true;
|
||||
renderer.shadowMapSoft = true;
|
||||
if(this.quality > 0 && !this.mobile)
|
||||
{
|
||||
renderer.physicallyBasedShading = true;
|
||||
renderer.gammaInput = true;
|
||||
renderer.gammaOutput = true;
|
||||
renderer.shadowMapEnabled = true;
|
||||
renderer.shadowMapSoft = true;
|
||||
}
|
||||
|
||||
renderer.autoClear = false;
|
||||
renderer.sortObjects = false;
|
||||
@@ -297,7 +319,8 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
|
||||
|
||||
this.composers.game = new THREE.EffectComposer( this.renderer, renderTarget );
|
||||
|
||||
var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
|
||||
var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
|
||||
effectScreen.renderToScreen = true;
|
||||
var effectVignette = new THREE.ShaderPass( THREE.ShaderExtras[ "vignette" ] );
|
||||
|
||||
var effectHex = new THREE.ShaderPass( bkcore.threejs.Shaders[ "hexvignette" ] );
|
||||
@@ -312,7 +335,7 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
|
||||
this.composers.game.addPass( renderSky );
|
||||
this.composers.game.addPass( renderModel );
|
||||
|
||||
if(this.quality > 0)
|
||||
if(this.quality > 0 && !this.mobile)
|
||||
{
|
||||
var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] );
|
||||
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.width, 1 / this.height );
|
||||
@@ -321,7 +344,7 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
|
||||
|
||||
this.extras.fxaa = effectFXAA;
|
||||
}
|
||||
if(this.quality > 1)
|
||||
if(this.quality > 1 && !this.mobile)
|
||||
{
|
||||
var effectBloom = new THREE.BloomPass( 0.8, 25, 4 , 256);
|
||||
|
||||
@@ -330,7 +353,10 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
|
||||
this.extras.bloom = effectBloom;
|
||||
}
|
||||
|
||||
this.composers.game.addPass( effectHex );
|
||||
if(!this.mobile || this.quality > 0)
|
||||
this.composers.game.addPass( effectHex );
|
||||
else
|
||||
this.composers.game.addPass( effectScreen );
|
||||
|
||||
|
||||
}
|
||||
@@ -343,7 +369,7 @@ bkcore.hexgl.HexGL.prototype.createMesh = function(parent, geometry, x, y, z, ma
|
||||
mesh.position.set( x, y, z );
|
||||
parent.add(mesh);
|
||||
|
||||
if(this.quality > 0)
|
||||
if(this.quality > 0 && !this.mobile)
|
||||
{
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
@@ -393,4 +419,7 @@ bkcore.hexgl.HexGL.prototype.tweakShipControls = function()
|
||||
c.driftLerp = 0.3;
|
||||
c.angularLerp = 0.4;
|
||||
}
|
||||
|
||||
if(this.godmode)
|
||||
c.shieldDamage = 0.0;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ bkcore.hexgl.ShipControls = function(ctx)
|
||||
|
||||
this.active = true;
|
||||
this.destroyed = false;
|
||||
this.falling = false;
|
||||
|
||||
this.dom = domElement;
|
||||
this.mesh = null;
|
||||
@@ -96,6 +97,8 @@ bkcore.hexgl.ShipControls = function(ctx)
|
||||
this.repulsionAmount = 0.0;
|
||||
this.repulsionForce = new THREE.Vector3();
|
||||
|
||||
this.fallVector = new THREE.Vector3(0,-20,0);
|
||||
|
||||
this.resetPos = null;
|
||||
this.resetRot = null;
|
||||
|
||||
@@ -115,16 +118,40 @@ bkcore.hexgl.ShipControls = function(ctx)
|
||||
right: false
|
||||
};
|
||||
|
||||
this.touchController = bkcore.TouchController.isTouchable() ? new bkcore.TouchController(
|
||||
domElement, ctx.width/2,
|
||||
function(state, touch, event){
|
||||
if(event.touches.length <= 1)
|
||||
self.key.forward = false;
|
||||
else
|
||||
self.key.forward = true;
|
||||
console.log(event.touches.length);
|
||||
console.log(self.key.forward);
|
||||
}) : null;
|
||||
this.touchController = null;
|
||||
this.orientationController = null;
|
||||
|
||||
if(ctx.controlType == 1 && bkcore.controllers.TouchController.isCompatible())
|
||||
{
|
||||
this.touchController = new bkcore.controllers.TouchController(
|
||||
domElement, ctx.width/2,
|
||||
function(state, touch, event){
|
||||
if(event.touches.length >= 4)
|
||||
window.location.reload(false);
|
||||
else if(event.touches.length == 3)
|
||||
ctx.restart();
|
||||
else if(event.touches.length <= 1)
|
||||
self.key.forward = false;
|
||||
else
|
||||
self.key.forward = true;
|
||||
});
|
||||
}
|
||||
else if(ctx.controlType == 2 && bkcore.controllers.OrientationController.isCompatible())
|
||||
{
|
||||
this.orientationController = new bkcore.controllers.OrientationController(
|
||||
domElement, true,
|
||||
function(state, touch, event){
|
||||
console.log(event.touches.length);
|
||||
if(event.touches.length >= 4)
|
||||
window.location.reload(false);
|
||||
else if(event.touches.length == 3)
|
||||
ctx.restart();
|
||||
else if(event.touches.length < 1)
|
||||
self.key.forward = false;
|
||||
else
|
||||
self.key.forward = true;
|
||||
});
|
||||
}
|
||||
|
||||
function onKeyDown(event)
|
||||
{
|
||||
@@ -212,8 +239,28 @@ bkcore.hexgl.ShipControls.prototype.destroy = function()
|
||||
this.collision.right = false;
|
||||
}
|
||||
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.fall = function()
|
||||
{
|
||||
this.active = false;
|
||||
this.collision.front = false;
|
||||
this.collision.left = false;
|
||||
this.collision.right = false;
|
||||
this.falling = true;
|
||||
_this = this;
|
||||
setTimeout(function(){
|
||||
_this.destroyed = true;
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.update = function(dt)
|
||||
{
|
||||
if(this.falling)
|
||||
{
|
||||
this.mesh.position.addSelf(this.fallVector);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.active) return;
|
||||
|
||||
this.rotation.y = 0;
|
||||
@@ -229,6 +276,11 @@ bkcore.hexgl.ShipControls.prototype.update = function(dt)
|
||||
angularAmount -= this.touchController.stickVector.x/100 * this.angularSpeed * dt;
|
||||
rollAmount += this.touchController.stickVector.x/100 * this.rollAngle;
|
||||
}
|
||||
if(this.orientationController != null)
|
||||
{
|
||||
angularAmount += this.orientationController.beta/45 * this.angularSpeed * dt;
|
||||
rollAmount -= this.orientationController.beta/45 * this.rollAngle;
|
||||
}
|
||||
|
||||
if(this.key.forward)
|
||||
this.speed += this.thrust * dt;
|
||||
@@ -478,6 +530,17 @@ bkcore.hexgl.ShipControls.prototype.collisionCheck = function(dt)
|
||||
this.speed = 0;
|
||||
}
|
||||
|
||||
// DIRTY GAMEOVER
|
||||
if(rCol < 128 && lCol < 128)
|
||||
{
|
||||
var fCol = this.collisionMap.getPixel(Math.round(pos.x+2), Math.round(pos.z+2)).r;
|
||||
if(fCol < 128)
|
||||
{
|
||||
console.log('GAMEOVER');
|
||||
this.fall();
|
||||
}
|
||||
}
|
||||
|
||||
this.speed *= this.collisionSpeedDecrease;
|
||||
this.speed *= (1-this.collisionSpeedDecreaseCoef*(1-collision.r/255));
|
||||
this.boost = 0;
|
||||
|
||||
@@ -37,11 +37,11 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
analyser: null,
|
||||
pixelRatio: 2048.0 / 6000.0,
|
||||
|
||||
load: function(opts, quality)
|
||||
load: function(opts, quality, mobile)
|
||||
{
|
||||
this.lib = new bkcore.threejs.Loader(opts);
|
||||
|
||||
if(quality < 1) // LOW
|
||||
if((quality < 1 && !mobile) || quality < 2) // LOW
|
||||
{
|
||||
this.lib.load({
|
||||
textures: {
|
||||
@@ -137,9 +137,9 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
}
|
||||
},
|
||||
|
||||
buildMaterials: function(quality)
|
||||
buildMaterials: function(quality, mobile)
|
||||
{
|
||||
if(this.quality < 1) // LOW
|
||||
if((quality < 1 && !mobile) || quality < 2) // LOW
|
||||
{
|
||||
this.materials.track = new THREE.MeshBasicMaterial({
|
||||
map: this.lib.get("textures", "track.cityscape.diffuse"),
|
||||
@@ -268,7 +268,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
}
|
||||
},
|
||||
|
||||
buildScenes: function(ctx, quality)
|
||||
buildScenes: function(ctx, quality, mobile)
|
||||
{
|
||||
// IMPORTANT
|
||||
this.analyser = this.lib.get("analysers", "track.cityscape.collision");
|
||||
@@ -311,7 +311,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
sun.position.set( -4000, 1200, 1800 );
|
||||
sun.lookAt(new THREE.Vector3());
|
||||
|
||||
if(quality > 0)
|
||||
if(quality > 0 && !mobile)
|
||||
{
|
||||
sun.castShadow = true;
|
||||
sun.shadowCameraNear = 50;
|
||||
@@ -371,7 +371,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
boosterLight: boosterLight,
|
||||
useParticles: false
|
||||
};
|
||||
if(quality > 0)
|
||||
if(quality > 0 && !mobile)
|
||||
{
|
||||
fxParams.textureCloud = this.lib.get("textures", "cloud");
|
||||
fxParams.textureSpark = this.lib.get("textures", "spark");
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
CACHE MANIFEST
|
||||
# v1.0.1-ffos-201302192207
|
||||
# HexGL by Thibaut Despoulain (BKcore.com)
|
||||
index.html
|
||||
css/BebasNeue-webfont.eot
|
||||
css/BebasNeue-webfont.ttf
|
||||
css/fonts.css
|
||||
css/mobile-controls-2.jpg
|
||||
css/mobile-over.jpg
|
||||
css/BebasNeue-webfont.svg
|
||||
css/BebasNeue-webfont.woff
|
||||
css/mobile-controls-1.jpg
|
||||
css/mobile.jpg
|
||||
css/touchcontroller.css
|
||||
libs/Three.dev.js
|
||||
libs/ShaderExtras.js
|
||||
libs/postprocessing/EffectComposer.js
|
||||
libs/postprocessing/RenderPass.js
|
||||
libs/postprocessing/BloomPass.js
|
||||
libs/postprocessing/ShaderPass.js
|
||||
libs/postprocessing/MaskPass.js
|
||||
libs/Detector.js
|
||||
libs/Stats.js
|
||||
libs/DAT.GUI.min.js
|
||||
bkcore.coffee/controllers/TouchController.js
|
||||
bkcore.coffee/controllers/OrientationController.js
|
||||
bkcore/Timer.js
|
||||
bkcore/ImageData.js
|
||||
bkcore/Utils.js
|
||||
bkcore/threejs/RenderManager.js
|
||||
bkcore/threejs/Shaders.js
|
||||
bkcore/threejs/Particles.js
|
||||
bkcore/threejs/Loader.js
|
||||
bkcore/hexgl/HUD.js
|
||||
bkcore/hexgl/RaceData.js
|
||||
bkcore/hexgl/ShipControls.js
|
||||
bkcore/hexgl/ShipEffects.js
|
||||
bkcore/hexgl/CameraChase.js
|
||||
bkcore/hexgl/Gameplay.js
|
||||
bkcore/hexgl/tracks/Cityscape.js
|
||||
bkcore/hexgl/HexGL.js
|
||||
geometries/bonus/base/base.js
|
||||
geometries/booster/booster.js
|
||||
geometries/ships/feisar/feisar.js
|
||||
geometries/tracks/cityscape/scrapers1.js
|
||||
geometries/tracks/cityscape/scrapers2.js
|
||||
geometries/tracks/cityscape/startbanner.js
|
||||
geometries/tracks/cityscape/start.js
|
||||
geometries/tracks/cityscape/track.js
|
||||
geometries/tracks/cityscape/bonus/speed.js
|
||||
textures/tracks/cityscape/collision.png
|
||||
textures/tracks/cityscape/diffuse.jpg
|
||||
textures/tracks/cityscape/height.png
|
||||
textures/tracks/cityscape/start/diffuse.jpg
|
||||
textures/tracks/cityscape/start/start.jpg
|
||||
textures/tracks/cityscape/scrapers2/diffuse.jpg
|
||||
textures/tracks/cityscape/scrapers1/diffuse.jpg
|
||||
textures/skybox/dawnclouds/nx.jpg
|
||||
textures/skybox/dawnclouds/ny.jpg
|
||||
textures/skybox/dawnclouds/nz.jpg
|
||||
textures/skybox/dawnclouds/px.jpg
|
||||
textures/skybox/dawnclouds/pz.jpg
|
||||
textures/skybox/dawnclouds/py.jpg
|
||||
textures/ships/feisar/diffuse.jpg
|
||||
textures/ships/feisar/booster/booster.png
|
||||
textures/ships/feisar/booster/boostersprite.jpg
|
||||
textures/bonus/base/diffuse.jpg
|
||||
textures/particles/cloud.png
|
||||
textures/particles/damage.png
|
||||
textures/particles/spark.png
|
||||
textures/hud/hud-bg.png
|
||||
textures/hud/hex.jpg
|
||||
textures/hud/hud-fg-speed.png
|
||||
textures/hud/hud-fg-shield.png
|
||||
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 246 KiB |
@@ -0,0 +1,117 @@
|
||||
<!doctype html>
|
||||
<html lang="en" manifest="cache.appcache">
|
||||
<head>
|
||||
<title>HexGL dev page</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="stylesheet" href="css/fonts.css" type="text/css" charset="utf-8">
|
||||
<style>
|
||||
body {
|
||||
background:#ccc;
|
||||
padding:0;
|
||||
margin:0;
|
||||
overflow:hidden;
|
||||
font-family:georgia;
|
||||
text-align:center;
|
||||
color: #666;
|
||||
}
|
||||
h1 {color: #666 ; }
|
||||
a { color:skyblue }
|
||||
canvas { pointer-events:none; }
|
||||
#overlay{
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="overlay"></div>
|
||||
<div id="main"></div>
|
||||
|
||||
<script src="libs/Three.dev.js"></script>
|
||||
<script src="libs/ShaderExtras.js"></script>
|
||||
<script src="libs/postprocessing/EffectComposer.js"></script>
|
||||
<script src="libs/postprocessing/RenderPass.js"></script>
|
||||
<script src="libs/postprocessing/BloomPass.js"></script>
|
||||
<script src="libs/postprocessing/ShaderPass.js"></script>
|
||||
<script src="libs/postprocessing/MaskPass.js"></script>
|
||||
<script src="libs/Detector.js"></script>
|
||||
<script src="libs/Stats.js"></script>
|
||||
<script src="libs/DAT.GUI.min.js"></script>
|
||||
|
||||
|
||||
<script src="bkcore.coffee/controllers/TouchController.js"></script>
|
||||
<script src="bkcore.coffee/controllers/OrientationController.js"></script>
|
||||
|
||||
<script src="bkcore/Timer.js"></script>
|
||||
<script src="bkcore/ImageData.js"></script>
|
||||
<script src="bkcore/Utils.js"></script>
|
||||
|
||||
<script src="bkcore/threejs/RenderManager.js"></script>
|
||||
<script src="bkcore/threejs/Shaders.js"></script>
|
||||
<script src="bkcore/threejs/Particles.js"></script>
|
||||
<script src="bkcore/threejs/Loader.js"></script>
|
||||
|
||||
<script src="bkcore/hexgl/HUD.js"></script>
|
||||
<script src="bkcore/hexgl/RaceData.js"></script>
|
||||
<script src="bkcore/hexgl/ShipControls.js"></script>
|
||||
<script src="bkcore/hexgl/ShipEffects.js"></script>
|
||||
<script src="bkcore/hexgl/CameraChase.js"></script>
|
||||
<script src="bkcore/hexgl/Gameplay.js"></script>
|
||||
|
||||
<script src="bkcore/hexgl/tracks/Cityscape.js"></script>
|
||||
|
||||
<script src="bkcore/hexgl/HexGL.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var SCREEN_WIDTH = window.innerWidth;
|
||||
var SCREEN_HEIGHT = window.innerHeight;
|
||||
|
||||
var container, hudcontainer;
|
||||
|
||||
var hexGL;
|
||||
|
||||
function init() {
|
||||
hudcontainer = document.getElementById("overlay");
|
||||
container = document.getElementById("main");
|
||||
|
||||
hexGL = new bkcore.hexgl.HexGL({
|
||||
document: document,
|
||||
width: SCREEN_WIDTH,
|
||||
height: SCREEN_HEIGHT,
|
||||
container: container,
|
||||
overlay: overlay,
|
||||
quality: bkcore.Utils.getURLParameter('quality'),
|
||||
difficulty: bkcore.Utils.getURLParameter('difficulty'),
|
||||
half: bkcore.Utils.getURLParameter('half'),
|
||||
mode: bkcore.Utils.getURLParameter('mode'),
|
||||
track: 'Cityscape'
|
||||
});
|
||||
|
||||
hexGL.load({
|
||||
onLoad: function(){
|
||||
console.log("ALL LOADED.");
|
||||
hexGL.init();
|
||||
hexGL.start();
|
||||
},
|
||||
onError: function(s){
|
||||
console.log("ERROR ON "+s+".");
|
||||
},
|
||||
onProgress: function(p, t, n)
|
||||
{
|
||||
console.log("LOADED "+t+" : "+n+" ( "+p.loaded+" / "+p.total+" ).");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
@@ -1,13 +1,21 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="en" manifest="cache.appcache">
|
||||
<head>
|
||||
<title>HexGL dev page</title>
|
||||
<title>HexGL</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="stylesheet" href="css/fonts.css" type="text/css" charset="utf-8">
|
||||
<link rel="icon" href="/icon_256.png" type="image/png">
|
||||
<link rel="shortcut icon" href="/icon_256.png" type="image/png">
|
||||
<style>
|
||||
html { background: #000000; }
|
||||
body {
|
||||
background:#ccc;
|
||||
background: url('css/mobile.jpg') no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-ms-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
padding:0;
|
||||
margin:0;
|
||||
overflow:hidden;
|
||||
@@ -17,18 +25,125 @@
|
||||
}
|
||||
h1 {color: #666 ; }
|
||||
a { color:skyblue }
|
||||
canvas { pointer-events:none; }
|
||||
#overlay{
|
||||
/*canvas { pointer-events:none; }*/
|
||||
html, body, #main, #titles, #controls, #over, #loading, canvas { width: 100%; height: 100%;}
|
||||
#overlay, #titles, #controls-1, #controls-2, #over, #loading {
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
#titles{
|
||||
z-index: 1001;
|
||||
}
|
||||
#controls-1{
|
||||
z-index: 1002;
|
||||
background: url('css/mobile-controls-1.jpg') no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-ms-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
display: none;
|
||||
}
|
||||
#controls-2{
|
||||
z-index: 1003;
|
||||
background: url('css/mobile-controls-2.jpg') no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-ms-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
display: none;
|
||||
}
|
||||
#over{
|
||||
z-index: 1004;
|
||||
background: url('css/mobile-over.jpg') no-repeat center center fixed;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-ms-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
display: none;
|
||||
}
|
||||
#loading{
|
||||
display: none;
|
||||
color: #fff;
|
||||
}
|
||||
#loading div{
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
text-align: right;
|
||||
font-size: 3em;
|
||||
font-weight: bold;
|
||||
font-family: arial, sans-serif;
|
||||
}
|
||||
#titles-logo{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 40%;
|
||||
text-align: center;
|
||||
font-size: 4em;
|
||||
font-weight: bold;
|
||||
font-family: arial, sans-serif;
|
||||
text-decoration: none;
|
||||
color: #444444;
|
||||
text-indent: -99999px;
|
||||
}
|
||||
#titles-logo div{
|
||||
display: block;
|
||||
top: 50%;
|
||||
position: absolute;
|
||||
margin-top: -40px;
|
||||
line-height: 80px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
#titles-buttons{
|
||||
position: absolute;
|
||||
left: 60%;
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
#titles-button tr td{
|
||||
}
|
||||
.titles-button{
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
font-family: arial, sans-serif;
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
.titles-button:active, .titles-button:focus{
|
||||
color: skyblue;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/touchcontroller.css" type="text/css" charset="utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="titles">
|
||||
<div id="titles-logo"><div>HexGL</div></div>
|
||||
<table id="titles-buttons">
|
||||
<tr><td class="titles-button" id="s-quality" onclick="rollQuality();">QUALITY: SD</td></tr>
|
||||
<tr><td class="titles-button" id="s-controls" onclick="rollControls();">CONTROLS: TOUCH</td></tr>
|
||||
<tr><td class="titles-button" onclick="init();">START</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="controls-1" onclick="start();"></div>
|
||||
<div id="controls-2" onclick="start();"></div>
|
||||
<div id="over" onclick="restart();"></div>
|
||||
<div id="loading"><div>Loading...</div></div>
|
||||
<div id="overlay"></div>
|
||||
<div id="main"></div>
|
||||
|
||||
@@ -43,6 +158,9 @@
|
||||
<script src="libs/Stats.js"></script>
|
||||
<script src="libs/DAT.GUI.min.js"></script>
|
||||
|
||||
<script src="bkcore.coffee/controllers/TouchController.js"></script>
|
||||
<script src="bkcore.coffee/controllers/OrientationController.js"></script>
|
||||
|
||||
<script src="bkcore/Timer.js"></script>
|
||||
<script src="bkcore/ImageData.js"></script>
|
||||
<script src="bkcore/Utils.js"></script>
|
||||
@@ -64,6 +182,32 @@
|
||||
<script src="bkcore/hexgl/HexGL.js"></script>
|
||||
|
||||
<script>
|
||||
try {
|
||||
var request = navigator.mozApps.getSelf();
|
||||
request.onsuccess = function() {
|
||||
if (request.result) {
|
||||
// we're installed
|
||||
} else {
|
||||
// not installed
|
||||
var conf = confirm('Would you like to install HexGL as an app?');
|
||||
if(conf)
|
||||
{
|
||||
var irequest = navigator.mozApps.install("http://ffos.hexgl.bkcore.com/package.webapp");
|
||||
irequest.onsuccess = function() {
|
||||
alert('HexGL is now installed. Please launch the app from the homescreen to cache assets.');
|
||||
};
|
||||
irequest.onerror = function(e) {
|
||||
alert('Error: '+irequest.error.name);
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
request.onerror = function() {
|
||||
console.warn('Error checking installation status: ' + this.error.message);
|
||||
};
|
||||
}catch(e){
|
||||
//TODO
|
||||
}
|
||||
|
||||
var SCREEN_WIDTH = window.innerWidth;
|
||||
var SCREEN_HEIGHT = window.innerHeight;
|
||||
@@ -72,9 +216,52 @@
|
||||
|
||||
var hexGL;
|
||||
|
||||
var q = 0, qmax = 2, c = 1, cmax = 2;
|
||||
var sq = ['SD', 'HD', 'ULTRA'];
|
||||
var sc = ['NONE', 'TOUCH', 'MOTION'];
|
||||
|
||||
var titles = document.getElementById("titles")
|
||||
var hudcontainer = document.getElementById("overlay");
|
||||
var gameover = document.getElementById("over");
|
||||
var controls1 = document.getElementById("controls-1");
|
||||
var controls2 = document.getElementById("controls-2");
|
||||
var squality = document.getElementById("s-quality");
|
||||
var scontrols = document.getElementById("s-controls");
|
||||
var loading = document.getElementById("loading");
|
||||
var container = document.getElementById("main");
|
||||
|
||||
function rollQuality() {
|
||||
q++;
|
||||
if(q > qmax) q = 0;
|
||||
squality.innerHTML = "QUALITY: " + sq[q];
|
||||
}
|
||||
|
||||
function rollControls() {
|
||||
c++;
|
||||
if(c > cmax) c = 1;
|
||||
scontrols.innerHTML = "CONTROLS: " + sc[c];
|
||||
}
|
||||
|
||||
function init() {
|
||||
hudcontainer = document.getElementById("overlay");
|
||||
container = document.getElementById("main");
|
||||
titles.style.display = "none";
|
||||
this['controls'+c].style.display = "block";
|
||||
}
|
||||
|
||||
function restart() {
|
||||
/*titles.style.display = "block";
|
||||
gameover.style.display = "none";*/
|
||||
location.reload(false);
|
||||
}
|
||||
|
||||
function start() {
|
||||
|
||||
controls1.style.display = "none";
|
||||
controls2.style.display = "none";
|
||||
container.style.display = "block";
|
||||
loading.style.display = "block";
|
||||
|
||||
quality = q < 2 ? 0 : 1;
|
||||
half = q < 1;
|
||||
|
||||
hexGL = new bkcore.hexgl.HexGL({
|
||||
document: document,
|
||||
@@ -82,17 +269,21 @@
|
||||
height: SCREEN_HEIGHT,
|
||||
container: container,
|
||||
overlay: overlay,
|
||||
quality: bkcore.Utils.getURLParameter('quality'),
|
||||
difficulty: bkcore.Utils.getURLParameter('difficulty'),
|
||||
half: bkcore.Utils.getURLParameter('half'),
|
||||
mode: bkcore.Utils.getURLParameter('mode'),
|
||||
track: 'Cityscape'
|
||||
gameover: gameover,
|
||||
quality: quality,
|
||||
track: 'Cityscape',
|
||||
hud: false,
|
||||
half: half,
|
||||
mobile: true,
|
||||
controlType: c,
|
||||
godmode: true
|
||||
});
|
||||
|
||||
hexGL.load({
|
||||
onLoad: function(){
|
||||
console.log("ALL LOADED.");
|
||||
hexGL.init();
|
||||
loading.style.display = "none";
|
||||
hexGL.start();
|
||||
},
|
||||
onError: function(s){
|
||||
@@ -105,7 +296,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
//init();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
var pgli = pgli || {};
|
||||
|
||||
pgli.App = gamecore.Base.extend("App",
|
||||
{ // static
|
||||
|
||||
},
|
||||
{ // instance
|
||||
|
||||
project: null,
|
||||
moduleList: null,
|
||||
editor: null,
|
||||
diagram: null,
|
||||
preview: null,
|
||||
nodeCount: 0,
|
||||
console: null,
|
||||
debug: 2, // 0:none, 1:inapp, 2:console, 3:both
|
||||
|
||||
init: function(domDiagram, domModuleList, domEditor, domPreview)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.moduleList = new pgli.ui.ModuleList(domModuleList);
|
||||
|
||||
this.editor = ace.edit(domEditor);
|
||||
this.editor.setFontSize("16px");
|
||||
this.editor.setTheme("ace/theme/monokai");
|
||||
this.editor.getSession().setMode("ace/mode/json");
|
||||
|
||||
this.diagram = new pgli.diagram.Diagram(domDiagram, 30);
|
||||
|
||||
this.preview = new pgli.render.CanvasRenderer(domPreview);
|
||||
|
||||
this.console = $('#console-text');
|
||||
|
||||
this.bindEvents();
|
||||
|
||||
pgli.lang.Parser.debug = self.debug;
|
||||
|
||||
window.trace = function(args)
|
||||
{
|
||||
if(!self.debug) return;
|
||||
for(var i=0, len=arguments.length; i<len; ++i)
|
||||
{
|
||||
if(self.debug < 2) console.log(arguments[i]);
|
||||
if(self.debug == 1 || self.debug == 3) return;
|
||||
self.console.append(arguments[i].toString()+"\n");
|
||||
self.console.scrollTop(
|
||||
self.console[0].scrollHeight - self.console.height()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
window.clearTrace = function()
|
||||
{
|
||||
self.console.text("");
|
||||
}
|
||||
},
|
||||
|
||||
bindEvents: function()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
$(window).on('resize', function(){ return self.resize.call(self); });
|
||||
$(document).bind('keydown', function(e){ return self.onKeyDown.call(self,e); });
|
||||
$('#modules').on('drop', function(e) { return self.onDropEvent.call(self,e); });
|
||||
//window.addEventListener("drop",function(e){ return self.onDropEvent.call(self,e); }) ;
|
||||
|
||||
},
|
||||
|
||||
bindProject: function(project)
|
||||
{
|
||||
this.nodeCount = 0;
|
||||
this.project = project;
|
||||
this.project.setAppInstance(this);
|
||||
this.moduleList.bindProject(project);
|
||||
this.preview.bindProject(project);
|
||||
this.draw();
|
||||
},
|
||||
|
||||
draw: function()
|
||||
{
|
||||
this.moduleList != undefined && this.moduleList.draw();
|
||||
//this.preview.draw();
|
||||
},
|
||||
|
||||
showInEditor: function(module)
|
||||
{
|
||||
this.project.setActiveFile(module);
|
||||
this.editor.getSession().setValue(this.project.files.get(module));
|
||||
},
|
||||
|
||||
getEditorContent: function()
|
||||
{
|
||||
return this.editor.getSession().getValue();
|
||||
},
|
||||
|
||||
addDiagramNode: function(key, module)
|
||||
{
|
||||
this.diagram.addNode(new pgli.diagram.Node(key, module, 50 + 160 * this.nodeCount++, 50));
|
||||
},
|
||||
|
||||
resize: function()
|
||||
{
|
||||
this.diagram.resize();
|
||||
this.preview.resize();
|
||||
},
|
||||
|
||||
saveModule: function()
|
||||
{
|
||||
for(var i=0; i<this.project.keys.length;i++)
|
||||
{
|
||||
var name = this.project.keys[i]
|
||||
var fileToSave = this.project.getModule(name);
|
||||
var jsonData = {file :'files/'+name ,obj: fileToSave};
|
||||
|
||||
$.ajax({
|
||||
url:"/",
|
||||
type:"POST",
|
||||
data: JSON.stringify(jsonData),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
dataType: "text",
|
||||
success:function(a)
|
||||
{
|
||||
console.log("AJAX POST OK: ", a);
|
||||
},
|
||||
error: function(a)
|
||||
{
|
||||
console.log("AJAX POST ERROR: ", a);
|
||||
}
|
||||
});
|
||||
|
||||
console.log("STARTED AJAX REQUEST");
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
onKeyDown: function(e)
|
||||
{
|
||||
if(e.keyCode==117)
|
||||
{
|
||||
this.updateDiagram();
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else if(e.keyCode==118)
|
||||
{
|
||||
this.preview.draw();
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
else if(e.keyCode==119)
|
||||
{
|
||||
this.saveModule();
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
updateDiagram:function()
|
||||
{
|
||||
this.project.rememberActiveFile();
|
||||
|
||||
for(var i = 0, len = this.project.keys.length; i<len; i++)
|
||||
{
|
||||
|
||||
var object = pgli.lang.Parser.parseModule(this.project.files.get(this.project.keys[i]));
|
||||
this.project.modules.put(this.project.keys[i], object);
|
||||
this.diagram.getNode(this.project.keys[i]).module = object;
|
||||
//this.getNode.updateModule()...
|
||||
|
||||
}
|
||||
|
||||
this.diagram.draw();
|
||||
},
|
||||
|
||||
onDropEvent: function(e)
|
||||
{
|
||||
trace("#Parsing dropped file(s)...");
|
||||
e.preventDefault();
|
||||
var self = this;
|
||||
|
||||
var length = e.originalEvent.dataTransfer.files.length;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var file = e.originalEvent.dataTransfer.files[i];
|
||||
console.log(file);
|
||||
|
||||
fileName = file.name;
|
||||
|
||||
if(i == 0 && this.project == null)
|
||||
{
|
||||
var path = window.prompt("Please prove project's root path (with trailing slash).", "../files/");
|
||||
trace("#Opening new project from ["+fileName+"]...");
|
||||
this.bindProject(new pgli.Project(path+fileName, function(){
|
||||
self.draw();
|
||||
self.showInEditor(self.project.root);
|
||||
}));
|
||||
}
|
||||
else
|
||||
this.project.loadFile(self.project.path+fileName,fileName,true,true);
|
||||
|
||||
}
|
||||
|
||||
this.draw();
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,389 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.render = pgli.render || {};
|
||||
|
||||
pgli.render.CanvasRenderer = gamecore.Base.extend('CanvasRenderer',
|
||||
{ // static
|
||||
|
||||
SCOPE_KEYWORDS: {
|
||||
'use': 0,
|
||||
'repeat': 1,
|
||||
'comment': 2
|
||||
},
|
||||
SCOPE_XFORMS: {
|
||||
'x': 1,
|
||||
'y': 2,
|
||||
'width': 3,
|
||||
'height': 4,
|
||||
'scale': 0
|
||||
},
|
||||
REPEAT_TYPES: {
|
||||
'none': 'no-repeat',
|
||||
'x': 'repeat-x',
|
||||
'y': 'repeat-y',
|
||||
'xy': 'repeat'
|
||||
}
|
||||
|
||||
},
|
||||
{ // instance
|
||||
|
||||
dom: null,
|
||||
container: null,
|
||||
canvas: null,
|
||||
context: null,
|
||||
width: 1024,
|
||||
height: 768,
|
||||
project: null,
|
||||
xform: [],
|
||||
xseek: -1,
|
||||
scope: [],
|
||||
sseek: -1,
|
||||
resources: {
|
||||
images: []
|
||||
},
|
||||
variables: null,
|
||||
|
||||
/**
|
||||
* Bind a new renderer to given canvas
|
||||
* @param jQuery.DOMElement domElement [description]
|
||||
* @param Integer width [description]
|
||||
* @param Integer height [description]
|
||||
*/
|
||||
init: function(domElement)
|
||||
{
|
||||
this.dom = domElement;
|
||||
this.container = $('#'+this.dom);
|
||||
this.canvas = document.createElement("Canvas");
|
||||
this.container.append(this.canvas);
|
||||
|
||||
this.resize();
|
||||
|
||||
this.variables = new gamecore.Hashtable();
|
||||
},
|
||||
|
||||
draw: function()
|
||||
{
|
||||
clearTrace();
|
||||
|
||||
if(!this.project)
|
||||
{
|
||||
trace("#Render failed: No project loaded");
|
||||
return;
|
||||
}
|
||||
trace("#Starting renderer...");
|
||||
|
||||
this.context.clearRect(0, 0, this.width, this.height);
|
||||
|
||||
var ratio = this.getRenderRatio();
|
||||
var root = this.project.getRootModule();
|
||||
var w = root.width*ratio;
|
||||
var h = root.height*ratio;
|
||||
var x = Math.round((this.width - w)/2);
|
||||
var y = Math.round((this.height - h)/2);
|
||||
|
||||
this.sreset();
|
||||
this.xreset(ratio, x, y, w, h);
|
||||
this.walkModule(root);
|
||||
},
|
||||
|
||||
walkModule: function(module)
|
||||
{
|
||||
if(!module) return;
|
||||
|
||||
trace("#Render: "+module.name);
|
||||
|
||||
if("params" in module) for(p in module.params)
|
||||
this.sset(p, module.params[p]);
|
||||
|
||||
if("vars" in module)
|
||||
this.actionVars(module.vars);
|
||||
|
||||
if("fill" in module)
|
||||
this.actionFill(module.fill);
|
||||
|
||||
if("layers" in module) for(var i=0, len=module.layers.length; i<len; ++i)
|
||||
{
|
||||
var layer = module.layers[i];
|
||||
if("use" in layer)
|
||||
{
|
||||
if("repeat" in layer)
|
||||
{
|
||||
var iterator;
|
||||
|
||||
try {
|
||||
iterator = pgli.lang.Parser.parseRepeat(layer.repeat, this.sget());
|
||||
trace("# Found repeat layer ["+iterator.varname+" from "+iterator.start+" to "+iterator.end+"]");
|
||||
} catch(e) {
|
||||
trace("(!) Syntax error in repeat expression ["+layer.repeat+"]");
|
||||
continue;
|
||||
}
|
||||
|
||||
while(iterator.loop())
|
||||
{
|
||||
this.sset(iterator.varname, iterator.step);
|
||||
this.walkLayer(layer);
|
||||
iterator.next();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.walkLayer(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
walkLayer: function(layer)
|
||||
{
|
||||
var static = pgli.render.CanvasRenderer;
|
||||
|
||||
this.xpush();
|
||||
this.spush();
|
||||
|
||||
for(k in layer)
|
||||
{
|
||||
if(k in static.SCOPE_KEYWORDS)
|
||||
continue;
|
||||
else if(k in static.SCOPE_XFORMS)
|
||||
{
|
||||
var val = pgli.lang.Parser.parseExpression(layer[k], this.sget(), this.xget());
|
||||
if(typeof(val) == "number")
|
||||
{
|
||||
val = Number(val)*this.xgetr();
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = val.search("%");
|
||||
if(p > 0)
|
||||
val = (Number(val.substr(O, p))/100)*this.xget()[static.SCOPE_XFORMS[k]];
|
||||
else continue;
|
||||
}
|
||||
if(k == "x" || k == "y")
|
||||
{
|
||||
val += this.xget()[static.SCOPE_XFORMS[k]];
|
||||
}
|
||||
this.xset(static.SCOPE_XFORMS[k], val);
|
||||
}
|
||||
else
|
||||
this.sset(k, pgli.lang.Parser.parseExpression(layer[k], this.sget()), this.xget());
|
||||
}
|
||||
|
||||
this.walkModule(this.project.getModule(layer.use));
|
||||
|
||||
this.spop();
|
||||
this.xpop();
|
||||
},
|
||||
|
||||
actionVars: function(opts)
|
||||
{
|
||||
var static = pgli.render.CanvasRenderer;
|
||||
|
||||
for(k in opts)
|
||||
{
|
||||
if(k in static.SCOPE_KEYWORDS || k in static.SCOPE_XFORMS)
|
||||
continue;
|
||||
else
|
||||
this.sset(k, pgli.lang.Parser.parseExpression(opts[k], this.sget(), this.xget()));
|
||||
}
|
||||
},
|
||||
|
||||
actionFill: function(opts)
|
||||
{
|
||||
var static = pgli.render.CanvasRenderer;
|
||||
|
||||
if(opts.type == "image")
|
||||
{
|
||||
//trace("# Fill(image)...")
|
||||
var image = this.loadImage(
|
||||
pgli.lang.Parser.parseExpression(opts.value, this.sget(), this.xget())
|
||||
);
|
||||
|
||||
if("repeat" in opts && opts.repeat in static.REPEAT_TYPES)
|
||||
{
|
||||
var pattern = this.context.createPattern(image, static.REPEAT_TYPES[opts.repeat]);
|
||||
|
||||
this.context.rect(this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
|
||||
this.context.fillStyle = pattern;
|
||||
this.context.fill();
|
||||
|
||||
//pattern = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.context.drawImage(image, this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
|
||||
}
|
||||
}
|
||||
else if(opts.type == "color")
|
||||
{
|
||||
//trace("# Fill(color)...")
|
||||
this.context.beginPath();
|
||||
this.context.rect(this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
|
||||
this.context.fillStyle = pgli.lang.Parser.parseExpression(opts.value, this.sget(), this.xget());
|
||||
this.context.fill();
|
||||
}
|
||||
else if(opts.type == "line")
|
||||
{
|
||||
//trace("# Fill(line)...")
|
||||
this.context.beginPath();
|
||||
this.context.rect(this.xgetx(), this.xgety(), this.xgetw(), this.xgeth());
|
||||
this.context.lineWidth = 1;
|
||||
this.context.strokeStyle = pgli.lang.Parser.parseExpression(opts.value, this.sget(), this.xget());
|
||||
this.context.stroke();
|
||||
}
|
||||
},
|
||||
|
||||
loadImage: function(url)
|
||||
{
|
||||
var self = this;
|
||||
if(url in this.resources.images)
|
||||
{
|
||||
return this.resources.images[url];
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("/!\\ Image is loading, will redraw onload.");
|
||||
var img = new Image();
|
||||
img.onload = function(){
|
||||
trace("#Image loaded, redrawing...");
|
||||
self.draw();
|
||||
};
|
||||
img.src = url;
|
||||
this.resources.images[url] = img;
|
||||
return img;
|
||||
}
|
||||
},
|
||||
|
||||
spush: function()
|
||||
{
|
||||
this.scope.push(this.cloneScope(this.sget()));
|
||||
this.sseek++;
|
||||
},
|
||||
|
||||
spop: function()
|
||||
{
|
||||
this.sseek--;
|
||||
return this.scope.pop();
|
||||
},
|
||||
|
||||
sreset: function()
|
||||
{
|
||||
this.scope = [{}];
|
||||
this.sseek = 0;
|
||||
},
|
||||
|
||||
sget: function()
|
||||
{
|
||||
return this.scope[this.sseek];
|
||||
},
|
||||
|
||||
sset: function(key, value)
|
||||
{
|
||||
this.scope[this.sseek][key] = value;
|
||||
},
|
||||
|
||||
xpush: function(ratio, x, y, h, w)
|
||||
{
|
||||
if(ratio == undefined)
|
||||
if(this.xseek == -1)
|
||||
this.xform.push([1.0, 0, 0, this.width, this.height]);
|
||||
else
|
||||
this.xform.push(this.xget().slice(0))
|
||||
else
|
||||
this.xform.push([ratio, x, y, h, w]);
|
||||
|
||||
this.xseek++;
|
||||
},
|
||||
|
||||
xpop: function()
|
||||
{
|
||||
this.xseek--;
|
||||
return this.xform.pop();
|
||||
},
|
||||
|
||||
xget: function()
|
||||
{
|
||||
return this.xform[this.xseek];
|
||||
},
|
||||
|
||||
xset: function(key, value)
|
||||
{
|
||||
this.xform[this.xseek][key] = value;
|
||||
},
|
||||
|
||||
xreset: function(ratio, x, y, h, w)
|
||||
{
|
||||
this.xseek = -1;
|
||||
this.xform = [];
|
||||
this.xpush(ratio, x, y, h, w);
|
||||
},
|
||||
|
||||
xgetr: function()
|
||||
{
|
||||
return this.xform[this.xseek][0];
|
||||
},
|
||||
|
||||
xgetx: function()
|
||||
{
|
||||
return this.xform[this.xseek][1];
|
||||
},
|
||||
|
||||
xgety: function()
|
||||
{
|
||||
return this.xform[this.xseek][2];
|
||||
},
|
||||
|
||||
xgetw: function()
|
||||
{
|
||||
return this.xform[this.xseek][3];
|
||||
},
|
||||
|
||||
xgeth: function()
|
||||
{
|
||||
return this.xform[this.xseek][4];
|
||||
},
|
||||
|
||||
cloneScope: (function()
|
||||
{
|
||||
return function (obj) { Clone.prototype=obj; return new Clone() };
|
||||
function Clone(){}
|
||||
}()),
|
||||
|
||||
bindProject: function(project)
|
||||
{
|
||||
this.project = project;
|
||||
},
|
||||
|
||||
resize: function()
|
||||
{
|
||||
var w = this.container.width();
|
||||
var h = this.container.height();
|
||||
|
||||
var size = 0.9*Math.min(w, h);
|
||||
this.width = size;
|
||||
this.height = size;
|
||||
var $canvas = $(this.canvas);
|
||||
$canvas.width(size);
|
||||
$canvas.height(size);
|
||||
this.canvas.width = size;
|
||||
this.canvas.height = size;
|
||||
$canvas.css('marginTop', this.container.height() / 2 - size / 2);
|
||||
$canvas.css('marginLeft', this.container.width() / 2 - size / 2);
|
||||
|
||||
this.context = this.canvas.getContext("2d");
|
||||
|
||||
/*var ctx = this.canvas.getContext("2d");
|
||||
ctx.clearRect(0, 0, size, size);
|
||||
ctx.canvas.width = ctx.canvas.height = size;
|
||||
ctx.font = 'bold 40px Arial';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillStyle = '#444';
|
||||
ctx.fillText("Preview", size/2, size/2);*/
|
||||
},
|
||||
|
||||
getRenderRatio: function()
|
||||
{
|
||||
var root = this.project.getRootModule();
|
||||
if(!root) return;
|
||||
return Math.min(this.width/root.width, this.height/root.height);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,148 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.diagram = pgli.diagram || {};
|
||||
|
||||
pgli.diagram.Diagram = gamecore.Base.extend('Diagram',
|
||||
{ // static
|
||||
|
||||
},
|
||||
{ // instance
|
||||
|
||||
dom: null,
|
||||
container: null,
|
||||
width: 1024,
|
||||
height: 768,
|
||||
|
||||
timer: null,
|
||||
redrawDelay: 1000/30,
|
||||
|
||||
stage: null,
|
||||
layers: {
|
||||
background: null,
|
||||
nodes: null,
|
||||
links: null
|
||||
},
|
||||
background: null,
|
||||
links: null,
|
||||
|
||||
project: null,
|
||||
|
||||
nodes: [],
|
||||
|
||||
/**
|
||||
* Bind a new renderer to given canvas
|
||||
* @param HTMLElement domContainer [description]
|
||||
* @param Integer width [description]
|
||||
* @param Integer height [description]
|
||||
* @param Integer autoRedraw If defined, sets redraw rate to given FPS
|
||||
*/
|
||||
init: function(domContainer, autoRedraw)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.dom = domContainer;
|
||||
this.container = $('#'+domContainer);
|
||||
this.width = this.container.width();
|
||||
this.height = this.container.height();
|
||||
|
||||
this.stage = new Kinetic.Stage({
|
||||
container: this.dom,
|
||||
width: this.width,
|
||||
height: this.height
|
||||
});
|
||||
|
||||
this.layers.background = new Kinetic.Layer();
|
||||
this.layers.nodes = new Kinetic.Layer();
|
||||
this.layers.links = new Kinetic.Layer();
|
||||
|
||||
this.background = new Kinetic.Rect({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
fill: "#272822"
|
||||
});
|
||||
|
||||
this.layers.background.add(this.background);
|
||||
|
||||
this.links = new pgli.diagram.Links(this);
|
||||
this.layers.links.add(this.links.shape);
|
||||
|
||||
this.stage.add(this.layers.background);
|
||||
this.stage.add(this.layers.nodes);
|
||||
this.stage.add(this.layers.links);
|
||||
|
||||
// Stage drag hack to trigger only on background drag
|
||||
var self = this;
|
||||
this.background.on("mousedown", function(){
|
||||
self.stage.setDraggable(true);
|
||||
self.stage.on("dragmove", function(){
|
||||
self.layers.background.setX(-this.getX());
|
||||
self.layers.background.setY(-this.getY());
|
||||
});
|
||||
self.stage.on("dragend", function(){
|
||||
this.off("dragend");
|
||||
this.off("dragmove");
|
||||
this.setDraggable(false);
|
||||
});
|
||||
});
|
||||
|
||||
if(autoRedraw != undefined && autoRedraw != false && autoRedraw > 0)
|
||||
{
|
||||
this.redrawDelay = 1000 / autoRedraw;
|
||||
this.timer = new bkcore.Timer();
|
||||
this.timer.start();
|
||||
this.autoRedraw(true);
|
||||
}
|
||||
},
|
||||
|
||||
addNode: function(node)
|
||||
{
|
||||
this.nodes.push(node);
|
||||
this.layers.nodes.add(node.shape);
|
||||
this.layers.nodes.draw();
|
||||
},
|
||||
|
||||
getNode: function(nodeKey)
|
||||
{
|
||||
var i = 0, len = this.nodes.length;
|
||||
while(i < len)
|
||||
{
|
||||
if(this.nodes[i].key == nodeKey)
|
||||
return this.nodes[i];
|
||||
i++;
|
||||
}
|
||||
console.warn("Error in Diagram: Unable to find node["+nodeKey+"]");
|
||||
return false;
|
||||
},
|
||||
|
||||
draw: function()
|
||||
{
|
||||
this.layers.background.draw();
|
||||
this.layers.nodes.draw();
|
||||
this.layers.links.draw();
|
||||
},
|
||||
|
||||
autoRedraw: function(keep)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if(this.timer.update() > this.redrawDelay)
|
||||
{
|
||||
this.timer.start();
|
||||
this.draw();
|
||||
}
|
||||
|
||||
if(keep)
|
||||
requestAnimFrame(function(){
|
||||
self.autoRedraw(true);
|
||||
});
|
||||
},
|
||||
|
||||
resize: function()
|
||||
{
|
||||
this.width = this.container.width();
|
||||
this.height = this.container.height();
|
||||
this.stage.setSize(this.width, this.height);
|
||||
this.background.setSize(this.width, this.height);
|
||||
this.draw();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.lang = pgli.lang || {};
|
||||
|
||||
pgli.lang.Iterator = gamecore.Base.extend('Iterator',
|
||||
// Static
|
||||
{
|
||||
MAX_ITERATIONS: 1000,
|
||||
|
||||
COMPARATORS: {
|
||||
"<": 0,
|
||||
">": 1,
|
||||
"<=": 2,
|
||||
">=": 3
|
||||
},
|
||||
|
||||
genComparatorMethod: function(type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
return function(a, b){ return a < b };
|
||||
case 1:
|
||||
return function(a, b){ return a > b };
|
||||
case 2:
|
||||
return function(a, b){ return a <= b };
|
||||
case 3:
|
||||
return function(a, b){ return a >= b };
|
||||
default:
|
||||
return function(a, b){ return false };
|
||||
}
|
||||
},
|
||||
|
||||
genStepMethod: function(type, scope, attr)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
return function(){ return --scope[attr] };
|
||||
case 0:
|
||||
case 2:
|
||||
default:
|
||||
return function(){ return ++scope[attr] };
|
||||
}
|
||||
}
|
||||
},
|
||||
// Instance
|
||||
{
|
||||
varname: "i",
|
||||
start: 0,
|
||||
end: 1,
|
||||
comparator: 0,
|
||||
compMethod: null,
|
||||
stepMethod: null,
|
||||
step: 0,
|
||||
iter: 0,
|
||||
|
||||
init: function(name, start, comparator, end)
|
||||
{
|
||||
var static = pgli.lang.Iterator;
|
||||
|
||||
if(comparator in static.COMPARATORS)
|
||||
this.comparator = static.COMPARATORS[comparator];
|
||||
else
|
||||
this.comparator = static.COMPARATORS["<"];
|
||||
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.step = start;
|
||||
|
||||
this.varname = name;
|
||||
this.compMethod = static.genComparatorMethod(this.comparator);
|
||||
this.stepMethod = static.genStepMethod(this.comparator, this, "step");
|
||||
},
|
||||
|
||||
loop: function()
|
||||
{
|
||||
return (this.iter < pgli.lang.Iterator.MAX_ITERATIONS && this.compMethod(this.step, this.end));
|
||||
},
|
||||
|
||||
next: function()
|
||||
{
|
||||
++this.iter;
|
||||
return this.stepMethod();
|
||||
},
|
||||
|
||||
toString: function()
|
||||
{
|
||||
return "Iterator("+this.varname+") "+this.start+" - "+this.step+" - "+this.end;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.diagram = pgli.diagram || {};
|
||||
|
||||
pgli.diagram.Links = gamecore.Base.extend('Links',
|
||||
{ // static
|
||||
bezierOffset: 50
|
||||
},
|
||||
{ // instance
|
||||
diagram: null,
|
||||
|
||||
shape: null,
|
||||
|
||||
init: function(diagram)
|
||||
{
|
||||
var static = pgli.diagram.Links;
|
||||
var self = this;
|
||||
|
||||
this.diagram = diagram;
|
||||
|
||||
this.shape = new Kinetic.Shape({
|
||||
drawFunc: function(ctx){
|
||||
ctx.beginPath();
|
||||
|
||||
for(var i = 0, len = self.diagram.nodes.length; i < len; i++)
|
||||
{
|
||||
var node = self.diagram.nodes[i];
|
||||
|
||||
if(! ("layers" in node.module)) continue;
|
||||
|
||||
for(var j = 0, _len = node.module.layers.length; j < _len; j++)
|
||||
{
|
||||
if(! ("use" in node.module.layers[j])) continue;
|
||||
|
||||
var start = node.getLayerSlot(j);
|
||||
var tNode = self.diagram.getNode(node.module.layers[j].use);
|
||||
if(!tNode) continue;
|
||||
var end = tNode.getSlot();
|
||||
|
||||
ctx.moveTo(start[0], start[1]);
|
||||
ctx.bezierCurveTo(
|
||||
start[0]+static.bezierOffset, start[1],
|
||||
end[0]-static.bezierOffset, end[1],
|
||||
end[0], end[1]);
|
||||
}
|
||||
}
|
||||
|
||||
this.stroke(ctx);
|
||||
},
|
||||
x: 0,
|
||||
y: 0,
|
||||
stroke: "#999",
|
||||
strokeWidth: 3,
|
||||
lineCap: "round"
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.ui = pgli.ui || {};
|
||||
|
||||
pgli.ui.ModuleList = gamecore.Base.extend('ModuleList',
|
||||
{ // static
|
||||
tplModuleItem: "<li data-path='$path'>$name</li>",
|
||||
tplModuleList: "<ul data-path='$path'>$list</ul>"
|
||||
},
|
||||
{ // instance
|
||||
|
||||
project: null,
|
||||
container: null,
|
||||
|
||||
init: function(domContainer)
|
||||
{
|
||||
this.container = $('#'+domContainer);
|
||||
this.container.on("click", "li", {object: this}, this.onModuleClick);
|
||||
},
|
||||
|
||||
bindProject: function(project)
|
||||
{
|
||||
this.project = project;
|
||||
},
|
||||
|
||||
draw: function()
|
||||
{
|
||||
var static = pgli.ui.ModuleList;
|
||||
var modules = "";
|
||||
var module = null;
|
||||
if(!this.project.isEmpty()) for(var i = 0, len = this.project.getModulesCount(); i < len; ++i)
|
||||
{
|
||||
key = this.project.getModuleKey(i);
|
||||
module = this.project.getModule(key);
|
||||
modules += static.tplModuleItem.replace("$path", key).replace("$name", key);
|
||||
}
|
||||
this.container.html(static.tplModuleList.replace("$list", modules));
|
||||
},
|
||||
|
||||
onModuleClick: function(event)
|
||||
{
|
||||
event.data.object.project.rememberActiveFile();
|
||||
event.data.object.project.getAppInstance().showInEditor($(this).attr("data-path"));
|
||||
event.data.object.container.find('li').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.diagram = pgli.diagram || {};
|
||||
|
||||
pgli.diagram.Node = gamecore.Base.extend('Node',
|
||||
{ // static
|
||||
layersWidth: 20,
|
||||
layersMargin: 20,
|
||||
layersHeight: 16,
|
||||
headerHeight: 40,
|
||||
slotX: 10,
|
||||
slotY: 14,
|
||||
slotRadius: 6
|
||||
},
|
||||
{ // instance
|
||||
module: null,
|
||||
|
||||
key: null,
|
||||
|
||||
shape: null,
|
||||
background: null,
|
||||
name: null,
|
||||
layers: null,
|
||||
slot: null,
|
||||
|
||||
sockets: [],
|
||||
|
||||
width: 150,
|
||||
height: 200,
|
||||
|
||||
init: function(key, module, x, y)
|
||||
{
|
||||
var static = pgli.diagram.Node;
|
||||
|
||||
this.key = key;
|
||||
this.module = module;
|
||||
|
||||
this.shape = new Kinetic.Group({
|
||||
x: x == undefined ? 0 : x,
|
||||
y: y == undefined ? 0 : y,
|
||||
draggable: true
|
||||
});
|
||||
|
||||
var layerCount = (module.layers != undefined ? module.layers.length : 0) + 1;
|
||||
|
||||
this.height = static.headerHeight + layerCount * static.layersHeight;
|
||||
|
||||
this.background = new Kinetic.Rect({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
fill: "#222",
|
||||
stroke: "#000",
|
||||
strokeWidth: 0.5,
|
||||
shadow: {
|
||||
color: "black",
|
||||
blur: 6,
|
||||
offset: [0, 0],
|
||||
opacity: 0.5
|
||||
}
|
||||
});
|
||||
|
||||
this.layers = new Kinetic.Shape({
|
||||
drawFunc: function(ctx){
|
||||
ctx.beginPath();
|
||||
for(var i=0, len = this.attrs.count; i < len; ++i)
|
||||
ctx.arc(10, 10+i*static.layersHeight, static.slotRadius, 0, Math.PI*2, true);
|
||||
ctx.closePath();
|
||||
this.fill(ctx);
|
||||
},
|
||||
x: this.width-static.layersWidth,
|
||||
y: static.layersMargin,
|
||||
count: layerCount,
|
||||
fill: "#111"
|
||||
});
|
||||
|
||||
this.slot = new Kinetic.Circle({
|
||||
x: static.slotX,
|
||||
y: static.slotY,
|
||||
radius: static.slotRadius,
|
||||
fill: "#111"
|
||||
});
|
||||
|
||||
this.name = new Kinetic.Text({
|
||||
x: 20,
|
||||
y: 6,
|
||||
text: module.name,
|
||||
fontSize: 13,
|
||||
fontFamily: "Ubuntu Mono",
|
||||
textFill: "#aaa"
|
||||
});
|
||||
|
||||
this.shape.on('mousedown', function(){
|
||||
this.moveToTop();
|
||||
});
|
||||
|
||||
this.shape.add(this.background);
|
||||
this.shape.add(this.name);
|
||||
this.shape.add(this.layers);
|
||||
this.shape.add(this.slot);
|
||||
},
|
||||
|
||||
updateLayers: function()
|
||||
{
|
||||
var layerCount = (module.layers != undefined ? module.layers.length : 0) + 1;
|
||||
this.layers.attrs.count = layerCount;
|
||||
},
|
||||
|
||||
getSlot: function()
|
||||
{
|
||||
var static = pgli.diagram.Node;
|
||||
return [this.shape.getX()+static.slotX,
|
||||
this.shape.getY()+static.slotY];
|
||||
},
|
||||
|
||||
getLayerSlot: function(index)
|
||||
{
|
||||
var static = pgli.diagram.Node;
|
||||
return [this.shape.getX()+this.width-static.layersWidth/2,
|
||||
this.shape.getY()+10+index*static.layersHeight+static.layersMargin];
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
var pgli = pgli || {};
|
||||
pgli.lang = pgli.lang || {};
|
||||
|
||||
pgli.lang.Parser = gamecore.Base.extend('Parser',
|
||||
{
|
||||
|
||||
xStruct: {
|
||||
"scale": 0,
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"width": 3,
|
||||
"height": 4
|
||||
},
|
||||
|
||||
|
||||
patternVar:/\@(\w+)/g,
|
||||
patternMethod: /\#(\w+)(\(([^\)]+)\))/g,
|
||||
|
||||
debug: 1,
|
||||
|
||||
|
||||
parseExpression: function(string, scope, xform)
|
||||
{
|
||||
static = pgli.lang.Parser;
|
||||
|
||||
var self = this;
|
||||
var orig = string;
|
||||
var s = (scope !== null && typeof(scope) !== "undefined")
|
||||
var x = (xform !== null && typeof(xform) !== "undefined" && xform.length > 0)
|
||||
|
||||
if(typeof(string) != "string")
|
||||
return string;
|
||||
|
||||
if(scope != undefined)
|
||||
{
|
||||
string = string.replace(this.patternVar,function(match,varName)
|
||||
{
|
||||
if(x && varName in static.xStruct)
|
||||
return xform[static.xStruct[varName]];
|
||||
else if(s && varName in scope)
|
||||
return scope[varName]
|
||||
else
|
||||
return 0
|
||||
});
|
||||
}
|
||||
|
||||
string = string.replace(this.patternMethod,function(match,methodName,a,params)
|
||||
{
|
||||
if(self.debug < 2) console.log(arguments);
|
||||
return self.execFunction(methodName, params);
|
||||
});
|
||||
|
||||
if(self.debug < 2) console.log("#Parsed expr: '"+string+"' from '"+orig+"'");
|
||||
|
||||
try {
|
||||
return eval(string);
|
||||
} catch (e) {
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
parseRepeat: function(string, scope)
|
||||
{
|
||||
var items = string.split(" ");
|
||||
|
||||
if(items.length != 4)
|
||||
throw "Syntax error in repeat expression";
|
||||
|
||||
if(self.debug < 2) console.warn(items[0].substr(1))
|
||||
if(self.debug < 2) console.warn(Number(this.parseExpression(items[1], scope)))
|
||||
if(self.debug < 2) console.warn(items[2])
|
||||
if(self.debug < 2) console.warn(Number(this.parseExpression(items[3], scope)))
|
||||
|
||||
return new pgli.lang.Iterator(
|
||||
items[0].substr(1),
|
||||
Number(this.parseExpression(items[1], scope)),
|
||||
items[2],
|
||||
Number(this.parseExpression(items[3], scope))
|
||||
);
|
||||
},
|
||||
|
||||
parseModule: function(string)
|
||||
{
|
||||
try
|
||||
{
|
||||
return JSON.parse(string);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
trace("(!) Syntax error in module.");
|
||||
return {error:"unable to parse module"};
|
||||
}
|
||||
},
|
||||
|
||||
execFunction: function(methodName, params)
|
||||
{
|
||||
var hasP = params != undefined;
|
||||
var p = hasP ? params.replace(" ", "").split(',') : [];
|
||||
|
||||
if(methodName == "random")
|
||||
{
|
||||
var r = Math.random();
|
||||
if(hasP && p.length == 2) try
|
||||
{
|
||||
var min = eval(p[0]);
|
||||
var max = eval(p[1]);
|
||||
r = Math.round(r * (max-min) + min);
|
||||
} catch(e) {
|
||||
console.warn('Bad method format: '+methodName+' / '+params);
|
||||
return 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
else if(methodName == "mod")
|
||||
{
|
||||
if(hasP && p.length == 2) try
|
||||
{
|
||||
var base = eval(p[0]);
|
||||
var div = eval(p[1]);
|
||||
if(div == 0) throw "Divide by 0";
|
||||
return Math.floor(base/div);
|
||||
} catch(e) {
|
||||
console.warn('Bad method format: '+methodName+' / '+params);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.warn("Unsupported method : "+methodName);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
var pgli = pgli || {};
|
||||
|
||||
|
||||
pgli.Project = gamecore.Base.extend('Project',
|
||||
{
|
||||
patternRoot: /\/([a-z]+\.pmod)/ig,
|
||||
patternPath: /([a-z\/]+\/)[a-z]+\.pmod/ig
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
appInstance: null,
|
||||
modules: null,
|
||||
activeFile: null,
|
||||
files:null,
|
||||
keys :[],
|
||||
name: "default",
|
||||
path: "/files/",
|
||||
root: "default.pmod",
|
||||
diagram: null,
|
||||
loadingQueue: [],
|
||||
onLoad: function() { console.log("Project loaded."); },
|
||||
|
||||
|
||||
|
||||
init : function(projectFile, onLoad)
|
||||
{
|
||||
this.onLoad = onLoad;
|
||||
this.modules = new gamecore.Hashtable();
|
||||
this.files = new gamecore.Hashtable();
|
||||
this.path = pgli.Project.patternPath.exec(projectFile)[1];
|
||||
this.root = pgli.Project.patternRoot.exec(projectFile)[1];
|
||||
|
||||
var self = this;
|
||||
|
||||
this.loadFile(projectFile,this.root,true,true);
|
||||
|
||||
},
|
||||
|
||||
loadFile: function(path,name,doDependencies,doDiagram)
|
||||
{
|
||||
trace("#Loading ["+name+"].");
|
||||
var self = this;
|
||||
var request = $.ajax({
|
||||
url: path,
|
||||
type: 'get',
|
||||
dataType: "text",
|
||||
})
|
||||
.success(function(data)
|
||||
{
|
||||
self.files.put(name, data);
|
||||
self.keys.push(name);
|
||||
|
||||
var object = pgli.lang.Parser.parseModule(data);
|
||||
self.modules.put(name, object);
|
||||
|
||||
if(doDependencies == true)
|
||||
self.loadDependencies(object);
|
||||
|
||||
if(doDiagram == true)
|
||||
self.getAppInstance().addDiagramNode(name, object);
|
||||
|
||||
trace("#["+name+"] loaded");
|
||||
|
||||
self.onLoad();
|
||||
})
|
||||
.error(function()
|
||||
{
|
||||
throw "Unable to load file: " + path;
|
||||
});
|
||||
},
|
||||
|
||||
loadDependencies: function(object)
|
||||
{
|
||||
|
||||
if(!("layers" in object))
|
||||
return;
|
||||
|
||||
var layers = object.layers;
|
||||
var self = this;
|
||||
|
||||
for (var i=0, len = layers.length; i<len ; i++)
|
||||
{
|
||||
if(!("use" in layers[i]) )
|
||||
continue;
|
||||
|
||||
var layerName = layers[i].use;
|
||||
|
||||
trace("#Found dependency ["+layerName+"]");
|
||||
|
||||
(function(name,self)
|
||||
{
|
||||
self.loadFile(self.path+name,name,true,true);
|
||||
|
||||
})(layerName,self);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getModulesCount: function()
|
||||
{
|
||||
return this.keys.length;
|
||||
},
|
||||
|
||||
getModule: function(key)
|
||||
{
|
||||
return this.modules.get(key);
|
||||
},
|
||||
|
||||
getFile: function(key)
|
||||
{
|
||||
return this.files.get(key);
|
||||
},
|
||||
|
||||
getModuleKey: function(index)
|
||||
{
|
||||
return this.keys[index];
|
||||
},
|
||||
|
||||
getRootModule: function()
|
||||
{
|
||||
return this.modules.get(this.root);
|
||||
},
|
||||
|
||||
isEmpty: function()
|
||||
{
|
||||
return (this.keys.length <= 0);
|
||||
},
|
||||
|
||||
setAppInstance: function(app)
|
||||
{
|
||||
this.appInstance = app;
|
||||
},
|
||||
|
||||
getAppInstance: function()
|
||||
{
|
||||
return this.appInstance;
|
||||
},
|
||||
|
||||
setActiveFile: function(key)
|
||||
{
|
||||
this.activeFile = key;
|
||||
},
|
||||
|
||||
rememberActiveFile: function()
|
||||
{
|
||||
if(!this.activeFile) return;
|
||||
|
||||
this.files.put(this.activeFile, this.getAppInstance().getEditorContent());
|
||||
}
|
||||
|
||||
/*updateDiagram: function()
|
||||
{
|
||||
|
||||
},
|
||||
|
||||
render: function(canvasRenderer)
|
||||
{
|
||||
//canvasRenderer.Render(modules, root, new Hashtable());
|
||||
}*/
|
||||
|
||||
});
|
||||
@@ -0,0 +1,166 @@
|
||||
/*!
|
||||
* @class bkcore.Timer
|
||||
*
|
||||
* new Date().getTime() wrapper to use as timers.
|
||||
*
|
||||
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* RAF shim
|
||||
*/
|
||||
window.requestAnimFrame = (function(){
|
||||
return window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function( callback ){
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
};
|
||||
})();
|
||||
|
||||
/*!
|
||||
* @package bkcore
|
||||
*/
|
||||
var bkcore = bkcore || {};
|
||||
|
||||
/*!
|
||||
* Creates a new timer, inactive by default.
|
||||
* Call Timer.start() to activate.
|
||||
*/
|
||||
bkcore.Timer = function()
|
||||
{
|
||||
this.time = {
|
||||
start: 0,
|
||||
current: 0,
|
||||
previous: 0,
|
||||
elapsed: 0,
|
||||
delta: 0
|
||||
}
|
||||
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Starts/restarts the timer.
|
||||
*/
|
||||
bkcore.Timer.prototype.start = function()
|
||||
{
|
||||
var now = new Date().getTime();
|
||||
|
||||
this.time.start = now;
|
||||
this.time.current = now;
|
||||
this.time.previous = now;
|
||||
this.time.elapsed = 0;
|
||||
this.time.delta = 0;
|
||||
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Restarts timer, returning last ms tick
|
||||
*/
|
||||
bkcore.Timer.prototype.restart = function()
|
||||
{
|
||||
var now = new Date().getTime();
|
||||
var e = now - this.time.start;
|
||||
|
||||
this.time.start = now;
|
||||
this.time.current = now;
|
||||
this.time.previous = now;
|
||||
this.time.elapsed = 0;
|
||||
this.time.delta = 0;
|
||||
|
||||
this.active = true;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Pauses(true)/Unpauses(false) the timer.
|
||||
*
|
||||
* @param bool Do pause
|
||||
*/
|
||||
bkcore.Timer.prototype.pause = function(bool)
|
||||
{
|
||||
this.active = !bool;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Update method to be called inside a RAF loop
|
||||
*/
|
||||
bkcore.Timer.prototype.update = function()
|
||||
{
|
||||
if(!this.active) return;
|
||||
|
||||
var now = new Date().getTime();
|
||||
|
||||
this.time.current = now;
|
||||
this.time.elapsed = this.time.current - this.time.start;
|
||||
this.time.delta = now - this.time.previous;
|
||||
this.time.previous = now;
|
||||
|
||||
return this.time.elapsed;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns elapsed milliseconds
|
||||
*/
|
||||
bkcore.Timer.prototype.getElapsed = function()
|
||||
{
|
||||
return this.time.elapsed;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns a formatted version of the current elapsed time using msToTime().
|
||||
*
|
||||
*
|
||||
*/
|
||||
bkcore.Timer.prototype.getElapsedTime = function()
|
||||
{
|
||||
return bkcore.Timer.msToTime(this.time.elapsed);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Formats a millisecond integer into a h/m/s/ms object
|
||||
*
|
||||
* @param x int In milliseconds
|
||||
* @return Object{h,m,s,ms}
|
||||
*/
|
||||
bkcore.Timer.msToTime = function(t)
|
||||
{
|
||||
var ms, s, m, h;
|
||||
|
||||
ms = t%1000;
|
||||
|
||||
s = Math.floor((t/1000)%60);
|
||||
|
||||
m = Math.floor((t/60000)%60);
|
||||
h = Math.floor((t/3600000));
|
||||
|
||||
return {h:h, m:m, s:s, ms:ms};
|
||||
}
|
||||
|
||||
/*!
|
||||
* Formats a millisecond integer into a h/m/s/ms object with prefix zeros
|
||||
*
|
||||
* @param x int In milliseconds
|
||||
* @return Object<string>{h,m,s,ms}
|
||||
*/
|
||||
bkcore.Timer.msToTimeString = function(t)
|
||||
{
|
||||
var ms, s, m, h;
|
||||
|
||||
ms = t%1000;
|
||||
if(ms < 10) ms = "00"+ms;
|
||||
else if(ms < 100) ms = "0"+ms;
|
||||
|
||||
s = Math.floor((t/1000)%60);
|
||||
if(s < 10) s = "0"+s;
|
||||
|
||||
m = Math.floor((t/60000)%60);
|
||||
h = Math.floor((t/3600000));
|
||||
|
||||
return {h:h, m:m, s:s, ms:ms};
|
||||
}
|
||||
@@ -0,0 +1,989 @@
|
||||
/**
|
||||
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
|
||||
* class.js
|
||||
* Classes and objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* @Class
|
||||
* A modified version of class.js to cater to static inheritance and deep object cloning
|
||||
* Based almost completely on class.js (Javascript MVC -- Justin Meyer, Brian Moschel, Michael Mayer and others)
|
||||
* (http://javascriptmvc.com/contribute.html)
|
||||
* Some portions adapted from Prototype JavaScript framework, version 1.6.0.1 (c) 2005-2007 Sam Stephenson
|
||||
* <p>
|
||||
* Class system for javascript
|
||||
* <p>
|
||||
* <code>
|
||||
* var Fighter = gamecore.Base.extend('Fighter',
|
||||
* {
|
||||
* // static (this is inherited as well)
|
||||
* firingSpeed: 1000
|
||||
* },
|
||||
* {
|
||||
* // instance
|
||||
*
|
||||
* hp: 0,
|
||||
* lastFireTime: 0,
|
||||
*
|
||||
* init: function(hp)
|
||||
* {
|
||||
* this.hp = hp;
|
||||
* },
|
||||
*
|
||||
* fire: function()
|
||||
* {
|
||||
* this._super(); // super methods!
|
||||
*
|
||||
* // do firing!
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* var gunship = new Fighter(100);
|
||||
* </code>
|
||||
*
|
||||
* Introspection:
|
||||
* <code>
|
||||
* gamecore.Base.extend(‘Fighter.Gunship’);
|
||||
* Fighter.Gunship.shortName; // ‘Gunship’
|
||||
* Fighter.Gunship.fullName; // ‘Fighter.Gunship’
|
||||
* Fighter.Gunship.namespace; // ‘Fighter’
|
||||
* </code>
|
||||
* <p>
|
||||
* Setup method will be called prior to any init -- nice if you want to do things without needing the
|
||||
* users to call _super in the init, as well as for normalizing parameters.
|
||||
* <code>
|
||||
* setup: function()
|
||||
* {
|
||||
* this.objectId = this.Class.totalObjects++;
|
||||
* this.uniqueId = this.Class.fullName + ':' + this.objectId;
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
|
||||
// compatible with jquery classing
|
||||
(function ($)
|
||||
{
|
||||
var regs = {
|
||||
undHash: /_|-/,
|
||||
colons: /::/,
|
||||
words: /([A-Z]+)([A-Z][a-z])/g,
|
||||
lowUp: /([a-z\d])([A-Z])/g,
|
||||
dash: /([a-z\d])([A-Z])/g,
|
||||
replacer: /\{([^\}]+)\}/g,
|
||||
dot: /\./
|
||||
},
|
||||
getNext = function (current, nextPart, add)
|
||||
{
|
||||
return current[nextPart] || ( add && (current[nextPart] = {}) );
|
||||
},
|
||||
isContainer = function (current)
|
||||
{
|
||||
var type = typeof current;
|
||||
return type && ( type == 'function' || type == 'object' );
|
||||
},
|
||||
getObject = function (objectName, roots, add)
|
||||
{
|
||||
var parts = objectName ? objectName.split(regs.dot) : [],
|
||||
length = parts.length,
|
||||
currents = $.isArray(roots) ? roots : [roots || window],
|
||||
current,
|
||||
ret,
|
||||
i,
|
||||
c = 0,
|
||||
type;
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return currents[0];
|
||||
}
|
||||
while (current = currents[c++])
|
||||
{
|
||||
for (i = 0; i < length - 1 && isContainer(current); i++)
|
||||
{
|
||||
current = getNext(current, parts[i], add);
|
||||
}
|
||||
if (isContainer(current))
|
||||
{
|
||||
|
||||
ret = getNext(current, parts[i], add);
|
||||
|
||||
if (ret !== undefined)
|
||||
{
|
||||
|
||||
if (add === false)
|
||||
{
|
||||
delete current[parts[i]];
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @class jQuery.String
|
||||
*
|
||||
* A collection of useful string helpers.
|
||||
*
|
||||
*/
|
||||
str = $.String = $.extend($.String || {}, {
|
||||
/**
|
||||
* @function
|
||||
* Gets an object from a string.
|
||||
* @param {String} name the name of the object to look for
|
||||
* @param {Array} [roots] an array of root objects to look for the name
|
||||
* @param {Boolean} [add] true to add missing objects to
|
||||
* the path. false to remove found properties. undefined to
|
||||
* not modify the root object
|
||||
*/
|
||||
getObject: getObject,
|
||||
/**
|
||||
* Capitalizes a string
|
||||
* @param {String} s the string.
|
||||
* @return {String} a string with the first character capitalized.
|
||||
*/
|
||||
capitalize: function (s, cache)
|
||||
{
|
||||
return s.charAt(0).toUpperCase() + s.substr(1);
|
||||
},
|
||||
/**
|
||||
* Capitalizes a string from something undercored. Examples:
|
||||
* @codestart
|
||||
* jQuery.String.camelize("one_two") //-> "oneTwo"
|
||||
* "three-four".camelize() //-> threeFour
|
||||
* @codeend
|
||||
* @param {String} s
|
||||
* @return {String} a the camelized string
|
||||
*/
|
||||
camelize: function (s)
|
||||
{
|
||||
s = str.classize(s);
|
||||
return s.charAt(0).toLowerCase() + s.substr(1);
|
||||
},
|
||||
/**
|
||||
* Like camelize, but the first part is also capitalized
|
||||
* @param {String} s
|
||||
* @return {String} the classized string
|
||||
*/
|
||||
classize: function (s, join)
|
||||
{
|
||||
var parts = s.split(regs.undHash),
|
||||
i = 0;
|
||||
for (; i < parts.length; i++)
|
||||
{
|
||||
parts[i] = str.capitalize(parts[i]);
|
||||
}
|
||||
|
||||
return parts.join(join || '');
|
||||
},
|
||||
/**
|
||||
* Like [jQuery.String.classize|classize], but a space separates each 'word'
|
||||
* @codestart
|
||||
* jQuery.String.niceName("one_two") //-> "One Two"
|
||||
* @codeend
|
||||
* @param {String} s
|
||||
* @return {String} the niceName
|
||||
*/
|
||||
niceName: function (s)
|
||||
{
|
||||
return str.classize(s, ' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Underscores a string.
|
||||
* @codestart
|
||||
* jQuery.String.underscore("OneTwo") //-> "one_two"
|
||||
* @codeend
|
||||
* @param {String} s
|
||||
* @return {String} the underscored string
|
||||
*/
|
||||
underscore: function (s)
|
||||
{
|
||||
return s.replace(regs.colons, '/').replace(regs.words, '$1_$2').replace(regs.lowUp, '$1_$2').replace(regs.dash, '_').toLowerCase();
|
||||
},
|
||||
/**
|
||||
* Returns a string with {param} replaced values from data.
|
||||
*
|
||||
* $.String.sub("foo {bar}",{bar: "far"})
|
||||
* //-> "foo far"
|
||||
*
|
||||
* @param {String} s The string to replace
|
||||
* @param {Object} data The data to be used to look for properties. If it's an array, multiple
|
||||
* objects can be used.
|
||||
* @param {Boolean} [remove] if a match is found, remove the property from the object
|
||||
*/
|
||||
sub: function (s, data, remove)
|
||||
{
|
||||
var obs = [];
|
||||
obs.push(s.replace(regs.replacer, function (whole, inside)
|
||||
{
|
||||
//convert inside to type
|
||||
var ob = getObject(inside, data, typeof remove == 'boolean' ? !remove : remove),
|
||||
type = typeof ob;
|
||||
if ((type === 'object' || type === 'function') && type !== null)
|
||||
{
|
||||
obs.push(ob);
|
||||
return "";
|
||||
} else
|
||||
{
|
||||
return "" + ob;
|
||||
}
|
||||
}));
|
||||
return obs.length <= 1 ? obs[0] : obs;
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
(function ($)
|
||||
{
|
||||
|
||||
// if we are initializing a new class
|
||||
var initializing = false,
|
||||
makeArray = $.makeArray,
|
||||
isFunction = $.isFunction,
|
||||
isArray = $.isArray,
|
||||
extend = $.extend,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
cloneObject = function(object)
|
||||
{
|
||||
if (!object || typeof(object) != 'object')
|
||||
return object;
|
||||
|
||||
// special case handling of array (deep copy them)
|
||||
if (object instanceof Array)
|
||||
{
|
||||
var clone = [];
|
||||
for (var c = 0; c < object.length; c++)
|
||||
clone[c] = cloneObject(object[c]);
|
||||
return clone;
|
||||
}
|
||||
else // otherwise, it's a normal object, clone it's properties
|
||||
{
|
||||
var cloneObj = {};
|
||||
for (var prop in object)
|
||||
cloneObj[prop] = cloneObject(object[prop]);
|
||||
return cloneObj;
|
||||
}
|
||||
},
|
||||
|
||||
concatArgs = function (arr, args)
|
||||
{
|
||||
return arr.concat(makeArray(args));
|
||||
},
|
||||
// tests if we can get super in .toString()
|
||||
fnTest = /xyz/.test(function ()
|
||||
{
|
||||
xyz;
|
||||
}) ? /\b_super\b/ : /.*/,
|
||||
// overwrites an object with methods, sets up _super
|
||||
// newProps - new properties
|
||||
// oldProps - where the old properties might be
|
||||
// addTo - what we are adding to
|
||||
inheritProps = function (newProps, oldProps, addTo)
|
||||
{
|
||||
addTo = addTo || newProps
|
||||
for (var name in newProps)
|
||||
{
|
||||
// Check if we're overwriting an existing function
|
||||
addTo[name] = isFunction(newProps[name]) &&
|
||||
isFunction(oldProps[name]) &&
|
||||
fnTest.test(newProps[name]) ? (function (name, fn)
|
||||
{
|
||||
return function ()
|
||||
{
|
||||
var tmp = this._super, ret;
|
||||
|
||||
// Add a new ._super() method that is the same method but on the super-class
|
||||
this._super = oldProps[name];
|
||||
|
||||
// The method only need to be bound temporarily, so we remove it when we're done executing
|
||||
ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
return ret;
|
||||
};
|
||||
})(name, newProps[name]) : newProps[name];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @class jQuery.Class
|
||||
* @plugin jquery/class
|
||||
* @tag core
|
||||
* @download dist/jquery/jquery.class.js
|
||||
* @test jquery/class/qunit.html
|
||||
*
|
||||
* Class provides simulated inheritance in JavaScript. Use clss to bridge the gap between
|
||||
* jQuery's functional programming style and Object Oriented Programming. It
|
||||
* is based off John Resig's [http://ejohn.org/blog/simple-javascript-inheritance/|Simple Class]
|
||||
* Inheritance library. Besides prototypal inheritance, it includes a few important features:
|
||||
*
|
||||
* - Static inheritance
|
||||
* - Introspection
|
||||
* - Namespaces
|
||||
* - Setup and initialization methods
|
||||
* - Easy callback function creation
|
||||
*
|
||||
*
|
||||
* ## Static v. Prototype
|
||||
*
|
||||
* Before learning about Class, it's important to
|
||||
* understand the difference between
|
||||
* a class's __static__ and __prototype__ properties.
|
||||
*
|
||||
* //STATIC
|
||||
* MyClass.staticProperty //shared property
|
||||
*
|
||||
* //PROTOTYPE
|
||||
* myclass = new MyClass()
|
||||
* myclass.prototypeMethod() //instance method
|
||||
*
|
||||
* A static (or class) property is on the Class constructor
|
||||
* function itself
|
||||
* and can be thought of being shared by all instances of the
|
||||
* Class. Prototype propertes are available only on instances of the Class.
|
||||
*
|
||||
* ## A Basic Class
|
||||
*
|
||||
* The following creates a Monster class with a
|
||||
* name (for introspection), static, and prototype members.
|
||||
* Every time a monster instance is created, the static
|
||||
* count is incremented.
|
||||
*
|
||||
* @codestart
|
||||
* $.Class.extend('Monster',
|
||||
* /* @static *|
|
||||
* {
|
||||
* count: 0
|
||||
* },
|
||||
* /* @prototype *|
|
||||
* {
|
||||
* init: function( name ) {
|
||||
*
|
||||
* // saves name on the monster instance
|
||||
* this.name = name;
|
||||
*
|
||||
* // sets the health
|
||||
* this.health = 10;
|
||||
*
|
||||
* // increments count
|
||||
* this.Class.count++;
|
||||
* },
|
||||
* eat: function( smallChildren ){
|
||||
* this.health += smallChildren;
|
||||
* },
|
||||
* fight: function() {
|
||||
* this.health -= 2;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* hydra = new Monster('hydra');
|
||||
*
|
||||
* dragon = new Monster('dragon');
|
||||
*
|
||||
* hydra.name // -> hydra
|
||||
* Monster.count // -> 2
|
||||
* Monster.shortName // -> 'Monster'
|
||||
*
|
||||
* hydra.eat(2); // health = 12
|
||||
*
|
||||
* dragon.fight(); // health = 8
|
||||
*
|
||||
* @codeend
|
||||
*
|
||||
*
|
||||
* Notice that the prototype <b>init</b> function is called when a new instance of Monster is created.
|
||||
*
|
||||
*
|
||||
* ## Inheritance
|
||||
*
|
||||
* When a class is extended, all static and prototype properties are available on the new class.
|
||||
* If you overwrite a function, you can call the base class's function by calling
|
||||
* <code>this._super</code>. Lets create a SeaMonster class. SeaMonsters are less
|
||||
* efficient at eating small children, but more powerful fighters.
|
||||
*
|
||||
*
|
||||
* Monster.extend("SeaMonster",{
|
||||
* eat: function( smallChildren ) {
|
||||
* this._super(smallChildren / 2);
|
||||
* },
|
||||
* fight: function() {
|
||||
* this.health -= 1;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* lockNess = new SeaMonster('Lock Ness');
|
||||
* lockNess.eat(4); //health = 12
|
||||
* lockNess.fight(); //health = 11
|
||||
*
|
||||
* ### Static property inheritance
|
||||
*
|
||||
* You can also inherit static properties in the same way:
|
||||
*
|
||||
* $.Class.extend("First",
|
||||
* {
|
||||
* staticMethod: function() { return 1;}
|
||||
* },{})
|
||||
*
|
||||
* First.extend("Second",{
|
||||
* staticMethod: function() { return this._super()+1;}
|
||||
* },{})
|
||||
*
|
||||
* Second.staticMethod() // -> 2
|
||||
*
|
||||
* ## Namespaces
|
||||
*
|
||||
* Namespaces are a good idea! We encourage you to namespace all of your code.
|
||||
* It makes it possible to drop your code into another app without problems.
|
||||
* Making a namespaced class is easy:
|
||||
*
|
||||
* @codestart
|
||||
* $.Class.extend("MyNamespace.MyClass",{},{});
|
||||
*
|
||||
* new MyNamespace.MyClass()
|
||||
* @codeend
|
||||
* <h2 id='introspection'>Introspection</h2>
|
||||
* Often, it's nice to create classes whose name helps determine functionality. Ruby on
|
||||
* Rails's [http://api.rubyonrails.org/classes/ActiveRecord/Base.html|ActiveRecord] ORM class
|
||||
* is a great example of this. Unfortunately, JavaScript doesn't have a way of determining
|
||||
* an object's name, so the developer must provide a name. Class fixes this by taking a String name for the class.
|
||||
* @codestart
|
||||
* $.Class.extend("MyOrg.MyClass",{},{})
|
||||
* MyOrg.MyClass.shortName //-> 'MyClass'
|
||||
* MyOrg.MyClass.fullName //-> 'MyOrg.MyClass'
|
||||
* @codeend
|
||||
* The fullName (with namespaces) and the shortName (without namespaces) are added to the Class's
|
||||
* static properties.
|
||||
*
|
||||
*
|
||||
* <h2>Setup and initialization methods</h2>
|
||||
* <p>
|
||||
* Class provides static and prototype initialization functions.
|
||||
* These come in two flavors - setup and init.
|
||||
* Setup is called before init and
|
||||
* can be used to 'normalize' init's arguments.
|
||||
* </p>
|
||||
* <div class='whisper'>PRO TIP: Typically, you don't need setup methods in your classes. Use Init instead.
|
||||
* Reserve setup methods for when you need to do complex pre-processing of your class before init is called.
|
||||
*
|
||||
* </div>
|
||||
* @codestart
|
||||
* $.Class.extend("MyClass",
|
||||
* {
|
||||
* setup: function() {} //static setup
|
||||
* init: function() {} //static constructor
|
||||
* },
|
||||
* {
|
||||
* setup: function() {} //prototype setup
|
||||
* init: function() {} //prototype constructor
|
||||
* })
|
||||
* @codeend
|
||||
*
|
||||
* <h3>Setup</h3>
|
||||
* <p>Setup functions are called before init functions. Static setup functions are passed
|
||||
* the base class followed by arguments passed to the extend function.
|
||||
* Prototype static functions are passed the Class constructor function arguments.</p>
|
||||
* <p>If a setup function returns an array, that array will be used as the arguments
|
||||
* for the following init method. This provides setup functions the ability to normalize
|
||||
* arguments passed to the init constructors. They are also excellent places
|
||||
* to put setup code you want to almost always run.</p>
|
||||
* <p>
|
||||
* The following is similar to how [jQuery.Controller.prototype.setup]
|
||||
* makes sure init is always called with a jQuery element and merged options
|
||||
* even if it is passed a raw
|
||||
* HTMLElement and no second parameter.
|
||||
* </p>
|
||||
* @codestart
|
||||
* $.Class.extend("jQuery.Controller",{
|
||||
* ...
|
||||
* },{
|
||||
* setup: function( el, options ) {
|
||||
* ...
|
||||
* return [$(el),
|
||||
* $.extend(true,
|
||||
* this.Class.defaults,
|
||||
* options || {} ) ]
|
||||
* }
|
||||
* })
|
||||
* @codeend
|
||||
* Typically, you won't need to make or overwrite setup functions.
|
||||
* <h3>Init</h3>
|
||||
*
|
||||
* <p>Init functions are called after setup functions.
|
||||
* Typically, they receive the same arguments
|
||||
* as their preceding setup function. The Foo class's <code>init</code> method
|
||||
* gets called in the following example:
|
||||
* </p>
|
||||
* @codestart
|
||||
* $.Class.Extend("Foo", {
|
||||
* init: function( arg1, arg2, arg3 ) {
|
||||
* this.sum = arg1+arg2+arg3;
|
||||
* }
|
||||
* })
|
||||
* var foo = new Foo(1,2,3);
|
||||
* foo.sum //-> 6
|
||||
* @codeend
|
||||
* <h2>Callbacks</h2>
|
||||
* <p>Similar to jQuery's proxy method, Class provides a
|
||||
* [jQuery.Class.static.callback callback]
|
||||
* function that returns a callback to a method that will always
|
||||
* have
|
||||
* <code>this</code> set to the class or instance of the class.
|
||||
* </p>
|
||||
* The following example uses this.callback to make sure
|
||||
* <code>this.name</code> is available in <code>show</code>.
|
||||
* @codestart
|
||||
* $.Class.extend("Todo",{
|
||||
* init: function( name ) { this.name = name }
|
||||
* get: function() {
|
||||
* $.get("/stuff",this.callback('show'))
|
||||
* },
|
||||
* show: function( txt ) {
|
||||
* alert(this.name+txt)
|
||||
* }
|
||||
* })
|
||||
* new Todo("Trash").get()
|
||||
* @codeend
|
||||
* <p>Callback is available as a static and prototype method.</p>
|
||||
*
|
||||
* <h2>Typing<h2>
|
||||
* Classes are automatically populating with three type related components:
|
||||
*
|
||||
* _types: a variable that contains an array of types of this class (extends history)
|
||||
* _fullTypeName: a string representation of the extends hierarchy
|
||||
* isA(string): a function you can call which will return true if the class is of a given type string.
|
||||
* <p>
|
||||
* Example:
|
||||
* <p>
|
||||
* Animal.extend('Tiger', {}, {});
|
||||
* Tiger._types; // ['Animal', 'Tiger']
|
||||
* Tiger._fullTypeName; // 'Animal | Tiger |"
|
||||
* Tiger.isA('Animal'); // true
|
||||
* </p>
|
||||
* @constructor Creating a new instance of an object that has extended jQuery.Class
|
||||
* calls the init prototype function and returns a new instance of the class.
|
||||
*
|
||||
*/
|
||||
|
||||
clss = $.Class = function ()
|
||||
{
|
||||
if (arguments.length)
|
||||
{
|
||||
return clss.extend.apply(clss, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
/* @Static*/
|
||||
extend(clss, {
|
||||
/**
|
||||
* @function callback
|
||||
* Returns a callback function for a function on this Class.
|
||||
* The callback function ensures that 'this' is set appropriately.
|
||||
* @codestart
|
||||
* $.Class.extend("MyClass",{
|
||||
* getData: function() {
|
||||
* this.showing = null;
|
||||
* $.get("data.json",this.callback('gotData'),'json')
|
||||
* },
|
||||
* gotData: function( data ) {
|
||||
* this.showing = data;
|
||||
* }
|
||||
* },{});
|
||||
* MyClass.showData();
|
||||
* @codeend
|
||||
* <h2>Currying Arguments</h2>
|
||||
* Additional arguments to callback will fill in arguments on the returning function.
|
||||
* @codestart
|
||||
* $.Class.extend("MyClass",{
|
||||
* getData: function( <b>callback</b> ) {
|
||||
* $.get("data.json",this.callback('process',<b>callback</b>),'json');
|
||||
* },
|
||||
* process: function( <b>callback</b>, jsonData ) { //callback is added as first argument
|
||||
* jsonData.processed = true;
|
||||
* callback(jsonData);
|
||||
* }
|
||||
* },{});
|
||||
* MyClass.getData(showDataFunc)
|
||||
* @codeend
|
||||
* <h2>Nesting Functions</h2>
|
||||
* Callback can take an array of functions to call as the first argument. When the returned callback function
|
||||
* is called each function in the array is passed the return value of the prior function. This is often used
|
||||
* to eliminate currying initial arguments.
|
||||
* @codestart
|
||||
* $.Class.extend("MyClass",{
|
||||
* getData: function( callback ) {
|
||||
* //calls process, then callback with value from process
|
||||
* $.get("data.json",this.callback(['process2',callback]),'json')
|
||||
* },
|
||||
* process2: function( type,jsonData ) {
|
||||
* jsonData.processed = true;
|
||||
* return [jsonData];
|
||||
* }
|
||||
* },{});
|
||||
* MyClass.getData(showDataFunc);
|
||||
* @codeend
|
||||
* @param {String|Array} fname If a string, it represents the function to be called.
|
||||
* If it is an array, it will call each function in order and pass the return value of the prior function to the
|
||||
* next function.
|
||||
* @return {Function} the callback function.
|
||||
*/
|
||||
callback: function (funcs)
|
||||
{
|
||||
//args that should be curried
|
||||
var args = makeArray(arguments),
|
||||
self;
|
||||
|
||||
funcs = args.shift();
|
||||
|
||||
if (!isArray(funcs))
|
||||
{
|
||||
funcs = [funcs];
|
||||
}
|
||||
|
||||
self = this;
|
||||
|
||||
return function class_cb()
|
||||
{
|
||||
var cur = concatArgs(args, arguments),
|
||||
isString,
|
||||
length = funcs.length,
|
||||
f = 0,
|
||||
func;
|
||||
|
||||
for (; f < length; f++)
|
||||
{
|
||||
func = funcs[f];
|
||||
if (!func)
|
||||
continue;
|
||||
|
||||
isString = typeof func == "string";
|
||||
if (isString && self._set_called)
|
||||
self.called = func;
|
||||
|
||||
cur = (isString ? self[func] : func).apply(self, cur || []);
|
||||
if (f < length - 1)
|
||||
cur = !isArray(cur) || cur._use_call ? [cur] : cur
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @function getObject
|
||||
* Gets an object from a String.
|
||||
* If the object or namespaces the string represent do not
|
||||
* exist it will create them.
|
||||
* @codestart
|
||||
* Foo = {Bar: {Zar: {"Ted"}}}
|
||||
* $.Class.getobject("Foo.Bar.Zar") //-> "Ted"
|
||||
* @codeend
|
||||
* @param {String} objectName the object you want to get
|
||||
* @param {Object} [current=window] the object you want to look in.
|
||||
* @return {Object} the object you are looking for.
|
||||
*/
|
||||
getObject: $.String.getObject,
|
||||
/**
|
||||
* @function newInstance
|
||||
* Creates a new instance of the class. This method is useful for creating new instances
|
||||
* with arbitrary parameters.
|
||||
* <h3>Example</h3>
|
||||
* @codestart
|
||||
* $.Class.extend("MyClass",{},{})
|
||||
* var mc = MyClass.newInstance.apply(null, new Array(parseInt(Math.random()*10,10))
|
||||
* @codeend
|
||||
* @return {class} instance of the class
|
||||
*/
|
||||
newInstance: function ()
|
||||
{
|
||||
var inst = this.rawInstance();
|
||||
var args;
|
||||
|
||||
if (inst.setup)
|
||||
args = inst.setup.apply(inst, arguments);
|
||||
|
||||
// Added by martin@playcraftlabs.com -- fix for deep cloning of properties
|
||||
for (var prop in inst.__proto__)
|
||||
inst[prop] = cloneObject(inst[prop]);
|
||||
|
||||
if (inst.init)
|
||||
inst.init.apply(inst, isArray(args) ? args : arguments);
|
||||
|
||||
return inst;
|
||||
},
|
||||
/**
|
||||
* Setup gets called on the inherting class with the base class followed by the
|
||||
* inheriting class's raw properties.
|
||||
*
|
||||
* Setup will deeply extend a static defaults property on the base class with
|
||||
* properties on the base class. For example:
|
||||
*
|
||||
* $.Class("MyBase",{
|
||||
* defaults : {
|
||||
* foo: 'bar'
|
||||
* }
|
||||
* },{})
|
||||
*
|
||||
* MyBase("Inheriting",{
|
||||
* defaults : {
|
||||
* newProp : 'newVal'
|
||||
* }
|
||||
* },{}
|
||||
*
|
||||
* Inheriting.defaults -> {foo: 'bar', 'newProp': 'newVal'}
|
||||
*
|
||||
* @param {Object} baseClass the base class that is being inherited from
|
||||
* @param {String} fullName the name of the new class
|
||||
* @param {Object} staticProps the static properties of the new class
|
||||
* @param {Object} protoProps the prototype properties of the new class
|
||||
*/
|
||||
setup: function (baseClass, fullName)
|
||||
{
|
||||
this.defaults = extend(true, {}, baseClass.defaults, this.defaults);
|
||||
if (this._types == undefined) this._types = [];
|
||||
this._types.push(this.fullName);
|
||||
if (this._fullTypeName == undefined) this._fullTypeName = '|';
|
||||
this._fullTypeName += this.fullName + '|';
|
||||
return arguments;
|
||||
},
|
||||
rawInstance: function ()
|
||||
{
|
||||
initializing = true;
|
||||
var inst = new this();
|
||||
initializing = false;
|
||||
return inst;
|
||||
},
|
||||
/**
|
||||
* Extends a class with new static and prototype functions. There are a variety of ways
|
||||
* to use extend:
|
||||
* @codestart
|
||||
* //with className, static and prototype functions
|
||||
* $.Class.extend('Task',{ STATIC },{ PROTOTYPE })
|
||||
* //with just classname and prototype functions
|
||||
* $.Class.extend('Task',{ PROTOTYPE })
|
||||
* //With just a className
|
||||
* $.Class.extend('Task')
|
||||
* @codeend
|
||||
* @param {String} [fullName] the classes name (used for classes w/ introspection)
|
||||
* @param {Object} [klass] the new classes static/class functions
|
||||
* @param {Object} [proto] the new classes prototype functions
|
||||
* @return {jQuery.Class} returns the new class
|
||||
*/
|
||||
extend: function (fullName, klass, proto)
|
||||
{
|
||||
// figure out what was passed
|
||||
if (typeof fullName != 'string')
|
||||
{
|
||||
proto = klass;
|
||||
klass = fullName;
|
||||
fullName = null;
|
||||
}
|
||||
if (!proto)
|
||||
{
|
||||
proto = klass;
|
||||
klass = null;
|
||||
}
|
||||
|
||||
proto = proto || {};
|
||||
var _super_class = this,
|
||||
_super = this.prototype,
|
||||
name, shortName, namespace, prototype;
|
||||
|
||||
// append the isA function
|
||||
this.isA = function(typeName)
|
||||
{
|
||||
return this._fullTypeName.indexOf('|'+typeName+'|') != -1;
|
||||
};
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
// don't run the init constructor)
|
||||
initializing = true;
|
||||
prototype = new this();
|
||||
initializing = false;
|
||||
// Copy the properties over onto the new prototype
|
||||
inheritProps(proto, _super, prototype);
|
||||
|
||||
// The dummy class constructor
|
||||
|
||||
function Class()
|
||||
{
|
||||
// All construction is actually done in the init method
|
||||
if (initializing) return;
|
||||
|
||||
if (this.constructor !== Class && arguments.length)
|
||||
{ //we are being called w/o new
|
||||
return arguments.callee.extend.apply(arguments.callee, arguments)
|
||||
} else
|
||||
{ //we are being called w/ new
|
||||
// copy objects
|
||||
|
||||
return this.Class.newInstance.apply(this.Class, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy old stuff onto class
|
||||
for (name in this)
|
||||
if (this.hasOwnProperty(name))
|
||||
Class[name] = cloneObject(this[name]);
|
||||
|
||||
// copy new props on class
|
||||
inheritProps(klass, this, Class);
|
||||
|
||||
// do namespace stuff
|
||||
if (fullName)
|
||||
{
|
||||
var parts = fullName.split(/\./);
|
||||
var shortName = parts.pop();
|
||||
|
||||
// Martin Wells (playcraft): bug fix. Don't add a namespace object if the class name
|
||||
// has no namespace elements (i.e. it's just "MyClass", not "MyProject.MyClass")
|
||||
if (parts.length > 0)
|
||||
{
|
||||
current = clss.getObject(parts.join('.'), window, true),
|
||||
namespace = current;
|
||||
}
|
||||
|
||||
current[shortName] = Class;
|
||||
}
|
||||
|
||||
// set things that can't be overwritten
|
||||
extend(Class, {
|
||||
prototype: prototype,
|
||||
namespace: namespace,
|
||||
shortName: shortName,
|
||||
constructor: Class,
|
||||
fullName: fullName
|
||||
});
|
||||
|
||||
//make sure our prototype looks nice
|
||||
Class.prototype.Class = Class.prototype.constructor = Class;
|
||||
|
||||
|
||||
/**
|
||||
* @attribute fullName
|
||||
* The full name of the class, including namespace, provided for introspection purposes.
|
||||
* @codestart
|
||||
* $.Class.extend("MyOrg.MyClass",{},{})
|
||||
* MyOrg.MyClass.shortName //-> 'MyClass'
|
||||
* MyOrg.MyClass.fullName //-> 'MyOrg.MyClass'
|
||||
* @codeend
|
||||
*/
|
||||
|
||||
var args = Class.setup.apply(Class, concatArgs([_super_class], arguments));
|
||||
|
||||
if (Class.init)
|
||||
{
|
||||
Class.init.apply(Class, args || []);
|
||||
}
|
||||
|
||||
/* @Prototype*/
|
||||
|
||||
return Class;
|
||||
/**
|
||||
* @function setup
|
||||
* If a setup method is provided, it is called when a new
|
||||
* instances is created. It gets passed the same arguments that
|
||||
* were given to the Class constructor function (<code> new Class( arguments ... )</code>).
|
||||
*
|
||||
* $.Class("MyClass",
|
||||
* {
|
||||
* setup: function( val ) {
|
||||
* this.val = val;
|
||||
* }
|
||||
* })
|
||||
* var mc = new MyClass("Check Check")
|
||||
* mc.val //-> 'Check Check'
|
||||
*
|
||||
* Setup is called before [jQuery.Class.prototype.init init]. If setup
|
||||
* return an array, those arguments will be used for init.
|
||||
*
|
||||
* $.Class("jQuery.Controller",{
|
||||
* setup : function(htmlElement, rawOptions){
|
||||
* return [$(htmlElement),
|
||||
* $.extend({}, this.Class.defaults, rawOptions )]
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* <div class='whisper'>PRO TIP:
|
||||
* Setup functions are used to normalize constructor arguments and provide a place for
|
||||
* setup code that extending classes don't have to remember to call _super to
|
||||
* run.
|
||||
* </div>
|
||||
*
|
||||
* Setup is not defined on $.Class itself, so calling super in inherting classes
|
||||
* will break. Don't do the following:
|
||||
*
|
||||
* $.Class("Thing",{
|
||||
* setup : function(){
|
||||
* this._super(); // breaks!
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* @return {Array|undefined} If an array is return, [jQuery.Class.prototype.init] is
|
||||
* called with those arguments; otherwise, the original arguments are used.
|
||||
*/
|
||||
//break up
|
||||
/**
|
||||
* @function init
|
||||
* If an <code>init</code> method is provided, it gets called when a new instance
|
||||
* is created. Init gets called after [jQuery.Class.prototype.setup setup], typically with the
|
||||
* same arguments passed to the Class
|
||||
* constructor: (<code> new Class( arguments ... )</code>).
|
||||
*
|
||||
* $.Class("MyClass",
|
||||
* {
|
||||
* init: function( val ) {
|
||||
* this.val = val;
|
||||
* }
|
||||
* })
|
||||
* var mc = new MyClass(1)
|
||||
* mc.val //-> 1
|
||||
*
|
||||
* [jQuery.Class.prototype.setup Setup] is able to modify the arguments passed to init. Read
|
||||
* about it there.
|
||||
*
|
||||
*/
|
||||
//Breaks up code
|
||||
/**
|
||||
* @attribute Class
|
||||
* References the static properties of the instance's class.
|
||||
* <h3>Quick Example</h3>
|
||||
* @codestart
|
||||
* // a class with a static classProperty property
|
||||
* $.Class.extend("MyClass", {classProperty : true}, {});
|
||||
*
|
||||
* // a new instance of myClass
|
||||
* var mc1 = new MyClass();
|
||||
*
|
||||
* //
|
||||
* mc1.Class.classProperty = false;
|
||||
*
|
||||
* // creates a new MyClass
|
||||
* var mc2 = new mc.Class();
|
||||
* @codeend
|
||||
* Getting static properties via the Class property, such as it's
|
||||
* [jQuery.Class.static.fullName fullName] is very common.
|
||||
*/
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
clss.prototype.
|
||||
/**
|
||||
* @function callback
|
||||
* Returns a callback function. This does the same thing as and is described better in [jQuery.Class.static.callback].
|
||||
* The only difference is this callback works
|
||||
* on a instance instead of a class.
|
||||
* @param {String|Array} fname If a string, it represents the function to be called.
|
||||
* If it is an array, it will call each function in order and pass the return value of the prior function to the
|
||||
* next function.
|
||||
* @return {Function} the callback function
|
||||
*/
|
||||
callback = clss.callback;
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,16 @@
|
||||
.ace_gutter {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.ace_sb {
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
#editor {
|
||||
background: #272822;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@font-face {
|
||||
font-family: 'Ubuntu Mono';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Ubuntu Mono Bold'), local('UbuntuMono-Bold'), url(bold.woff) format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Ubuntu Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'), url(normal.woff) format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Ubuntu Mono';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
src: local('Ubuntu Mono Bold Italic'), local('UbuntuMono-BoldItalic'), url(bolditalic.woff) format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Ubuntu Mono';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: local('Ubuntu Mono Italic'), local('UbuntuMono-Italic'), url(italic.woff) format('woff');
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
|
||||
* gamecore.js
|
||||
* Namespace wrappers and the base class
|
||||
*/
|
||||
|
||||
window.gamecore = {};
|
||||
gamecore.Class = $.Class;
|
||||
|
||||
/**
|
||||
* @class gamecore.Base
|
||||
* A base class providing logging, object counting and unique object id's
|
||||
* Examples:
|
||||
*
|
||||
* Unique ID and total objects:
|
||||
* <code>
|
||||
* var Fighter = gamecore.Base.extend('Fighter', {}, {});
|
||||
* var fighter1 = new Fighter();
|
||||
* var fighter2 = new Fighter();
|
||||
* fighter1.uniqueId; // -> 'Fighter:0'
|
||||
* fighter2.uniqueId; // -> 'Fighter:1'
|
||||
* Fighter.totalObjects; // -> 2
|
||||
* </code>
|
||||
*
|
||||
* Logging: (log, info, warn, error, debug)
|
||||
* <code>
|
||||
* fighter1.warn('oops'); // == console.log('Fighter:0 [WARN] oops');
|
||||
*/
|
||||
|
||||
gamecore.Base = gamecore.Class('gamecore.Base',
|
||||
///
|
||||
/// STATIC
|
||||
///
|
||||
{
|
||||
totalObjects: 0,
|
||||
WARN: 'WARN',
|
||||
DEBUG: 'DEBUG',
|
||||
ERROR: 'ERROR',
|
||||
INFO: 'INFO',
|
||||
|
||||
log: function(id, type, message)
|
||||
{
|
||||
var idString = '';
|
||||
if (id) idString = ':'+id;
|
||||
console.log(this.fullName + idString + ' [' + type + '] ' + message);
|
||||
},
|
||||
|
||||
warn: function (message)
|
||||
{
|
||||
this.log(null, this.WARN, message);
|
||||
},
|
||||
|
||||
debug: function (message)
|
||||
{
|
||||
this.log(null, this.DEBUG, message);
|
||||
},
|
||||
|
||||
error: function (message)
|
||||
{
|
||||
this.log(null, this.ERROR, message);
|
||||
},
|
||||
|
||||
info: function (message)
|
||||
{
|
||||
this.log(null, this.INFO, message);
|
||||
},
|
||||
|
||||
assert: function(msg, condition)
|
||||
{
|
||||
if (!condition)
|
||||
throw msg;
|
||||
}
|
||||
|
||||
},
|
||||
///
|
||||
/// INSTANCE
|
||||
///
|
||||
{
|
||||
objectId: 0,
|
||||
uniqueId: null,
|
||||
|
||||
init: function()
|
||||
{
|
||||
},
|
||||
|
||||
setup: function()
|
||||
{
|
||||
this.objectId = this.Class.totalObjects++;
|
||||
this.uniqueId = this.Class.fullName + ':' + this.objectId;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {String} A system-wide unique Id for this object instance
|
||||
*/
|
||||
getUniqueId: function()
|
||||
{
|
||||
// if you see a null error here, then likely you have forgotten to call
|
||||
// this._super in a subclassed init method.
|
||||
return this.uniqueId;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {String} A hash matching this object. Override this to implement different
|
||||
* kinds of object hashing in derived classes.
|
||||
*/
|
||||
hashCode: function()
|
||||
{
|
||||
return this.getUniqueId();
|
||||
},
|
||||
|
||||
warn: function (message)
|
||||
{
|
||||
this.Class.log(this.objectId, this.Class.WARN, message);
|
||||
},
|
||||
debug: function (message)
|
||||
{
|
||||
this.Class.log(this.objectId, this.Class.DEBUG, message);
|
||||
},
|
||||
error: function (message)
|
||||
{
|
||||
this.Class.log(this.objectId, this.Class.ERROR, message);
|
||||
},
|
||||
info: function (message)
|
||||
{
|
||||
this.Class.log(this.objectId, this.Class.INFO, message);
|
||||
},
|
||||
|
||||
toString: function()
|
||||
{
|
||||
return this.Class.fullName + ' [id: ' + this.objectId + ']';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
/**
|
||||
* A map of linked lists mapped by a string value
|
||||
*/
|
||||
gamecore.HashList = gamecore.Base.extend('gamecore.HashList',
|
||||
{},
|
||||
{
|
||||
hashtable: null,
|
||||
|
||||
init: function()
|
||||
{
|
||||
this.hashtable = new gamecore.Hashtable();
|
||||
},
|
||||
|
||||
add: function(key, object)
|
||||
{
|
||||
// find the list associated with this key and add the object to it
|
||||
var list = this.hashtable.get(key);
|
||||
if (list == null)
|
||||
{
|
||||
// no list associated with this key yet, so let's make one
|
||||
list = new pc.LinkedList();
|
||||
this.hashtable.put(key, list);
|
||||
}
|
||||
list.add(object);
|
||||
},
|
||||
|
||||
remove: function(key, object)
|
||||
{
|
||||
var list = this.hashtable.get(key);
|
||||
if (list == null) throw "No list for a key in hashlist when removing";
|
||||
list.remove(object);
|
||||
},
|
||||
|
||||
get: function(key)
|
||||
{
|
||||
return this.hashtable.get(key);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
@@ -0,0 +1,468 @@
|
||||
/**
|
||||
* Copyright 2010 Tim Down.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Author: Tim Down <tim@timdown.co.uk>
|
||||
* Version: 2.1
|
||||
* Build date: 21 March 2010
|
||||
* Website: http://www.timdown.co.uk/jshashtable
|
||||
*
|
||||
* (Slight mod to add to gamecore namespace -- martin@playcraftlabs.com)
|
||||
*/
|
||||
|
||||
/**
|
||||
* jshashtable
|
||||
*
|
||||
* jshashtable is a JavaScript implementation of a hash table. It creates a single constructor function called Hashtable
|
||||
* in the global scope.
|
||||
* Example:
|
||||
* <code>
|
||||
* var map = new gamecore.Hashtable();
|
||||
* map.put('test1', obj);
|
||||
* var obj = map.get('test1');
|
||||
* </code>
|
||||
*/
|
||||
|
||||
gamecore.Hashtable = (function ()
|
||||
{
|
||||
var FUNCTION = "function";
|
||||
|
||||
var arrayRemoveAt = (typeof Array.prototype.splice == FUNCTION) ?
|
||||
function (arr, idx)
|
||||
{
|
||||
arr.splice(idx, 1);
|
||||
} :
|
||||
|
||||
function (arr, idx)
|
||||
{
|
||||
var itemsAfterDeleted, i, len;
|
||||
if (idx === arr.length - 1)
|
||||
{
|
||||
arr.length = idx;
|
||||
} else
|
||||
{
|
||||
itemsAfterDeleted = arr.slice(idx + 1);
|
||||
arr.length = idx;
|
||||
for (i = 0, len = itemsAfterDeleted.length; i < len; ++i)
|
||||
{
|
||||
arr[idx + i] = itemsAfterDeleted[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function hashObject(obj)
|
||||
{
|
||||
var hashCode;
|
||||
if (typeof obj == "string")
|
||||
{
|
||||
return obj;
|
||||
} else if (typeof obj.hashCode == FUNCTION)
|
||||
{
|
||||
// Check the hashCode method really has returned a string
|
||||
hashCode = obj.hashCode();
|
||||
return (typeof hashCode == "string") ? hashCode : hashObject(hashCode);
|
||||
} else if (typeof obj.toString == FUNCTION)
|
||||
{
|
||||
return obj.toString();
|
||||
} else
|
||||
{
|
||||
try
|
||||
{
|
||||
return String(obj);
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
// For host objects (such as ActiveObjects in IE) that have no toString() method and throw an error when
|
||||
// passed to String()
|
||||
return Object.prototype.toString.call(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function equals_fixedValueHasEquals(fixedValue, variableValue)
|
||||
{
|
||||
return fixedValue.equals(variableValue);
|
||||
}
|
||||
|
||||
function equals_fixedValueNoEquals(fixedValue, variableValue)
|
||||
{
|
||||
return (typeof variableValue.equals == FUNCTION) ?
|
||||
variableValue.equals(fixedValue) : (fixedValue === variableValue);
|
||||
}
|
||||
|
||||
function createKeyValCheck(kvStr)
|
||||
{
|
||||
return function (kv)
|
||||
{
|
||||
if (kv === null)
|
||||
{
|
||||
throw new Error("null is not a valid " + kvStr);
|
||||
} else if (typeof kv == "undefined")
|
||||
{
|
||||
throw new Error(kvStr + " must not be undefined");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value");
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Bucket(hash, firstKey, firstValue, equalityFunction)
|
||||
{
|
||||
this[0] = hash;
|
||||
this.entries = [];
|
||||
this.addEntry(firstKey, firstValue);
|
||||
|
||||
if (equalityFunction !== null)
|
||||
{
|
||||
this.getEqualityFunction = function ()
|
||||
{
|
||||
return equalityFunction;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var EXISTENCE = 0, ENTRY = 1, ENTRY_INDEX_AND_VALUE = 2;
|
||||
|
||||
function createBucketSearcher(mode)
|
||||
{
|
||||
return function (key)
|
||||
{
|
||||
var i = this.entries.length, entry, equals = this.getEqualityFunction(key);
|
||||
while (i--)
|
||||
{
|
||||
entry = this.entries[i];
|
||||
if (equals(key, entry[0]))
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case EXISTENCE:
|
||||
return true;
|
||||
case ENTRY:
|
||||
return entry;
|
||||
case ENTRY_INDEX_AND_VALUE:
|
||||
return [ i, entry[1] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
function createBucketLister(entryProperty)
|
||||
{
|
||||
return function (aggregatedArr)
|
||||
{
|
||||
var startIndex = aggregatedArr.length;
|
||||
for (var i = 0, len = this.entries.length; i < len; ++i)
|
||||
{
|
||||
aggregatedArr[startIndex + i] = this.entries[i][entryProperty];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Bucket.prototype = {
|
||||
getEqualityFunction:function (searchValue)
|
||||
{
|
||||
return (typeof searchValue.equals == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals;
|
||||
},
|
||||
|
||||
getEntryForKey:createBucketSearcher(ENTRY),
|
||||
|
||||
getEntryAndIndexForKey:createBucketSearcher(ENTRY_INDEX_AND_VALUE),
|
||||
|
||||
removeEntryForKey:function (key)
|
||||
{
|
||||
var result = this.getEntryAndIndexForKey(key);
|
||||
if (result)
|
||||
{
|
||||
arrayRemoveAt(this.entries, result[0]);
|
||||
return result[1];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
addEntry:function (key, value)
|
||||
{
|
||||
this.entries[this.entries.length] = [key, value];
|
||||
},
|
||||
|
||||
keys:createBucketLister(0),
|
||||
|
||||
values:createBucketLister(1),
|
||||
|
||||
getEntries:function (entries)
|
||||
{
|
||||
var startIndex = entries.length;
|
||||
for (var i = 0, len = this.entries.length; i < len; ++i)
|
||||
{
|
||||
// Clone the entry stored in the bucket before adding to array
|
||||
entries[startIndex + i] = this.entries[i].slice(0);
|
||||
}
|
||||
},
|
||||
|
||||
containsKey:createBucketSearcher(EXISTENCE),
|
||||
|
||||
containsValue:function (value)
|
||||
{
|
||||
var i = this.entries.length;
|
||||
while (i--)
|
||||
{
|
||||
if (value === this.entries[i][1])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Supporting functions for searching hashtable buckets
|
||||
|
||||
function searchBuckets(buckets, hash)
|
||||
{
|
||||
var i = buckets.length, bucket;
|
||||
while (i--)
|
||||
{
|
||||
bucket = buckets[i];
|
||||
if (hash === bucket[0])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getBucketForHash(bucketsByHash, hash)
|
||||
{
|
||||
var bucket = bucketsByHash[hash];
|
||||
|
||||
// Check that this is a genuine bucket and not something inherited from the bucketsByHash's prototype
|
||||
return ( bucket && (bucket instanceof Bucket) ) ? bucket : null;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
function Hashtable(hashingFunctionParam, equalityFunctionParam)
|
||||
{
|
||||
var that = this;
|
||||
var buckets = [];
|
||||
var bucketsByHash = {};
|
||||
|
||||
var hashingFunction = (typeof hashingFunctionParam == FUNCTION) ? hashingFunctionParam : hashObject;
|
||||
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
|
||||
|
||||
this.put = function (key, value)
|
||||
{
|
||||
checkKey(key);
|
||||
checkValue(value);
|
||||
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
bucket = getBucketForHash(bucketsByHash, hash);
|
||||
if (bucket)
|
||||
{
|
||||
// Check this bucket to see if it already contains this key
|
||||
bucketEntry = bucket.getEntryForKey(key);
|
||||
if (bucketEntry)
|
||||
{
|
||||
// This bucket entry is the current mapping of key to value, so replace old value and we're done.
|
||||
oldValue = bucketEntry[1];
|
||||
bucketEntry[1] = value;
|
||||
} else
|
||||
{
|
||||
// The bucket does not contain an entry for this key, so add one
|
||||
bucket.addEntry(key, value);
|
||||
}
|
||||
} else
|
||||
{
|
||||
// No bucket exists for the key, so create one and put our key/value mapping in
|
||||
bucket = new Bucket(hash, key, value, equalityFunction);
|
||||
buckets[buckets.length] = bucket;
|
||||
bucketsByHash[hash] = bucket;
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
this.get = function (key)
|
||||
{
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
if (bucket)
|
||||
{
|
||||
// Check this bucket to see if it contains this key
|
||||
var bucketEntry = bucket.getEntryForKey(key);
|
||||
if (bucketEntry)
|
||||
{
|
||||
// This bucket entry is the current mapping of key to value, so return the value.
|
||||
return bucketEntry[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.containsKey = function (key)
|
||||
{
|
||||
checkKey(key);
|
||||
var bucketKey = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, bucketKey);
|
||||
|
||||
return bucket ? bucket.containsKey(key) : false;
|
||||
};
|
||||
|
||||
this.containsValue = function (value)
|
||||
{
|
||||
checkValue(value);
|
||||
var i = buckets.length;
|
||||
while (i--)
|
||||
{
|
||||
if (buckets[i].containsValue(value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.clear = function ()
|
||||
{
|
||||
buckets.length = 0;
|
||||
bucketsByHash = {};
|
||||
};
|
||||
|
||||
this.isEmpty = function ()
|
||||
{
|
||||
return !buckets.length;
|
||||
};
|
||||
|
||||
var createBucketAggregator = function (bucketFuncName)
|
||||
{
|
||||
return function ()
|
||||
{
|
||||
var aggregated = [], i = buckets.length;
|
||||
while (i--)
|
||||
{
|
||||
buckets[i][bucketFuncName](aggregated);
|
||||
}
|
||||
return aggregated;
|
||||
};
|
||||
};
|
||||
|
||||
this.keys = createBucketAggregator("keys");
|
||||
this.values = createBucketAggregator("values");
|
||||
this.entries = createBucketAggregator("getEntries");
|
||||
|
||||
this.remove = function (key)
|
||||
{
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key), bucketIndex, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
|
||||
if (bucket)
|
||||
{
|
||||
// Remove entry from this bucket for this key
|
||||
oldValue = bucket.removeEntryForKey(key);
|
||||
if (oldValue !== null)
|
||||
{
|
||||
// Entry was removed, so check if bucket is empty
|
||||
if (!bucket.entries.length)
|
||||
{
|
||||
// Bucket is empty, so remove it from the bucket collections
|
||||
bucketIndex = searchBuckets(buckets, hash);
|
||||
arrayRemoveAt(buckets, bucketIndex);
|
||||
delete bucketsByHash[hash];
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldValue;
|
||||
};
|
||||
|
||||
this.size = function ()
|
||||
{
|
||||
var total = 0, i = buckets.length;
|
||||
while (i--)
|
||||
{
|
||||
total += buckets[i].entries.length;
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
this.each = function (callback)
|
||||
{
|
||||
var entries = that.entries(), i = entries.length, entry;
|
||||
while (i--)
|
||||
{
|
||||
entry = entries[i];
|
||||
callback(entry[0], entry[1]);
|
||||
}
|
||||
};
|
||||
|
||||
this.putAll = function (hashtable, conflictCallback)
|
||||
{
|
||||
var entries = hashtable.entries();
|
||||
var entry, key, value, thisValue, i = entries.length;
|
||||
var hasConflictCallback = (typeof conflictCallback == FUNCTION);
|
||||
while (i--)
|
||||
{
|
||||
entry = entries[i];
|
||||
key = entry[0];
|
||||
value = entry[1];
|
||||
|
||||
// Check for a conflict. The default behaviour is to overwrite the value for an existing key
|
||||
if (hasConflictCallback && (thisValue = that.get(key)))
|
||||
{
|
||||
value = conflictCallback(key, thisValue, value);
|
||||
}
|
||||
that.put(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
this.clone = function ()
|
||||
{
|
||||
var clone = new Hashtable(hashingFunctionParam, equalityFunctionParam);
|
||||
clone.putAll(that);
|
||||
return clone;
|
||||
};
|
||||
|
||||
/**
|
||||
* Added by martin@playcratlabs.com to support debug dumping of hash arrays
|
||||
*/
|
||||
this.toString = function ()
|
||||
{
|
||||
var result = '';
|
||||
var keys = this.keys();
|
||||
for (var i = 0; i < keys.length; i++)
|
||||
{
|
||||
var obj = this.get(keys[i]);
|
||||
result += keys[i].toString() + ' = ' + obj.toString() + '\n';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Hashtable;
|
||||
})();
|
||||
@@ -0,0 +1,204 @@
|
||||
body {
|
||||
overflow: hidden;
|
||||
font-family: "Ubuntu sans", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
color: #ddd;
|
||||
line-height: 1em;
|
||||
background: #1e1e1e;
|
||||
}
|
||||
|
||||
#panel-center {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 200px;
|
||||
right: 400px;
|
||||
}
|
||||
|
||||
#panel-left {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 200px;
|
||||
|
||||
background: #191919;
|
||||
}
|
||||
|
||||
#panel-right {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
z-index: 30;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 400px;
|
||||
|
||||
background: #191919;
|
||||
}
|
||||
|
||||
#editor {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#diagram {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
#editor-separator, #preview-separator {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
z-index: 300;
|
||||
background: #191919;
|
||||
border-top: 1px solid #292929;
|
||||
border-bottom: 1px solid #292929;
|
||||
}
|
||||
#preview-separator {
|
||||
z-index: 400;
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
#left-separator {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 3px;
|
||||
z-index: 300;
|
||||
background: #191919;
|
||||
}
|
||||
|
||||
#right-separator {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 3px;
|
||||
z-index: 300;
|
||||
background: #191919;
|
||||
}
|
||||
|
||||
#preview {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 50%;
|
||||
left: 3px;
|
||||
width: 396px;
|
||||
|
||||
background: #1e1e1e;
|
||||
border-left: 1px solid #292929;
|
||||
z-index: 210;
|
||||
}
|
||||
|
||||
#console {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
left: 3px;
|
||||
width: 396px;
|
||||
z-index: 220;
|
||||
background: #1e1e1e;
|
||||
border-left: 1px solid #292929;
|
||||
}
|
||||
|
||||
#console-text {
|
||||
background: transparent;
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #666;
|
||||
text-shadow: 0px 1px 1px #000000;
|
||||
filter: dropshadow(color=#000000, offx=0, offy=1);
|
||||
padding: 6px;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
scroll: none;
|
||||
}
|
||||
|
||||
#preview canvas {
|
||||
background: #161616;
|
||||
}
|
||||
|
||||
#modules {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 196px;
|
||||
|
||||
font-size: 13px;
|
||||
|
||||
background: #1e1e1e;
|
||||
border-right: 1px solid #292929;
|
||||
}
|
||||
|
||||
#modules ul {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
list-style: none;
|
||||
margin: 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#modules li {
|
||||
list-style: none;
|
||||
line-height: 2.0em;
|
||||
padding: 0 20px;
|
||||
background: #1e1e1e;
|
||||
cursor: pointer;
|
||||
|
||||
text-shadow: 0px 1px 1px #000000;
|
||||
filter: dropshadow(color=#000000, offx=0, offy=1);
|
||||
}
|
||||
|
||||
#modules li:hover {
|
||||
background: #434343; /* Old browsers */
|
||||
background: -moz-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* FF3.6+ */
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#888), color-stop(4%,#4e4e4e), color-stop(96%,#434343), color-stop(100%,#1e1e1e)); /* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* Opera 11.10+ */
|
||||
background: -ms-linear-gradient(top, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* IE10+ */
|
||||
background: linear-gradient(to bottom, #888 0%, #4e4e4e 4%, #434343 96%, #1e1e1e 100%); /* W3C */
|
||||
|
||||
}
|
||||
|
||||
#modules li.active {
|
||||
background: #292929;
|
||||
}
|
||||
|
||||
#render
|
||||
{
|
||||
position: absolute;
|
||||
z-index: 9999999;
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
/**
|
||||
* gamecore.js - Copyright 2012 Playcraft Labs, Inc. (see licence.txt)
|
||||
* pool.js
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class gamecore.Pool
|
||||
* Easy (high-performance) object pooling
|
||||
*
|
||||
* A pool of objects for use in situations where you want to minimize object life cycling (and
|
||||
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
|
||||
* collection for small numbers of objects.
|
||||
* <p>
|
||||
* This class maintains mutual an array of objects which are free. If you wish to maintain a list of both
|
||||
* free and used then see the gamecore.DualPool.
|
||||
* <p>
|
||||
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
|
||||
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
|
||||
* <p>
|
||||
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
|
||||
* You need to "acquire" one and then reset its state, usually via a static create factory method.
|
||||
* <p>
|
||||
* Example:
|
||||
* <code>
|
||||
* Point = gamecore.Pooled('Point',
|
||||
* {
|
||||
* // Static constructor
|
||||
* create:function (x, y)
|
||||
* {
|
||||
* var n = this._super();
|
||||
* n.x = x;
|
||||
* n.y = y;
|
||||
* return n;
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* x:0, y:0, // instance
|
||||
*
|
||||
* init: function(x, y)
|
||||
* {
|
||||
* this.x = x;
|
||||
* this.y = y;
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* To then access the object from the pool, use create, instead of new. Then release it.
|
||||
* <code>
|
||||
* var p = Point.create(100, 100);
|
||||
* // ... do something
|
||||
* p.release();
|
||||
* </code>
|
||||
*
|
||||
*/
|
||||
|
||||
gamecore.Pool = gamecore.Base.extend('gamecore.Pool',
|
||||
{
|
||||
INITIAL_POOL_SIZE:1,
|
||||
|
||||
pools:new gamecore.Hashtable(), // all your pools belong to us
|
||||
totalPooled:0,
|
||||
totalUsed:0,
|
||||
|
||||
/**
|
||||
* Acquire an object from a pool based on the class[name]. Typically this method is
|
||||
* automatically called from
|
||||
* @param classType Class of object to create
|
||||
*/
|
||||
acquire:function (classType)
|
||||
{
|
||||
var pool = this.getPool(classType);
|
||||
if (pool == undefined || pool == null)
|
||||
{
|
||||
// create a pool for this type of class
|
||||
//this.info('Constructing a new pool for ' + classType.fullName + ' objects.');
|
||||
pool = new gamecore.Pool(classType, this.INITIAL_POOL_SIZE);
|
||||
this.pools.put(classType.fullName, pool);
|
||||
}
|
||||
|
||||
return pool.acquire();
|
||||
},
|
||||
|
||||
/**
|
||||
* Releases an object back into it's corresponding object pool
|
||||
* @param pooledObj Object to return to the pool
|
||||
*/
|
||||
release:function (pooledObj)
|
||||
{
|
||||
var pool = this.pools.get(pooledObj.Class.fullName);
|
||||
if (pool == undefined)
|
||||
throw "Oops, trying to release an object of type " + pooledObj.Class.fullName +
|
||||
" but no pool exists. Did you new an object instead of using create.";
|
||||
|
||||
pool.release(pooledObj);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the pool associated with the given classType, or null if no pool currently exists
|
||||
*/
|
||||
getPool:function (classType)
|
||||
{
|
||||
return this.pools.get(classType.fullName);
|
||||
},
|
||||
|
||||
getStats:function ()
|
||||
{
|
||||
var s = '';
|
||||
|
||||
var keys = this.pools.keys();
|
||||
for (var i = 0; i < keys.length; i++)
|
||||
{
|
||||
var key = keys[i];
|
||||
var pool = this.pools.get(key);
|
||||
s += key + ': ' + pool.getStats() + '\n';
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
freeList:null,
|
||||
expansion: 1,
|
||||
traces: null,
|
||||
|
||||
/**
|
||||
* Constructs a pool using a base of objects passed in as an array.
|
||||
* @param classType Class name of the type of objects in the pool
|
||||
* @param initial Starting number of objects in the pool
|
||||
*/
|
||||
init:function (classType, initial)
|
||||
{
|
||||
this._super();
|
||||
this.classType = classType;
|
||||
this.freeList = [];
|
||||
|
||||
// instantiate the initial objects for the pool
|
||||
this.expand(initial);
|
||||
},
|
||||
|
||||
|
||||
startTracing:function ()
|
||||
{
|
||||
if (this.tracing) return;
|
||||
this.tracing = true;
|
||||
if (this.traces)
|
||||
this.traces.clear();
|
||||
else
|
||||
this.traces = new gamecore.Hashtable();
|
||||
},
|
||||
|
||||
stopTracing:function ()
|
||||
{
|
||||
this.tracing = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Expand the pool of objects by constructing a bunch of new ones. The pool will
|
||||
* automatically expand itself by 10% each time it runs out of space, so generally you
|
||||
* shouldn't need to use this.
|
||||
* @param howMany Number of new objects you want to add
|
||||
*/
|
||||
expand:function (howMany)
|
||||
{
|
||||
gamecore.Pool.totalPooled += howMany;
|
||||
|
||||
//debug: if you want to track expansion
|
||||
//this.debug('expanding ' + this.classType.fullName + ' by ' + howMany + ' total=' + gamecore.Pool.totalPooled);
|
||||
|
||||
for (var i = 0; i < howMany; i++)
|
||||
this.freeList.push(new this.classType());
|
||||
},
|
||||
|
||||
getFreeCount: function()
|
||||
{
|
||||
return this.freeList.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the next free object by moving it from the free pool to the used
|
||||
* one. If no free objects are available it returns the oldest from the used
|
||||
* pool.
|
||||
* access to the object
|
||||
*/
|
||||
acquire:function ()
|
||||
{
|
||||
// check if we have anymore to give out
|
||||
if (this.freeList.length <= 0)
|
||||
{
|
||||
// create some more space (expand by 20%, minimum 1)
|
||||
this.expansion = Math.round(this.expansion*1.2)+1;
|
||||
this.expand(this.expansion);
|
||||
}
|
||||
|
||||
if (this.tracing)
|
||||
{
|
||||
var stack = printStackTrace();
|
||||
var pos = stack.length - 1;
|
||||
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
|
||||
pos--;
|
||||
var count = this.traces.get(stack[pos]);
|
||||
if (count == null)
|
||||
this.traces.put(stack[pos], { value:1 });
|
||||
else
|
||||
count.value++;
|
||||
}
|
||||
|
||||
return this.freeList.pop();
|
||||
},
|
||||
|
||||
/**
|
||||
* Releases an object by moving it from the used list back to the free list.
|
||||
* @param obj {pc.Base} The obj to release back into the pool
|
||||
*/
|
||||
release:function (obj)
|
||||
{
|
||||
this.freeList.push(obj);
|
||||
},
|
||||
|
||||
getStats:function ()
|
||||
{
|
||||
var s = this.Class.fullName + ' stats: ' + this.freeList.length + ' free.\n';
|
||||
|
||||
if (this.tracing)
|
||||
{
|
||||
s += 'TRACING\n';
|
||||
var traceKeys = this.traces.keys();
|
||||
for (var k in traceKeys)
|
||||
s += traceKeys[k] + ' (' + this.traces.get(traceKeys[k]).value + ')\n';
|
||||
}
|
||||
return s;
|
||||
},
|
||||
|
||||
dump:function (msg)
|
||||
{
|
||||
this.info('================== ' + msg + ' ===================');
|
||||
this.info('FREE');
|
||||
this.freeList.dump();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the number of objects in the pool
|
||||
*/
|
||||
size:function ()
|
||||
{
|
||||
return this.freeList.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the LinkedList of currently free objects in the pool
|
||||
*/
|
||||
getFreeList:function ()
|
||||
{
|
||||
return this.freeList;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* @class gamecore.DualPool
|
||||
* Easy (high-performance) object pooling
|
||||
*
|
||||
* A pool of objects for use in situations where you want to minimize object life cycling (and
|
||||
* subsequently garbage collection). It also serves as a very high speed, minimal overhead
|
||||
* collection for small numbers of objects.
|
||||
* <p>
|
||||
* This class maintains mutual set of doubly-linked lists in order to differentiate between
|
||||
* objects that are in use and those that are unallocated from the pool. This allows for much
|
||||
* faster cycling of only the in-use objects.
|
||||
* <p>
|
||||
* Pools are managed by class type, and will auto-expand as required. You can create a custom initial pool
|
||||
* size by deriving from the Pool class and statically overriding INITIAL_POOL_SIZE.
|
||||
* <p>
|
||||
* Keep in mind that objects that are pooled are not constructed; they are "reset" when handed out.
|
||||
* You need to "acquire" one and then reset its state, usually via a static create factory method.
|
||||
* <p>
|
||||
* Example:
|
||||
* <code>
|
||||
* Point = gamecore.Pooled('Point',
|
||||
* {
|
||||
* // Static constructor
|
||||
* create:function (x, y)
|
||||
* {
|
||||
* var n = this._super();
|
||||
* n.x = x;
|
||||
* n.y = y;
|
||||
* return n;
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* x:0, y:0, // instance
|
||||
*
|
||||
* init: function(x, y)
|
||||
* {
|
||||
* this.x = x;
|
||||
* this.y = y;
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* To then access the object from the pool, use create, instead of new. Then release it.
|
||||
* <code>
|
||||
* var p = Point.create(100, 100);
|
||||
* // ... do something
|
||||
* p.release();
|
||||
* </code>
|
||||
*
|
||||
*/
|
||||
|
||||
gamecore.DualPool = gamecore.Pool.extend('gamecore.DualPool',
|
||||
{
|
||||
acquire:function (classType)
|
||||
{
|
||||
var pool = this.getPool(classType);
|
||||
if (pool == undefined || pool == null)
|
||||
{
|
||||
pool = new gamecore.DualPool(classType, this.INITIAL_POOL_SIZE);
|
||||
this.pools.put(classType.fullName, pool);
|
||||
}
|
||||
|
||||
return pool.acquire();
|
||||
},
|
||||
|
||||
getStats:function ()
|
||||
{
|
||||
var s = '';
|
||||
|
||||
var keys = this.pools.keys();
|
||||
for (var i = 0; i < keys.length; i++)
|
||||
{
|
||||
var key = keys[i];
|
||||
var pool = this.pools.get(key);
|
||||
s += key + ' (free: ' + pool.freeList.length() + ' used: ' + pool.usedList.length() + ')\n';
|
||||
}
|
||||
return s;
|
||||
}
|
||||
},
|
||||
///
|
||||
/// INSTANCE
|
||||
///
|
||||
{
|
||||
freeList:null,
|
||||
usedList:null,
|
||||
|
||||
/**
|
||||
* Constructs a pool using a base of objects passed in as an array.
|
||||
* @param classType Class name of the type of objects in the pool
|
||||
* @param initial Starting number of objects in the pool
|
||||
*/
|
||||
init:function (classType, initial)
|
||||
{
|
||||
this.classType = classType;
|
||||
this.usedList = new gamecore.LinkedList();
|
||||
this.freeList = new gamecore.LinkedList();
|
||||
|
||||
// instantiate the initial objects for the pool
|
||||
this.expand(initial);
|
||||
},
|
||||
|
||||
/**
|
||||
* Expand the pool of objects by constructing a bunch of new ones. The pool will
|
||||
* automatically expand itself by 10% each time it runs out of space, so generally you
|
||||
* shouldn't need to use this.
|
||||
* @param howMany Number of new objects you want to add
|
||||
*/
|
||||
expand:function (howMany)
|
||||
{
|
||||
// this.info('Expanding ' + this.classType.fullName + ' pool from ' + this.size() +
|
||||
// ' to ' + (this.size() + howMany) + ' objects');
|
||||
gamecore.Pool.totalPooled += howMany;
|
||||
for (var i = 0; i < howMany; i++)
|
||||
this.freeList.add(new this.classType());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the next free object by moving it from the free pool to the used
|
||||
* one. If no free objects are available it returns the oldest from the used
|
||||
* pool.
|
||||
* access to the object
|
||||
*/
|
||||
returnObj:null,
|
||||
|
||||
acquire:function ()
|
||||
{
|
||||
// check if we have anymore to give out
|
||||
if (this.freeList.first == null)
|
||||
// create some more space (expand by 20%, minimum 1)
|
||||
this.expand(Math.round(this.size() / 5) + 1);
|
||||
|
||||
this.returnObj = this.freeList.first.obj;
|
||||
this.freeList.remove(this.returnObj);
|
||||
this.returnObj.destroyed = false;
|
||||
this.usedList.add(this.returnObj);
|
||||
|
||||
if (this.tracing)
|
||||
{
|
||||
var stack = printStackTrace();
|
||||
var pos = stack.length - 1;
|
||||
while (stack[pos].indexOf('Class.addTo') == 0 && pos > 0)
|
||||
pos--;
|
||||
var count = this.traces.get(stack[pos]);
|
||||
if (count == null)
|
||||
this.traces.put(stack[pos], { value:1 });
|
||||
else
|
||||
count.value++;
|
||||
}
|
||||
|
||||
return this.returnObj;
|
||||
},
|
||||
|
||||
/**
|
||||
* Releases an object by moving it from the used list back to the free list.
|
||||
* @param obj {pc.Base} The obj to release back into the pool
|
||||
*/
|
||||
release:function (obj)
|
||||
{
|
||||
this.freeList.add(obj);
|
||||
this.usedList.remove(obj);
|
||||
},
|
||||
|
||||
dump:function (msg)
|
||||
{
|
||||
this.info('================== ' + msg + ' ===================');
|
||||
this.info('FREE');
|
||||
this.freeList.dump();
|
||||
this.info('USED');
|
||||
this.usedList.dump();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the number of objects in the pool
|
||||
*/
|
||||
size:function ()
|
||||
{
|
||||
return this.freeList.count + this.usedList.count;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the LinkedList of current used objects in the pool
|
||||
* @return {*}
|
||||
*/
|
||||
getUsedList:function ()
|
||||
{
|
||||
return this.usedList;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @class gamecore.Pooled
|
||||
* Used as a base class for objects which are life cycle managed in an object pool.
|
||||
*/
|
||||
gamecore.Pooled = gamecore.Base('gamecore.Pooled',
|
||||
///
|
||||
/// STATICS
|
||||
///
|
||||
{
|
||||
/**
|
||||
* Static factory method for creating a new object based on its class. This method
|
||||
* should be called using this._super from the Class.create that derives from this.
|
||||
* @returns An object from the pool
|
||||
*/
|
||||
create:function ()
|
||||
{
|
||||
return gamecore.Pool.acquire(this);
|
||||
},
|
||||
|
||||
getPool:function ()
|
||||
{
|
||||
return gamecore.Pool.getPool(this);
|
||||
}
|
||||
|
||||
},
|
||||
///
|
||||
/// INSTANCE
|
||||
///
|
||||
{
|
||||
destroyed:false,
|
||||
|
||||
init:function ()
|
||||
{
|
||||
this._super();
|
||||
},
|
||||
|
||||
release:function ()
|
||||
{
|
||||
this.onRelease();
|
||||
gamecore.Pool.release(this);
|
||||
},
|
||||
|
||||
onRelease:function ()
|
||||
{
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @class gamecore.DualPooled
|
||||
* Used as a base class for objects which are life cycle managed in an object pool (the DualPool edition)
|
||||
*/
|
||||
gamecore.DualPooled = gamecore.Base('gamecore.DualPooled',
|
||||
///
|
||||
/// STATICS
|
||||
///
|
||||
{
|
||||
/**
|
||||
* Static factory method for creating a new object based on its class. This method
|
||||
* should be called using this._super from the Class.create that derives from this.
|
||||
* @returns An object from the pool
|
||||
*/
|
||||
create:function ()
|
||||
{
|
||||
return gamecore.DualPool.acquire(this);
|
||||
},
|
||||
|
||||
getPool:function ()
|
||||
{
|
||||
return gamecore.DualPool.getPool(this);
|
||||
}
|
||||
|
||||
},
|
||||
///
|
||||
/// INSTANCE
|
||||
///
|
||||
{
|
||||
destroyed:false,
|
||||
|
||||
init:function ()
|
||||
{
|
||||
this._super();
|
||||
},
|
||||
|
||||
release:function ()
|
||||
{
|
||||
this.onRelease();
|
||||
gamecore.DualPool.release(this);
|
||||
},
|
||||
|
||||
onRelease:function ()
|
||||
{
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
ace.define("ace/theme/monokai",["require","exports","module","ace/lib/dom"],function(a,b,c){b.isDark=!0,b.cssClass="ace-monokai",b.cssText=".ace-monokai .ace_editor { border: 2px solid rgb(159, 159, 159)}.ace-monokai .ace_editor.ace_focus { border: 2px solid #327fbd}.ace-monokai .ace_gutter { background: #2f3129; color: #f1f1f1}.ace-monokai .ace_print_margin { width: 1px; background: #555651}.ace-monokai .ace_scroller { background-color: #272822}.ace-monokai .ace_text-layer { color: #F8F8F2}.ace-monokai .ace_cursor { border-left: 2px solid #F8F8F0}.ace-monokai .ace_cursor.ace_overwrite { border-left: 0px; border-bottom: 1px solid #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection { background: #49483E}.ace-monokai.multiselect .ace_selection.start { box-shadow: 0 0 3px 0px #272822; border-radius: 2px}.ace-monokai .ace_marker-layer .ace_step { background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket { margin: -1px 0 0 -1px; border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active_line { background: #202020}.ace-monokai .ace_gutter_active_line { background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected_word { border: 1px solid #49483E}.ace-monokai .ace_invisible { color: #49483E}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta,.ace-monokai .ace_storage { color: #F92672}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other { color: #AE81FF}.ace-monokai .ace_invalid { color: #F8F8F0; background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated { color: #F8F8F0; background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function { color: #66D9EF}.ace-monokai .ace_fold { background-color: #A6E22E; border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type { font-style: italic; color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable { color: #A6E22E}.ace-monokai .ace_variable.ace_parameter { font-style: italic; color: #FD971F}.ace-monokai .ace_string { color: #E6DB74}.ace-monokai .ace_comment { color: #75715E}.ace-monokai .ace_markup.ace_underline { text-decoration: underline}.ace-monokai .ace_indent-guide { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNQ11D6z7Bq1ar/ABCKBG6g04U2AAAAAElFTkSuQmCC) right repeat-y}";var d=a("../lib/dom");d.importCssString(b.cssText,b.cssClass)})
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "HexGL",
|
||||
"description": "HexGL v1.0.1-ffos",
|
||||
"launch_path": "/index.html",
|
||||
"icons": {
|
||||
"32": "/icon_32.png",
|
||||
"64": "/icon_64.png",
|
||||
"128": "/icon_128.png",
|
||||
"256": "/icon_256.png"
|
||||
},
|
||||
"developer": {
|
||||
"name": "Thibaut Despoulain (BKcore)",
|
||||
"url": "http://bkcore.com"
|
||||
},
|
||||
"installs_allowed_from": ["*"],
|
||||
"default_locale": "en",
|
||||
"orientation": ["landscape"]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "HexGL",
|
||||
"description": "HexGL v1.0.1-ffos",
|
||||
"package_path" : "package.zip",
|
||||
"version": "1",
|
||||
"developer": {
|
||||
"name": "Thibaut Despoulain (BKcore)",
|
||||
"url": "http://bkcore.com"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 340 B |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 419 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 288 KiB |
|
After Width: | Height: | Size: 307 KiB |
|
After Width: | Height: | Size: 328 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 385 KiB |
|
After Width: | Height: | Size: 205 KiB |
|
After Width: | Height: | Size: 633 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 308 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 203 KiB |
|
After Width: | Height: | Size: 434 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 419 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 288 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 385 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 64 KiB |