This repository has been archived on 2020-04-21. You can view files and clone it, but cannot push or open issues or pull requests.
2020-04-18 04:36:23 -04:00

1071 lines
37 KiB
JavaScript

function createCanvas(id) {
var tempCanvas = document.createElement("canvas");
tempCanvas.id = id;
tempCanvas.width = canvases.cvs.width;
tempCanvas.height = canvases.cvs.height;
tempCanvas.style = "image-rendering:pixelated;image-rendering: crisp-edges;display:none";//display:none;
document.body.appendChild(tempCanvas);
canvases[`${id}cvs`] = document.getElementById(id);
canvases[`${id}ctx`] = canvases[`${id}cvs`].getContext("2d");
}
function startLoops() {
try {draw} catch (err){console.warn(bug+" no draw function found");return null;}
try {update} catch (err){console.warn(bug+" no update function found");return null;}
try {input} catch (err){seperateInputLoop=false;}
onAssetsLoaded();
requestAnimationFrame(drawLoop);
setInterval(updateLoop,1000/updateFPS);
if(seperateInputLoop) {
setInterval(inputLoop,4);
}
}
function mousePosition() {
if(drawMode===0) {
return {x:(mousePos.x)-camera.x,y:(mousePos.y)-camera.y};
} else if(drawMode===1) {
var xoff = canvases.cvs.width/2;
var yoff = canvases.cvs.height/2;
return {x:((mousePos.x-xoff)/camera.zoom+xoff)-camera.x,y:((mousePos.y-yoff)/camera.zoom+yoff)-camera.y};
} else {
var xoff = canvases.cvs.width/2;
var yoff = canvases.cvs.height/2;
var tempPos = {x:((mousePos.x-xoff)/camera.zoom+xoff)-camera.x,y:((mousePos.y-yoff)/camera.zoom+yoff)-camera.y};
var center = {x:-camera.x + cw/2, y:-camera.y + ch/2};
var tempAngle = pointTo(center,tempPos) - camera.angle;
var tempDist = dist(center,tempPos);
return {x:center.x + (Math.cos(tempAngle) * tempDist),y:center.y + (Math.sin(tempAngle) * tempDist)}
}
}
function addStyle() {
var tempStyle = document.createElement("style");
tempStyle.id="gamejsstyle";
document.head.appendChild(tempStyle);
var tempMeta = document.createElement("meta");
tempMeta.setAttribute("charset","utf-8");
document.head.appendChild(tempMeta);
}
function rand(min,max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function radToDeg(rad) {return rad / Math.PI * 180;}
function degToRad(deg) {return deg * Math.PI / 180;}
function velocity(angle) {
return {x:Math.sin(angle),y:Math.cos(angle)};
}
function pointTo(point,targetPoint) {
var adjacent = (targetPoint.x - point.x);
var opposite = (targetPoint.y - point.y);
var h = Math.atan2(opposite, adjacent);
return h;
}
function loadImagesAndSounds() {
var curpath="";
context = new AudioContext();
sfxVolumeNode = context.createGain();
sfxVolumeNode.connect(context.destination);
bmgVolumeNode = context.createGain();
bmgVolumeNode.connect(context.destination);
deeper(images,"image");
deeper(audio,"sound");
function deeper(curpos,type) {
let addedPath="";
for(let j=0;j<curpos.length;j++) {
if(typeof curpos[j]=="string") {
if(j==0) {
curpath+=curpos[j];
addedPath = curpos[j];
} else {
if(type=="image") {
let name = curpath + curpos[j];
imagePaths.push(name);
let temp = new Image();
temp.src = name;
temp.onerror = function () {
console.warn(bug+" "+this.src + " was not found");
};
temp.onload = function() {spriteLoad(name,temp);}
imgs.push(temp);
} else if(type=="sound") {
audioPaths.push(curpath + curpos[j]);
newSound(curpath + curpos[j]);
}
}
}
if(typeof curpos[j]=="object") {
deeper(curpos[j],type);
}
}
curpath = curpath.slice(0,curpath.length-addedPath.length);
}
loadingCircle = new Image();
loadingCircle.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAf0lEQVQ4jc2SuxHAIAxDbY4pMpHmyJSeKGuQKpyj2Hy6qETPQvhQCWRmDRfeZ4cJAGW28mAUyL4Pqmx2nfK+zaR59glRHo5qZi0BaPHmbDhiyuzdsza9wcrtEVtG4Ip+FLCzTM+WneWxPv9gpQUzmhncLPOHUCYfHr4/C4r2dQPfhkeIbjeYWgAAAABJRU5ErkJggg==";
clickSound = new Audio("data:audio/x-wav;base64,UklGRowBAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YWgBAADa/6T/2/+S/x//pP769Xr4fPh5+H34evh7+Pv6gf18/QIAhQcIDxUZFR4VHhgeEx6TFgkPCgqAAnz49/X18HLu7ubo4eXc5dzj3Gjf5+Fr5G7pce759YECiwwRFBQZlxuXG5cbFRmTFo8RCAoAAPz69/X08G7udO5s7vz1dvj++nv9gP3+/wEAgwKBAogHkBEpLUNG1lzqcPV683r4eu51ZmnVV7w+qypy88fDoKAXlAqKBoUAgIeHlpYsrTu87Ot9/ZIRGxkoKDEtqionIxgZiwfj5lnaz9JN0E3QV9pd3+Tm9fUBAAQFBwWNDBEPFxSYFpsWEA9+/fP1dfNt83bz8fX9+gQFkAwPDxQPEQ+IBwIAdfjv8OLm2+HX3Nrh4+bm63n4BAUUDx0ZqyCrJSkelBGEAnb4a+5a5Njcztxc31jkZunx9QgFGhQfGa0gqCCuIKkgpRsaFIsHdfhj6dfh0NzM19Th6es=");
let pos = {x:cw/2-100,y:ch/2-100};
optionsButtons.screenSize = {x:pos.x+160,y:pos.y+12,w:50,h:20};
optionsButtons.sfx = {x:pos.x+125,y:pos.y+40,w:120,h:20};
optionsButtons.bmg = {x:pos.x+125,y:pos.y+70,w:120,h:20};
loadLoop();
}
function loadLoop() {
if(Object.keys(sprites).length == imagePaths.length && audioPaths.length == audioLoadedLength) {
startLoops();
imagePaths=[];
audioPaths=[];
imgs=[];
} else {
curCtx.fillStyle="#2d2d2d";
curCtx.fillRect(0,0,cw,ch);
text(`audio: ${audioLoadedLength}/${audioPaths.length}`,10,30,"white",2);
text(`sprites: ${Object.keys(sprites).length}/${imagePaths.length}`,10,10,"white",2);
curCtx.setTransform(1, 0, 0, 1, Math.round(cw/2), Math.round(ch/2));
curCtx.rotate(loadAng);
loadAng+=0.1;
curCtx.drawImage(loadingCircle,Math.round(-8),Math.round(-8));
curCtx.setTransform(1, 0, 0, 1, 0, 0);
requestAnimationFrame(loadLoop);
}
}
function spriteLoad(path,image) {
let startpos;
let endpos = path.lastIndexOf(".");
for(let j=endpos-1;acceptableChars.includes(path[j]);j--) {startpos=j;}
let spriteName = path.slice(startpos,endpos)
let dsize=Math.max(image.width,image.height)/2;
sprites[spriteName] = {spr:image,drawLimitSize:dsize};
}
function newSound(src) {
let startpos;
let endpos = src.lastIndexOf(".");
for(let j=endpos-1;acceptableChars.includes(src[j]);j--) {startpos=j;}
let soundName = src.slice(startpos,endpos);
sounds[soundName] = {nodes:[],volNodes:[],src:src,type:"sfx",volume:1};
sounds[soundName].nodes = [1];
let loadingSound = new Audio();
loadingSound.onerror = function () {
console.warn(bug+" "+ src + " was not found");
};
loadingSound.src = src;
loadingSound.preload='auto';
loadingSound.addEventListener('canplaythrough', function() {
audioLoadedLength++;
}, false);
sounds[soundName].nodes.push(loadingSound);
let soundNode = context.createMediaElementSource(loadingSound);
let gainNode = context.createGain();
soundNode.connect(gainNode);
gainNode.connect(sfxVolumeNode);
abuffer.push(soundNode);
volumeList.push(gainNode);
sounds[soundName].volNodes.push(volumeList.length-1);
}
function addSound(sound) {
let loadingSound = new Audio();
loadingSound.src = sound.src;
loadingSound.preload='auto';
sound.nodes.splice(sound.nodes[0],0,loadingSound);
let soundNode = context.createMediaElementSource(loadingSound);
let gainNode = context.createGain();
gainNode.gain.value=sound.volume;
soundNode.connect(gainNode);
gainNode.connect(sound.type=="sfx"?sfxVolumeNode:bmgVolumeNode);
abuffer.push(soundNode);
volumeList.push(gainNode);
sound.volNodes.push(volumeList.length-1);
volumeList[sound.volNodes[sound.volNodes.length-1]].gain.value = volumeList[sound.volNodes[0]].gain.value
}
function play(sound) {
s=sound.nodes;
if(s[s[0]].ended || !(s[s[0]].played.length)) {
s[s[0]].play();
s[0]++;
if(s[0]==s.length) {
s[0]=1;
}
} else {
addSound(sound);
s[s[0]].play();
s[0]++;
if(s[0]==s.length) {
s[0]=1;
}
}
}
function setVolume(sound,volume) {
for(let i=0,l=sound.volNodes.length;i<l;i++) {
volumeList[sound.volNodes[i]].gain.value = volume;
}
}
function setType(sound,newType) {
for(let i=0,l=sound.volNodes.length;i<l;i++) {
volumeList[sound.volNodes[i]].disconnect(sound.type=="sfx"?sfxVolumeNode:bmgVolumeNode);
volumeList[sound.volNodes[i]].connect(newType=="sfx"?sfxVolumeNode:bmgVolumeNode);
}
sound.type = newType;
}
function stop(sound) {
s=sound.nodes;
for(let i=1;i<s.length;i++) {
s[i].pause();
s[i].currentTime = 0;
}
}
function handleOptionsInput() {
let ImTierdMakemenuwork=true;
if(optionsMenu) {
if(mousePress[0]) {
if(rectpoint(optionsButtons.screenSize,mousePos)) {
if(screenSize=="1:1") {
screenSize = "fit";
canvasScale=0;
} else {
screenSize = "1:1";
canvasScale=1;
}
}
if(!rectpoint({x:cw/2,y:ch/2,w:200,h:200},mousePos)) {
optionsMenu=false;
ImTierdMakemenuwork=false;
}
}
if(mouseDown[0]) {
if(rectpoint(optionsButtons.sfx,mousePos)) {
volume.sfx = (mousePos.x-(optionsButtons.sfx.x-60))/120;
}
if(rectpoint(optionsButtons.bmg,mousePos)) {
volume.bgm = (mousePos.x-(optionsButtons.bmg.x-60))/120;
}
}
}
if(mousePos.x>cw-32&&mousePos.y<32) {
if(mousePress[0]&&ImTierdMakemenuwork) {
clickSound.play();
paused=true;
optionsMenu=!optionsMenu;
}
optionsHover = 25;
} else {
optionsHover = 0;
}
if(mousePos.x<cw-32&&mousePos.x>cw-64&&mousePos.y<32) {
pauseHover = 25;
if(mousePress[0]) {
clickSound.play();
paused=!paused;
}
} else {
pauseHover = 0;
}
}
function addFont() {
var tempStyle = document.createElement("style");
tempStyle.innerHTML = `
@font-face {
font-family: 'PixelArial11';
src: url("./pixelmix.ttf") format('truetype');
font-weight: 900;
font-style: normal;
}
html {font-family: 'PixelArial11' !important; font-size: 16px;}
`;
document.head.appendChild(tempStyle);
canvases.ctx.textBaseline = "hanging";
canvases.ctx.textAlign = "left";
}
var scaleDefault = 1;
function img(img,x,y,angle=0,sx=scaleDefault,sy=scaleDefault) {
var half = img.drawLimitSize;
if((x+half>drawLimitLeft&&x-half<drawLimitRight&&y+half>drawLimitTop&&y-half<drawLimitBottom)||absDraw) {
let spr = img.spr;
if(angle===0&&sx===1&&sy===1) {
curCtx.drawImage(spr,Math.round(x+camera.x+difx-(spr.width/2)),Math.round(y+camera.y+dify-(spr.height/2)));
} else {
curCtx.setTransform(sx, 0, 0, sy, Math.round(x+camera.x+difx), Math.round(y+camera.y+dify));
curCtx.rotate(angle);
curCtx.drawImage(spr,Math.round(-spr.width/2),Math.round(-spr.height/2));
curCtx.setTransform(1, 0, 0, 1, 0, 0);
}
}
}
function imgIgnoreCutoff(img,x,y,angle=0,sx=1,sy=1) {
let spr = img.spr;
if(angle===0&&sx===1&&sy===1) {
curCtx.drawImage(spr,Math.round(x+camera.x+difx-(spr.width/2)),Math.round(y+camera.y+dify-(spr.height/2)));
} else {
curCtx.setTransform(sx, 0, 0, sy, Math.round(x+camera.x+difx), Math.round(y+camera.y+dify));
curCtx.rotate(angle);
curCtx.drawImage(spr,Math.round(-spr.width/2),Math.round(-spr.height/2));
curCtx.setTransform(1, 0, 0, 1, 0, 0);
}
}
function rect(x,y,w,h,color) {
curCtx.fillStyle = color;
curCtx.fillRect(x-(w/2)+camera.x+difx,y-(h/2)+camera.y+dify,w,h);
}
function circle(x,y,r,color) {
curCtx.beginPath();
curCtx.arc(x+camera.x+difx, y+camera.y+dify, r, 0, 2 * Math.PI, false);
curCtx.fillStyle = color;
curCtx.fill();
}
function line(x1, y1, x2, y2, color) {
curCtx.beginPath();
curCtx.strokeStyle = color;
curCtx.moveTo(x1 + camera.x + difx, y1 + camera.y + dify);
curCtx.lineTo(x2 + camera.x + difx , y2 + camera.y + dify);
curCtx.stroke();
}
function shape(x,y,relitivePoints,color) {
x+=camera.x+difx;
y+=camera.y+dify;
curCtx.fillStyle = color;
curCtx.beginPath();
curCtx.moveTo(x+relitivePoints[0].x, y+relitivePoints[0].y);
for(let i=1,l=relitivePoints.length;i<l;i++) {
curCtx.lineTo(x+relitivePoints[i].x, y+relitivePoints[i].y);
}
curCtx.fill();
}
function text(txt,x,y,color="black",size=1,maxWidth=cw) {
txt = txt.toString();
curCtx.fillStyle = color;
curCtx.font = `${Math.round(size)*8}px PixelArial11`;
//I hate text wrapping now
var txtList = txt.split("\n"); //split string on enters
for(let i=0;i<txtList.length;i++) { //go through array of strings
if(curCtx.measureText(txtList[i]).width>maxWidth) { //if the string is too big, divide up into smaller strings
var tempTxt = txtList[i].split(" "); //split into individual words
var tempStr=""; //string for measuring size
var addAmount=0; //track where in the txtList we are
txtList.splice(i,1); //remove the too long string
for(let j=0;j<tempTxt.length;j++) { //go through the split up string
if(curCtx.measureText(tempStr + tempTxt[j] + " ").width<maxWidth) { //if adding a word doesn't make tempStr too long, add it, other wise, add tempStr to txtList;
tempStr += tempTxt[j] + " ";
} else {
if(j==0) {tempStr+=tempTxt[j];} //if we are here when j is 0, we have one word that is longer then the maxWidth, so we just draw it
txtList.splice(i+addAmount,0,tempStr); //put tempStr in txtList
addAmount++; //move the position we put the tempStr in
tempStr=""; //reset tempStr
tempTxt.splice(0,(j==0?1:j)); //delete words that have been used
j=-1; //make it so in the next loop, j starts at 0
}
}
if(tempStr.length!=0) {
txtList.splice(i+addAmount,0,tempStr); //add any leftover text
}
}
}
for(let i=0;i<txtList.length;i++) {
curCtx.fillText(txtList[i],x+camera.x+difx,y+camera.y+dify+((i+(drawMode?1:0))*8*size+(size*i)));
}
}
function textWidth(txt,size=1) {
txt = txt.toString();
curCtx.font = `${Math.round(size)*8}px PixelArial11`;
return curCtx.measureText(txt).width;
}
function centerCameraOn(x,y) {
camera.x = -x+canvases.cvs.width/2;
camera.y = -y+canvases.cvs.height/2;
}
function moveCamera(x,y) {
camera.x -= y * Math.sin(camera.angle);
camera.y -= y * Math.cos(camera.angle);
camera.x -= x * Math.sin(camera.angle + 1.57079632);
camera.y -= x * Math.cos(camera.angle + 1.57079632);
}
function imgRotScale(x,y,angle,scale,pic,ctx) { //used for camera movement
ctx.setTransform(scale, 0, 0, scale, x, y);
ctx.rotate(angle);
ctx.drawImage(pic,-pic.width/2,-pic.height/2);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
function drawCursor() {
if(cursor.sprite&&mouseOnCanvas) {
if(cursor.alignment) {
canvases.ctx.drawImage(cursor.sprite.spr,mousePos.x-Math.round(cursor.sprite.spr.width/2),mousePos.y-Math.round(cursor.sprite.spr.height/2));
} else {
canvases.ctx.drawImage(cursor.sprite.spr,mousePos.x,mousePos.y);
}
cursor.show = false;
} else {
cursor.show = true;
}
}
function render() {
if(drawMode===1) {
imgRotScale(canvases.cvs.width/2,canvases.cvs.height/2,0,camera.zoom,canvases.buffer1cvs,canvases.ctx);
}
if(drawMode===2) {
imgRotScale(canvases.cvs.width/2,canvases.cvs.height/2,camera.angle,1,canvases.buffer2cvs,canvases.buffer1ctx);
imgRotScale(canvases.cvs.width/2,canvases.cvs.height/2,0,camera.zoom,canvases.buffer1cvs,canvases.ctx);
}
}
function clearCanvases() {
canvases.ctx.clearRect(0,0,canvases.cvs.width,canvases.cvs.height);
canvases.buffer1ctx.clearRect(0,0,canvases.buffer1cvs.width,canvases.buffer1cvs.height);
canvases.buffer2ctx.clearRect(0,0,canvases.buffer2cvs.width,canvases.buffer2cvs.height);
}
function switchDrawMode() {
if(camera.zoom<1) {camera.zoom=1;}
if(camera.angle!=0) {
drawMode=2;
} else if(camera.zoom!=1) {
drawMode=1;
} else {
drawMode=0;
}
switch (drawMode) {
case 0: curCtx = canvases.ctx; break;
case 1: curCtx = canvases.buffer1ctx; break;
case 2: curCtx = canvases.buffer2ctx; break;
}
}
function resizeBuffers() {
var tempSize = maxCvsSize/camera.zoom;
var tempSizeAndPadding = tempSize + (tempSize/2)
canvases.buffer2cvs.width = tempSizeAndPadding;
canvases.buffer2cvs.height = tempSizeAndPadding;
if(drawMode===2) {
difx = (canvases.buffer2cvs.width - canvases.cvs.width)/2;
dify = (canvases.buffer2cvs.height - canvases.cvs.height)/2;
} else {
difx=0;
dify=0;
}
canvases.buffer2ctx.imageSmoothingEnabled = false;
}
function scaleCanvases() { //scales canvas by canvas scale, if scale is 0, canvas will try to fit screen
var style = document.getElementById("gamejsstyle");
if(canvasScale==0) {
var tempScale = Math.min(Math.floor(window.innerWidth/canvases.cvs.width),Math.floor(window.innerHeight/canvases.cvs.height));
tempScale=tempScale<1?1:tempScale;
autoScale=tempScale;
style.innerHTML = `#game {image-rendering:pixelated;image-rendering: crisp-edges;width:${tempScale*canvases.cvs.width}px;cursor: ${cursor.show?"crosshair":"none"};}`;
} else {
style.innerHTML = `#game {image-rendering:pixelated;image-rendering: crisp-edges;width:${Math.floor(canvasScale*canvases.cvs.width)}px;cursor: ${cursor.show?"crosshair":"none"};}`;
}
}
function drawButtons() {
let pos = {x:cw-16,y:16};
//options
rect(pos.x,pos.y,34,34,"#9c9c9c");
let c = optionsHover+45;
rect(pos.x,pos.y,32,32,`rgb(${c},${c},${c})`);
c = optionsHover + 69;
let cc = `rgb(${c},${c},${c})`;
rect(pos.x,pos.y-6,26,4,cc);
rect(pos.x-6,pos.y-6,4,8,cc);
rect(pos.x,pos.y+6,26,4,cc);
rect(pos.x+11,pos.y+6,4,8,cc);
//pause
pos.x-=33;
rect(pos.x,pos.y,34,34,"#9c9c9c");
c = pauseHover+45;
rect(pos.x,pos.y,32,32,`rgb(${c},${c},${c})`);
c = pauseHover + 69;
cc = `rgb(${c},${c},${c})`;
if(paused) {
shape(pos.x,pos.y,[{x:-7,y:-10},{x:-7,y:10},{x:10,y:0}],cc);
} else {
rect(pos.x+6,pos.y,6,20,cc);
rect(pos.x-6,pos.y,6,20,cc);
}
}
function drawOptionsMenu() {
if(optionsMenu) {
let pos = {x:cw/2-100,y:ch/2-100};
rect(cw/2,ch/2,200,200,"#242424");
text("Screen Size:",pos.x+2,pos.y+2,"white",2);
let b = optionsButtons.screenSize;
rect(b.x,b.y,b.w,b.h,"#444444");
text(screenSize,pos.x+145,pos.y+4,"white",2);
text("sfx",pos.x+2,pos.y+30,"white",2);
b = optionsButtons.sfx;
rect(b.x,b.y,b.w,b.h-10,"#444444");
rect((b.x-60)+(volume.sfx*120),b.y,8,20,"#444444");
text("bmg",pos.x+2,pos.y+60,"white",2);
b = optionsButtons.bmg;
rect(b.x,b.y,b.w,b.h-10,"#444444");
rect((b.x-60)+(volume.bgm*120),b.y,8,20,"#444444");
}
}
var k={a:65,b:66,c:67,d:68,e:69,f:70,g:71,h:72,i:73,j:74,k:75,l:76,m:77,n:78,o:79,p:80,q:81,r:82,s:83,t:84,u:85,v:86,w:87,x:88,y:89,z:90,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,BACKTICK:192,MINUS:189,EQUALS:187,OPENSQUARE:219,ENDSQUARE:221,SEMICOLON:186,SINGLEQUOTE:222,BACKSLASH:220,COMMA:188,PERIOD:190,SLASH:191,ENTER:13,BACKSPACE:8,TAB:9,CAPSLOCK:20,SHIFT:16,CONTROL:17,ALT:18,META:91,LEFTBACKSLASH:226,ESCAPE:27,HOME:36,END:35,PAGEUP:33,PAGEDOWN:34,DELETE:46,INSERT:45,PAUSE:19,UP:38,DOWN:40,LEFT:37,RIGHT:39,CONTEXT:93,SPACE:32,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123};
var keyPress = [];
var keyDown = [];
var mousePress = [];
var mouseDown = [];
var scroll = 0;
var mousePos = {
x:0,
y:0
}
var preventedEvents = [false,true,true];
function addListenersTo(elementToListenTo) {
window.addEventListener("keydown",kdown);
window.addEventListener("keyup",kup);
elementToListenTo.addEventListener("mousedown",mdown);
elementToListenTo.addEventListener("mouseup",mup);
elementToListenTo.addEventListener("mousemove",mmove);
elementToListenTo.addEventListener("contextmenu",cmenu);
elementToListenTo.addEventListener("wheel",scrl);
}
function removeListenersFrom(elementToListenTo) {
window.removeEventListener("keydown",kdown);
window.removeEventListener("keyup",kup);
elementToListenTo.removeEventListener("mousedown",mdown);
elementToListenTo.removeEventListener("mouseup",mup);
elementToListenTo.removeEventListener("mousemove",mmove);
elementToListenTo.removeEventListener("contextmenu",cmenu);
elementToListenTo.removeEventListener("wheel",scrl);
}
function resetInput() {
for(var i=0;i<keyPress.length;i++){if(keyPress[i]){keyPress[i]=0}}
for(var i=0;i<mousePress.length;i++){if(mousePress[i]){mousePress[i]=0}}
scroll=0;
}
function kdown(e) {
var h=e.keyCode;
keyPress[h]=keyPress[h]==[][[]]?1:0;
keyDown[h]=1;
if(preventedEvents[0]) {e.preventDefault()}
}
function kup(e) {
var h=e.keyCode;
delete keyPress[h];
delete keyDown[h];
}
function mdown(e) {
var h=e.button;
mousePress[h]=mousePress[h]==[][[]]?1:0;
mouseDown[h]=1;
if(preventedEvents[1]) {e.preventDefault()}
}
function mup(e) {
var h=e.button;
delete mousePress[h];
delete mouseDown[h];
}
function mmove(e) {
mousePos.x=e.offsetX/(!canvasScale?autoScale:canvasScale);
mousePos.y=e.offsetY/(!canvasScale?autoScale:canvasScale);
}
function cmenu(e) {
if(preventedEvents[1]) {e.preventDefault()}
}
function scrl(e) {
scroll+=-1*(e.deltaY/100);
if(preventedEvents[2]) {e.preventDefault()}
}
function dist(point1,point2) {
let one = (point2.x - point1.x);
let two = (point2.y - point1.y);
return Math.sqrt((one*one)+(two*two));
}
function circlecircle(circle1,circle2) {
if( dist(circle1,circle2) < (circle1.r + circle2.r)) {
return true;
} else {
return false;
}
}
function circlepoint(circle,point) {
if( dist(circle,point) < circle.r) {
return true;
} else {
return false;
}
}
function rectrect(rect1,rect2) {
if(rect1.x + rect1.w/2 >= rect2.x - rect2.w/2 &&
rect1.x - rect1.w/2 <= rect2.x + rect2.w/2 &&
rect1.y + rect1.h/2 >= rect2.y - rect2.h/2 &&
rect1.y - rect1.h/2 <= rect2.y + rect2.h/2) {
return true;
} else {
return false;
}
}
function rectpoint(rect,point) {
if(rect.x + rect.w/2 >= point.x &&
rect.x - rect.w/2 <= point.x &&
rect.y + rect.h/2 >= point.y &&
rect.y - rect.h/2 <= point.y ) {
return true;
} else {
return false;
}
}
function circlerect(circle,rect) { //credit: https://yal.cc/rectangle-circle-intersection-test/
let rectHalfWidth = rect.w/2;
let rectHalfHeight = rect.h/2;
let deltaX = circle.x - Math.max(rect.x - rectHalfWidth, Math.min(circle.x, rect.x + rectHalfWidth));
let deltaY = circle.y - Math.max(rect.y - rectHalfHeight, Math.min(circle.y, rect.y + rectHalfHeight));
return (deltaX * deltaX + deltaY * deltaY) < (circle.r * circle.r);
}
function circleOnSideRect(circle,rect) {
let rectHalfWidth = rect.w/2;
let rectHalfHeight = rect.h/2;
let left = rect.x - rectHalfWidth;
let right = rect.x + rectHalfWidth;
let top = rect.y - rectHalfHeight;
let bottom = rect.y + rectHalfHeight;
let cx = circle.x;
let cy = circle.y;
if(cy < top && cx > left && cx < right) { // top side
return 0;
} else if(cy > bottom && cx > left && cx < right) { // bottom side
return 2;
} else if (cx < left && cy > top && cy < bottom) { // left side
return 3;
} else if (cx > right && cy > top && cy < bottom) { // right side
return 1;
} else {
let returnValue=0; // 0 = top, 1 = right, 2 = bottom, 3 = left
let topleft = dist (circle,{x:left,y:top});
let topright = dist (circle,{x:right,y:top});
let bottomleft = dist (circle,{x:left,y:bottom});
let bottomright = dist (circle,{x:right,y:bottom});
switch(Math.min(topleft,topright,bottomleft,bottomright)) { // find what corner the cricle is closer to, then determine what side it is closer to
case topleft:
var m = slope(rect,{x:left,y:top});
var mperp = -(1/m);
var b = yIntercept(rect,m);
var bperp = yIntercept(circle,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 3;} else {returnValue = 0;}
break;
case topright:
var m = slope(rect,{x:right,y:top});
var mperp = -(1/m);
var b = yIntercept(rect,m);
var bperp = yIntercept(circle,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 0;} else {returnValue = 1;}
break;
case bottomleft:
var m = slope(rect,{x:left,y:bottom});
var mperp = -(1/m);
var b = yIntercept(rect,m);
var bperp = yIntercept(circle,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 3;} else {returnValue = 2;}
break;
case bottomright:
var m = slope(rect,{x:right,y:bottom});
var mperp = -(1/m);
var b = yIntercept(rect,m);
var bperp = yIntercept(circle,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 2;} else {returnValue = 1;}
break;
}
return returnValue;
}
}
function rectOnSideRect(rect1,rect2) {
let rectHalfWidth2 = rect2.w/2;
let rectHalfHeight2 = rect2.h/2;
let left2 = rect2.x - rectHalfWidth2;
let right2 = rect2.x + rectHalfWidth2;
let top2 = rect2.y - rectHalfHeight2;
let bottom2 = rect2.y + rectHalfHeight2;
let rectHalfWidth1 = rect1.w/2;
let rectHalfHeight1 = rect1.h/2;
let rx1 = rect1.x;
let ry1 = rect1.y;
let left1 = rx1 - rectHalfWidth1;
let right1 = rx1 + rectHalfWidth1;
let top1 = ry1 - rectHalfHeight1;
let bottom1 = ry1 + rectHalfHeight1;
// find what point is closer to the rectangle
let topleft1 = dist (rect2,{x:left1,y:top1});
let topright1 = dist (rect2,{x:right1,y:top1});
let bottomleft1 = dist (rect2,{x:left1,y:bottom1});
let bottomright1 = dist (rect2,{x:right1,y:bottom1});
let topmiddle1 = dist (rect2,{x:rx1,y:top1});
let rightmiddle1 = dist (rect2,{x:right1,y:ry1});
let bottommiddle1 = dist (rect2,{x:rx1,y:bottom1});
let leftmiddle1 = dist (rect2,{x:left1,y:ry1});
let cx = rx1;
let cy = ry1;
switch(Math.min(topleft1,topright1,bottomleft1,bottomright1,topmiddle1,rightmiddle1,bottommiddle1,leftmiddle1)) {
//set the point we are testing to the closest point to the rectangle
case topleft1:
cx -= rect1.w/2;
cy -= rect1.h/2;
break;
case topright1:
cx += rect1.w/2;
cy -= rect1.h/2;
break;
case bottomleft1:
cx -= rect1.w/2;
cy += rect1.h/2;
break;
case bottomright1:
cx += rect1.w/2;
cy += rect1.h/2;
break;
case topmiddle1:
cy -= rect1.h/2;
break;
case rightmiddle1:
cx += rect1.w/2;
break;
case bottommiddle1:
cy += rect1.h/2;
break;
case leftmiddle1:
cx -= rect1.w/2;
break;
}
if(cy < top2 && cx > left2 && cx < right2) { // top side
return 0;
} else if(cy > bottom2 && cx > left2 && cx < right2) { // bottom side
return 2;
} else if (cx < left2 && cy > top2 && cy < bottom2) { // left side
return 3;
} else if (cx > right2 && cy > top2 && cy < bottom2) { // right side
return 1;
} else {
let returnValue=0; // 0 = top, 1 = right, 2 = bottom, 3 = left
let determiningPoint = {x:cx,y:cy};
let topleft = dist (determiningPoint,{x:left2,y:top2});
let topright = dist (determiningPoint,{x:right2,y:top2});
let bottomleft = dist (determiningPoint,{x:left2,y:bottom2});
let bottomright = dist (determiningPoint,{x:right2,y:bottom2});
switch(Math.min(topleft,topright,bottomleft,bottomright)) { // find what corner the point is closer to, then determine what side it is closer to
case topleft:
var m = slope(rect2,{x:left2,y:top2});
var mperp = -(1/m);
var b = yIntercept(rect2,m);
var bperp = yIntercept(determiningPoint,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 3;} else {returnValue = 0;}
break;
case topright:
var m = slope(rect2,{x:right2,y:top2});
var mperp = -(1/m);
var b = yIntercept(rect2,m);
var bperp = yIntercept(determiningPoint,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 0;} else {returnValue = 1;}
break;
case bottomleft:
var m = slope(rect2,{x:left2,y:bottom2});
var mperp = -(1/m);
var b = yIntercept(rect2,m);
var bperp = yIntercept(determiningPoint,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 3;} else {returnValue = 2;}
break;
case bottomright:
var m = slope(rect2,{x:right2,y:bottom2});
var mperp = -(1/m);
var b = yIntercept(rect2,m);
var bperp = yIntercept(determiningPoint,mperp);
var mid = POI(m,b,mperp,bperp);
if(cx<mid) {returnValue = 2;} else {returnValue = 1;}
break;
}
return returnValue;
}
}
function slope(point1,point2) {
return ((point2.y-point1.y)/(point2.x-point1.x));
}
function yIntercept(point,slope) {
return point.y - (slope * point.x);
}
function POI(m1,b1,m2,b2) {
x = (b2 - b1) / (m1 - m2);
return x;
//y = m1 * x + b1;
}
function ifRectOnEdgeBounce(rect) {
let rx = rect.x;
let ry = rect.y;
let rw = rect.w/2;
let rh = rect.h/2;
if(rx+rw>edge.right) {
rect.v.x *= -1;
rect.x = edge.right-rw;
}
if(rx-rw<edge.left) {
rect.v.x *= -1;
rect.x = edge.left+rw;
}
if(ry+rh>edge.bottom) {
rect.v.y *= -1;
rect.y = edge.bottom-rh;
}
if(ry-rh<edge.top) {
rect.v.y *= -1;
rect.y = edge.top+rh;
}
}
function ifCircleOnEdgeBounce(circle) {
let cx = circle.x;
let cy = circle.y;
let cr = circle.r;
if(cx+cr>edge.right) {
circle.v.x *= -1;
circle.x = edge.right-cr;
}
if(cx-cr<edge.left) {
circle.v.x *= -1;
circle.x = edge.left+cr;
}
if(cy+cr>edge.bottom) {
circle.v.y *= -1;
circle.y = edge.bottom-cr;
}
if(cy-cr<edge.top) {
circle.v.y *= -1;
circle.y = edge.top+cr;
}
}
// create globals
var canvases={cvs:null,ctx:null,buffer1cvs:null,buffer1ctx:null,buffer2cvs:null,buffer2ctx:null}, // visable and hidden canvases
cw, // canvas width
ch, // canvas height
camera={zoom:1,angle:0,x:0,y:0}, // affects how everything is drawn
updateFPS=60,
gameStarted=false,
drawMode=0, // 0=normal, 1=zoomed, 2=zoomed/rotated, set automatically depending on camera
absDraw=false,
curCtx, // what canvas to draw to
maxCvsSize, // used by second buffer
canvasScale=1,
difx=0, // offsets for drawing
dify=0,
seperateInputLoop=true,
edge={top:null,bottom:null,left:null,right:null}, // used by if___OnEdgeBounce, set to canvas size at setup, can be changed whenever
drawLimitLeft,
drawLimitRight,
drawLimitTop,
drawLimitBottom,
sizeDif,
bug="\uD83D\uDC1B",
loadingCircle,
loadAng=0,
optionsHover=0,
pauseHover=0,
optionsMenu=false,
optionsButtons={},
clickSound,
paused=false,
screenSize="1:1",
autoScale=1,
images=[], // put image paths here
imagePaths=[],
imgs=[],
sprites={}, // loaded images
audio=[], // put audio paths here
audioPaths=[],
sounds={}, // loaded sounds
abuffer = [], // audio nodes shoved here
volumeList = [], // gain nodes shoved here
audioLoadedLength=0,
volume={sfx:1,bgm:1};
/* options
future:
modefileable checklist
key bindings
*/
cursor = {sprite:null,alignment:1,show:true}, // 0=topleft, 1=centered
mouseOnCanvas=false;
const acceptableChars="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_-. ";//for image names
const AudioContext = window.AudioContext||window.webkitAudioContext;
var context;
var sfxVolumeNode;
var bmgVolumeNode;
document.getElementById("game").onmouseout = function() {mouseOnCanvas = false;}
document.getElementById("game").onmouseover = function() {mouseOnCanvas = true;}
//setup canvases and input
function setup(physicsFPS) {
updateFPS = physicsFPS;
canvases.cvs = document.getElementById("game");
canvases.ctx = canvases.cvs.getContext("2d", { alpha: false });
canvases.cvs.onmousedown = function () {if(!gameStarted){loadImagesAndSounds();gameStarted=true;}}
createCanvas("buffer1");
createCanvas("buffer2");
canvases.ctx.imageSmoothingEnabled = false;
canvases.buffer1ctx.imageSmoothingEnabled = false;
canvases.buffer2ctx.imageSmoothingEnabled = false;
maxCvsSize=Math.max(canvases.cvs.width,canvases.cvs.height);
sizeDif=maxCvsSize-Math.min(canvases.cvs.width,canvases.cvs.height);
cw=canvases.cvs.width;
ch=canvases.cvs.height;
edge={top:0,bottom:ch,left:0,right:cw};
addFont();
addStyle();
addListenersTo(canvases.cvs);
curCtx = canvases.ctx;
requestAnimationFrame(startButton);
function startButton() {
curCtx.fillStyle="#2d2d2d";
curCtx.fillRect(0,0,cw,ch);//debugger;
circle(cw/2,ch/2,27,"#066312");
circle(cw/2,ch/2,23,"#149124");
shape(cw/2,ch/2,[{x:-7,y:-15},{x:-7,y:15},{x:15,y:0}],"#47f55d");
if(!gameStarted) {requestAnimationFrame(startButton);}
}
}
function drawLoop() {
cw=canvases.cvs.width;
ch=canvases.cvs.height;
scaleCanvases();
switchDrawMode();
resizeBuffers();
clearCanvases();
var limitModifyer = 0;
if(drawMode==2) {limitModifyer=canvases.buffer2cvs.width-maxCvsSize;}
drawLimitLeft = -camera.x - (drawMode==2?sizeDif:0) - limitModifyer;
drawLimitRight = -camera.x + maxCvsSize + (drawMode==2?sizeDif:0) + limitModifyer;
drawLimitTop = -camera.y -(drawMode==2?sizeDif:0) - limitModifyer;
drawLimitBottom = -camera.y + maxCvsSize + (drawMode==2?sizeDif:0) + limitModifyer;
draw();
render();
curCtx=canvases.ctx;
difx=0;dify=0;
var camCache = {x:camera.x,y:camera.y};
var drawModeCache = drawMode;
camera.x=0;camera.y=0;
drawMode=0;
absDraw=true;
absoluteDraw();
absDraw=false;
drawButtons();
drawOptionsMenu();
drawCursor();
drawMode=drawModeCache;
camera.x = camCache.x;
camera.y = camCache.y;
requestAnimationFrame(drawLoop);
}
function updateLoop() {
if(seperateInputLoop==false) {
handleOptionsInput();
}
sfxVolumeNode.gain.value = volume.sfx;
bmgVolumeNode.gain.value = volume.bgm;
if(!paused) {
update();
}
if(seperateInputLoop==false) {
resetInput();
}
}
function inputLoop() {
handleOptionsInput();
if(!paused) {
input();
}
resetInput();
}