216 lines
7.2 KiB
JavaScript
216 lines
7.2 KiB
JavaScript
var ktk = ktk || {};
|
|
/* rip popular js libs */
|
|
ktk.pipes = (function() {
|
|
/**** types ****/
|
|
var T = {
|
|
Object: function() {
|
|
this.set = function(key, value) {
|
|
this._[key] = value;
|
|
}
|
|
this.get = function(key) {
|
|
return this._[key];
|
|
}
|
|
this.has = function(key) {
|
|
return (typeof this._[key] === undefined || this._[key] === null) ? false : true
|
|
}
|
|
},
|
|
Pipe: function() {
|
|
T.Object.call(this);
|
|
/*** private ***/
|
|
var _ = {
|
|
x : 0,
|
|
y : 0,
|
|
absolute_x: 0,
|
|
absolute_y: 0,
|
|
angle : 0,
|
|
name : '',
|
|
absolute_angle: 0,
|
|
rotation_force: 0, // force in angles per gametick
|
|
rotation_velocity: 0, // current rotational velocity
|
|
rotation_drag: .05, // .05 angles per gametick(16ms)
|
|
origin_x : 0,
|
|
origin_y : 0,
|
|
pivot_x : 0,
|
|
pivot_y : 0,
|
|
total_origin_x: 0,
|
|
total_origin_y: 0,
|
|
image : new Image(),
|
|
children : [],
|
|
parent : null
|
|
}; this._ = _;
|
|
_.image.src = "img/pipe.png";
|
|
/*** public ***/
|
|
this.onUpdate = function(delta) {
|
|
this.set('angle', this.get('angle')+this.get('rotation_force'));
|
|
var x = 0, y = 0;
|
|
var ox = 0, oy = 0;
|
|
if (this.has('parent')) {
|
|
this.set('absolute_x', this.get('x') + this.get('parent').get('absolute_x') + this.get('parent').get('pivot_x'));
|
|
this.set('absolute_y', this.get('y') + this.get('parent').get('absolute_y') + this.get('parent').get('pivot_y'));
|
|
this.set('absolute_angle', this.get('angle') + this.get('parent').get('absolute_angle'));
|
|
} else {
|
|
this.set('absolute_x', this.get('x'));
|
|
this.set('absolute_y', this.get('y'));
|
|
this.set('absolute_angle', this.get('angle'));
|
|
}
|
|
var xy;
|
|
if (this.has('parent')) {
|
|
xy = $.rotatePoint(this.get('absolute_x')-this.get('origin_x'), this.get('absolute_y')-this.get('origin_y'), this.get('parent').get('absolute_x')+this.get('parent').get('pivot_x'), this.get('parent').get('absolute_y')+this.get('parent').get('pivot_y'), this.get('angle'));
|
|
} else {
|
|
xy = [this.get('absolute_x'), this.get('absolute_y')];
|
|
}
|
|
this.set('absolute_x', xy[0]);
|
|
this.set('absolute_y', xy[1]);
|
|
// Update our children
|
|
for (var child_index = 0; child_index < _.children.length; child_index++) {
|
|
_.children[child_index].onUpdate(delta);
|
|
}
|
|
};
|
|
this.onRender = function() {
|
|
$.getContext().save();
|
|
$.getContext().translate(this.get('absolute_x'), this.get('absolute_y'));
|
|
$.getContext().rotate(this.get('absolute_angle') * Math.PI / 180);
|
|
$.getContext().drawImage(_.image, 0, 0);
|
|
if (this.get('name') !== '') {
|
|
$.getContext().fillText(this.get('name')+this.get('absolute_angle'), 0, 0);
|
|
}
|
|
$.getContext().restore();
|
|
// Render our children
|
|
for (var child_index = 0; child_index < _.children.length; child_index++) {
|
|
_.children[child_index].onRender();
|
|
}
|
|
};
|
|
/* hierarchy methods */
|
|
this.disown = function(object) {
|
|
var childIndex = _.children.indexOf(object);
|
|
if (childIndex >= 0) {
|
|
_.children.splice(childIndex, 1);
|
|
object.set('parent', null);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
this.attach = function(object) {
|
|
if (object.has('parent')) {
|
|
object.get('parent').disown(object);
|
|
}
|
|
object.set('parent', this);
|
|
_.children.push(object);
|
|
}
|
|
}
|
|
};
|
|
/**** private ****/
|
|
var _ = {
|
|
objects: [],
|
|
accumulator: 0,
|
|
curr_timestamp: new Date(),
|
|
last_timestamp: new Date(),
|
|
last_timeout: -1,
|
|
curr_delta: 0,
|
|
last_delta: 0,
|
|
last_rendertimestamp: 0,
|
|
doUpdateLoop: function() {
|
|
_.last_timestamp = _.curr_timestamp;
|
|
_.curr_timestamp = new Date();
|
|
_.curr_delta = _.curr_timestamp - _.last_timestamp;
|
|
_.accumulator += _.curr_delta;
|
|
var thisFrameStart = new Date();
|
|
while (_.accumulator >= $.tickrate) {
|
|
_.onUpdate($.tickrate);
|
|
_.accumulator -= $.tickrate;
|
|
}
|
|
var thisFrameEnd = new Date();
|
|
var thisFrameDelta = _.last_delta = thisFrameEnd - thisFrameStart;
|
|
var delay = $.tickrate - _.accumulator;
|
|
_.last_timeout = window.setTimeout(_.doUpdateLoop, (delay >= 0 ? delay : 0));
|
|
},
|
|
/* Called whenever the physics or state should be updated */
|
|
onUpdate: function(delta) {
|
|
for (var i = 0; i < _.objects.length; i++) {
|
|
_.objects[i].onUpdate(delta);
|
|
}
|
|
},
|
|
/* Called whenever possible to re-render the scene */
|
|
onRender: function(ts) { // ts = timestamp
|
|
var delta_rendertimestamp = ts - _.last_rendertimestamp;
|
|
// Clear our screen
|
|
_.ctx.clearRect(0, 0, _.canvas.width, _.canvas.height);
|
|
_.ctx.fillText("frametime: " + _.last_delta, 0, 10);
|
|
_.ctx.fillText("fpms: " + delta_rendertimestamp, 0, 20);
|
|
// Do our rendering.
|
|
for (var i = 0; i < _.objects.length; i++) {
|
|
_.objects[i].onRender();
|
|
}
|
|
_.last_rendertimestamp = ts;
|
|
// Continue our loop
|
|
window.requestAnimationFrame(_.onRender);
|
|
}
|
|
};
|
|
/**** public ****/
|
|
var $ = {
|
|
tickrate: 16, // 16 updates per second
|
|
/* Initialization method, called externally to set up everything */
|
|
onLoad: function(el) {
|
|
if (el.tagName !== 'CANVAS') {
|
|
alert('target element _must_ be a canvas');
|
|
throw(el);
|
|
}
|
|
_.canvas = el;
|
|
_.ctx = el.getContext("2d");
|
|
_.ctx.mozImageSmoothingEnabled = false;
|
|
_.ctx.webkitImageSmoothingEnabled = false;
|
|
_.ctx.msImageSmoothingEnabled = false;
|
|
_.ctx.imageSmoothingEnabled = false;
|
|
$.setupPlayfield();
|
|
_.doUpdateLoop();
|
|
_.onRender();
|
|
},
|
|
createObject: function(object_name) {
|
|
if (!T[object_name]) {
|
|
throw object_name+" is not a valid object.";
|
|
}
|
|
return new T[object_name];
|
|
},
|
|
addObject: function(object) {
|
|
_.objects.push(object);
|
|
},
|
|
/* Called to setup our playfield. public to allow overriding. */
|
|
setupPlayfield: function() {
|
|
let obj = $.createObject("Pipe");
|
|
//obj.set('rotation_force', .25);
|
|
obj.set('x', _.canvas.width/2);
|
|
obj.set('y', _.canvas.height/2);
|
|
obj.set('name', 'A');
|
|
obj.set('origin_x', 4);
|
|
obj.set('origin_y', 8);
|
|
obj.set('pivot_x', 56);
|
|
obj.set('pivot_y', 4);
|
|
let obj2 = $.createObject("Pipe");
|
|
obj2.set('rotation_force', .5);
|
|
obj2.set('angle', 0);
|
|
obj2.set('name', 'B');
|
|
obj2.set('origin_x', 4);
|
|
obj2.set('origin_y', 8);
|
|
obj.attach(obj2);
|
|
$.addObject(obj);
|
|
},
|
|
getContext: function() {
|
|
return _.ctx;
|
|
},
|
|
rotatePoint: function(ox, oy, px, py, angle) {
|
|
var c = Math.cos(angle * Math.PI / 180);
|
|
var s = Math.sin(angle * Math.PI / 180);
|
|
ox -= px;
|
|
oy -= py;
|
|
var x = ox * c - oy * s;
|
|
var y = ox * s + oy * c;
|
|
ox = x + px;
|
|
oy = y + py;
|
|
/*ox = c * (ox - px) - s * (oy - py) + px;
|
|
oy = s * (ox - px) + c * (oy - py) + py;*/
|
|
return [ox, oy];
|
|
}
|
|
};
|
|
return $;
|
|
})();
|