Merge pull request #13 from BKcore/leapmotion
Merge dev and leapmotion changes to master.
@@ -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"
|
||||
@@ -9,12 +9,22 @@ Source code of [HexGL](http://hexgl.bkcore.com), the futuristic HTML5 racing gam
|
||||
|
||||
## License
|
||||
|
||||
Unless specified in the file, HexGL's code and resources are licensed under the *Creative Commons Attribution-NonCommercial 3.0 Unported License*.
|
||||
Unless specified in the file, HexGL's code and resources are licensed under the *Creative Commons Attribution-NonCommercial 3.0 Unported License*.
|
||||
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
|
||||
|
||||
If you feel like you deserve another license for a special case, [drop me a note](http://bkcore.com/contact.html), and we'll talk about it.
|
||||
|
||||
## Installation
|
||||
|
||||
cd ~/
|
||||
git clone git://github.com/BKcore/HexGL.git
|
||||
cd HexGL
|
||||
python -m SimpleHTTPServer
|
||||
chromium index.html
|
||||
|
||||
To use full size textures, swap the two textures/ and textures.full/ directories.
|
||||
|
||||
## Regarding the code
|
||||
|
||||
As of now the code is pretty much raw and undocumented. I'll be commenting it someday, but that won't be until I've finished the next content update and code refactoring sorry!
|
||||
@@ -24,4 +34,4 @@ There will also be some refactoring, when I get some time :P
|
||||
|
||||
After much thinking, I've decided to release HexGL's source code under CC 3.0 BY-NC until further notice. This is not a definite choice, and the game may end up under the MIT license someday.
|
||||
|
||||
Feel free to post issues, patch or anything to make the game better.
|
||||
Feel free to post issues, patch or anything to make the game better.
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
###
|
||||
Loads an image and gives access to pixel data.
|
||||
|
||||
@class bkcore.ImageData
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class ImageData
|
||||
|
||||
###
|
||||
Creates a new ImageData object
|
||||
|
||||
@param path string The path of the image
|
||||
@param callback function A callback function to be called
|
||||
once th eimage is loaded
|
||||
###
|
||||
constructor: (path, callback)->
|
||||
|
||||
@image = new Image
|
||||
@pixels = null
|
||||
@canvas = null
|
||||
@loaded = false
|
||||
|
||||
@image.onload = ()=>
|
||||
|
||||
@canvas = document.createElement('canvas')
|
||||
@canvas.width = @image.width
|
||||
@canvas.height = @image.height
|
||||
|
||||
context = @canvas.getContext('2d')
|
||||
context.drawImage(@image, 0, 0)
|
||||
|
||||
@pixels = context.getImageData(0,0, @canvas.width, @canvas.height)
|
||||
@loaded = true
|
||||
|
||||
context = null
|
||||
@canvas = null
|
||||
@image = null
|
||||
|
||||
callback?.call(@)
|
||||
|
||||
@image.crossOrigin = "anonymous"
|
||||
@image.src = path
|
||||
|
||||
###
|
||||
Gets pixel RGBA data at given index
|
||||
|
||||
@param x int In pixels
|
||||
@param y int In pixels
|
||||
@return Object{r,g,b,a}
|
||||
###
|
||||
getPixel: (x, y)->
|
||||
|
||||
if !@pixels? or x < 0 or y < 0 or x >= @pixels.width or y >= @pixels.height
|
||||
return {r: 0, g: 0, b:0, a:0}
|
||||
|
||||
i = (y*@pixels.width + x) * 4
|
||||
|
||||
return {
|
||||
r: @pixels.data[i]
|
||||
g: @pixels.data[i+1]
|
||||
b: @pixels.data[i+2]
|
||||
a: @pixels.data[i+3]
|
||||
}
|
||||
|
||||
###
|
||||
Gets pixel RGBA data at given float index using bilinear interpolation
|
||||
|
||||
@param x float In subpixels
|
||||
@param y float In subpixels
|
||||
@return Object{r,g,b,a}
|
||||
###
|
||||
getPixelBilinear: (fx, fy)->
|
||||
|
||||
x = Math.floor(fx)
|
||||
y = Math.floor(fy)
|
||||
rx = fx - x - .5
|
||||
ry = fy - y - .5
|
||||
ax = Math.abs(rx)
|
||||
ay = Math.abs(ry)
|
||||
dx = if rx < 0 then -1 else 1
|
||||
dy = if ry < 0 then -1 else 1
|
||||
|
||||
c = @getPixel(x, y)
|
||||
cx = @getPixel(x+dx, y)
|
||||
cy = @getPixel(x, y+dy)
|
||||
cxy = @getPixel(x+dx, y+dy)
|
||||
|
||||
cf1 = [
|
||||
(1-ax) * c.r + ax * cx.r
|
||||
(1-ax) * c.g + ax * cx.g
|
||||
(1-ax) * c.b + ax * cx.b
|
||||
(1-ax) * c.a + ax * cx.a
|
||||
]
|
||||
|
||||
cf2 = [
|
||||
(1-ax) * cy.r + ax * cxy.r
|
||||
(1-ax) * cy.g + ax * cxy.g
|
||||
(1-ax) * cy.b + ax * cxy.b
|
||||
(1-ax) * cy.a + ax * cxy.a
|
||||
]
|
||||
|
||||
return {
|
||||
r: (1-ay) * cf1[0] + ay * cf2[0]
|
||||
g: (1-ay) * cf1[1] + ay * cf2[1]
|
||||
b: (1-ay) * cf1[2] + ay * cf2[2]
|
||||
a: (1-ay) * cf1[3] + ay * cf2[3]
|
||||
}
|
||||
|
||||
###
|
||||
Gets pixel data at given index
|
||||
as 3-bytes integer (for floating-point textures erzats, from RGB values)
|
||||
|
||||
@param x int In pixels
|
||||
@param y int In pixels
|
||||
@return int (R + G*255 + B*255*255)
|
||||
###
|
||||
getPixelF: (x, y)->
|
||||
|
||||
c = @getPixel(x, y)
|
||||
return c.r + c.g * 255 + c.b * 255 * 255
|
||||
|
||||
###
|
||||
Gets pixel data at given float index using bilinear interpolationas
|
||||
as 3-bytes integer (for floating-point textures erzats, from RGB values)
|
||||
|
||||
@param x float In subpixels
|
||||
@param y float In subpixels
|
||||
@return Object{r,g,b,a}
|
||||
###
|
||||
getPixelFBilinear: (fx, fy)->
|
||||
|
||||
c = @getPixelBilinear(fx, fy)
|
||||
return c.r + c.g * 255 + c.b * 255 * 255
|
||||
|
||||
###
|
||||
Exports
|
||||
@package bkcore
|
||||
###
|
||||
exports = exports ? @
|
||||
exports.bkcore ||= {}
|
||||
exports.bkcore.ImageData = ImageData
|
||||
@@ -0,0 +1,156 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
|
||||
/*
|
||||
Loads an image and gives access to pixel data.
|
||||
|
||||
@class bkcore.ImageData
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var ImageData, exports;
|
||||
|
||||
ImageData = (function() {
|
||||
/*
|
||||
Creates a new ImageData object
|
||||
|
||||
@param path string The path of the image
|
||||
@param callback function A callback function to be called
|
||||
once th eimage is loaded
|
||||
*/
|
||||
|
||||
function ImageData(path, callback) {
|
||||
var _this = this;
|
||||
this.image = new Image;
|
||||
this.pixels = null;
|
||||
this.canvas = null;
|
||||
this.loaded = false;
|
||||
this.image.onload = function() {
|
||||
var context;
|
||||
_this.canvas = document.createElement('canvas');
|
||||
_this.canvas.width = _this.image.width;
|
||||
_this.canvas.height = _this.image.height;
|
||||
context = _this.canvas.getContext('2d');
|
||||
context.drawImage(_this.image, 0, 0);
|
||||
_this.pixels = context.getImageData(0, 0, _this.canvas.width, _this.canvas.height);
|
||||
_this.loaded = true;
|
||||
context = null;
|
||||
_this.canvas = null;
|
||||
_this.image = null;
|
||||
return callback != null ? callback.call(_this) : void 0;
|
||||
};
|
||||
this.image.crossOrigin = "anonymous";
|
||||
this.image.src = path;
|
||||
}
|
||||
|
||||
/*
|
||||
Gets pixel RGBA data at given index
|
||||
|
||||
@param x int In pixels
|
||||
@param y int In pixels
|
||||
@return Object{r,g,b,a}
|
||||
*/
|
||||
|
||||
|
||||
ImageData.prototype.getPixel = function(x, y) {
|
||||
var i;
|
||||
if (!(this.pixels != null) || x < 0 || y < 0 || x >= this.pixels.width || y >= this.pixels.height) {
|
||||
return {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
a: 0
|
||||
};
|
||||
}
|
||||
i = (y * this.pixels.width + x) * 4;
|
||||
return {
|
||||
r: this.pixels.data[i],
|
||||
g: this.pixels.data[i + 1],
|
||||
b: this.pixels.data[i + 2],
|
||||
a: this.pixels.data[i + 3]
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Gets pixel RGBA data at given float index using bilinear interpolation
|
||||
|
||||
@param x float In subpixels
|
||||
@param y float In subpixels
|
||||
@return Object{r,g,b,a}
|
||||
*/
|
||||
|
||||
|
||||
ImageData.prototype.getPixelBilinear = function(fx, fy) {
|
||||
var ax, ay, c, cf1, cf2, cx, cxy, cy, dx, dy, rx, ry, x, y;
|
||||
x = Math.floor(fx);
|
||||
y = Math.floor(fy);
|
||||
rx = fx - x - .5;
|
||||
ry = fy - y - .5;
|
||||
ax = Math.abs(rx);
|
||||
ay = Math.abs(ry);
|
||||
dx = rx < 0 ? -1 : 1;
|
||||
dy = ry < 0 ? -1 : 1;
|
||||
c = this.getPixel(x, y);
|
||||
cx = this.getPixel(x + dx, y);
|
||||
cy = this.getPixel(x, y + dy);
|
||||
cxy = this.getPixel(x + dx, y + dy);
|
||||
cf1 = [(1 - ax) * c.r + ax * cx.r, (1 - ax) * c.g + ax * cx.g, (1 - ax) * c.b + ax * cx.b, (1 - ax) * c.a + ax * cx.a];
|
||||
cf2 = [(1 - ax) * cy.r + ax * cxy.r, (1 - ax) * cy.g + ax * cxy.g, (1 - ax) * cy.b + ax * cxy.b, (1 - ax) * cy.a + ax * cxy.a];
|
||||
return {
|
||||
r: (1 - ay) * cf1[0] + ay * cf2[0],
|
||||
g: (1 - ay) * cf1[1] + ay * cf2[1],
|
||||
b: (1 - ay) * cf1[2] + ay * cf2[2],
|
||||
a: (1 - ay) * cf1[3] + ay * cf2[3]
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
Gets pixel data at given index
|
||||
as 3-bytes integer (for floating-point textures erzats, from RGB values)
|
||||
|
||||
@param x int In pixels
|
||||
@param y int In pixels
|
||||
@return int (R + G*255 + B*255*255)
|
||||
*/
|
||||
|
||||
|
||||
ImageData.prototype.getPixelF = function(x, y) {
|
||||
var c;
|
||||
c = this.getPixel(x, y);
|
||||
return c.r + c.g * 255 + c.b * 255 * 255;
|
||||
};
|
||||
|
||||
/*
|
||||
Gets pixel data at given float index using bilinear interpolationas
|
||||
as 3-bytes integer (for floating-point textures erzats, from RGB values)
|
||||
|
||||
@param x float In subpixels
|
||||
@param y float In subpixels
|
||||
@return Object{r,g,b,a}
|
||||
*/
|
||||
|
||||
|
||||
ImageData.prototype.getPixelFBilinear = function(fx, fy) {
|
||||
var c;
|
||||
c = this.getPixelBilinear(fx, fy);
|
||||
return c.r + c.g * 255 + c.b * 255 * 255;
|
||||
};
|
||||
|
||||
return ImageData;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Exports
|
||||
@package bkcore
|
||||
*/
|
||||
|
||||
|
||||
exports = exports != null ? exports : this;
|
||||
|
||||
exports.bkcore || (exports.bkcore = {});
|
||||
|
||||
exports.bkcore.ImageData = ImageData;
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,118 @@
|
||||
###
|
||||
new Date().getTime() wrapper to use as timer.
|
||||
|
||||
@class bkcore.Timer
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class Timer
|
||||
|
||||
###
|
||||
Creates a new timer, inactive by default.
|
||||
Call Timer.start() to activate.
|
||||
###
|
||||
constructor: ()->
|
||||
|
||||
@time =
|
||||
start: 0
|
||||
current: 0
|
||||
previous: 0
|
||||
elapsed: 0
|
||||
delta: 0
|
||||
|
||||
@active = false
|
||||
|
||||
###
|
||||
Starts/restarts the timer.
|
||||
###
|
||||
start: ()->
|
||||
|
||||
now = (new Date).getTime()
|
||||
|
||||
@time.start = now
|
||||
@time.current = now
|
||||
@time.previous = now
|
||||
@time.elapsed = 0
|
||||
@time.delta = 0
|
||||
|
||||
@active = true
|
||||
|
||||
###
|
||||
Pauses(true)/Unpauses(false) the timer.
|
||||
|
||||
@param bool Do pause
|
||||
###
|
||||
pause: (doPause)->
|
||||
|
||||
@active = not doPause
|
||||
|
||||
###
|
||||
Update method to be called inside a RAF loop
|
||||
###
|
||||
update: ()->
|
||||
|
||||
if not @active then return
|
||||
|
||||
now = (new Date).getTime()
|
||||
|
||||
@time.current = now
|
||||
@time.elapsed = @time.current - @time.start
|
||||
@time.delta = now - @time.previous
|
||||
@time.previous = now
|
||||
|
||||
###
|
||||
Returns a formatted version of the current elapsed time using msToTime().
|
||||
###
|
||||
getElapsedTime: ()->
|
||||
|
||||
return @constructor.msToTime(@time.elapsed)
|
||||
|
||||
###
|
||||
Formats a millisecond integer into a h/m/s/ms object
|
||||
|
||||
@param x int In milliseconds
|
||||
@return Object{h,m,s,ms}
|
||||
###
|
||||
@msToTime: (t)->
|
||||
|
||||
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}
|
||||
###
|
||||
@msToTimeString: (t)->
|
||||
|
||||
time = @msToTime(t)
|
||||
|
||||
time.h = @zfill(time.h, 2)
|
||||
time.m = @zfill(time.m, 2)
|
||||
time.s = @zfill(time.s, 2)
|
||||
time.ms = @zfill(time.ms, 4)
|
||||
|
||||
return time
|
||||
|
||||
###
|
||||
Convert given integer to string and fill with heading zeros
|
||||
|
||||
@param num int Number to convert/fill
|
||||
@param size int Desired string size
|
||||
###
|
||||
@zfill: (num, size)->
|
||||
|
||||
len = size - num.toString().length
|
||||
return if len > 0 then new Array(len+1).join('0') + num else num.toString()
|
||||
|
||||
###
|
||||
Exports
|
||||
@package bkcore
|
||||
###
|
||||
exports = exports ? @
|
||||
exports.bkcore ||= {}
|
||||
exports.bkcore.Timer = Timer
|
||||
@@ -0,0 +1,159 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
|
||||
/*
|
||||
new Date().getTime() wrapper to use as timer.
|
||||
|
||||
@class bkcore.Timer
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var Timer, exports;
|
||||
|
||||
Timer = (function() {
|
||||
/*
|
||||
Creates a new timer, inactive by default.
|
||||
Call Timer.start() to activate.
|
||||
*/
|
||||
|
||||
function Timer() {
|
||||
this.time = {
|
||||
start: 0,
|
||||
current: 0,
|
||||
previous: 0,
|
||||
elapsed: 0,
|
||||
delta: 0
|
||||
};
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Starts/restarts the timer.
|
||||
*/
|
||||
|
||||
|
||||
Timer.prototype.start = function() {
|
||||
var now;
|
||||
now = (new Date).getTime();
|
||||
this.time.start = now;
|
||||
this.time.current = now;
|
||||
this.time.previous = now;
|
||||
this.time.elapsed = 0;
|
||||
this.time.delta = 0;
|
||||
return this.active = true;
|
||||
};
|
||||
|
||||
/*
|
||||
Pauses(true)/Unpauses(false) the timer.
|
||||
|
||||
@param bool Do pause
|
||||
*/
|
||||
|
||||
|
||||
Timer.prototype.pause = function(doPause) {
|
||||
return this.active = !doPause;
|
||||
};
|
||||
|
||||
/*
|
||||
Update method to be called inside a RAF loop
|
||||
*/
|
||||
|
||||
|
||||
Timer.prototype.update = function() {
|
||||
var now;
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
now = (new Date).getTime();
|
||||
this.time.current = now;
|
||||
this.time.elapsed = this.time.current - this.time.start;
|
||||
this.time.delta = now - this.time.previous;
|
||||
return this.time.previous = now;
|
||||
};
|
||||
|
||||
/*
|
||||
Returns a formatted version of the current elapsed time using msToTime().
|
||||
*/
|
||||
|
||||
|
||||
Timer.prototype.getElapsedTime = function() {
|
||||
return this.constructor.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}
|
||||
*/
|
||||
|
||||
|
||||
Timer.msToTime = function(t) {
|
||||
var h, m, ms, s;
|
||||
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,
|
||||
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}
|
||||
*/
|
||||
|
||||
|
||||
Timer.msToTimeString = function(t) {
|
||||
var time;
|
||||
time = this.msToTime(t);
|
||||
time.h = this.zfill(time.h, 2);
|
||||
time.m = this.zfill(time.m, 2);
|
||||
time.s = this.zfill(time.s, 2);
|
||||
time.ms = this.zfill(time.ms, 4);
|
||||
return time;
|
||||
};
|
||||
|
||||
/*
|
||||
Convert given integer to string and fill with heading zeros
|
||||
|
||||
@param num int Number to convert/fill
|
||||
@param size int Desired string size
|
||||
*/
|
||||
|
||||
|
||||
Timer.zfill = function(num, size) {
|
||||
var len;
|
||||
len = size - num.toString().length;
|
||||
if (len > 0) {
|
||||
return new Array(len + 1).join('0') + num;
|
||||
} else {
|
||||
return num.toString();
|
||||
}
|
||||
};
|
||||
|
||||
return Timer;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Exports
|
||||
@package bkcore
|
||||
*/
|
||||
|
||||
|
||||
exports = exports != null ? exports : this;
|
||||
|
||||
exports.bkcore || (exports.bkcore = {});
|
||||
|
||||
exports.bkcore.Timer = Timer;
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,185 @@
|
||||
###
|
||||
Various useful methods
|
||||
|
||||
@class bkcore.Utils
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class Utils
|
||||
|
||||
###
|
||||
Creates a bkcore.threejs.Shaders["normalV"|"normal"] material
|
||||
with given parameters
|
||||
###
|
||||
@createNormalMaterial = (opts)->
|
||||
|
||||
opts ?= {}
|
||||
opts.ambient ?= 0x444444
|
||||
opts.normalScale ?= 1.0
|
||||
opts.reflectivity ?= 0.9
|
||||
opts.shininess ?= 42
|
||||
opts.metal ?= false
|
||||
|
||||
shadername = if opts.perPixel then "normalV" else "normal"
|
||||
shader = bkcore.threejs.Shaders[shadername]
|
||||
uniforms = THREE.UniformsUtils.clone(shader.uniforms)
|
||||
|
||||
uniforms["enableDiffuse"].value = true
|
||||
uniforms["enableSpecular"].value = true
|
||||
uniforms["enableReflection"].value = !!opts.cube
|
||||
uniforms["tNormal"].texture = opts.normal
|
||||
uniforms["tDiffuse"].texture = opts.diffuse
|
||||
uniforms["tSpecular"].texture = opts.specular
|
||||
uniforms["uAmbientColor"].value.setHex(opts.ambient)
|
||||
uniforms["uAmbientColor"].value.convertGammaToLinear()
|
||||
uniforms["uNormalScale"].value = opts.normalScale
|
||||
|
||||
if opts.cube?
|
||||
uniforms["tCube"].texture = opts.cube
|
||||
uniforms["uReflectivity"].value = opts.reflectivity
|
||||
|
||||
parameters = {
|
||||
fragmentShader: shader.fragmentShader
|
||||
vertexShader: shader.vertexShader
|
||||
uniforms: uniforms
|
||||
lights: true
|
||||
fog: false
|
||||
}
|
||||
|
||||
material = new THREE.ShaderMaterial(parameters)
|
||||
material.perPixel = true
|
||||
material.metal = opts.metal
|
||||
|
||||
return material
|
||||
|
||||
###
|
||||
Projects an object origin vector to screen using given camera
|
||||
@param THREE.Object3D object The object which origin you want to project
|
||||
@param THREE.Camera camera The camera of the projection
|
||||
@return THEE.Vector3 Projected verctor
|
||||
###
|
||||
@projectOnScreen: (object, camera)->
|
||||
|
||||
mat = new THREE.Matrix4()
|
||||
mat.multiply(camera.matrixWorldInverse, object.matrixWorld)
|
||||
mat.multiply(camera.projectionMatrix , mat)
|
||||
|
||||
c = mat.n44
|
||||
lPos = new THREE.Vector3(mat.n14/c, mat.n24/c, mat.n34/c)
|
||||
return lPos.multiplyScalar(0.5).addScalar(0.5)
|
||||
|
||||
###
|
||||
Get an url parameter
|
||||
@param String name Parameter slug
|
||||
@return Mixed
|
||||
###
|
||||
@URLParameters: null
|
||||
@getURLParameter: (name)->
|
||||
|
||||
if !@URLParameters?
|
||||
@URLParameters = {}
|
||||
window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, (m, key, val)=>
|
||||
@URLParameters[key] = val
|
||||
)
|
||||
|
||||
return @URLParameters[name]
|
||||
|
||||
###
|
||||
Get top offset of an element
|
||||
@param obj HTMLElement
|
||||
###
|
||||
@getOffsetTop: (obj)->
|
||||
|
||||
curtop = obj.offsetTop
|
||||
|
||||
if obj.offsetParent
|
||||
while obj = obj.offsetParent
|
||||
curtop += obj.offsetTop
|
||||
|
||||
return curtop
|
||||
|
||||
###
|
||||
Scrolls page to given element id
|
||||
@param string id The ID of the element
|
||||
###
|
||||
@scrollTo: (id)->
|
||||
|
||||
window.scroll(0, @getOffsetTop(document.getElementById(id)))
|
||||
|
||||
###
|
||||
Add or remove a class from an element
|
||||
@param string id [description]
|
||||
@param string cssclass [description]
|
||||
@param bool active [description]
|
||||
###
|
||||
@updateClass: (id, cssclass, active)->
|
||||
|
||||
e = document.getElementById(id)
|
||||
return unless e?
|
||||
|
||||
if active
|
||||
e.classList.add(cssclass)
|
||||
else
|
||||
e.classList.remove(cssclass)
|
||||
|
||||
###
|
||||
Performs an XMLHttpRequest
|
||||
@param string url [description]
|
||||
@param bool postData true = POST, false = GET
|
||||
@param {Function} callback [description]
|
||||
@param {Object} data [description]
|
||||
###
|
||||
@request: (url, postData, callback, data)->
|
||||
|
||||
XMLHttpFactories = [
|
||||
()-> return new XMLHttpRequest()
|
||||
()-> return new ActiveXObject("Msxml2.XMLHTTP")
|
||||
()-> return new ActiveXObject("Msxml3.XMLHTTP")
|
||||
()-> return new ActiveXObject("Microsoft.XMLHTTP")
|
||||
]
|
||||
|
||||
createXMLHTTPObject = () ->
|
||||
|
||||
xmlhttp = false
|
||||
|
||||
for i in [0..XMLHttpFactories.length]
|
||||
try
|
||||
xmlhttp = XMLHttpFactories[i]()
|
||||
catch e
|
||||
continue
|
||||
break
|
||||
|
||||
return xmlhttp
|
||||
|
||||
req = createXMLHTTPObject()
|
||||
return unless req?
|
||||
|
||||
method = if postData? then "POST" else "GET"
|
||||
|
||||
qdata = "o=bk"
|
||||
if data?
|
||||
for i, val of data
|
||||
qdata += "&"+i+"="+val
|
||||
url += "?"+qdata if postData?
|
||||
|
||||
req.open(method,url,true)
|
||||
|
||||
if postData?
|
||||
req.setRequestHeader('Content-type','application/x-www-form-urlencoded')
|
||||
|
||||
req.onreadystatechange = () ->
|
||||
return unless req.readyState is 4
|
||||
return unless req.status is 200 or req.status is 304
|
||||
callback?(req)
|
||||
|
||||
req.send(qdata)
|
||||
|
||||
return req
|
||||
|
||||
|
||||
###
|
||||
Exports
|
||||
@package bkcore
|
||||
###
|
||||
exports = exports ? @
|
||||
exports.bkcore ||= {}
|
||||
exports.bkcore.Utils = Utils
|
||||
@@ -0,0 +1,240 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
|
||||
/*
|
||||
Various useful methods
|
||||
|
||||
@class bkcore.Utils
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var Utils, exports;
|
||||
|
||||
Utils = (function() {
|
||||
/*
|
||||
Creates a bkcore.threejs.Shaders["normalV"|"normal"] material
|
||||
with given parameters
|
||||
*/
|
||||
|
||||
function Utils() {}
|
||||
|
||||
Utils.createNormalMaterial = function(opts) {
|
||||
var material, parameters, shader, shadername, uniforms, _ref, _ref1, _ref2, _ref3, _ref4;
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
if ((_ref = opts.ambient) == null) {
|
||||
opts.ambient = 0x444444;
|
||||
}
|
||||
if ((_ref1 = opts.normalScale) == null) {
|
||||
opts.normalScale = 1.0;
|
||||
}
|
||||
if ((_ref2 = opts.reflectivity) == null) {
|
||||
opts.reflectivity = 0.9;
|
||||
}
|
||||
if ((_ref3 = opts.shininess) == null) {
|
||||
opts.shininess = 42;
|
||||
}
|
||||
if ((_ref4 = opts.metal) == null) {
|
||||
opts.metal = false;
|
||||
}
|
||||
shadername = opts.perPixel ? "normalV" : "normal";
|
||||
shader = bkcore.threejs.Shaders[shadername];
|
||||
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
|
||||
uniforms["enableDiffuse"].value = true;
|
||||
uniforms["enableSpecular"].value = true;
|
||||
uniforms["enableReflection"].value = !!opts.cube;
|
||||
uniforms["tNormal"].texture = opts.normal;
|
||||
uniforms["tDiffuse"].texture = opts.diffuse;
|
||||
uniforms["tSpecular"].texture = opts.specular;
|
||||
uniforms["uAmbientColor"].value.setHex(opts.ambient);
|
||||
uniforms["uAmbientColor"].value.convertGammaToLinear();
|
||||
uniforms["uNormalScale"].value = opts.normalScale;
|
||||
if (opts.cube != null) {
|
||||
uniforms["tCube"].texture = opts.cube;
|
||||
uniforms["uReflectivity"].value = opts.reflectivity;
|
||||
}
|
||||
parameters = {
|
||||
fragmentShader: shader.fragmentShader,
|
||||
vertexShader: shader.vertexShader,
|
||||
uniforms: uniforms,
|
||||
lights: true,
|
||||
fog: false
|
||||
};
|
||||
material = new THREE.ShaderMaterial(parameters);
|
||||
material.perPixel = true;
|
||||
material.metal = opts.metal;
|
||||
return material;
|
||||
};
|
||||
|
||||
/*
|
||||
Projects an object origin vector to screen using given camera
|
||||
@param THREE.Object3D object The object which origin you want to project
|
||||
@param THREE.Camera camera The camera of the projection
|
||||
@return THEE.Vector3 Projected verctor
|
||||
*/
|
||||
|
||||
|
||||
Utils.projectOnScreen = function(object, camera) {
|
||||
var c, lPos, mat;
|
||||
mat = new THREE.Matrix4();
|
||||
mat.multiply(camera.matrixWorldInverse, object.matrixWorld);
|
||||
mat.multiply(camera.projectionMatrix, mat);
|
||||
c = mat.n44;
|
||||
lPos = new THREE.Vector3(mat.n14 / c, mat.n24 / c, mat.n34 / c);
|
||||
return lPos.multiplyScalar(0.5).addScalar(0.5);
|
||||
};
|
||||
|
||||
/*
|
||||
Get an url parameter
|
||||
@param String name Parameter slug
|
||||
@return Mixed
|
||||
*/
|
||||
|
||||
|
||||
Utils.URLParameters = null;
|
||||
|
||||
Utils.getURLParameter = function(name) {
|
||||
var _this = this;
|
||||
if (!(this.URLParameters != null)) {
|
||||
this.URLParameters = {};
|
||||
window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, val) {
|
||||
return _this.URLParameters[key] = val;
|
||||
});
|
||||
}
|
||||
return this.URLParameters[name];
|
||||
};
|
||||
|
||||
/*
|
||||
Get top offset of an element
|
||||
@param obj HTMLElement
|
||||
*/
|
||||
|
||||
|
||||
Utils.getOffsetTop = function(obj) {
|
||||
var curtop;
|
||||
curtop = obj.offsetTop;
|
||||
if (obj.offsetParent) {
|
||||
while (obj = obj.offsetParent) {
|
||||
curtop += obj.offsetTop;
|
||||
}
|
||||
}
|
||||
return curtop;
|
||||
};
|
||||
|
||||
/*
|
||||
Scrolls page to given element id
|
||||
@param string id The ID of the element
|
||||
*/
|
||||
|
||||
|
||||
Utils.scrollTo = function(id) {
|
||||
return window.scroll(0, this.getOffsetTop(document.getElementById(id)));
|
||||
};
|
||||
|
||||
/*
|
||||
Add or remove a class from an element
|
||||
@param string id [description]
|
||||
@param string cssclass [description]
|
||||
@param bool active [description]
|
||||
*/
|
||||
|
||||
|
||||
Utils.updateClass = function(id, cssclass, active) {
|
||||
var e;
|
||||
e = document.getElementById(id);
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
if (active) {
|
||||
return e.classList.add(cssclass);
|
||||
} else {
|
||||
return e.classList.remove(cssclass);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Performs an XMLHttpRequest
|
||||
@param string url [description]
|
||||
@param bool postData true = POST, false = GET
|
||||
@param {Function} callback [description]
|
||||
@param {Object} data [description]
|
||||
*/
|
||||
|
||||
|
||||
Utils.request = function(url, postData, callback, data) {
|
||||
var XMLHttpFactories, createXMLHTTPObject, i, method, qdata, req, val;
|
||||
XMLHttpFactories = [
|
||||
function() {
|
||||
return new XMLHttpRequest();
|
||||
}, function() {
|
||||
return new ActiveXObject("Msxml2.XMLHTTP");
|
||||
}, function() {
|
||||
return new ActiveXObject("Msxml3.XMLHTTP");
|
||||
}, function() {
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
];
|
||||
createXMLHTTPObject = function() {
|
||||
var i, xmlhttp, _i, _ref;
|
||||
xmlhttp = false;
|
||||
for (i = _i = 0, _ref = XMLHttpFactories.length; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
try {
|
||||
xmlhttp = XMLHttpFactories[i]();
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return xmlhttp;
|
||||
};
|
||||
req = createXMLHTTPObject();
|
||||
if (req == null) {
|
||||
return;
|
||||
}
|
||||
method = postData != null ? "POST" : "GET";
|
||||
qdata = "o=bk";
|
||||
if (data != null) {
|
||||
for (i in data) {
|
||||
val = data[i];
|
||||
qdata += "&" + i + "=" + val;
|
||||
if (postData != null) {
|
||||
url += "?" + qdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
req.open(method, url, true);
|
||||
if (postData != null) {
|
||||
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
}
|
||||
req.onreadystatechange = function() {
|
||||
if (req.readyState !== 4) {
|
||||
return;
|
||||
}
|
||||
if (!(req.status === 200 || req.status === 304)) {
|
||||
return;
|
||||
}
|
||||
return typeof callback === "function" ? callback(req) : void 0;
|
||||
};
|
||||
req.send(qdata);
|
||||
return req;
|
||||
};
|
||||
|
||||
return Utils;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Exports
|
||||
@package bkcore
|
||||
*/
|
||||
|
||||
|
||||
exports = exports != null ? exports : this;
|
||||
|
||||
exports.bkcore || (exports.bkcore = {});
|
||||
|
||||
exports.bkcore.Utils = Utils;
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,72 @@
|
||||
###
|
||||
OrientationController (Orientation + buttons) for touch devices
|
||||
|
||||
@class bkcore.OrientationController
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class OrientationController
|
||||
|
||||
@isCompatible: ->
|
||||
return ('DeviceOrientationEvent' of window)
|
||||
|
||||
###
|
||||
Creates a new OrientationController
|
||||
|
||||
@param dom DOMElement The element that will listen to touch events
|
||||
@param registerTouch bool Enable touch detection
|
||||
@param touchCallback function Callback for touches
|
||||
###
|
||||
constructor: (@dom, @registerTouch=true, @touchCallback=null) ->
|
||||
@active = true
|
||||
@alpha = 0.0
|
||||
@beta = 0.0
|
||||
@gamma = 0.0
|
||||
@dalpha = null
|
||||
@dbeta = null
|
||||
@dgamma = null
|
||||
@touches = null
|
||||
|
||||
window.addEventListener('deviceorientation', ((e)=> @orientationChange(e)), false)
|
||||
if @registerTouch
|
||||
@dom.addEventListener('touchstart', ((e)=> @touchStart(e)), false)
|
||||
@dom.addEventListener('touchend', ((e)=> @touchEnd(e)), false)
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
orientationChange: (event) ->
|
||||
return if not @active
|
||||
if(@dalpha == null)
|
||||
console.log "calbrate", event.beta
|
||||
@dalpha = event.alpha
|
||||
@dbeta = event.beta
|
||||
@dgamma = event.gamma
|
||||
@alpha = event.alpha - @dalpha
|
||||
@beta = event.beta - @dbeta
|
||||
@gamma = event.gamma - @dgamma
|
||||
false
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
touchStart: (event) ->
|
||||
return if not @active
|
||||
for touch in event.changedTouches
|
||||
@touchCallback?(on, touch, event)
|
||||
@touches = event.touches
|
||||
false
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
touchEnd: (event) ->
|
||||
return if not @active
|
||||
for touch in event.changedTouches
|
||||
@touchCallback?(on, touch, event)
|
||||
@touches = event.touches
|
||||
false
|
||||
|
||||
exports = exports ? @
|
||||
exports.bkcore ||= {}
|
||||
exports.bkcore.controllers ||= {}
|
||||
exports.bkcore.controllers.OrientationController = OrientationController
|
||||
@@ -0,0 +1,130 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
|
||||
/*
|
||||
OrientationController (Orientation + buttons) for touch devices
|
||||
|
||||
@class bkcore.OrientationController
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var OrientationController, exports, _base;
|
||||
|
||||
OrientationController = (function() {
|
||||
|
||||
OrientationController.isCompatible = function() {
|
||||
return 'DeviceOrientationEvent' in window;
|
||||
};
|
||||
|
||||
/*
|
||||
Creates a new OrientationController
|
||||
|
||||
@param dom DOMElement The element that will listen to touch events
|
||||
@param registerTouch bool Enable touch detection
|
||||
@param touchCallback function Callback for touches
|
||||
*/
|
||||
|
||||
|
||||
function OrientationController(dom, registerTouch, touchCallback) {
|
||||
var _this = this;
|
||||
this.dom = dom;
|
||||
this.registerTouch = registerTouch != null ? registerTouch : true;
|
||||
this.touchCallback = touchCallback != null ? touchCallback : null;
|
||||
this.active = true;
|
||||
this.alpha = 0.0;
|
||||
this.beta = 0.0;
|
||||
this.gamma = 0.0;
|
||||
this.dalpha = null;
|
||||
this.dbeta = null;
|
||||
this.dgamma = null;
|
||||
this.touches = null;
|
||||
window.addEventListener('deviceorientation', (function(e) {
|
||||
return _this.orientationChange(e);
|
||||
}), false);
|
||||
if (this.registerTouch) {
|
||||
this.dom.addEventListener('touchstart', (function(e) {
|
||||
return _this.touchStart(e);
|
||||
}), false);
|
||||
this.dom.addEventListener('touchend', (function(e) {
|
||||
return _this.touchEnd(e);
|
||||
}), false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
OrientationController.prototype.orientationChange = function(event) {
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
if (this.dalpha === null) {
|
||||
console.log("calbrate", event.beta);
|
||||
this.dalpha = event.alpha;
|
||||
this.dbeta = event.beta;
|
||||
this.dgamma = event.gamma;
|
||||
}
|
||||
this.alpha = event.alpha - this.dalpha;
|
||||
this.beta = event.beta - this.dbeta;
|
||||
this.gamma = event.gamma - this.dgamma;
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
OrientationController.prototype.touchStart = function(event) {
|
||||
var touch, _i, _len, _ref;
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
_ref = event.changedTouches;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
touch = _ref[_i];
|
||||
if (typeof this.touchCallback === "function") {
|
||||
this.touchCallback(true, touch, event);
|
||||
}
|
||||
}
|
||||
this.touches = event.touches;
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
OrientationController.prototype.touchEnd = function(event) {
|
||||
var touch, _i, _len, _ref;
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
_ref = event.changedTouches;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
touch = _ref[_i];
|
||||
if (typeof this.touchCallback === "function") {
|
||||
this.touchCallback(true, touch, event);
|
||||
}
|
||||
}
|
||||
this.touches = event.touches;
|
||||
return false;
|
||||
};
|
||||
|
||||
return OrientationController;
|
||||
|
||||
})();
|
||||
|
||||
exports = exports != null ? exports : this;
|
||||
|
||||
exports.bkcore || (exports.bkcore = {});
|
||||
|
||||
(_base = exports.bkcore).controllers || (_base.controllers = {});
|
||||
|
||||
exports.bkcore.controllers.OrientationController = OrientationController;
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,109 @@
|
||||
###
|
||||
TouchController (stick + buttons) for touch devices
|
||||
Based on the touch demo by Seb Lee-Delisle <http://seb.ly/>
|
||||
|
||||
@class bkcore.controllers.TouchController
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class TouchController
|
||||
|
||||
@isCompatible: ->
|
||||
return ('ontouchstart' of document.documentElement);
|
||||
|
||||
###
|
||||
Creates a new TouchController
|
||||
|
||||
@param dom DOMElement The element that will listen to touch events
|
||||
@param stickMargin int The left margin in px for stick detection
|
||||
@param buttonCallback function Callback for non-stick touches
|
||||
###
|
||||
constructor: (@dom, @stickMargin=200, @buttonCallback=null) ->
|
||||
@active = true
|
||||
@touches = null
|
||||
@stickID = -1
|
||||
@stickPos = new Vec2(0, 0)
|
||||
@stickStartPos = new Vec2(0, 0)
|
||||
@stickVector = new Vec2(0, 0)
|
||||
|
||||
@dom.addEventListener('touchstart', ((e)=> @touchStart(e)), false)
|
||||
@dom.addEventListener('touchmove', ((e)=> @touchMove(e)), false)
|
||||
@dom.addEventListener('touchend', ((e)=> @touchEnd(e)), false)
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
touchStart: (event) ->
|
||||
return if not @active
|
||||
for touch in event.changedTouches
|
||||
if @stickID < 0 and touch.clientX < @stickMargin
|
||||
@stickID = touch.identifier
|
||||
@stickStartPos.set(touch.clientX, touch.clientY)
|
||||
@stickPos.copy(@stickStartPos)
|
||||
@stickVector.set(0, 0)
|
||||
continue
|
||||
else
|
||||
@buttonCallback?(on, touch, event)
|
||||
@touches = event.touches
|
||||
false
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
touchMove: (event) ->
|
||||
event.preventDefault()
|
||||
return if not @active
|
||||
for touch in event.changedTouches
|
||||
if @stickID is touch.identifier
|
||||
@stickPos.set(touch.clientX, touch.clientY)
|
||||
@stickVector.copy(@stickPos).substract(@stickStartPos)
|
||||
break
|
||||
@touches = event.touches
|
||||
false
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
touchEnd: (event) ->
|
||||
return if not @active
|
||||
@touches = event.touches
|
||||
for touch in event.changedTouches
|
||||
if @stickID is touch.identifier
|
||||
@stickID = -1
|
||||
@stickVector.set(0, 0)
|
||||
break
|
||||
else
|
||||
@buttonCallback?(off, touch, event)
|
||||
false
|
||||
|
||||
###
|
||||
Internal class used for vector2
|
||||
@class Vec2
|
||||
@private
|
||||
###
|
||||
class Vec2
|
||||
|
||||
constructor: (@x = 0, @y = 0) ->
|
||||
|
||||
substract: (vec) ->
|
||||
@x -= vec.x
|
||||
@y -= vec.y
|
||||
@
|
||||
|
||||
copy: (vec) ->
|
||||
@x = vec.x
|
||||
@y = vec.y
|
||||
@
|
||||
|
||||
set: (x, y) ->
|
||||
@x = x
|
||||
@y = y
|
||||
@
|
||||
|
||||
###
|
||||
Exports
|
||||
@package bkcore
|
||||
###
|
||||
exports = exports ? @
|
||||
exports.bkcore ||= {}
|
||||
exports.bkcore.controllers ||= {}
|
||||
exports.bkcore.controllers.TouchController = TouchController
|
||||
@@ -0,0 +1,186 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
|
||||
/*
|
||||
TouchController (stick + buttons) for touch devices
|
||||
Based on the touch demo by Seb Lee-Delisle <http://seb.ly/>
|
||||
|
||||
@class bkcore.controllers.TouchController
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var TouchController, Vec2, exports, _base;
|
||||
|
||||
TouchController = (function() {
|
||||
|
||||
TouchController.isCompatible = function() {
|
||||
return 'ontouchstart' in document.documentElement;
|
||||
};
|
||||
|
||||
/*
|
||||
Creates a new TouchController
|
||||
|
||||
@param dom DOMElement The element that will listen to touch events
|
||||
@param stickMargin int The left margin in px for stick detection
|
||||
@param buttonCallback function Callback for non-stick touches
|
||||
*/
|
||||
|
||||
|
||||
function TouchController(dom, stickMargin, buttonCallback) {
|
||||
var _this = this;
|
||||
this.dom = dom;
|
||||
this.stickMargin = stickMargin != null ? stickMargin : 200;
|
||||
this.buttonCallback = buttonCallback != null ? buttonCallback : null;
|
||||
this.active = true;
|
||||
this.touches = null;
|
||||
this.stickID = -1;
|
||||
this.stickPos = new Vec2(0, 0);
|
||||
this.stickStartPos = new Vec2(0, 0);
|
||||
this.stickVector = new Vec2(0, 0);
|
||||
this.dom.addEventListener('touchstart', (function(e) {
|
||||
return _this.touchStart(e);
|
||||
}), false);
|
||||
this.dom.addEventListener('touchmove', (function(e) {
|
||||
return _this.touchMove(e);
|
||||
}), false);
|
||||
this.dom.addEventListener('touchend', (function(e) {
|
||||
return _this.touchEnd(e);
|
||||
}), false);
|
||||
}
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
TouchController.prototype.touchStart = function(event) {
|
||||
var touch, _i, _len, _ref;
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
_ref = event.changedTouches;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
touch = _ref[_i];
|
||||
if (this.stickID < 0 && touch.clientX < this.stickMargin) {
|
||||
this.stickID = touch.identifier;
|
||||
this.stickStartPos.set(touch.clientX, touch.clientY);
|
||||
this.stickPos.copy(this.stickStartPos);
|
||||
this.stickVector.set(0, 0);
|
||||
continue;
|
||||
} else {
|
||||
if (typeof this.buttonCallback === "function") {
|
||||
this.buttonCallback(true, touch, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.touches = event.touches;
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
TouchController.prototype.touchMove = function(event) {
|
||||
var touch, _i, _len, _ref;
|
||||
event.preventDefault();
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
_ref = event.changedTouches;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
touch = _ref[_i];
|
||||
if (this.stickID === touch.identifier) {
|
||||
this.stickPos.set(touch.clientX, touch.clientY);
|
||||
this.stickVector.copy(this.stickPos).substract(this.stickStartPos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.touches = event.touches;
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
TouchController.prototype.touchEnd = function(event) {
|
||||
var touch, _i, _len, _ref;
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
this.touches = event.touches;
|
||||
_ref = event.changedTouches;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
touch = _ref[_i];
|
||||
if (this.stickID === touch.identifier) {
|
||||
this.stickID = -1;
|
||||
this.stickVector.set(0, 0);
|
||||
break;
|
||||
} else {
|
||||
if (typeof this.buttonCallback === "function") {
|
||||
this.buttonCallback(false, touch, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return TouchController;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Internal class used for vector2
|
||||
@class Vec2
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
Vec2 = (function() {
|
||||
|
||||
function Vec2(x, y) {
|
||||
this.x = x != null ? x : 0;
|
||||
this.y = y != null ? y : 0;
|
||||
}
|
||||
|
||||
Vec2.prototype.substract = function(vec) {
|
||||
this.x -= vec.x;
|
||||
this.y -= vec.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
Vec2.prototype.copy = function(vec) {
|
||||
this.x = vec.x;
|
||||
this.y = vec.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
Vec2.prototype.set = function(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
return this;
|
||||
};
|
||||
|
||||
return Vec2;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Exports
|
||||
@package bkcore
|
||||
*/
|
||||
|
||||
|
||||
exports = exports != null ? exports : this;
|
||||
|
||||
exports.bkcore || (exports.bkcore = {});
|
||||
|
||||
(_base = exports.bkcore).controllers || (_base.controllers = {});
|
||||
|
||||
exports.bkcore.controllers.TouchController = TouchController;
|
||||
|
||||
}).call(this);
|
||||
@@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>CoffeeScript Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="Timer.js"></script>
|
||||
<script src="ImageData.js"></script>
|
||||
<script src="../libs/Three.r53.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,199 @@
|
||||
###
|
||||
Particle system wrapper/helper
|
||||
|
||||
@class bkcore.threejs.Particles
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class Particles
|
||||
|
||||
###
|
||||
Creates a new particle system using given parameters
|
||||
|
||||
@param {Object{max, spawnRate, spawn, velocity, randomness,
|
||||
force, spawnRadius, life, friction, color, color2, tint,
|
||||
texture, size, blending, depthTest, transparent, opacity}} opts
|
||||
###
|
||||
constructor: (opts)->
|
||||
|
||||
@black = new THREE.Color(0x000000)
|
||||
@white = new THREE.Color(0xffffff)
|
||||
|
||||
@material = new THREE.ParticleBasicMaterial(
|
||||
color: opts.tint ? 0xffffff
|
||||
map: opts.texture ? null
|
||||
size: opts.size ? 4
|
||||
blending: opts.blending ? THREE.AdditiveBlending
|
||||
depthTest: opts.depthTest ? false
|
||||
transparent: opts.transparent ? true
|
||||
vertexColors: true
|
||||
opacity: opts.opacity ? 1.0
|
||||
sizeAttenuation: true
|
||||
)
|
||||
|
||||
@max = opts.max ? 1000
|
||||
@spawnRate = opts.spawnRate ? 0
|
||||
|
||||
@spawn = opts.spawn ? new THREE.Vector3()
|
||||
@velocity = opts.velocity ? new THREE.Vector3()
|
||||
@randomness = opts.randomness ? new THREE.Vector3()
|
||||
@force = opts.force ? new THREE.Vector3()
|
||||
@spawnRadius = opts.spawnRadius ? new THREE.Vector3()
|
||||
@life = opts.life ? 60
|
||||
@ageing = 1 / @life
|
||||
@friction = opts.friction ? 1.0
|
||||
@color = new THREE.Color(opts.color ? 0xffffff)
|
||||
@color2 = if opts.color2? then new THREE.Color(opts.color2) else null
|
||||
|
||||
@position = opts.position ? new THREE.Vector3()
|
||||
@rotation = opts.rotation ? new THREE.Vector3()
|
||||
@sort = opts.sort ? false
|
||||
|
||||
@pool = []
|
||||
@buffer = []
|
||||
@geometry = null
|
||||
@system = null
|
||||
|
||||
@build()
|
||||
|
||||
###
|
||||
Emits given number of particles
|
||||
@param int count
|
||||
###
|
||||
emit: (count)->
|
||||
|
||||
emitable = Math.min(count, @pool.length)
|
||||
|
||||
for i in [0..emitable]
|
||||
|
||||
p = @pool.pop()
|
||||
p.available = false
|
||||
|
||||
p.position.copy(@spawn).addSelf(
|
||||
@randomVector().multiplySelf(@spawnRadius)
|
||||
)
|
||||
p.velocity.copy(@velocity).addSelf(
|
||||
@randomVector().multiplySelf(@randomness)
|
||||
)
|
||||
p.force.copy(@force)
|
||||
p.basecolor.copy(@color)
|
||||
|
||||
if @color2?
|
||||
p.basecolor.lerpSelf(@color2, Math.random())
|
||||
|
||||
p.life = 1.0
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
build: ()->
|
||||
|
||||
@geometry = new THREE.Geometry()
|
||||
@geometry.dynamic = true
|
||||
|
||||
@pool = []
|
||||
@buffer = []
|
||||
|
||||
for i in [0..@max]
|
||||
|
||||
p = new bkcore.threejs.Particle()
|
||||
@pool.push(p)
|
||||
@buffer.push(p)
|
||||
@geometry.vertices.push(p.position)
|
||||
@geometry.colors.push(p.color)
|
||||
|
||||
@system = new THREE.ParticleSystem(@geometry, @material)
|
||||
@system.position = @position
|
||||
@system.rotation = @rotation
|
||||
@system.sort = @sort
|
||||
|
||||
###
|
||||
@private
|
||||
###
|
||||
randomVector: ()->
|
||||
|
||||
return new THREE.Vector3(
|
||||
Math.random()*2-1,
|
||||
Math.random()*2-1,
|
||||
Math.random()*2-1
|
||||
)
|
||||
|
||||
###
|
||||
Updates particles (should be call in a RAF loop)
|
||||
@param float dt time delta ~1.0
|
||||
###
|
||||
update: (dt)->
|
||||
|
||||
df = new THREE.Vector3()
|
||||
dv = new THREE.Vector3()
|
||||
|
||||
for i in [0..@buffer.length]
|
||||
|
||||
p = @buffer[i]
|
||||
continue if p.available
|
||||
|
||||
p.life -= @ageing
|
||||
|
||||
if p.life <= 0
|
||||
p.reset()
|
||||
@pool.push(p)
|
||||
continue
|
||||
|
||||
|
||||
l = if p.life > 0.5 then 1.0 else p.life + 0.5
|
||||
p.color.setRGB(
|
||||
l * p.basecolor.r,
|
||||
l * p.basecolor.g,
|
||||
l * p.basecolor.b
|
||||
)
|
||||
|
||||
if @friction != 1.0
|
||||
p.velocity.multiplyScalar(@friction)
|
||||
|
||||
df.copy(p.force).multiplyScalar(dt)
|
||||
p.velocity.addSelf(df)
|
||||
|
||||
dv.copy(p.velocity).multiplyScalar(dt)
|
||||
p.position.addSelf(dv)
|
||||
|
||||
if @spawnRate > 0
|
||||
@emit(@spawnRate)
|
||||
|
||||
@geometry.verticesNeedUpdate = true
|
||||
@geometry.colorsNeedUpdate = true
|
||||
|
||||
###
|
||||
Particle sub class
|
||||
|
||||
@class bkcore.threejs.Particle
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
###
|
||||
class Particle
|
||||
|
||||
constructor: ()->
|
||||
|
||||
@position = new THREE.Vector3(-10000,-10000,-10000)
|
||||
@velocity = new THREE.Vector3()
|
||||
@force = new THREE.Vector3()
|
||||
@color = new THREE.Color(0x000000)
|
||||
@basecolor = new THREE.Color(0x000000)
|
||||
@life = 0.0
|
||||
@available = true
|
||||
|
||||
reset: ()->
|
||||
@position.set(0,-100000,0)
|
||||
@velocity.set(0,0,0)
|
||||
@force.set(0,0,0)
|
||||
@color.setRGB(0,0,0)
|
||||
@basecolor.setRGB(0,0,0)
|
||||
@life = 0.0
|
||||
@available = true
|
||||
|
||||
###
|
||||
Exports
|
||||
@package bkcore.threejs
|
||||
###
|
||||
exports = exports ? @
|
||||
exports.bkcore ||= {}
|
||||
exports.bkcore.threejs ||= {}
|
||||
exports.bkcore.threejs.Particle = Particle
|
||||
exports.bkcore.threejs.Particles = Particles
|
||||
@@ -0,0 +1,210 @@
|
||||
// Generated by CoffeeScript 1.4.0
|
||||
|
||||
/*
|
||||
Particle system wrapper/helper
|
||||
|
||||
@class bkcore.threejs.Particles
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
var Particle, Particles, exports, _base;
|
||||
|
||||
Particles = (function() {
|
||||
/*
|
||||
Creates a new particle system using given parameters
|
||||
|
||||
@param {Object{max, spawnRate, spawn, velocity, randomness,
|
||||
force, spawnRadius, life, friction, color, color2, tint,
|
||||
texture, size, blending, depthTest, transparent, opacity}} opts
|
||||
*/
|
||||
|
||||
function Particles(opts) {
|
||||
var _ref, _ref1, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref18, _ref19, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
|
||||
this.black = new THREE.Color(0x000000);
|
||||
this.white = new THREE.Color(0xffffff);
|
||||
this.material = new THREE.ParticleBasicMaterial({
|
||||
color: (_ref = opts.tint) != null ? _ref : 0xffffff,
|
||||
map: (_ref1 = opts.texture) != null ? _ref1 : null,
|
||||
size: (_ref2 = opts.size) != null ? _ref2 : 4,
|
||||
blending: (_ref3 = opts.blending) != null ? _ref3 : THREE.AdditiveBlending,
|
||||
depthTest: (_ref4 = opts.depthTest) != null ? _ref4 : false,
|
||||
transparent: (_ref5 = opts.transparent) != null ? _ref5 : true,
|
||||
vertexColors: true,
|
||||
opacity: (_ref6 = opts.opacity) != null ? _ref6 : 1.0,
|
||||
sizeAttenuation: true
|
||||
});
|
||||
this.max = (_ref7 = opts.max) != null ? _ref7 : 1000;
|
||||
this.spawnRate = (_ref8 = opts.spawnRate) != null ? _ref8 : 0;
|
||||
this.spawn = (_ref9 = opts.spawn) != null ? _ref9 : new THREE.Vector3();
|
||||
this.velocity = (_ref10 = opts.velocity) != null ? _ref10 : new THREE.Vector3();
|
||||
this.randomness = (_ref11 = opts.randomness) != null ? _ref11 : new THREE.Vector3();
|
||||
this.force = (_ref12 = opts.force) != null ? _ref12 : new THREE.Vector3();
|
||||
this.spawnRadius = (_ref13 = opts.spawnRadius) != null ? _ref13 : new THREE.Vector3();
|
||||
this.life = (_ref14 = opts.life) != null ? _ref14 : 60;
|
||||
this.ageing = 1 / this.life;
|
||||
this.friction = (_ref15 = opts.friction) != null ? _ref15 : 1.0;
|
||||
this.color = new THREE.Color((_ref16 = opts.color) != null ? _ref16 : 0xffffff);
|
||||
this.color2 = opts.color2 != null ? new THREE.Color(opts.color2) : null;
|
||||
this.position = (_ref17 = opts.position) != null ? _ref17 : new THREE.Vector3();
|
||||
this.rotation = (_ref18 = opts.rotation) != null ? _ref18 : new THREE.Vector3();
|
||||
this.sort = (_ref19 = opts.sort) != null ? _ref19 : false;
|
||||
this.pool = [];
|
||||
this.buffer = [];
|
||||
this.geometry = null;
|
||||
this.system = null;
|
||||
this.build();
|
||||
}
|
||||
|
||||
/*
|
||||
Emits given number of particles
|
||||
@param int count
|
||||
*/
|
||||
|
||||
|
||||
Particles.prototype.emit = function(count) {
|
||||
var emitable, i, p, _i, _results;
|
||||
emitable = Math.min(count, this.pool.length);
|
||||
_results = [];
|
||||
for (i = _i = 0; 0 <= emitable ? _i <= emitable : _i >= emitable; i = 0 <= emitable ? ++_i : --_i) {
|
||||
p = this.pool.pop();
|
||||
p.available = false;
|
||||
p.position.copy(this.spawn).addSelf(this.randomVector().multiplySelf(this.spawnRadius));
|
||||
p.velocity.copy(this.velocity).addSelf(this.randomVector().multiplySelf(this.randomness));
|
||||
p.force.copy(this.force);
|
||||
p.basecolor.copy(this.color);
|
||||
if (this.color2 != null) {
|
||||
p.basecolor.lerpSelf(this.color2, Math.random());
|
||||
}
|
||||
_results.push(p.life = 1.0);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
Particles.prototype.build = function() {
|
||||
var i, p, _i, _ref;
|
||||
this.geometry = new THREE.Geometry();
|
||||
this.geometry.dynamic = true;
|
||||
this.pool = [];
|
||||
this.buffer = [];
|
||||
for (i = _i = 0, _ref = this.max; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
p = new bkcore.threejs.Particle();
|
||||
this.pool.push(p);
|
||||
this.buffer.push(p);
|
||||
this.geometry.vertices.push(p.position);
|
||||
this.geometry.colors.push(p.color);
|
||||
}
|
||||
this.system = new THREE.ParticleSystem(this.geometry, this.material);
|
||||
this.system.position = this.position;
|
||||
this.system.rotation = this.rotation;
|
||||
return this.system.sort = this.sort;
|
||||
};
|
||||
|
||||
/*
|
||||
@private
|
||||
*/
|
||||
|
||||
|
||||
Particles.prototype.randomVector = function() {
|
||||
return new THREE.Vector3(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1);
|
||||
};
|
||||
|
||||
/*
|
||||
Updates particles (should be call in a RAF loop)
|
||||
@param float dt time delta ~1.0
|
||||
*/
|
||||
|
||||
|
||||
Particles.prototype.update = function(dt) {
|
||||
var df, dv, i, l, p, _i, _ref;
|
||||
df = new THREE.Vector3();
|
||||
dv = new THREE.Vector3();
|
||||
for (i = _i = 0, _ref = this.buffer.length; 0 <= _ref ? _i <= _ref : _i >= _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
p = this.buffer[i];
|
||||
if (p.available) {
|
||||
continue;
|
||||
}
|
||||
p.life -= this.ageing;
|
||||
if (p.life <= 0) {
|
||||
p.reset();
|
||||
this.pool.push(p);
|
||||
continue;
|
||||
}
|
||||
l = p.life > 0.5 ? 1.0 : p.life + 0.5;
|
||||
p.color.setRGB(l * p.basecolor.r, l * p.basecolor.g, l * p.basecolor.b);
|
||||
if (this.friction !== 1.0) {
|
||||
p.velocity.multiplyScalar(this.friction);
|
||||
}
|
||||
df.copy(p.force).multiplyScalar(dt);
|
||||
p.velocity.addSelf(df);
|
||||
dv.copy(p.velocity).multiplyScalar(dt);
|
||||
p.position.addSelf(dv);
|
||||
}
|
||||
if (this.spawnRate > 0) {
|
||||
this.emit(this.spawnRate);
|
||||
}
|
||||
this.geometry.verticesNeedUpdate = true;
|
||||
return this.geometry.colorsNeedUpdate = true;
|
||||
};
|
||||
|
||||
return Particles;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Particle sub class
|
||||
|
||||
@class bkcore.threejs.Particle
|
||||
@author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
*/
|
||||
|
||||
|
||||
Particle = (function() {
|
||||
|
||||
function Particle() {
|
||||
this.position = new THREE.Vector3(-10000, -10000, -10000);
|
||||
this.velocity = new THREE.Vector3();
|
||||
this.force = new THREE.Vector3();
|
||||
this.color = new THREE.Color(0x000000);
|
||||
this.basecolor = new THREE.Color(0x000000);
|
||||
this.life = 0.0;
|
||||
this.available = true;
|
||||
}
|
||||
|
||||
Particle.prototype.reset = function() {
|
||||
this.position.set(0, -100000, 0);
|
||||
this.velocity.set(0, 0, 0);
|
||||
this.force.set(0, 0, 0);
|
||||
this.color.setRGB(0, 0, 0);
|
||||
this.basecolor.setRGB(0, 0, 0);
|
||||
this.life = 0.0;
|
||||
return this.available = true;
|
||||
};
|
||||
|
||||
return Particle;
|
||||
|
||||
})();
|
||||
|
||||
/*
|
||||
Exports
|
||||
@package bkcore.threejs
|
||||
*/
|
||||
|
||||
|
||||
exports = exports != null ? exports : this;
|
||||
|
||||
exports.bkcore || (exports.bkcore = {});
|
||||
|
||||
(_base = exports.bkcore).threejs || (_base.threejs = {});
|
||||
|
||||
exports.bkcore.threejs.Particle = Particle;
|
||||
|
||||
exports.bkcore.threejs.Particles = Particles;
|
||||
|
||||
}).call(this);
|
||||
@@ -71,8 +71,6 @@ bkcore.Timer.prototype.update = function()
|
||||
|
||||
/*!
|
||||
* Returns a formatted version of the current elapsed time using msToTime().
|
||||
*
|
||||
*
|
||||
*/
|
||||
bkcore.Timer.prototype.getElapsedTime = function()
|
||||
{
|
||||
|
||||
@@ -17,6 +17,12 @@ bkcore.hexgl.CameraChase = function(opts)
|
||||
this.speedOffsetMax = 10;
|
||||
this.speedOffsetStep = 0.05;
|
||||
|
||||
this.modes = {
|
||||
CHASE: 0,
|
||||
ORBIT: 1
|
||||
}
|
||||
this.mode = this.modes.CHASE;
|
||||
|
||||
this.camera = opts.camera;
|
||||
this.targetObject = opts.target;
|
||||
this.cameraCube = opts.cameraCube == undefined ? null : opts.cameraCube;
|
||||
@@ -24,26 +30,43 @@ bkcore.hexgl.CameraChase = function(opts)
|
||||
this.yoffset = opts.yoffest == undefined ? 8.0 : opts.yoffest;
|
||||
this.zoffset = opts.zoffset == undefined ? 10.0 : opts.zoffset;
|
||||
this.viewOffset = opts.viewOffset == undefined ? 10.0 : opts.viewOffset;
|
||||
this.orbitOffset = 12;
|
||||
this.lerp = opts.lerp == undefined ? 0.5 : opts.lerp;
|
||||
this.time = 0.0;
|
||||
}
|
||||
|
||||
bkcore.hexgl.CameraChase.prototype.update = function(dt, ratio)
|
||||
{
|
||||
this.dir.set(0,0,1);
|
||||
this.up.set(0,1,0);
|
||||
if(this.mode == this.modes.CHASE)
|
||||
{
|
||||
this.dir.set(0,0,1);
|
||||
this.up.set(0,1,0);
|
||||
|
||||
this.targetObject.matrix.rotateAxis(this.up);
|
||||
this.targetObject.matrix.rotateAxis(this.dir);
|
||||
this.targetObject.matrix.rotateAxis(this.up);
|
||||
this.targetObject.matrix.rotateAxis(this.dir);
|
||||
|
||||
this.speedOffset += (this.speedOffsetMax*ratio - this.speedOffset) * Math.min(1, 0.3*dt);
|
||||
this.speedOffset += (this.speedOffsetMax*ratio - this.speedOffset) * Math.min(1, 0.3*dt);
|
||||
|
||||
this.target.copy(this.targetObject.position);
|
||||
this.target.subSelf(this.dir.multiplyScalar(this.zoffset + this.speedOffset));
|
||||
this.target.addSelf(this.up.multiplyScalar(this.yoffset));
|
||||
this.target.y += -this.up.y + this.yoffset;
|
||||
this.camera.position.copy(this.target, this.lerp);
|
||||
|
||||
this.camera.lookAt(this.dir.normalize().multiplyScalar(this.viewOffset).addSelf(this.targetObject.position));
|
||||
this.target.copy(this.targetObject.position);
|
||||
this.target.subSelf(this.dir.multiplyScalar(this.zoffset + this.speedOffset));
|
||||
this.target.addSelf(this.up.multiplyScalar(this.yoffset));
|
||||
this.target.y += -this.up.y + this.yoffset;
|
||||
this.camera.position.copy(this.target);
|
||||
|
||||
this.camera.lookAt(this.dir.normalize().multiplyScalar(this.viewOffset).addSelf(this.targetObject.position));
|
||||
}
|
||||
else if(this.mode == this.modes.ORBIT)
|
||||
{
|
||||
this.time += dt*.008;
|
||||
this.dir.set(
|
||||
Math.cos(this.time)*this.orbitOffset,
|
||||
this.yoffset/2,
|
||||
Math.sin(this.time)*this.orbitOffset
|
||||
);
|
||||
this.target.copy(this.targetObject.position).addSelf(this.dir);
|
||||
this.camera.position.copy(this.target);
|
||||
this.camera.lookAt(this.targetObject.position);
|
||||
}
|
||||
|
||||
if(this.cameraCube != null)
|
||||
this.cameraCube.rotation.copy(this.camera.rotation);
|
||||
|
||||
@@ -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();
|
||||
@@ -27,6 +27,7 @@ bkcore.hexgl.Gameplay = function(opts)
|
||||
|
||||
this.hud = opts.hud;
|
||||
this.shipControls = opts.shipControls;
|
||||
this.cameraControls = opts.cameraControls;
|
||||
this.track = opts.track;
|
||||
this.analyser = opts.analyser;
|
||||
this.pixelRatio = opts.pixelRatio;
|
||||
@@ -37,6 +38,7 @@ bkcore.hexgl.Gameplay = function(opts)
|
||||
FINISH: 1,
|
||||
DESTROYED: 2,
|
||||
WRONGWAY: 3,
|
||||
REPLAY: 4,
|
||||
NONE: -1
|
||||
};
|
||||
this.result = this.results.NONE;
|
||||
@@ -49,9 +51,13 @@ bkcore.hexgl.Gameplay = function(opts)
|
||||
this.finishTime = null;
|
||||
this.onFinish = opts.onFinish == undefined ? function(){console.log("FINISH");} : opts.onFinish;
|
||||
|
||||
this.raceData = null;
|
||||
|
||||
this.modes.timeattack = function()
|
||||
{
|
||||
self.hud.updateTime(self.timer.getElapsedTime());
|
||||
self.raceData.tick(this.timer.time.elapsed);
|
||||
|
||||
self.hud != null && self.hud.updateTime(self.timer.getElapsedTime());
|
||||
var cp = self.checkPoint();
|
||||
|
||||
if(cp == self.track.checkpoints.start && self.previousCheckPoint == self.track.checkpoints.last)
|
||||
@@ -68,10 +74,10 @@ bkcore.hexgl.Gameplay = function(opts)
|
||||
else
|
||||
{
|
||||
self.lap++;
|
||||
self.hud.updateLap(self.lap, self.maxLaps);
|
||||
self.hud != null && self.hud.updateLap(self.lap, self.maxLaps);
|
||||
|
||||
if(self.lap == self.maxLaps)
|
||||
self.hud.display("Final lap", 0.5);
|
||||
self.hud != null && self.hud.display("Final lap", 0.5);
|
||||
}
|
||||
}
|
||||
else if(cp != -1 && cp != self.previousCheckPoint)
|
||||
@@ -84,20 +90,30 @@ bkcore.hexgl.Gameplay = function(opts)
|
||||
{
|
||||
self.end(self.results.DESTROYED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.modes.replay = function()
|
||||
{
|
||||
self.raceData.applyInterpolated(this.timer.time.elapsed);
|
||||
|
||||
if(self.raceData.seek == self.raceData.last)
|
||||
{
|
||||
self.end(self.result.REPLAY);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
bkcore.hexgl.Gameplay.prototype.simu = function()
|
||||
{
|
||||
this.lapTimes = [92300, 91250, 90365];
|
||||
this.finishTime = this.lapTimes[0]+this.lapTimes[1]+this.lapTimes[2];
|
||||
this.hud.display("Finish");
|
||||
if(this.hud != null) this.hud.display("Finish");
|
||||
this.step = 100;
|
||||
this.result = this.results.FINISH;
|
||||
this.shipControls.active = false;
|
||||
}
|
||||
|
||||
bkcore.hexgl.Gameplay.prototype.start = function()
|
||||
bkcore.hexgl.Gameplay.prototype.start = function(opts)
|
||||
{
|
||||
this.finishTime = null;
|
||||
this.score = null;
|
||||
@@ -108,12 +124,35 @@ bkcore.hexgl.Gameplay.prototype.start = function()
|
||||
|
||||
this.previousCheckPoint = this.track.checkpoints.start;
|
||||
|
||||
this.raceData = new bkcore.hexgl.RaceData(this.track.name, this.mode, this.shipControls);
|
||||
if(this.mode == 'replay')
|
||||
{
|
||||
this.cameraControls.mode = this.cameraControls.modes.ORBIT;
|
||||
if(this.hud != null) this.hud.messageOnly = true;
|
||||
|
||||
try {
|
||||
var d = localStorage['race-'+this.track.name+'-replay'];
|
||||
if(d == undefined)
|
||||
{
|
||||
console.error('No replay data for '+'race-'+this.track.name+'-replay'+'.');
|
||||
return false;
|
||||
}
|
||||
this.raceData.import(
|
||||
JSON.parse(d)
|
||||
);
|
||||
}
|
||||
catch(e) { console.error('Bad replay format : '+e); return false; }
|
||||
}
|
||||
|
||||
this.active = true;
|
||||
this.step = 0;
|
||||
this.timer.start();
|
||||
this.hud.resetTime();
|
||||
this.hud.display("Get ready", 1);
|
||||
this.hud.updateLap(this.lap, this.maxLaps);
|
||||
if(this.hud != null)
|
||||
{
|
||||
this.hud.resetTime();
|
||||
this.hud.display("Get ready", 1);
|
||||
this.hud.updateLap(this.lap, this.maxLaps);
|
||||
}
|
||||
}
|
||||
|
||||
bkcore.hexgl.Gameplay.prototype.end = function(result)
|
||||
@@ -127,12 +166,12 @@ bkcore.hexgl.Gameplay.prototype.end = function(result)
|
||||
|
||||
if(result == this.results.FINISH)
|
||||
{
|
||||
this.hud.display("Finish");
|
||||
if(this.hud != null) this.hud.display("Finish");
|
||||
this.step = 100;
|
||||
}
|
||||
else if(result == this.results.DESTROYED)
|
||||
{
|
||||
this.hud.display("Destroyed");
|
||||
if(this.hud != null) this.hud.display("Destroyed");
|
||||
this.step = 100;
|
||||
}
|
||||
}
|
||||
@@ -145,25 +184,27 @@ bkcore.hexgl.Gameplay.prototype.update = function()
|
||||
|
||||
if(this.step == 0 && this.timer.time.elapsed >= this.countDownDelay+this.startDelay)
|
||||
{
|
||||
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.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.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.display("Go", 0.5);
|
||||
if(this.hud != null) this.hud.display("Go", 0.5);
|
||||
this.step = 4;
|
||||
this.timer.start();
|
||||
this.shipControls.active = true;
|
||||
|
||||
if(this.mode != "replay")
|
||||
this.shipControls.active = true;
|
||||
}
|
||||
else if(this.step == 4)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,9 @@ bkcore.hexgl.HUD = function(opts)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.visible = true;
|
||||
this.messageOnly = false;
|
||||
|
||||
this.width = opts.width;
|
||||
this.height = opts.height;
|
||||
|
||||
@@ -124,7 +127,11 @@ bkcore.hexgl.HUD.prototype.update = function(speed, speedRatio, shield, shieldRa
|
||||
var SCREEN_HW = SCREEN_WIDTH / 2;
|
||||
var SCREEN_HH = SCREEN_HEIGHT / 2;
|
||||
|
||||
//this.ctx.clearRect(0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT);
|
||||
if(!this.visible)
|
||||
{
|
||||
this.ctx.clearRect(0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT);
|
||||
return;
|
||||
}
|
||||
|
||||
var w = this.bg.width;
|
||||
var h = this.bg.height;
|
||||
@@ -148,39 +155,42 @@ bkcore.hexgl.HUD.prototype.update = function(speed, speedRatio, shield, shieldRa
|
||||
{
|
||||
this.ctx.clearRect(0 , oh , SCREEN_WIDTH , nh);
|
||||
|
||||
this.ctx.drawImage(this.bg, o, oh, nw, nh);
|
||||
if(!this.messageOnly)
|
||||
{
|
||||
this.ctx.drawImage(this.bg, o, oh, nw, nh);
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(bw+ba+SCREEN_HW, oh);
|
||||
this.ctx.lineTo(-(bw+ba)+SCREEN_HW, oh);
|
||||
this.ctx.lineTo(-bw+SCREEN_HW, SCREEN_HEIGHT);
|
||||
this.ctx.lineTo(bw+SCREEN_HW, SCREEN_HEIGHT);
|
||||
this.ctx.lineTo(bw+ba+SCREEN_HW, oh);
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.fgspeed, o, oh, nw, nh);
|
||||
this.ctx.restore();
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(bw+ba+SCREEN_HW, oh);
|
||||
this.ctx.lineTo(-(bw+ba)+SCREEN_HW, oh);
|
||||
this.ctx.lineTo(-bw+SCREEN_HW, SCREEN_HEIGHT);
|
||||
this.ctx.lineTo(bw+SCREEN_HW, SCREEN_HEIGHT);
|
||||
this.ctx.lineTo(bw+ba+SCREEN_HW, oh);
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.fgspeed, o, oh, nw, nh);
|
||||
this.ctx.restore();
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(-sw+SCREEN_HW, oh+sy);
|
||||
this.ctx.lineTo(sw+SCREEN_HW, oh+sy);
|
||||
this.ctx.lineTo(sw+SCREEN_HW, oh+sh+sy);
|
||||
this.ctx.lineTo(-sw+SCREEN_HW, oh+sh+sy);
|
||||
this.ctx.lineTo(-sw+SCREEN_HW, oh+sh);
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.fgshield, o, oh, nw, nh);
|
||||
this.ctx.restore();
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(-sw+SCREEN_HW, oh+sy);
|
||||
this.ctx.lineTo(sw+SCREEN_HW, oh+sy);
|
||||
this.ctx.lineTo(sw+SCREEN_HW, oh+sh+sy);
|
||||
this.ctx.lineTo(-sw+SCREEN_HW, oh+sh+sy);
|
||||
this.ctx.lineTo(-sw+SCREEN_HW, oh+sh);
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.fgshield, o, oh, nw, nh);
|
||||
this.ctx.restore();
|
||||
|
||||
// SPEED
|
||||
this.ctx.font = (SCREEN_WIDTH/this.speedFontRatio)+"px "+this.font;
|
||||
this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
|
||||
this.ctx.fillText(speed, SCREEN_HW, SCREEN_HEIGHT - nh*0.57);
|
||||
// SPEED
|
||||
this.ctx.font = (SCREEN_WIDTH/this.speedFontRatio)+"px "+this.font;
|
||||
this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
|
||||
this.ctx.fillText(speed, SCREEN_HW, SCREEN_HEIGHT - nh*0.57);
|
||||
|
||||
// SHIELD
|
||||
this.ctx.font = (SCREEN_WIDTH/this.shieldFontRatio)+"px "+this.font;
|
||||
this.ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
|
||||
this.ctx.fillText(shield, SCREEN_HW, SCREEN_HEIGHT - nh*0.44);
|
||||
// SHIELD
|
||||
this.ctx.font = (SCREEN_WIDTH/this.shieldFontRatio)+"px "+this.font;
|
||||
this.ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
|
||||
this.ctx.fillText(shield, SCREEN_HW, SCREEN_HEIGHT - nh*0.44);
|
||||
}
|
||||
}
|
||||
else if(this.step == 1)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* HexGL
|
||||
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
|
||||
*/
|
||||
|
||||
@@ -19,8 +19,9 @@ 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;
|
||||
this.height = opts.height == undefined ? window.innerHeight : opts.height;
|
||||
|
||||
@@ -32,6 +33,10 @@ bkcore.hexgl.HexGL = function(opts)
|
||||
|
||||
this.track = bkcore.hexgl.tracks[ opts.track == undefined ? 'Cityscape' : opts.track ];
|
||||
|
||||
this.mode = opts.mode == undefined ? 'timeattack' : opts.mode;
|
||||
|
||||
this.controlType = opts.controlType == undefined ? 1 : opts.controlType;
|
||||
|
||||
if(this.half)
|
||||
{
|
||||
this.width /= 2;
|
||||
@@ -54,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;
|
||||
@@ -64,9 +73,9 @@ bkcore.hexgl.HexGL = function(opts)
|
||||
|
||||
this.initRenderer();
|
||||
|
||||
function onKeyPress(event)
|
||||
function onKeyPress(event)
|
||||
{
|
||||
if(event.keyCode == 27/*escape*/)
|
||||
if(event.keyCode == 27/*escape*/)
|
||||
{
|
||||
self.reset();
|
||||
}
|
||||
@@ -84,7 +93,7 @@ bkcore.hexgl.HexGL.prototype.start = function()
|
||||
|
||||
function raf()
|
||||
{
|
||||
requestAnimationFrame( raf );
|
||||
if(self && self.active) requestAnimationFrame( raf );
|
||||
self.update();
|
||||
}
|
||||
|
||||
@@ -102,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();
|
||||
}
|
||||
|
||||
@@ -120,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()
|
||||
@@ -137,17 +147,15 @@ bkcore.hexgl.HexGL.prototype.initGameplay = function()
|
||||
var self = this;
|
||||
|
||||
this.gameplay = new bkcore.hexgl.Gameplay({
|
||||
mode: "timeattack",
|
||||
mode: this.mode,
|
||||
hud: this.hud,
|
||||
shipControls: this.components.shipControls,
|
||||
cameraControls: this.components.cameraChase,
|
||||
analyser: this.track.analyser,
|
||||
pixelRatio: this.track.pixelRatio,
|
||||
track: {
|
||||
checkpoints: this.track.checkpoints,
|
||||
spawn: this.track.spawn,
|
||||
spawnRotation: this.track.spawnRotation
|
||||
},
|
||||
track: this.track,
|
||||
onFinish: function() {
|
||||
self.components.shipControls.terminate();
|
||||
self.displayScore(this.finishTime, this.lapTimes);
|
||||
}
|
||||
});
|
||||
@@ -157,7 +165,24 @@ bkcore.hexgl.HexGL.prototype.initGameplay = function()
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
|
||||
{
|
||||
var t = 'cityscape';
|
||||
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.gameover !== null)
|
||||
{
|
||||
this.gameover.style.display = "block";
|
||||
this.gameover.children[0].innerHTML = tf.m + "'" + tf.s + "''" + tf.ms;
|
||||
this.containers.main.parentElement.style.display = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
var t = this.track;
|
||||
var dc = this.document.getElementById("finish");
|
||||
var ds = this.document.getElementById("finish-state");
|
||||
var dh = this.document.getElementById("finish-hallmsg");
|
||||
@@ -172,12 +197,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)
|
||||
{
|
||||
@@ -189,6 +208,9 @@ bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
|
||||
{
|
||||
dr != undefined && (dr.innerHTML = "New local record!");
|
||||
localStorage['score-'+t+'-'+d] = f;
|
||||
|
||||
// Export race data
|
||||
localStorage['race-'+t+'-replay'] = JSON.Stringify(this.gameplay.raceData.export());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -250,25 +272,30 @@ 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;
|
||||
renderer.setSize( this.width, this.height );
|
||||
renderer.domElement.style.position = "relative";
|
||||
|
||||
this.containers.main.appendChild( renderer.domElement );
|
||||
this.containers.main.appendChild( renderer.domElement );
|
||||
this.canvas = renderer.domElement;
|
||||
this.renderer = renderer;
|
||||
this.manager = new bkcore.threejs.RenderManager(renderer);
|
||||
}
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.initHUD = function()
|
||||
{
|
||||
if(!this.displayHUD) return;
|
||||
this.hud = new bkcore.hexgl.HUD({
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
@@ -276,7 +303,7 @@ bkcore.hexgl.HexGL.prototype.initHUD = function()
|
||||
bg: this.track.lib.get("images", "hud.bg"),
|
||||
speed: this.track.lib.get("images", "hud.speed"),
|
||||
shield: this.track.lib.get("images", "hud.shield")
|
||||
});
|
||||
});
|
||||
this.containers.overlay.appendChild(this.hud.canvas);
|
||||
}
|
||||
|
||||
@@ -285,7 +312,7 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
|
||||
var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
|
||||
var renderTarget = new THREE.WebGLRenderTarget( this.width, this.height, renderTargetParameters );
|
||||
|
||||
// GAME COMPOSER
|
||||
// GAME COMPOSER
|
||||
var renderSky = new THREE.RenderPass( this.manager.get("sky").scene, this.manager.get("sky").camera );
|
||||
|
||||
var renderModel = new THREE.RenderPass( this.manager.get("game").scene, this.manager.get("game").camera );
|
||||
@@ -293,7 +320,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" ] );
|
||||
@@ -308,17 +336,17 @@ bkcore.hexgl.HexGL.prototype.initGameComposer = function()
|
||||
this.composers.game.addPass( renderSky );
|
||||
this.composers.game.addPass( renderModel );
|
||||
|
||||
if(this.quality > 0)
|
||||
{
|
||||
var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] );
|
||||
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.width, 1 / this.height );
|
||||
// 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 );
|
||||
|
||||
this.composers.game.addPass( effectFXAA );
|
||||
|
||||
this.extras.fxaa = effectFXAA;
|
||||
}
|
||||
if(this.quality > 1)
|
||||
{
|
||||
// this.composers.game.addPass( effectFXAA );
|
||||
|
||||
// this.extras.fxaa = effectFXAA;
|
||||
// }
|
||||
if(this.quality > 1 && !this.mobile)
|
||||
{
|
||||
var effectBloom = new THREE.BloomPass( 0.8, 25, 4 , 256);
|
||||
|
||||
this.composers.game.addPass( effectBloom );
|
||||
@@ -326,12 +354,15 @@ 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 );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
bkcore.hexgl.HexGL.prototype.createMesh = function(parent, geometry, x, y, z, mat)
|
||||
bkcore.hexgl.HexGL.prototype.createMesh = function(parent, geometry, x, y, z, mat)
|
||||
{
|
||||
geometry.computeTangents();
|
||||
|
||||
@@ -339,7 +370,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;
|
||||
@@ -389,4 +420,7 @@ bkcore.hexgl.HexGL.prototype.tweakShipControls = function()
|
||||
c.driftLerp = 0.3;
|
||||
c.angularLerp = 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
if(this.godmode)
|
||||
c.shieldDamage = 0.0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* HexGL
|
||||
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
|
||||
*/
|
||||
|
||||
var bkcore = bkcore || {};
|
||||
bkcore.hexgl = bkcore.hexgl || {};
|
||||
|
||||
bkcore.hexgl.RaceData = function(track, mode, shipControls)
|
||||
{
|
||||
this.track = track;
|
||||
this.mode = mode;
|
||||
this.shipControls = shipControls;
|
||||
|
||||
this.rate = 2; // 1 / rate
|
||||
this.rateState = 1;
|
||||
|
||||
this.data = [];
|
||||
this.last = -1;
|
||||
this.seek = 0;
|
||||
|
||||
this._p = new THREE.Vector3();
|
||||
this._pp = new THREE.Vector3();
|
||||
this._np = new THREE.Vector3();
|
||||
this._q = new THREE.Quaternion();
|
||||
this._pq = new THREE.Quaternion();
|
||||
this._nq = new THREE.Quaternion();
|
||||
}
|
||||
|
||||
bkcore.hexgl.RaceData.prototype.tick = function(time)
|
||||
{
|
||||
if(this.rateState == 1)
|
||||
{
|
||||
var p = this.shipControls.getPosition();
|
||||
var q = this.shipControls.getQuaternion();
|
||||
this.data.push([
|
||||
time,
|
||||
p.x, p.y, p.z,
|
||||
q.x, q.y, q.z, q.w
|
||||
]);
|
||||
++this.last;
|
||||
}
|
||||
else if(this.rateState == this.rate)
|
||||
{
|
||||
this.rateState = 0;
|
||||
}
|
||||
|
||||
this.rate++;
|
||||
}
|
||||
|
||||
bkcore.hexgl.RaceData.prototype.applyInterpolated = function(time)
|
||||
{
|
||||
while(this.seek < this.last && this.data[this.seek+1][0] < time)
|
||||
++this.seek;
|
||||
|
||||
var prev = this.data[this.seek];
|
||||
this._pp.set(prev[1], prev[2], prev[3]);
|
||||
this._pq.set(prev[4], prev[5], prev[6], prev[7]);
|
||||
|
||||
if(this.seek < 0)
|
||||
{
|
||||
console.warn('Bad race data.');
|
||||
return;
|
||||
}
|
||||
|
||||
// no interpolation
|
||||
if(this.seek == this.last || this.seek == 0)
|
||||
this.shipControls.teleport(this._pp, this._pq);
|
||||
|
||||
// interpolation
|
||||
var next = this.data[this.seek+1];
|
||||
this._np.set(next[1], next[2], next[3]);
|
||||
this._nq.set(next[4], next[5], next[6], next[7]);
|
||||
|
||||
var t = (time-prev[0]) / (next[0]-prev[0]);
|
||||
this._p.copy(this._pp).lerpSelf(this._np, t);
|
||||
this._q.copy(this._pq).slerpSelf(this._nq, t);
|
||||
|
||||
this.shipControls.teleport(this._p, this._q);
|
||||
}
|
||||
|
||||
bkcore.hexgl.RaceData.prototype.reset = function()
|
||||
{
|
||||
this.seek = 0;
|
||||
}
|
||||
|
||||
bkcore.hexgl.RaceData.prototype.export = function()
|
||||
{
|
||||
return this.data;
|
||||
}
|
||||
|
||||
bkcore.hexgl.RaceData.prototype.import = function(imp)
|
||||
{
|
||||
this.data = imp;
|
||||
this.last = this.data.length-1;
|
||||
console.log(this.data);
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
/*
|
||||
* HexGL
|
||||
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
|
||||
*/
|
||||
|
||||
var bkcore = bkcore || {};
|
||||
bkcore.hexgl = bkcore.hexgl || {};
|
||||
|
||||
bkcore.hexgl.ShipControls = function(domElement)
|
||||
bkcore.hexgl.ShipControls = function(ctx)
|
||||
{
|
||||
var self = this;
|
||||
var domElement = ctx.document;
|
||||
|
||||
this.active = true;
|
||||
this.destroyed = false;
|
||||
this.falling = false;
|
||||
|
||||
this.dom = domElement;
|
||||
this.mesh = null;
|
||||
@@ -25,7 +27,7 @@ bkcore.hexgl.ShipControls = function(domElement)
|
||||
this.thrust = 0.02;
|
||||
this.airBrake = 0.02;
|
||||
this.maxSpeed = 7.0;
|
||||
this.boosterSpeed = this.maxSpeed * 0.4;
|
||||
this.boosterSpeed = this.maxSpeed * 0.2;
|
||||
this.boosterDecay = 0.01;
|
||||
this.angularSpeed = 0.005;
|
||||
this.airAngularSpeed = 0.0065;
|
||||
@@ -73,7 +75,7 @@ bkcore.hexgl.ShipControls = function(domElement)
|
||||
this.rollAngle = 0.6;
|
||||
this.rollLerp = 0.08;
|
||||
this.rollDirection = new THREE.Vector3(0,0,1);
|
||||
|
||||
|
||||
this.gradient = 0.0;
|
||||
this.gradientTarget = 0.0;
|
||||
this.gradientLerp = 0.05;
|
||||
@@ -95,6 +97,8 @@ bkcore.hexgl.ShipControls = function(domElement)
|
||||
this.repulsionAmount = 0.0;
|
||||
this.repulsionForce = new THREE.Vector3();
|
||||
|
||||
this.fallVector = new THREE.Vector3(0,-20,0);
|
||||
|
||||
this.resetPos = null;
|
||||
this.resetRot = null;
|
||||
|
||||
@@ -114,9 +118,121 @@ bkcore.hexgl.ShipControls = function(domElement)
|
||||
right: false
|
||||
};
|
||||
|
||||
function onKeyDown(event)
|
||||
this.touchController = null;
|
||||
this.orientationController = null;
|
||||
|
||||
if(ctx.controlType == 1 && bkcore.controllers.TouchController.isCompatible())
|
||||
{
|
||||
switch(event.keyCode)
|
||||
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 == 3 && bkcore.controllers.OrientationController.isCompatible())
|
||||
{
|
||||
this.orientationController = new bkcore.controllers.OrientationController(
|
||||
domElement, true,
|
||||
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)
|
||||
{
|
||||
if(Leap == null)
|
||||
throw new Error("Unable to reach LeapJS!");
|
||||
|
||||
var leapInfo = this.leapInfo = document.getElementById('leapinfo');
|
||||
isServerConnected = false;
|
||||
var lb = this.leapBridge = {
|
||||
isConnected: true,
|
||||
hasHands: false,
|
||||
palmNormal: [0, 0, 0]
|
||||
};
|
||||
|
||||
function updateInfo()
|
||||
{
|
||||
if(!isServerConnected)
|
||||
{
|
||||
leapInfo.innerHTML = 'Waiting for the Leap Motion Controller server...'
|
||||
leapInfo.style.display = 'block';
|
||||
}
|
||||
else if(lb.isConnected && lb.hasHands)
|
||||
{
|
||||
leapInfo.style.display = 'none';
|
||||
}
|
||||
else if(!lb.isConnected)
|
||||
{
|
||||
leapInfo.innerHTML = 'Please connect your Leap Motion Controller.'
|
||||
leapInfo.style.display = 'block';
|
||||
}
|
||||
else if(!lb.hasHands)
|
||||
{
|
||||
leapInfo.innerHTML = 'Put your hand over the Leap Motion Controller to play.'
|
||||
leapInfo.style.display = 'block';
|
||||
}
|
||||
}
|
||||
updateInfo();
|
||||
|
||||
var lc = this.leapController = new Leap.Controller({enableGestures: false});
|
||||
lc.on('connect', function()
|
||||
{
|
||||
isServerConnected = true;
|
||||
updateInfo();
|
||||
});
|
||||
lc.on('deviceConnected', function()
|
||||
{
|
||||
lb.isConnected = true;
|
||||
updateInfo();
|
||||
});
|
||||
lc.on('deviceDisconnected', function()
|
||||
{
|
||||
lb.isConnected = false;
|
||||
updateInfo();
|
||||
});
|
||||
lc.on('frame', function(frame)
|
||||
{
|
||||
if(!lb.isConnected) return;
|
||||
hand = frame.hands[0];
|
||||
if(typeof hand === 'undefined')
|
||||
{
|
||||
if(lb.hasHands)
|
||||
{
|
||||
lb.hasHands = false;
|
||||
updateInfo();
|
||||
}
|
||||
lb.palmNormal = [0, 0, 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!lb.hasHands)
|
||||
{
|
||||
lb.hasHands = true;
|
||||
updateInfo();
|
||||
}
|
||||
lb.palmNormal = hand.palmNormal;
|
||||
}
|
||||
});
|
||||
lc.connect();
|
||||
}
|
||||
|
||||
function onKeyDown(event)
|
||||
{
|
||||
switch(event.keyCode)
|
||||
{
|
||||
case 38: /*up*/ self.key.forward = true; break;
|
||||
|
||||
@@ -134,9 +250,9 @@ bkcore.hexgl.ShipControls = function(domElement)
|
||||
}
|
||||
};
|
||||
|
||||
function onKeyUp(event)
|
||||
function onKeyUp(event)
|
||||
{
|
||||
switch(event.keyCode)
|
||||
switch(event.keyCode)
|
||||
{
|
||||
case 38: /*up*/ self.key.forward = false; break;
|
||||
|
||||
@@ -186,11 +302,22 @@ bkcore.hexgl.ShipControls.prototype.reset = function(position, rotation)
|
||||
|
||||
this.dummy.matrix.setPosition(this.dummy.position);
|
||||
this.dummy.matrix.setRotationFromQuaternion(this.dummy.quaternion);
|
||||
|
||||
|
||||
this.mesh.matrix.identity();
|
||||
this.mesh.applyMatrix(this.dummy.matrix);
|
||||
}
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.terminate = function()
|
||||
{
|
||||
this.destroy();
|
||||
|
||||
if(this.leapController != null)
|
||||
{
|
||||
this.leapController.disconnect();
|
||||
this.leapInfo.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.destroy = function()
|
||||
{
|
||||
this.active = false;
|
||||
@@ -200,9 +327,26 @@ 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.active) return;
|
||||
if(this.falling)
|
||||
{
|
||||
this.mesh.position.addSelf(this.fallVector);
|
||||
return;
|
||||
}
|
||||
|
||||
this.rotation.y = 0;
|
||||
this.movement.set(0,0,0);
|
||||
@@ -211,46 +355,73 @@ bkcore.hexgl.ShipControls.prototype.update = function(dt)
|
||||
|
||||
var rollAmount = 0.0;
|
||||
var angularAmount = 0.0;
|
||||
var yawLeap = 0.0;
|
||||
|
||||
if(this.key.forward)
|
||||
this.speed += this.thrust * dt;
|
||||
else
|
||||
this.speed -= this.airResist * dt;
|
||||
if(this.key.left)
|
||||
if(this.leapBridge != null && this.leapBridge.hasHands)
|
||||
{
|
||||
angularAmount += this.angularSpeed * dt;
|
||||
rollAmount -= this.rollAngle;
|
||||
rollAmount -= this.leapBridge.palmNormal[0] * 3.5 * this.rollAngle;
|
||||
yawLeap = -this.leapBridge.palmNormal[2] * 0.6;
|
||||
}
|
||||
if(this.key.right)
|
||||
{
|
||||
angularAmount -= this.angularSpeed * dt;
|
||||
rollAmount += this.rollAngle;
|
||||
}
|
||||
if(this.key.ltrigger)
|
||||
|
||||
if(this.active)
|
||||
{
|
||||
|
||||
if(this.touchController != null)
|
||||
{
|
||||
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.leapBridge != null && this.leapBridge.hasHands)
|
||||
{
|
||||
angularAmount += this.leapBridge.palmNormal[0] * 2 * this.angularSpeed * dt;
|
||||
this.speed += Math.max(0.0, (0.5 + this.leapBridge.palmNormal[2])) * 3 * this.thrust * dt;
|
||||
}
|
||||
|
||||
if(this.key.forward)
|
||||
this.speed += this.thrust * dt;
|
||||
else
|
||||
this.speed -= this.airResist * dt;
|
||||
if(this.key.left)
|
||||
angularAmount += this.airAngularSpeed * dt;
|
||||
else
|
||||
angularAmount += this.airAngularSpeed * 0.5 * dt;
|
||||
this.speed -= this.airBrake * dt;
|
||||
this.drift += (this.airDrift - this.drift) * this.driftLerp;
|
||||
this.movement.x += this.speed * this.drift * dt;
|
||||
if(this.drift > 0.0)
|
||||
this.movement.z -= this.speed * this.drift * dt;
|
||||
rollAmount -= this.rollAngle * 0.7;
|
||||
}
|
||||
if(this.key.rtrigger)
|
||||
{
|
||||
{
|
||||
angularAmount += this.angularSpeed * dt;
|
||||
rollAmount -= this.rollAngle;
|
||||
}
|
||||
if(this.key.right)
|
||||
angularAmount -= this.airAngularSpeed * dt;
|
||||
else
|
||||
angularAmount -= this.airAngularSpeed * 0.5 * dt;
|
||||
this.speed -= this.airBrake * dt;
|
||||
this.drift += (-this.airDrift - this.drift) * this.driftLerp;
|
||||
this.movement.x += this.speed * this.drift * dt;
|
||||
if(this.drift < 0.0)
|
||||
this.movement.z += this.speed * this.drift * dt;
|
||||
rollAmount += this.rollAngle * 0.7;
|
||||
{
|
||||
angularAmount -= this.angularSpeed * dt;
|
||||
rollAmount += this.rollAngle;
|
||||
}
|
||||
if(this.key.ltrigger)
|
||||
{
|
||||
if(this.key.left)
|
||||
angularAmount += this.airAngularSpeed * dt;
|
||||
else
|
||||
angularAmount += this.airAngularSpeed * 0.5 * dt;
|
||||
this.speed -= this.airBrake * dt;
|
||||
this.drift += (this.airDrift - this.drift) * this.driftLerp;
|
||||
this.movement.x += this.speed * this.drift * dt;
|
||||
if(this.drift > 0.0)
|
||||
this.movement.z -= this.speed * this.drift * dt;
|
||||
rollAmount -= this.rollAngle * 0.7;
|
||||
}
|
||||
if(this.key.rtrigger)
|
||||
{
|
||||
if(this.key.right)
|
||||
angularAmount -= this.airAngularSpeed * dt;
|
||||
else
|
||||
angularAmount -= this.airAngularSpeed * 0.5 * dt;
|
||||
this.speed -= this.airBrake * dt;
|
||||
this.drift += (-this.airDrift - this.drift) * this.driftLerp;
|
||||
this.movement.x += this.speed * this.drift * dt;
|
||||
if(this.drift < 0.0)
|
||||
this.movement.z += this.speed * this.drift * dt;
|
||||
rollAmount += this.rollAngle * 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
this.angular += (angularAmount - this.angular) * this.angularLerp;
|
||||
@@ -306,7 +477,7 @@ bkcore.hexgl.ShipControls.prototype.update = function(dt)
|
||||
this.mesh.matrix.identity();
|
||||
|
||||
// Gradient (Mesh only, no dummy physics impact)
|
||||
var gradientDelta = (this.gradientTarget - this.gradient) * this.gradientLerp;
|
||||
var gradientDelta = (this.gradientTarget - (yawLeap + this.gradient)) * this.gradientLerp;
|
||||
if(Math.abs(gradientDelta) > this.epsilon) this.gradient += gradientDelta;
|
||||
if(Math.abs(this.gradient) > this.epsilon)
|
||||
{
|
||||
@@ -337,6 +508,45 @@ bkcore.hexgl.ShipControls.prototype.update = function(dt)
|
||||
}
|
||||
};
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.teleport = function(pos, quat)
|
||||
{
|
||||
this.quaternion.copy(quat);
|
||||
this.dummy.quaternion.copy(this.quaternion);
|
||||
|
||||
this.dummy.position.copy(pos);
|
||||
this.dummy.matrix.setPosition(this.dummy.position);
|
||||
|
||||
//console.log(pos.x, pos.y, pos.z);
|
||||
|
||||
this.dummy.matrix.setRotationFromQuaternion(this.dummy.quaternion);
|
||||
|
||||
if(this.mesh != null)
|
||||
{
|
||||
this.mesh.matrix.identity();
|
||||
/*
|
||||
// Gradient (Mesh only, no dummy physics impact)
|
||||
var gradientDelta = (this.gradientTarget - this.gradient) * this.gradientLerp;
|
||||
if(Math.abs(gradientDelta) > this.epsilon) this.gradient += gradientDelta;
|
||||
if(Math.abs(this.gradient) > this.epsilon)
|
||||
{
|
||||
this.gradientAxis.set(1,0,0);
|
||||
this.mesh.matrix.rotateByAxis(this.gradientAxis, this.gradient);
|
||||
}
|
||||
|
||||
// Tilting (Idem)
|
||||
var tiltDelta = (this.tiltTarget - this.tilt) * this.tiltLerp;
|
||||
if(Math.abs(tiltDelta) > this.epsilon) this.tilt += tiltDelta;
|
||||
if(Math.abs(this.tilt) > this.epsilon)
|
||||
{
|
||||
this.tiltAxis.set(0,0,1);
|
||||
this.mesh.matrix.rotateByAxis(this.tiltAxis, this.tilt);
|
||||
}
|
||||
*/
|
||||
this.mesh.applyMatrix(this.dummy.matrix);
|
||||
this.mesh.updateMatrixWorld(true);
|
||||
}
|
||||
}
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.boosterCheck = function(dt)
|
||||
{
|
||||
if(!this.collisionMap || !this.collisionMap.loaded)
|
||||
@@ -396,9 +606,9 @@ bkcore.hexgl.ShipControls.prototype.collisionCheck = function(dt)
|
||||
var rPos = this.repulsionVRight.addSelf(pos);
|
||||
var lCol = this.collisionMap.getPixel(Math.round(lPos.x), Math.round(lPos.z)).r;
|
||||
var rCol = this.collisionMap.getPixel(Math.round(rPos.x), Math.round(rPos.z)).r;
|
||||
|
||||
this.repulsionAmount = Math.max(0.8,
|
||||
Math.min(this.repulsionCap,
|
||||
|
||||
this.repulsionAmount = Math.max(0.8,
|
||||
Math.min(this.repulsionCap,
|
||||
this.speed * this.repulsionRatio
|
||||
)
|
||||
);
|
||||
@@ -421,6 +631,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;
|
||||
@@ -488,7 +709,7 @@ bkcore.hexgl.ShipControls.prototype.heightCheck = function(dt)
|
||||
x = this.heightMap.pixels.width/2 + this.tiltVector.x * this.heightPixelRatio;
|
||||
z = this.heightMap.pixels.height/2 + this.tiltVector.z * this.heightPixelRatio;
|
||||
|
||||
nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
|
||||
nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
|
||||
}
|
||||
|
||||
if(nheight < 16777)
|
||||
@@ -506,7 +727,7 @@ bkcore.hexgl.ShipControls.prototype.getRealSpeed = function(scale)
|
||||
bkcore.hexgl.ShipControls.prototype.getRealSpeedRatio = function()
|
||||
{
|
||||
return Math.min(
|
||||
this.maxSpeed,
|
||||
this.maxSpeed,
|
||||
this.speed+this.boost
|
||||
) / this.maxSpeed;
|
||||
};
|
||||
@@ -532,4 +753,14 @@ bkcore.hexgl.ShipControls.prototype.getShield = function(scale)
|
||||
this.shield
|
||||
* (scale == undefined ? 1 : scale)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.getPosition = function()
|
||||
{
|
||||
return this.dummy.position;
|
||||
}
|
||||
|
||||
bkcore.hexgl.ShipControls.prototype.getQuaternion = function()
|
||||
{
|
||||
return this.dummy.quaternion;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* HexGL
|
||||
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
|
||||
*/
|
||||
|
||||
@@ -46,7 +46,7 @@ bkcore.hexgl.ShipEffects = function(opts)
|
||||
texture: opts.textureSpark,
|
||||
size: 2,
|
||||
life: 60,
|
||||
max: 500
|
||||
max: 200
|
||||
}),
|
||||
|
||||
leftClouds: new bkcore.threejs.Particles(
|
||||
@@ -59,7 +59,7 @@ bkcore.hexgl.ShipEffects = function(opts)
|
||||
size: 6,
|
||||
blending: THREE.NormalBlending,
|
||||
life: 60,
|
||||
max: 500,
|
||||
max: 200,
|
||||
spawn: new THREE.Vector3(3,-0.3,0),
|
||||
spawnRadius: new THREE.Vector3(1,1,2),
|
||||
velocity: new THREE.Vector3(0,0,-0.4),
|
||||
@@ -75,7 +75,7 @@ bkcore.hexgl.ShipEffects = function(opts)
|
||||
texture: opts.textureSpark,
|
||||
size: 2,
|
||||
life: 60,
|
||||
max: 500
|
||||
max: 200
|
||||
}),
|
||||
|
||||
rightClouds: new bkcore.threejs.Particles(
|
||||
@@ -88,7 +88,7 @@ bkcore.hexgl.ShipEffects = function(opts)
|
||||
size: 6,
|
||||
blending: THREE.NormalBlending,
|
||||
life: 60,
|
||||
max: 500,
|
||||
max: 200,
|
||||
spawn: new THREE.Vector3(-3,-0.3,0),
|
||||
spawnRadius: new THREE.Vector3(1,1,2),
|
||||
velocity: new THREE.Vector3(0,0,-0.4),
|
||||
@@ -105,7 +105,7 @@ bkcore.hexgl.ShipEffects = function(opts)
|
||||
|
||||
bkcore.hexgl.ShipEffects.prototype.update = function(dt)
|
||||
{
|
||||
var boostRatio, opacity, scale, intensity, random;
|
||||
var boostRatio, opacity, scale, intensity, random;
|
||||
|
||||
if(this.shipControls.destroyed)
|
||||
{
|
||||
@@ -144,8 +144,8 @@ bkcore.hexgl.ShipEffects.prototype.update = function(dt)
|
||||
this.particles.leftSparks.velocity.copy(this.pVel).x *= -1;
|
||||
this.particles.leftSparks.spawn.copy(this.pOffset).x *= -1;
|
||||
|
||||
if(this.shipControls.mesh)
|
||||
{
|
||||
if(this.shipControls.mesh)
|
||||
{
|
||||
// RIGHT
|
||||
this.shipControls.mesh.matrix.rotateAxis(this.particles.rightSparks.spawn);
|
||||
this.particles.rightSparks.spawn.multiplyScalar(this.pOffsetS).addSelf(this.shipControls.dummy.position);
|
||||
@@ -168,14 +168,14 @@ bkcore.hexgl.ShipEffects.prototype.update = function(dt)
|
||||
|
||||
if(this.shipControls.collision.right)
|
||||
{
|
||||
this.particles.rightSparks.emit(Math.round(30*dt));
|
||||
this.particles.rightClouds.emit(Math.round(10*dt));
|
||||
this.particles.rightSparks.emit(10);
|
||||
this.particles.rightClouds.emit(5);
|
||||
}
|
||||
|
||||
if(this.shipControls.collision.left)
|
||||
{
|
||||
this.particles.leftSparks.emit(Math.round(30*dt));
|
||||
this.particles.leftClouds.emit(Math.round(10*dt));
|
||||
this.particles.leftSparks.emit(10);
|
||||
this.particles.leftClouds.emit(5);
|
||||
}
|
||||
|
||||
this.particles.rightSparks.update(dt);
|
||||
@@ -183,4 +183,4 @@ bkcore.hexgl.ShipEffects.prototype.update = function(dt)
|
||||
this.particles.leftSparks.update(dt);
|
||||
this.particles.leftClouds.update(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* HexGL
|
||||
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,8 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
lib: null,
|
||||
materials: {},
|
||||
|
||||
name: "Cityscape",
|
||||
|
||||
checkpoints: {
|
||||
list: [0,1,2],
|
||||
start: 0,
|
||||
@@ -21,8 +23,8 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
},
|
||||
|
||||
spawn: {
|
||||
x: -1134*2,
|
||||
y: 387,
|
||||
x: -1134*2,
|
||||
y: 387,
|
||||
z: -443*2
|
||||
},
|
||||
|
||||
@@ -35,15 +37,17 @@ 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: {
|
||||
'hex' : "textures/hud/hex.jpg",
|
||||
'spark' : "textures/particles/spark.png",
|
||||
'cloud' : "textures/particles/cloud.png",
|
||||
'ship.feisar.diffuse' : "textures/ships/feisar/diffuse.jpg",
|
||||
'booster.diffuse' : "textures/ships/feisar/booster/booster.png",
|
||||
'booster.sprite' : "textures/ships/feisar/booster/boostersprite.jpg",
|
||||
@@ -80,36 +84,36 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
});
|
||||
}
|
||||
else // HIGH
|
||||
{
|
||||
{console.log('HIGH');
|
||||
this.lib.load({
|
||||
textures: {
|
||||
'hex' : "textures/hud/hex.jpg",
|
||||
'spark' : "textures/particles/spark.png",
|
||||
'cloud' : "textures/particles/cloud.png",
|
||||
'ship.feisar.diffuse' : "textures/ships/feisar/diffuse.jpg",
|
||||
'ship.feisar.specular' : "textures/ships/feisar/specular.jpg",
|
||||
'ship.feisar.normal' : "textures/ships/feisar/normal.jpg",
|
||||
'booster.diffuse' : "textures/ships/feisar/booster/booster.png",
|
||||
'booster.sprite' : "textures/ships/feisar/booster/boostersprite.jpg",
|
||||
'track.cityscape.diffuse' : "textures/tracks/cityscape/diffuse.jpg",
|
||||
'track.cityscape.specular' : "textures/tracks/cityscape/specular.jpg",
|
||||
'track.cityscape.normal' : "textures/tracks/cityscape/normal.jpg",
|
||||
'track.cityscape.scrapers1.diffuse' : "textures/tracks/cityscape/scrapers1/diffuse.jpg",
|
||||
'track.cityscape.scrapers1.specular': "textures/tracks/cityscape/scrapers1/specular.jpg",
|
||||
'track.cityscape.scrapers1.normal' : "textures/tracks/cityscape/scrapers1/normal.jpg",
|
||||
'track.cityscape.scrapers2.diffuse' : "textures/tracks/cityscape/scrapers2/diffuse.jpg",
|
||||
'track.cityscape.scrapers2.specular': "textures/tracks/cityscape/scrapers2/specular.jpg",
|
||||
'track.cityscape.scrapers2.normal' : "textures/tracks/cityscape/scrapers2/normal.jpg",
|
||||
'track.cityscape.start.diffuse' : "textures/tracks/cityscape/start/diffuse.jpg",
|
||||
'track.cityscape.start.specular' : "textures/tracks/cityscape/start/specular.jpg",
|
||||
'track.cityscape.start.normal' : "textures/tracks/cityscape/start/normal.jpg",
|
||||
'track.cityscape.start.banner' : "textures/tracks/cityscape/start/start.jpg",
|
||||
'bonus.base.diffuse' : "textures/bonus/base/diffuse.jpg",
|
||||
'bonus.base.normal' : "textures/bonus/base/normal.jpg",
|
||||
'bonus.base.specular' : "textures/bonus/base/specular.jpg"
|
||||
'hex' : "textures.full/hud/hex.jpg",
|
||||
'spark' : "textures.full/particles/spark.png",
|
||||
'cloud' : "textures.full/particles/cloud.png",
|
||||
'ship.feisar.diffuse' : "textures.full/ships/feisar/diffuse.jpg",
|
||||
'ship.feisar.specular' : "textures.full/ships/feisar/specular.jpg",
|
||||
'ship.feisar.normal' : "textures.full/ships/feisar/normal.jpg",
|
||||
'booster.diffuse' : "textures.full/ships/feisar/booster/booster.png",
|
||||
'booster.sprite' : "textures.full/ships/feisar/booster/boostersprite.jpg",
|
||||
'track.cityscape.diffuse' : "textures.full/tracks/cityscape/diffuse.jpg",
|
||||
'track.cityscape.specular' : "textures.full/tracks/cityscape/specular.jpg",
|
||||
'track.cityscape.normal' : "textures.full/tracks/cityscape/normal.jpg",
|
||||
'track.cityscape.scrapers1.diffuse' : "textures.full/tracks/cityscape/scrapers1/diffuse.jpg",
|
||||
'track.cityscape.scrapers1.specular': "textures.full/tracks/cityscape/scrapers1/specular.jpg",
|
||||
'track.cityscape.scrapers1.normal' : "textures.full/tracks/cityscape/scrapers1/normal.jpg",
|
||||
'track.cityscape.scrapers2.diffuse' : "textures.full/tracks/cityscape/scrapers2/diffuse.jpg",
|
||||
'track.cityscape.scrapers2.specular': "textures.full/tracks/cityscape/scrapers2/specular.jpg",
|
||||
'track.cityscape.scrapers2.normal' : "textures.full/tracks/cityscape/scrapers2/normal.jpg",
|
||||
'track.cityscape.start.diffuse' : "textures.full/tracks/cityscape/start/diffuse.jpg",
|
||||
'track.cityscape.start.specular' : "textures.full/tracks/cityscape/start/specular.jpg",
|
||||
'track.cityscape.start.normal' : "textures.full/tracks/cityscape/start/normal.jpg",
|
||||
'track.cityscape.start.banner' : "textures.full/tracks/cityscape/start/start.jpg",
|
||||
'bonus.base.diffuse' : "textures.full/bonus/base/diffuse.jpg",
|
||||
'bonus.base.normal' : "textures.full/bonus/base/normal.jpg",
|
||||
'bonus.base.specular' : "textures.full/bonus/base/specular.jpg"
|
||||
},
|
||||
texturesCube: {
|
||||
'skybox.dawnclouds' : "textures/skybox/dawnclouds/%1.jpg"
|
||||
'skybox.dawnclouds' : "textures.full/skybox/dawnclouds/%1.jpg"
|
||||
},
|
||||
geometries: {
|
||||
'bonus.base' : "geometries/bonus/base/base.js",
|
||||
@@ -123,21 +127,21 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
'track.cityscape.bonus.speed' : "geometries/tracks/cityscape/bonus/speed.js"
|
||||
},
|
||||
analysers: {
|
||||
'track.cityscape.collision' : "textures/tracks/cityscape/collision.png",
|
||||
'track.cityscape.height' : "textures/tracks/cityscape/height.png"
|
||||
'track.cityscape.collision' : "textures.full/tracks/cityscape/collision.png",
|
||||
'track.cityscape.height' : "textures.full/tracks/cityscape/height.png"
|
||||
},
|
||||
images: {
|
||||
'hud.bg' : "textures/hud/hud-bg.png",
|
||||
'hud.speed' : "textures/hud/hud-fg-speed.png",
|
||||
'hud.shield' : "textures/hud/hud-fg-shield.png"
|
||||
'hud.bg' : "textures.full/hud/hud-bg.png",
|
||||
'hud.speed' : "textures.full/hud/hud-fg-speed.png",
|
||||
'hud.shield' : "textures.full/hud/hud-fg-shield.png"
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
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"),
|
||||
@@ -159,7 +163,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
});
|
||||
|
||||
this.materials.booster = new THREE.MeshBasicMaterial({
|
||||
map: this.lib.get("textures", "booster.diffuse"),
|
||||
map: this.lib.get("textures", "booster.diffuse"),
|
||||
transparent: true
|
||||
});
|
||||
|
||||
@@ -175,11 +179,11 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
|
||||
this.materials.start = new THREE.MeshBasicMaterial({
|
||||
map: this.lib.get("textures", "track.cityscape.start.diffuse"),
|
||||
ambient: 0xcccccc
|
||||
ambient: 0xcccccc
|
||||
});
|
||||
|
||||
this.materials.startBanner = new THREE.MeshBasicMaterial({
|
||||
map: this.lib.get("textures", "track.cityscape.start.banner"),
|
||||
map: this.lib.get("textures", "track.cityscape.start.banner"),
|
||||
transparent: false
|
||||
});
|
||||
}
|
||||
@@ -221,7 +225,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
});
|
||||
|
||||
this.materials.booster = new THREE.MeshBasicMaterial({
|
||||
map: this.lib.get("textures", "booster.diffuse"),
|
||||
map: this.lib.get("textures", "booster.diffuse"),
|
||||
transparent: true
|
||||
});
|
||||
|
||||
@@ -260,13 +264,13 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
});
|
||||
|
||||
this.materials.startBanner = new THREE.MeshBasicMaterial({
|
||||
map: this.lib.get("textures", "track.cityscape.start.banner"),
|
||||
map: this.lib.get("textures", "track.cityscape.start.banner"),
|
||||
transparent: false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
buildScenes: function(ctx, quality)
|
||||
buildScenes: function(ctx, quality, mobile)
|
||||
{
|
||||
// IMPORTANT
|
||||
this.analyser = this.lib.get("analysers", "track.cityscape.collision");
|
||||
@@ -297,9 +301,9 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
|
||||
var ambient = 0xbbbbbb, diffuse = 0xffffff, specular = 0xffffff, shininess = 42, scale = 23;
|
||||
|
||||
// MAIN SCENE
|
||||
// MAIN SCENE
|
||||
var camera = new THREE.PerspectiveCamera( 70, ctx.width / ctx.height, 1, 60000 );
|
||||
|
||||
|
||||
var scene = new THREE.Scene();
|
||||
scene.add( camera );
|
||||
scene.add( new THREE.AmbientLight( ambient ) );
|
||||
@@ -309,7 +313,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;
|
||||
@@ -328,15 +332,15 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
|
||||
// SHIP
|
||||
var ship = ctx.createMesh(scene, this.lib.get("geometries", "ship.feisar"), -1134*2, 10, -443*2, this.materials.ship);
|
||||
|
||||
|
||||
var booster = ctx.createMesh(ship, this.lib.get("geometries", "booster"), 0, 0.665, -3.8, this.materials.booster);
|
||||
booster.depthWrite = false;
|
||||
|
||||
var boosterSprite = new THREE.Sprite({
|
||||
map: this.lib.get("textures", "booster.sprite"),
|
||||
blending: THREE.AdditiveBlending,
|
||||
useScreenCoordinates: false,
|
||||
color: 0xffffff
|
||||
var boosterSprite = new THREE.Sprite({
|
||||
map: this.lib.get("textures", "booster.sprite"),
|
||||
blending: THREE.AdditiveBlending,
|
||||
useScreenCoordinates: false,
|
||||
color: 0xffffff
|
||||
});
|
||||
boosterSprite.scale.set(0.02, 0.02, 0.02);
|
||||
boosterSprite.mergeWith3D = false;
|
||||
@@ -348,7 +352,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
ship.add(boosterLight);
|
||||
|
||||
// SHIP CONTROLS
|
||||
var shipControls = new bkcore.hexgl.ShipControls(ctx.document);
|
||||
var shipControls = new bkcore.hexgl.ShipControls(ctx);
|
||||
shipControls.collisionMap = this.lib.get("analysers", "track.cityscape.collision");
|
||||
shipControls.collisionPixelRatio = 2048.0 / 6000.0;
|
||||
shipControls.collisionDetection = true;
|
||||
@@ -369,7 +373,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");
|
||||
@@ -406,7 +410,7 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
var dt = delta/16.6;
|
||||
|
||||
this.objects.components.shipControls.update(dt);
|
||||
|
||||
|
||||
this.objects.components.shipEffects.update(dt);
|
||||
|
||||
this.objects.components.cameraChase.update(dt, this.objects.components.shipControls.getSpeedRatio());
|
||||
@@ -421,10 +425,10 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
this.objects.components.cameraChase.cameraCube.rotation.copy(c.rotation);*/
|
||||
|
||||
this.objects.composers.game.render(dt);
|
||||
this.objects.hud.update(
|
||||
this.objects.components.shipControls.getRealSpeed(100),
|
||||
this.objects.components.shipControls.getRealSpeedRatio(),
|
||||
this.objects.components.shipControls.getShield(100),
|
||||
if(this.objects.hud) this.objects.hud.update(
|
||||
this.objects.components.shipControls.getRealSpeed(100),
|
||||
this.objects.components.shipControls.getRealSpeedRatio(),
|
||||
this.objects.components.shipControls.getShield(100),
|
||||
this.objects.components.shipControls.getShieldRatio()
|
||||
);
|
||||
if(this.objects.components.shipControls.getShieldRatio() < 0.2)
|
||||
@@ -442,4 +446,4 @@ bkcore.hexgl.tracks.Cityscape = {
|
||||
lowFPS: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: 82 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
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,234 @@
|
||||
@-webkit-keyframes anim {
|
||||
0% { -webkit-transform: translateY(10px) }
|
||||
50% { -webkit-transform: translateY(-10px) }
|
||||
100% { -webkit-transform: translateY(10px) }
|
||||
}
|
||||
@-moz-keyframes anim {
|
||||
0% { -moz-transform: translateY(10px) }
|
||||
50% { -moz-transform: translateY(-10px) }
|
||||
100% { -moz-transform: translateY(10px) }
|
||||
}
|
||||
@-o-keyframes anim {
|
||||
0% { -o-transform: translateY(10px) }
|
||||
50% { -o-transform: translateY(-10px) }
|
||||
100% { -o-transform: translateY(10px) }
|
||||
}
|
||||
@keyframes anim {
|
||||
0% { transform: translateY(10px) }
|
||||
50% { transform: translateY(-10px) }
|
||||
100% { transform: translateY(10px) }
|
||||
}
|
||||
|
||||
@-webkit-keyframes animbg {
|
||||
0% { -webkit-transform: translateY(5px) }
|
||||
50% { -webkit-transform: translateY(-5px) }
|
||||
100% { -webkit-transform: translateY(5px) }
|
||||
}
|
||||
@-moz-keyframes animbg {
|
||||
0% { -moz-transform: translateY(5px) }
|
||||
50% { -moz-transform: translateY(-5px) }
|
||||
100% { -moz-transform: translateY(5px) }
|
||||
}
|
||||
@-o-keyframes animbg {
|
||||
0% { -o-transform: translateY(5px) }
|
||||
50% { -o-transform: translateY(-5px) }
|
||||
100% { -o-transform: translateY(5px) }
|
||||
}
|
||||
@keyframes animbg {
|
||||
0% { transform: translateY(5px) }
|
||||
50% { transform: translateY(-5px) }
|
||||
100% { transform: translateY(5px) }
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html, body {
|
||||
overflow: hidden;
|
||||
font-family: 'BebasNeueRegular', arial, sans-serif;
|
||||
background: white;
|
||||
}
|
||||
|
||||
#global {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
background: url('bg.jpg') no-repeat center center fixed;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
-moz-background-size: cover;
|
||||
-webkit-background-size: cover;
|
||||
-ms-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
-webkit-transform: translateZ(0);
|
||||
-moz-transform: translateZ(0);
|
||||
-o-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
-webkit-animation: animbg 3s ease-in-out infinite;
|
||||
-moz-animation: animbg 3s ease-in-out infinite;
|
||||
-o-animation: animbg 3s ease-in-out infinite;
|
||||
animation: animbg 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
#title {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
right: 0;
|
||||
bottom: 5%;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
background: url('title.png') no-repeat center top;
|
||||
-moz-background-size: auto 50%;
|
||||
-webkit-background-size: auto 50%;
|
||||
-ms-background-size: auto 50%;
|
||||
-o-background-size: auto 50%;
|
||||
background-size: auto 50%;
|
||||
-webkit-transform: translateZ(0);
|
||||
-moz-transform: translateZ(0);
|
||||
-o-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
-webkit-animation: anim 3s ease-in-out infinite;
|
||||
-moz-animation: anim 3s ease-in-out infinite;
|
||||
-o-animation: anim 3s ease-in-out infinite;
|
||||
animation: anim 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
#menucontainer {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
right: 0;
|
||||
bottom: 10%;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#menu {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
font-family: 'BebasNeueRegular', arial, sans-serif;
|
||||
text-transform: uppercase;
|
||||
color: #4190bb;
|
||||
}
|
||||
|
||||
#menu div {
|
||||
padding: 0.1em 0 0 0;
|
||||
margin: 0 0;
|
||||
cursor: pointer;
|
||||
-moz-text-shadow: 0 0 10px rgb(255,255,255);
|
||||
-webkit-text-shadow: 0 0 10px rgb(255,255,255);
|
||||
text-shadow: 0 0 10px rgb(255,255,255);
|
||||
-webkit-transform-origin-y: 50%;
|
||||
-webkit-transition: -webkit-transform 0.2s;
|
||||
-webkit-transform: translateZ(0px) scaleY(0.8);
|
||||
transform-origin-y: 50%;
|
||||
transition: transform 0.2s ease;
|
||||
transform: translateZ(0px) scaleY(0.8);
|
||||
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIgc3RvcC1vcGFjaXR5PSIwIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjQwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIgc3RvcC1vcGFjaXR5PSIwLjUiLz4KICAgIDxzdG9wIG9mZnNldD0iNjAlIiBzdG9wLWNvbG9yPSIjZmZmZmZmIiBzdG9wLW9wYWNpdHk9IjAuNSIvPgogICAgPHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjZmZmZmZmIiBzdG9wLW9wYWNpdHk9IjAiLz4KICA8L2xpbmVhckdyYWRpZW50PgogIDxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZC11Y2dnLWdlbmVyYXRlZCkiIC8+Cjwvc3ZnPg==);
|
||||
background: -moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.5) 40%, rgba(255,255,255,0.5) 60%, rgba(255,255,255,0) 100%); /* FF3.6+ */
|
||||
background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(255,255,255,0)), color-stop(40%,rgba(255,255,255,0.5)), color-stop(60%,rgba(255,255,255,0.5)), color-stop(100%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0.5) 40%,rgba(255,255,255,0.5) 60%,rgba(255,255,255,0) 100%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0.5) 40%,rgba(255,255,255,0.5) 60%,rgba(255,255,255,0) 100%); /* Opera 11.10+ */
|
||||
background: -ms-linear-gradient(left, rgba(255,255,255,0) 0%,rgba(255,255,255,0.5) 40%,rgba(255,255,255,0.5) 60%,rgba(255,255,255,0) 100%); /* IE10+ */
|
||||
background: linear-gradient(to right, rgba(255,255,255,0) 0%,rgba(255,255,255,0.5) 40%,rgba(255,255,255,0.5) 60%,rgba(255,255,255,0) 100%); /* W3C */
|
||||
}
|
||||
|
||||
#menu div:hover {
|
||||
color: #f66439;
|
||||
-webkit-transform: scaleY(1.0);
|
||||
transform: scaleY(1.1);
|
||||
}
|
||||
|
||||
#start {
|
||||
font-size: 1.8em;
|
||||
color: #f66439;
|
||||
}
|
||||
|
||||
#start:hover {
|
||||
color: #f8854b !important;
|
||||
}
|
||||
|
||||
#step-2 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: black;
|
||||
vertical-align: bottom;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: white;
|
||||
font-size: 2em;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-background-size: 60% auto;
|
||||
-webkit-background-size: 60% auto;
|
||||
-ms-background-size: 60% auto;
|
||||
-o-background-size: 60% auto;
|
||||
background-size: 60% auto;
|
||||
}
|
||||
|
||||
#step-3 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: black;
|
||||
}
|
||||
|
||||
#step-3 #progressbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: auto;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 0%;
|
||||
background: white;
|
||||
}
|
||||
|
||||
#step-5 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: black;
|
||||
text-align: center;
|
||||
padding: 100px 20px;
|
||||
color: white;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#step-5 #time {
|
||||
font-size: 4em
|
||||
}
|
||||
|
||||
#leapinfo {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-size: 3em;
|
||||
padding-top: 200px;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
After Width: | Height: | Size: 473 KiB |
@@ -0,0 +1,8 @@
|
||||
* {
|
||||
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
|
||||
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
|
||||
/* make transparent link selection, adjust last value opacity 0 to 1.0 */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
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,111 +1,115 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<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>
|
||||
<head>
|
||||
<title>HexGL by BKcore</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="HexGL is a futuristic racing game built by Thibaut Despoulain (BKcore) using HTML5, Javascript and WebGL. Come challenge your friends on this fast-paced 3D game!">
|
||||
<meta property="og:title" content="HexGL, the HTML5 futuristic racing game." />
|
||||
<meta property="og:type" content="game" />
|
||||
<meta property="og:url" content="http://hexgl.bkcore.com/" />
|
||||
<meta property="og:image" content="http://hexgl.bkcore.com/image.png" />
|
||||
<meta property="og:site_name" content="HexGL by BKcore" />
|
||||
<meta property="fb:admins" content="1482017639" />
|
||||
<link rel="icon" href="http://hexgl.bkcore.com/favicon.png" type="image/png">
|
||||
<link rel="shortcut icon" href="http://hexgl.bkcore.com/favicon.png" type="image/png">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="stylesheet" href="css/multi.css" type="text/css" charset="utf-8">
|
||||
<link rel="stylesheet" href="css/fonts.css" type="text/css" charset="utf-8">
|
||||
<style>
|
||||
body {
|
||||
padding:0;
|
||||
margin:0;
|
||||
}
|
||||
canvas { pointer-events:none; width: 100%;}
|
||||
#overlay{
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
//analytics
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-26274524-4']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="overlay"></div>
|
||||
<div id="main"></div>
|
||||
<body>
|
||||
<div id="step-1">
|
||||
<div id="global"></div>
|
||||
<div id="title">
|
||||
</div>
|
||||
<div id="menucontainer">
|
||||
<div id="menu">
|
||||
<div id="start">Start</div>
|
||||
<div id="s-controlType">Controls: LeapMotion</div>
|
||||
<div id="s-quality">Quality: High</div>
|
||||
<div id="s-platform">Platform: Desktop</div>
|
||||
<div id="s-godmode">Godmode: On</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="step-2" style="display: none">
|
||||
<div id="ctrl-help">Click/Touch to continue.</div>
|
||||
</div>
|
||||
<div id="step-3" style="display: none">
|
||||
<div id="progressbar"></div>
|
||||
</div>
|
||||
<div id="step-4" style="display: none">
|
||||
<div id="overlay"></div>
|
||||
<div id="main"></div>
|
||||
</div>
|
||||
<div id="step-5" style="display: none">
|
||||
<div id="time"></div>
|
||||
<div id="ctrl-help">Click/Touch to continue.</div>
|
||||
</div>
|
||||
|
||||
<script src="js/Three.dev.js"></script>
|
||||
<script src="js/ShaderExtras.js"></script>
|
||||
<script src="js/postprocessing/EffectComposer.js"></script>
|
||||
<script src="js/postprocessing/RenderPass.js"></script>
|
||||
<script src="js/postprocessing/BloomPass.js"></script>
|
||||
<script src="js/postprocessing/ShaderPass.js"></script>
|
||||
<script src="js/postprocessing/MaskPass.js"></script>
|
||||
<script src="js/Detector.js"></script>
|
||||
<script src="js/Stats.js"></script>
|
||||
<script src="js/DAT.GUI.min.js"></script>
|
||||
<div id="leapinfo" style="display: none"></div>
|
||||
|
||||
<script src="bkcore/Timer.js"></script>
|
||||
<script src="bkcore/ImageData.js"></script>
|
||||
<script src="bkcore/Utils.js"></script>
|
||||
<script src="libs/leap-0.4.1.min.js"></script>
|
||||
<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/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.coffee/controllers/TouchController.js"></script>
|
||||
<script src="bkcore.coffee/controllers/OrientationController.js"></script>
|
||||
|
||||
<script src="bkcore/hexgl/HUD.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/Timer.js"></script>
|
||||
<script src="bkcore/ImageData.js"></script>
|
||||
<script src="bkcore/Utils.js"></script>
|
||||
|
||||
<script src="bkcore/hexgl/tracks/Cityscape.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/HexGL.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>
|
||||
<script src="bkcore/hexgl/tracks/Cityscape.js"></script>
|
||||
|
||||
var SCREEN_WIDTH = window.innerWidth;
|
||||
var SCREEN_HEIGHT = window.innerHeight;
|
||||
<script src="bkcore/hexgl/HexGL.js"></script>
|
||||
|
||||
var container, hudcontainer;
|
||||
<script src="launch.js"></script>
|
||||
|
||||
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'),
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
$ = (_) -> document.getElementById _
|
||||
|
||||
init = (controlType, quality, platform, godmode) ->
|
||||
hexGL = new bkcore.hexgl.HexGL(
|
||||
document: document
|
||||
width: window.innerWidth
|
||||
height: window.innerHeight
|
||||
container: $ 'main'
|
||||
overlay: $ 'overlay'
|
||||
gameover: $ 'step-5'
|
||||
quality: quality
|
||||
difficulty: 0,
|
||||
half: (platform is 1 and quality < 1)
|
||||
mobile: platform is 1
|
||||
hud: platform is 0
|
||||
controlType: controlType
|
||||
godmode: godmode
|
||||
track: 'Cityscape'
|
||||
)
|
||||
window.hexGL=hexGL
|
||||
|
||||
progressbar = $ 'progressbar'
|
||||
hexGL.load(
|
||||
onLoad: ->
|
||||
console.log 'LOADED.'
|
||||
hexGL.init()
|
||||
$('step-3').style.display = 'none'
|
||||
$('step-4').style.display = 'block'
|
||||
hexGL.start()
|
||||
onError: (s) ->
|
||||
console.error "Error loading #{ s }."
|
||||
onProgress: (p, t, n) ->
|
||||
console.log("LOADED "+t+" : "+n+" ( "+p.loaded+" / "+p.total+" ).")
|
||||
progressbar.style.width = "#{ p.loaded / p.total * 100 }%"
|
||||
)
|
||||
|
||||
u = bkcore.Utils.getURLParameter
|
||||
s = [
|
||||
['controlType', ['KEYBOARD', 'TOUCH', 'LEAP MOTION CONTROLLER'], 0, 0, 'Controls: ']
|
||||
['quality', ['LOW', 'MID', 'HIGH'], 2, 2, 'Quality: ']
|
||||
['platform', ['DESKTOP', 'MOBILE'], 0, 0, 'Platform: ']
|
||||
['godmode', ['OFF', 'ON'], 0, 1, 'Godmode: ']
|
||||
]
|
||||
for a in s
|
||||
do(a)->
|
||||
a[3] = u(a[0]) ? a[2]
|
||||
e = $ "s-#{a[0]}"
|
||||
(f = -> e.innerHTML = a[4]+a[1][a[3]])()
|
||||
e.onclick = -> f(a[3] = (a[3]+1)%a[1].length)
|
||||
$('start').onclick = ->
|
||||
$('step-1').style.display = 'none'
|
||||
$('step-2').style.display = 'block'
|
||||
$('step-2').style.backgroundImage = "url(css/help-#{s[0][3]}.png)"
|
||||
$('step-2').onclick = ->
|
||||
$('step-2').style.display = 'none'
|
||||
$('step-3').style.display = 'block'
|
||||
init s[0][3], s[1][3], s[2][3], s[3][3]
|
||||
$('step-5').onclick = ->
|
||||
window.location.reload()
|
||||
@@ -0,0 +1,83 @@
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var $, a, init, s, u, _fn, _i, _len;
|
||||
|
||||
$ = function(_) {
|
||||
return document.getElementById(_);
|
||||
};
|
||||
|
||||
init = function(controlType, quality, platform, godmode) {
|
||||
var hexGL, progressbar;
|
||||
hexGL = new bkcore.hexgl.HexGL({
|
||||
document: document,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
container: $('main'),
|
||||
overlay: $('overlay'),
|
||||
gameover: $('step-5'),
|
||||
quality: quality,
|
||||
difficulty: 0,
|
||||
half: platform === 1 && quality < 1,
|
||||
mobile: platform === 1,
|
||||
hud: platform === 0,
|
||||
controlType: controlType,
|
||||
godmode: godmode,
|
||||
track: 'Cityscape'
|
||||
});
|
||||
window.hexGL = hexGL;
|
||||
progressbar = $('progressbar');
|
||||
return hexGL.load({
|
||||
onLoad: function() {
|
||||
console.log('LOADED.');
|
||||
hexGL.init();
|
||||
$('step-3').style.display = 'none';
|
||||
$('step-4').style.display = 'block';
|
||||
return hexGL.start();
|
||||
},
|
||||
onError: function(s) {
|
||||
return console.error("Error loading " + s + ".");
|
||||
},
|
||||
onProgress: function(p, t, n) {
|
||||
console.log("LOADED " + t + " : " + n + " ( " + p.loaded + " / " + p.total + " ).");
|
||||
return progressbar.style.width = "" + (p.loaded / p.total * 100) + "%";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
u = bkcore.Utils.getURLParameter;
|
||||
|
||||
s = [['controlType', ['KEYBOARD', 'TOUCH', 'LEAP MOTION CONTROLLER'], 0, 0, 'Controls: '], ['quality', ['LOW', 'MID', 'HIGH'], 2, 2, 'Quality: '], ['platform', ['DESKTOP', 'MOBILE'], 0, 0, 'Platform: '], ['godmode', ['OFF', 'ON'], 0, 1, 'Godmode: ']];
|
||||
|
||||
_fn = function(a) {
|
||||
var e, f, _ref;
|
||||
a[3] = (_ref = u(a[0])) != null ? _ref : a[2];
|
||||
e = $("s-" + a[0]);
|
||||
(f = function() {
|
||||
return e.innerHTML = a[4] + a[1][a[3]];
|
||||
})();
|
||||
return e.onclick = function() {
|
||||
return f(a[3] = (a[3] + 1) % a[1].length);
|
||||
};
|
||||
};
|
||||
for (_i = 0, _len = s.length; _i < _len; _i++) {
|
||||
a = s[_i];
|
||||
_fn(a);
|
||||
}
|
||||
|
||||
$('start').onclick = function() {
|
||||
$('step-1').style.display = 'none';
|
||||
$('step-2').style.display = 'block';
|
||||
return $('step-2').style.backgroundImage = "url(css/help-" + s[0][3] + ".png)";
|
||||
};
|
||||
|
||||
$('step-2').onclick = function() {
|
||||
$('step-2').style.display = 'none';
|
||||
$('step-3').style.display = 'block';
|
||||
return init(s[0][3], s[1][3], s[2][3], s[3][3]);
|
||||
};
|
||||
|
||||
$('step-5').onclick = function() {
|
||||
return window.location.reload();
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
@@ -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-mobile.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 |