// 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.translate(center.d[0],center.d[1]); ctx.rotate(-origRot); ctx.translate(-center.d[0],-center.d[1]); 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 = rad2vec(this.rotation.getRadAngle() + (rotation instanceof vector ? rotation : new vector([0,1])).getRadAngle()); var center = refPos.add(this.size.mag(0.5)); ctx.translate(center.d[0],center.d[1]); ctx.rotate(refRot.getRadAngle()); ctx.translate(-center.d[0],-center.d[1]); if (this.shapes.length) { this.shapes.forEach(shape => shape.render(ctx,refPos,refRot)); } if (this.containers.length) { this.containers.forEach(cont => cont.renderContainer(ctx,refPos,refRot)); } ctx.translate(center.d[0],center.d[1]); ctx.rotate(-origRot); ctx.translate(-center.d[0],-center.d[1]); } 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); }); } }