Skip to content

Instantly share code, notes, and snippets.

@sjkillen
Last active August 29, 2015 13:57
Show Gist options
  • Save sjkillen/9713289 to your computer and use it in GitHub Desktop.
Save sjkillen/9713289 to your computer and use it in GitHub Desktop.
Spenjin
<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>
@sjkillen
Copy link
Author

My implementation of "construct2-like" recycling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment