// 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) { ///////////////////////////////// work starts here this. } } function collide(objectA,objectB,callBackFunction) { var ASpeed = Math.abs(objectA.speed); var BSpeed = Math.abs(objectB.speed); var simAX = ASpeed <= BSpeed ? objectA.x : objectB.x; var simAY = ASpeed <= BSpeed ? objectA.y : objectB.y; var simBX = ASpeed <= BSpeed ? objectB.x : objectA.x; var simBY = ASpeed <= BSpeed ? objectB.y : objectA.y; var simADir = ASpeed <= BSpeed ? objectA.direction : objectB.direction; var simBDir = ASpeed <= BSpeed ? objectB.direction : objectA.direction; var simASpeed = ASpeed <= BSpeed ? objectA.speed : objectB.speed; var simBSpeed = ASpeed <= BSpeed ? objectB.speed : objectA.speed; var simAheight = ASpeed <= BSpeed ? objectA.sizeX : objectB.sizeX; var simBheight = ASpeed <= BSpeed ? objectB.sizeX : objectA.sizeX; var simAwidth = ASpeed <= BSpeed ? objectA.sizeY : objectB.sizeY; var simBwidth = ASpeed <= BSpeed ? objectB.sizeY : objectA.sizeY; var thetaA = deg2rad(simADir); var deltaAX = Math.cos(thetaA)*simASpeed; var deltaAY = Math.sin(thetaA)*simASpeed; var thetaB = deg2rad(simBDir); var deltaBX = Math.cos(thetaB)*simBSpeed; var deltaBY = Math.sin(thetaB)*simBSpeed; var fastest = Math.max(Math.abs(objectA.speed),Math.abs(objectB.speed)); for (var t = 0; t <= fastest; t++) { var tFraction = t/(fastest+1); var Atop = simAY+(tFraction * deltaAY); var Abottom = simAY+(tFraction * deltaAY)+simAheight; var Aleft = simAX+(tFraction * deltaAX); var Aright = simAX+(tFraction * deltaAX)+simAwidth; var Btop = simBY+(tFraction * deltaBY); var Bbottom = simBY+(tFraction * deltaBY)+simBheight; var Bleft = simBX+(tFraction * deltaBX); var Bright = simBX+(tFraction * deltaBX)+simBwidth; if ( pointInside(Aleft,Atop,Btop,Bright,Bbottom,Bleft) | pointInside(Aright,Atop,Btop,Bright,Bbottom,Bleft) | pointInside(Aleft,Abottom,Btop,Bright,Bbottom,Bleft) | pointInside(Aright,Abottom,Btop,Bright,Bbottom,Bleft) | pointInside(Bleft,Btop,Atop,Aright,Abottom,Aleft) | pointInside(Bright,Btop,Atop,Aright,Abottom,Aleft) | pointInside(Bleft,Bbottom,Atop,Aright,Abottom,Aleft) | pointInside(Bright,Bbottom,Atop,Aright,Abottom,Aleft) ){ return callBackFunction(objectA,objectB,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); } }); } }