314 lines
10 KiB
JavaScript
314 lines
10 KiB
JavaScript
// bluepixle.js
|
|
// This library is to help make using canvas tags easier
|
|
// requires bluemath.js
|
|
|
|
class shape {
|
|
constructor(type,coordinates,dimentions,rotation,fColor,bColor,bStyle,extraObject) {
|
|
this.type = "string" == typeof type ? (["rect","elipse","image"].includes(type) ? type : "rect") : "rect";
|
|
this.coordinates = coordinates instanceof vector ? coordinates : new vector([0,0]);
|
|
this.dimentions = dimentions instanceof vector ? dimentions : new vector([1,1]);
|
|
this.rotation = rotation instanceof vector ? rotation : new vector([0,1]);
|
|
this.fColor = "string" == typeof fColor ? fColor : undefined;
|
|
this.bColor = "string" == typeof bColor ? bColor : undefined;
|
|
this.bStyle = "number" == typeof bStyle ? bStyle : undefined;
|
|
this.extraObject = "object" == typeof extraObject ? extraObject : {};
|
|
if ("image" == this.type) {
|
|
this.imageData =
|
|
this.extraObject.imageData instanceof ImageData ?
|
|
this.extraObject.imageData :
|
|
new ImageData(
|
|
new Uint8ClampedArray([
|
|
255,0,0,255,
|
|
0,0,0,0,
|
|
255,0,0,255,
|
|
0,0,0,0,
|
|
255,0,0,255,
|
|
0,0,0,0,
|
|
255,0,0,255,
|
|
0,0,0,0,
|
|
255,0,0,255
|
|
]),3,3);
|
|
this.image = createImageBitmap(this.imageData);
|
|
}
|
|
|
|
}
|
|
|
|
render(ctx,position,rotation) {
|
|
// Save current defaults
|
|
var local = {};
|
|
local.fillStyle = "string" == typeof ctx.fillStyle ? ctx.fillStyle : undefined;
|
|
local.strokeStyle = "string" == ctx.strokeStyle ? ctx.strokeStyle : undefined;
|
|
local.lineWidth = "number" == ctx.lineWidth ? ctx.lineWidth : undefined;
|
|
local.imageSmoothingEnabled = ctx.imageSmoothingEnabled;
|
|
// calculate origin and rotation
|
|
var origin = this.coordinates.add(position instanceof vector ? position : new vector([0,0]));
|
|
var origRot = this.rotation.getRadAngle() + (rotation instanceof vector ? rotation : new vector([0,1])).getRadAngle();
|
|
var center = origin.add(this.dimentions.mag(0.5));
|
|
// Rotate
|
|
ctx.translate(center.d[0],center.d[1]);
|
|
ctx.rotate(origRot);
|
|
ctx.translate(-center.d[0],-center.d[1]);
|
|
// Draw
|
|
ctx.fillStyle = this.fcolor;
|
|
ctx.strokeStyle = this.bColor;
|
|
ctx.lineWidth = this.bStyle;
|
|
if("rect" == this.type) {
|
|
ctx.fillRect(origin.d[0],origin.d[1],this.dimentions.d[0],this.dimentions.d[1]);
|
|
ctx.strokeRect(origin.d[0],origin.d[1],this.dimentions.d[0],this.dimentions.d[1]);
|
|
} else if ("elipse" == this.type) {
|
|
ctx.beginPath();
|
|
ctx.ellipse(center.d[0],center.d[1],dimentions.d[0]/2,dimentions.d[1]/2,0,0,360);
|
|
ctx.stroke();
|
|
ctx.fill();
|
|
} else if ("image" == this.type) {
|
|
this.image.then(function (image) {
|
|
ctx.imageSmoothingEnabled = false;
|
|
ctx.drawImage(image,origin.d[0],origin.d[0],this.dimentions.d[0],this.dimentions.d[1]);
|
|
});
|
|
}
|
|
// restore context defaults
|
|
ctx.setTransform(1,0,0,1,0,0);
|
|
ctx.fillStyle = local.fillStyle;
|
|
ctx.strokeStyle = local.strokeStyle;
|
|
ctx.lineWidth = local.lineWidth;
|
|
ctx.imageSmoothingEnabled = local.imageSmoothingEnabled;
|
|
}
|
|
|
|
grow (amp) {
|
|
this.dimentions = this.dimentions.amp(amp);
|
|
}
|
|
}
|
|
|
|
class container {
|
|
constructor(coordinates,dimentions,rotation) {
|
|
this.coordinates = coordinates instanceof vector ? coordinates : new vector([0,0]);
|
|
this.size = dimentions instanceof vector ? dimentions : new vector([1,1]);
|
|
this.rotation = rotation instanceof vector ? rotation : new vector([0,1]);
|
|
this.movementVector = new vector([0,0]);
|
|
this.shapes = [];
|
|
this.containers = [];
|
|
}
|
|
|
|
addShape(myShape) {
|
|
if (myShape instanceof shape) {
|
|
this.shapes.push(myShape);
|
|
} else {
|
|
throw new TypeError("addShape Method must be given a shape object");
|
|
}
|
|
}
|
|
|
|
addContainer(myContainer) {
|
|
if (myContainer instanceof container) {
|
|
this.containers.push(container);
|
|
} else {
|
|
throw new TypeError("addContainer Method must be given a container object");
|
|
}
|
|
}
|
|
|
|
move(delta) {
|
|
delta = !isNaN(delta) ? delta : 0;
|
|
this.coordinates = this.coordinates.add(this.movementVector.mag(delta));
|
|
}
|
|
|
|
renderContainer(ctx,position,rotation) {
|
|
position = position instanceof vector ? position : new vector([0,0]);
|
|
rotation = rotation instanceof vector ? rotation : new vector([0,1]);
|
|
var refPos = this.coordinates.add(position);
|
|
var refRot = this.rotation.add(rotation);
|
|
if (this.shapes.length) {
|
|
this.shapes.forEach(shape => shape.render(ctx,refPos,refRot));
|
|
}
|
|
if (this.containers.length) {
|
|
this.containers.forEach(container => container.renderContainer(ctx,refPos,refRot));
|
|
}
|
|
}
|
|
|
|
grow(amp) {
|
|
amp = !isNaN(amp) ? amp : 1;
|
|
this.position.mag(amp);
|
|
if (this.shapes.length) {
|
|
this.shapes.forEach(shape => shape.grow(amp));
|
|
}
|
|
if (this.containers.length) {
|
|
this.containers.forEach( container => container.grow(amp));
|
|
}
|
|
}
|
|
|
|
bounce(surface) {
|
|
this.movementVector = this.movementVector.reflect(surface);
|
|
}
|
|
|
|
overlap(otherContainer, callbackFunction) {
|
|
var slowest = this.movementVector.getLength() <= otherContainer.movementVector.getLength() ? this : otherContainer;
|
|
var fastest = this.movementVector.getLength() <= otherContainer.movementVector.getLength() ? otherContainer : this;
|
|
|
|
var quickest = fastest.movementVector.getLength();
|
|
for (var t = 0; t <= quickest; t++) {
|
|
var tFraction = t/(quickest+1);
|
|
var Atop = slowest.coordinates.d[1]+(tFraction * slowest.movementVector.d[1]);
|
|
var Abottom = slowest.coordinates.d[1]+(tFraction * slowest.movementVector.d[1])+slowest.dimentions.d[0];
|
|
var Aleft = slowest.coordinates.d[0]+(tFraction * slowest.movementVector.d[0]);
|
|
var Aright = slowest.coordinates.d[0]+(tFraction * slowest.movementVector.d[0])+slowest.dimentions.d[1];
|
|
var Btop = fastest.coordinates.d[1]+(tFraction * fastest.movementVector.d[1]);
|
|
var Bbottom = fastest.coordinates.d[1]+(tFraction * fastest.movementVector.d[1])+fastest.dimentions.d[0];
|
|
var Bleft = fastest.coordinates.d[0]+(tFraction * fastest.movementVector.d[0]);
|
|
var Bright = fastest.coordinates.d[0]+(tFraction * fastest.movementVector.d[0])+fastest.dimentions.d[1];
|
|
|
|
var Abound = new bound([Aleft,Atop],[Aright,Abottom]);
|
|
var Bbound = new bound([Bleft,Btop],[Bright,Bbottom]);
|
|
if (
|
|
Bbound.inbounds([Aleft,Atop]) |
|
|
Bbound.inbounds([Aright,Atop]) |
|
|
Bbound.inbounds([Aleft,Abottom]) |
|
|
Bbound.inbounds([Aright,Abottom]) |
|
|
Abound.inbounds([Bleft,Btop]) |
|
|
Abound.inbounds([Bright,Btop]) |
|
|
Abound.inbounds([Bleft,Bbottom]) |
|
|
Abound.inbounds([Bright,Bbottom])
|
|
){
|
|
return callBackFunction(this,otherContainer,t);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function chase (source,target,max,minDis,acc) {
|
|
acc /= 100;
|
|
var sourceCenterX = source.x + (source.sizeX/2);
|
|
var sourceCenterY = source.y + (source.sizeY/2);
|
|
var targetCenterX = target.x + (target.sizeX/2);
|
|
var targetCenterY = target.y + (target.sizeY/2);
|
|
var deltaX = targetCenterX - sourceCenterX;
|
|
var deltaY = targetCenterY - sourceCenterY;
|
|
var theta = Math.atan2(deltaY,deltaX);
|
|
var dis = Math.sqrt(Math.pow(Math.abs(deltaX),2)+Math.pow(Math.abs(deltaY),2));
|
|
var dir = theta;
|
|
if (dis > minDis) {
|
|
dis = dis <= max ? dis : max;
|
|
source.direction = rad2deg(dir);
|
|
source.speed = (dis-minDis)*acc;
|
|
source.move(source.direction,source.speed);
|
|
}
|
|
}
|
|
|
|
function drawPixel (ctx, x, y, r, g, b, a) {
|
|
// Always validate your input
|
|
if (false == ctx instanceof CanvasRenderingContext2D) {
|
|
return new TypeError("ctx must be a 2D rendering context for canvas.");
|
|
}
|
|
x = x <= ctx.canvas.width ? x : ctx.canvas.width;
|
|
y = y <= ctx.canvas.height ? y : ctx.canvas.height;
|
|
r = r <= 255 ? r : 255;
|
|
r = r >= 0 ? r : 0;
|
|
g = g <= 255 ? g : 255;
|
|
g = g >= 0 ? g : 0;
|
|
b = b <= 255 ? b : 255;
|
|
b = b >= 0 ? b : 0;
|
|
a = a <= 255 ? a : 255;
|
|
a = a >= 0 ? a : 0;
|
|
// Do the thing
|
|
ctx.putImageData(new ImageData(new Uint8ClampedArray([r,g,b,a]),1,1),x,y);
|
|
}
|
|
|
|
class frameBuffer {
|
|
constructor(ctx, height, width) {
|
|
this.ctx = ctx;
|
|
this.height = height;
|
|
this.width = width;
|
|
this.containerArray = [];
|
|
}
|
|
|
|
addContainer(containerObject) { //might change this to auto create containers.
|
|
if (containerObject instanceof container) {
|
|
var index = this.containerArray.push(containerObject);
|
|
return this.containerArray[ index - 1];
|
|
} else {
|
|
throw new TypeError("addContainer Method must be given a container object");
|
|
}
|
|
}
|
|
|
|
pushFrame() {
|
|
var ctx = this.ctx;
|
|
ctx.clearRect(0,0,this.width,this.height);
|
|
this.containerArray.forEach(
|
|
function (container) { container.renderContainer(ctx,0,0); });
|
|
}
|
|
|
|
}
|
|
|
|
class starfield {
|
|
constructor (buffer,boundWidth,boundHeight,centerX,centerY,starCount,starLife,starSpeed) {
|
|
//Validate things
|
|
this.centerX = centerX;
|
|
this.centerY = centerY;
|
|
this.starLife = starLife;
|
|
this.starSpeed = starSpeed;
|
|
//Math the things
|
|
this.topBound = centerY - (boundHeight/2);
|
|
this.bottomBound = centerY + (boundHeight/2);
|
|
this.leftBound = centerX - (boundWidth/2);
|
|
this.rightBound = centerX + (boundWidth/2);
|
|
this.stars = [];
|
|
this.container = buffer.addContainer(
|
|
new container(this.centerX,this.centerY,0,0,0));
|
|
this.container.nestContainer();
|
|
for (var count = 1; count <= starCount; count++) {
|
|
var star = this.container.addShape(
|
|
new shape(
|
|
"rect",
|
|
((Math.random()*boundWidth)-(boundWidth/2)),
|
|
((Math.random()*boundHeight)-(boundHeight/2)),
|
|
1,1,
|
|
"#ffffff",
|
|
"#ffffff",
|
|
1));
|
|
this.stars.push({
|
|
"container":star,
|
|
"life":this.starLife,
|
|
"speed":this.starSpeed});
|
|
}
|
|
}
|
|
|
|
forward() {
|
|
var me = this;
|
|
this.stars.forEach(function (star) {
|
|
if (
|
|
(star.life > 0) &
|
|
(star.container.shape.x > me.leftBound - me.centerX) &
|
|
(star.container.shape.x < me.rightBound - me.centerX) &
|
|
(star.container.shape.y > me.topBound - me.centerY) &
|
|
(star.container.shape.y < me.bottomBound - me.centerY)) {
|
|
var xOffset = star.container.shape.x;
|
|
var yOffset = star.container.shape.y;
|
|
star.life--;
|
|
var c = 255*((me.starLife-star.life)/me.starLife)*4;
|
|
star.container.grow(5/me.starLife);
|
|
star.container.shape.fColor = "rgb("+c+","+c+","+c+")";
|
|
star.container.shape.bColor = "rgb("+c+","+c+","+c+")";
|
|
star.speed+=me.starSpeed;
|
|
star.container.shape.x +=
|
|
star.speed*((xOffset/me.centerX)*0.5);
|
|
star.container.shape.y +=
|
|
star.speed*((yOffset/me.centerY)*0.5);
|
|
} else {
|
|
star.container.x = 0;
|
|
star.container.y = 0;
|
|
star.life = me.starLife;
|
|
star.speed = me.starSpeed;
|
|
star.container.shape.sizeX = 1;
|
|
star.container.shape.sizeY = 1;
|
|
star.container.shape.fColor = "rgb(0,0,0)";
|
|
star.container.shape.bColor = "rgb(0,0,0)";
|
|
star.container.shape.x =
|
|
(Math.random()*(me.rightBound-me.leftBound))
|
|
-(me.centerX);
|
|
star.container.shape.y =
|
|
(Math.random()*(me.bottomBound-me.topBound))
|
|
-(me.centerY);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|