Last active
August 29, 2015 13:57
-
-
Save sjkillen/9713289 to your computer and use it in GitHub Desktop.
Spenjin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
'use strict'; | |
var createGameObjectConstructor = (function () { | |
var recent = function () {//every actual object constructor will share this method | |
return (this.instanceArray.length> 0) ? this.instanceArray[this.instanceArray.length - 1] :null; | |
};//add more functions like this to create methods for the "final constructor" | |
var countDescriptor={get: function() {return this.instanceArray.length; } }; | |
return function (constructor, prototypeProps) {//createGameObjectConstructor | |
//convert prototypeProps into properties object | |
for (var i in prototypeProps){ | |
var quicksave=prototypeProps[i]; | |
prototypeProps[i]={ | |
value:quicksave, | |
writable: false, | |
enumerable: true, | |
configurable: false | |
} | |
} | |
var instanceRecycleStack = []; | |
var outerProto={//TODO: eventually find a way to only create this once | |
destroy:function() { | |
ret.instanceArray.splice(ret.instanceArray.indexOf(this),1); | |
if (instanceRecycleStack.length<100) {instanceRecycleStack.push(this);}//add to recycle pile | |
} | |
}; | |
var innerProto=Object.create(outerProto,prototypeProps) | |
innerProto.constructor = constructor;//all objects can refer back to their constructor | |
innerProto.super=outerProto; | |
constructor.prototype = innerProto;//never actually used here...Yet | |
function ret() {//function that is returned | |
if (instanceRecycleStack.length>0) { | |
var instance=instanceRecycleStack.pop(); | |
constructor.apply(instance, arguments);//reuse old instance | |
} | |
else { | |
var instance = Object.create(innerProto);//make new instance if there is none to recycle | |
constructor.apply(instance, arguments);//call constructor on new object | |
Object.seal(instance);//sealed for recyclibility | |
} | |
ret.instanceArray.push(instance); | |
return instance; | |
}; | |
ret.recent = recent; | |
ret.instanceArray = []; | |
Object.defineProperty(ret, "count", countDescriptor); | |
return ret; | |
} | |
}()); | |
//TEST CASES | |
var Monster = createGameObjectConstructor(function () { | |
this.pos=Vec3(0,0,0); | |
}, { | |
eatHuman:function () { | |
console.log('human consumed'); | |
}, | |
destroy:function(){ | |
this.pos.destroy();//destroy Vec3 | |
this.super.destroy.call(this);//destroy self | |
} | |
}); | |
var Vec3 = createGameObjectConstructor(function(x,y,z){ | |
this.x=x; | |
this.y=y; | |
this.z=z; | |
},{ | |
translate:function(x,y,z){ | |
this.x+=x; | |
this.y+=y; | |
this.z+=z; | |
} | |
} | |
); | |
var Clock = (function() { | |
var loopingDescriptor={ | |
get:function(){ | |
if (this.loopId!==false) {return true;} | |
else {return false;} | |
}, | |
set:function(bool){ | |
if (bool && this.loopId===false){ | |
if (typeof (this.loopType)==='number'){ | |
this.loopId=window.setInterval(this.__executeMissionsBound, this.loopType); | |
} | |
else { | |
this.loopId=window.requestAnimationFrame(this.__executeMissionsBound); | |
} | |
} | |
else if (!bool && this.loopId!==false){ | |
if (typeof (this.loopType)==='number'){ | |
window.clearInterval(this.loopId); | |
this.loopId=false; | |
} | |
else { | |
window.cancelAnimationFrame(this.loopId); | |
this.loopId=false; | |
} | |
} | |
} | |
}; | |
var deltaMilisecondsDescriptor={ | |
get:function(){ | |
return (new Date().getTime())-this.timeStamp;//final-initial | |
} | |
}; | |
var __executeMissions=function(){ | |
this.timeStamp=(new Date().getTime());//time in miliseconds | |
if (this.looping) {this.loopId=window.requestAnimationFrame(this.__executeMissionsBound);} | |
for (var i in this.__missions){//not ordered | |
this.__missions[i](); | |
} | |
}; | |
return createGameObjectConstructor(function(loopType){//loopType: framerate number or it'll use RAF | |
this.timeStamp=(new Date().getTime()); | |
Object.defineProperty(this,'deltaMiliseconds', deltaMilisecondsDescriptor); | |
this.loopType=loopType; | |
this.loopId=false; | |
this.__executeMissionsBound=__executeMissions.bind(this);//bound to this so it can be called from interval | |
Object.defineProperty(this,'looping', loopingDescriptor); | |
this.__missions = [];//stack of functions for clock to call on interval | |
},{ | |
pinMission:function(mission){//add mission (function) to clock | |
this.__missions.push(mission); | |
}, | |
destroy:function(){ | |
this.looping=false; | |
this.super.destroy.call(this); | |
} | |
}); | |
}()); | |
var View = createGameObjectConstructor(function(canvasElementId){ | |
this.canvasElement=document.getElementById(canvasElementId); | |
this.context=this.canvasElement.getContext('2d'); | |
this.slides=[]; | |
},(function(){ | |
var Slide=createGameObjectConstructor(function(view){//where objects are stored | |
this.view=view; | |
view.slides.push(this); | |
},{ | |
destroy:function(fromView){//if being destroyed from a View splicing will mess it up | |
if (!fromView) {this.view.slides.splice(this.view.slides.indexOf(this),1);} | |
this.super.destroy.call(this); | |
} | |
} | |
); | |
return { | |
Slide:function(){ | |
return Slide(this); | |
}, | |
destroy:function(){ | |
for (var i in this.slides){ | |
this.slides[i].destroy(true);//true because its from a View | |
} | |
this.super.destroy.call(this); | |
} | |
} | |
}()) | |
); | |
</script> | |
<canvas id='c'></canvas> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My implementation of "construct2-like" recycling