//Variables------------------------------------------------------------------------------------------------------ var FPS = 60; var framesElapsed = 0; var c = document.getElementById("ballgame"); var ctx = c.getContext("2d"); const width = c.width; const height = c.height; const playerPos = [0, 0, 0, 0]; const inputDir = [0, 0]; var termOpen = false; var termString = "help"; var command; var cmdHistory = [""]; var historyIndex = 0; var plrFill = getRandomColor(); var plrOutline = "000000"; var colorChangeOnBounce = false; var splatAlpha = 0.4; var splat = true; var splatSizeMax = 250; var splatSizeMin = 100; var splatX = []; var splatY = []; var splatColor = []; var splatSize = []; var splatFrames = []; var plrSize = 10; var maxVel = 100; var accel = 1; var friction = 1; const fontURL = "../resources/fonts/TeleSys.ttf"; const TeleSys = new FontFace("TeleSys", `url(${fontURL})`); document.fonts.add(TeleSys); ctx.font = "16px TeleSys"; //Functions------------------------------------------------------------------------------------------------------ function draw() { //draw player ctx.clearRect(0, 0, width, height); if (splat) { for (let i = 0; i < splatX.length; i++) { ctx.fillStyle = convertHexToRgbA(splatColor[i], splatAlpha); ctx.strokeStyle = convertHexToRgbA(splatColor[i], 0); ctx.beginPath(); ctx.arc( splatX[i] + width / 2, //x splatY[i] + height / 2, //y splatGrow(i), //px 0, //idk 2 * Math.PI, //rad ); ctx.fill(); ctx.stroke(); } } ctx.fillStyle = "#" + plrFill; ctx.strokeStyle = "#" + plrOutline; ctx.beginPath(); ctx.arc( playerPos[0] + width / 2, //x playerPos[1] + height / 2, //y plrSize / 2, //px 0, //idk 2 * Math.PI, //rad ); ctx.fill(); ctx.stroke(); //draw terminal if (termOpen) { ctx.fillStyle = "#000000"; ctx.fillText("(" + historyIndex + ")> " + termString, 5, 20); for (let i = 0; i < cmdHistory.length; i++) { ctx.fillText(i + 1 + "_ " + cmdHistory[i], 5, i * 20 + 40); } } } function checkKeys() { if (!termOpen) { //ball mode function checkKeyDown(event) { if (event.key == "d") { //Right inputDir[0] = 1; } if (event.key == "a") { //Left inputDir[0] = -1; } if (event.key == "w") { //Up inputDir[1] = -1; } if (event.key == "s") { //Down inputDir[1] = 1; } if (event.key == "c" && !termOpen) { termOpen = true; } } function checkKeyUp(event) { if (event.key == "a" || event.key == "d") { inputDir[0] = 0; } if (event.key == "w" || event.key == "s") { inputDir[1] = 0; } } document.onkeydown = checkKeyDown; document.onkeyup = checkKeyUp; } else { //terminal mode function doTyping(event) { if (event.key == "c" && event.ctrlKey) { termString = ""; } else if (event.key.length == 1) { termString = termString + event.key; } else { if (event.key == "Escape") { termOpen = false; } if (event.key == "Backspace") { termString = termString.substring(0, termString.length - 1); } if ( event.key == "ArrowUp" && historyIndex <= cmdHistory.length - 1 ) { termString = cmdHistory[historyIndex]; historyIndex++; } if (event.key == "ArrowDown") { if (historyIndex > 1) { historyIndex--; termString = cmdHistory[historyIndex - 1]; } else { historyIndex = 0; termString = ""; } } } //command submission-------------------------------------!! if (event.key == "Enter") { var regexPass = false; command = termString; var cmdArray = [command]; cmdHistory = cmdArray.concat(cmdHistory); termString = ""; termOpen = false; //define the commands and regex here //color change on bounce command================= if ( !command .substring(0, 5) .toUpperCase() .localeCompare("CCONB") ) { if ( !command .substring(6) .toUpperCase() .localeCompare("TRUE") ) { colorChangeOnBounce = true; } else if ( !command .substring(6) .toUpperCase() .localeCompare("FALSE") ) { colorChangeOnBounce = false; } else { cmdArray[0] = "CConB: Syntax error"; cmdHistory = cmdArray.concat(cmdHistory); termOpen = true; } regexPass = true; } //echo command================= if ( !command.substring(0, 4).toUpperCase().localeCompare("ECHO") ) { if ( !command .substring(5) .toUpperCase() .localeCompare("SIZE") ) { cmdArray[0] = "// (size) Size: " + plrSize + "px"; } if ( !command .substring(5) .toUpperCase() .localeCompare("FILL") ) { cmdArray[0] = "// (fill) Fill color: #" + plrFill; } if ( !command .substring(5) .toUpperCase() .localeCompare("OUTLINE") ) { cmdArray[0] = "// (outline) Outline color: #" + plrOutline; } if ( !command .substring(5, 10) .toUpperCase() .localeCompare("SPLAT") ) { if ( !command .substring(11) .toUpperCase() .localeCompare("MAX") ) { cmdArray[0] = "// (splat) Maximum splat size: " + splatSizeMax + "px"; } else if ( !command .substring(11) .toUpperCase() .localeCompare("MIN") ) { cmdArray[0] = "// (splat) Minimum splat size: " + splatSizeMin + "px"; } else if ( !command .substring(11) .toUpperCase() .localeCompare("ALPHA") ) { cmdArray[0] = "// (splat) Splat alpha value: " + splatAlpha; } else { cmdArray[0] = "// (splat) Splat enabled: " + splat; } } if ( !command .substring(5) .toUpperCase() .localeCompare("CCONB") ) { cmdArray[0] = "// (CConB) Color change on bounce enabled: " + colorChangeOnBounce; } if ( !command .substring(5) .toUpperCase() .localeCompare("MAXVEL") ) { cmdArray[0] = "// (maxvel) Maximum velocity: " + maxVel; } if ( !command .substring(5) .toUpperCase() .localeCompare("ACCEL") ) { cmdArray[0] = "// (accel) Acceleration rate: " + accel; } if ( !command .substring(5) .toUpperCase() .localeCompare("FRICTION") ) { cmdArray[0] = "// (friction) Friction: " + friction; } if ( !command .substring(5) .toUpperCase() .localeCompare("ECHO") ) { cmdArray[0] = "echo! echo!"; } if ( !command .substring(5) .toUpperCase() .localeCompare("CLEAR") ) { cmdArray[0] = "// (clear) w-. what. why"; } if ( !command .substring(5) .toUpperCase() .localeCompare("HELP") ) { showHelp(); } cmdHistory = cmdArray.concat(cmdHistory); termOpen = true; regexPass = true; } //clear command================= if ( !command .substring(0, 5) .toUpperCase() .localeCompare("CLEAR") ) { cmdHistory = [""]; termOpen = true; regexPass = true; } //acceleration command================= if ( !command .substring(0, 5) .toUpperCase() .localeCompare("ACCEL") ) { accel = command.substring(6); regexPass = true; } //friction command================= if ( !command .substring(0, 8) .toUpperCase() .localeCompare("FRICTION") ) { friction = command.substring(9); regexPass = true; } //velocity command================= if ( !command .substring(0, 6) .toUpperCase() .localeCompare("MAXVEL") ) { maxVel = command.substring(7); regexPass = true; } //splat command================= if ( !command .substring(0, 5) .toUpperCase() .localeCompare("SPLAT") ) { if ( !command .substring(6, 9) .toUpperCase() .localeCompare("MAX") ) { splatSizeMax = parseInt(command.substring(10), 10); } else if ( !command .substring(6, 9) .toUpperCase() .localeCompare("MIN") ) { splatSizeMin = parseInt(command.substring(10), 10); } else { if ( !command .substring(6) .toUpperCase() .localeCompare("TRUE") ) { splat = true; } else if ( !command .substring(6) .toUpperCase() .localeCompare("FALSE") ) { splat = false; splatX = []; splatY = []; splatColor = []; splatSize = []; splatFrames = []; } else if ( !command .substring(6, 11) .toUpperCase() .localeCompare("ALPHA") ) { splatAlpha = Number(command.substring(12)); } else { cmdArray[0] = "Splat: Syntax error"; cmdHistory = cmdArray.concat(cmdHistory); termOpen = true; } } regexPass = true; } //outline color command================= if ( !command .substring(0, 7) .toUpperCase() .localeCompare("OUTLINE") ) { if (!command.substring(8, 9).localeCompare("#")) { plrOutline = command.substring(9, 15).toUpperCase(); regexPass = true; } else { plrOutline = command.substring(8, 14).toUpperCase(); regexPass = true; } } //fill color command================= if ( !command.substring(0, 4).toUpperCase().localeCompare("FILL") ) { if (!command.substring(5, 6).localeCompare("#")) { plrFill = command.substring(6, 12).toUpperCase(); regexPass = true; } else { plrFill = command.substring(5, 11).toUpperCase(); regexPass = true; } } //size command================= if ( !command.substring(0, 4).toUpperCase().localeCompare("SIZE") ) { plrSize = command.substring(5); regexPass = true; } //help command================= if ( !command.substring(0, 4).toUpperCase().localeCompare("HELP") ) { showHelp(command.substring()); termOpen = true; regexPass = true; } //regex checker================= if (command == "" || command.substring(0, 2) == "//") { regexPass = true; } //regex fail handler================= if (!regexPass) { cmdArray[0] = "Command not recognized"; termString = ""; cmdHistory = cmdArray.concat(cmdHistory); termOpen = true; } //reset historyIndex historyIndex = 0; } } document.onkeydown = doTyping; } } function doPlayerPhys() { //change x velocity if (inputDir[0] != 0) { //increase velocity playerPos[2] = playerPos[2] + (inputDir[0] / 10) * accel; } else { //decrease velocity playerPos[2] = playerPos[2] * (1 - 0.005 * friction); } //change y velocity if (inputDir[1] != 0) { //increase velocity playerPos[3] = playerPos[3] + (inputDir[1] / 10) * accel; } else { //decrease velocity playerPos[3] = playerPos[3] * (1 - 0.005 * friction); } //clamp velocity playerPos[2] = playerPos[2].clamp(maxVel * -1, maxVel); playerPos[3] = playerPos[3].clamp(maxVel * -1, maxVel); //bounce check if (playerPos[0] > width / 2 - plrSize / 2) { playerPos[2] = Math.abs(playerPos[2]) * -1; doSplat(); if (colorChangeOnBounce) { plrFill = getRandomColor(); } } else if (playerPos[0] < width / -2 + plrSize / 2) { playerPos[2] = Math.abs(playerPos[2]); doSplat(); if (colorChangeOnBounce) { plrFill = getRandomColor(); } } if (playerPos[1] > height / 2 - plrSize / 2) { playerPos[3] = Math.abs(playerPos[3]) * -1; doSplat(); if (colorChangeOnBounce) { plrFill = getRandomColor(); } } else if (playerPos[1] < height / -2 + plrSize / 2) { playerPos[3] = Math.abs(playerPos[3]); doSplat(); if (colorChangeOnBounce) { plrFill = getRandomColor(); } } //apply motion playerPos[0] = playerPos[0] + playerPos[2]; playerPos[1] = playerPos[1] + playerPos[3]; } //adds function examplevar.clamp(min, max) Number.prototype.clamp = function (min, max) { return Math.min(Math.max(this, min), max); }; function showHelp(cmd) { var cmdArray = []; if (!cmd.substring(5).toUpperCase().localeCompare("SPLAT")) { cmdArray[0] = "// SPLAT HELP:"; cmdArray[1] = "// splat (true/false) -- Enable or disable splatting"; cmdArray[2] = "// splat max (#) -- Change max splat size (default: 250)"; cmdArray[3] = "// splat min (#) -- Change min splat size (default: 100)"; cmdArray[4] = "// splat alpha (#) -- Set splat alpha from 0-1 (default: 0.4)"; cmdHistory = cmdArray.concat(cmdHistory); cmdArray = []; } else { cmdArray[0] = "// COMMAND HELP:"; cmdArray[1] = "// help -- Show these lines"; cmdArray[2] = "// size (px) -- Change ball size (default: 10)"; cmdArray[3] = "// fill (hex) -- Change ball fill color"; cmdArray[4] = "// outline (hex) -- Change ball outline color"; cmdArray[5] = "// splat (true/false) -- Do 'help splat' for more info"; cmdArray[6] = "// CConB (true/false) -- Enable or disable fill color change on bounce"; cmdArray[7] = "// maxvel (#) -- Set max velocity (default: 100)"; cmdArray[8] = "// accel (#) -- Set acceleration speed (default: 1)"; cmdArray[9] = "// friction (#) -- Set speed at which ball slows (default: 1)"; cmdArray[10] = "// echo (cmd) -- Check the value of a command"; cmdArray[11] = "// (up arrow, down arrow) -- Cycle through command history"; cmdArray[12] = "// clear -- Clear command history"; cmdArray[13] = "// (ctrl + c) -- Clear current command line input"; cmdHistory = cmdArray.concat(cmdHistory); cmdArray = []; } } function doSplat() { splatX.push(playerPos[0]); splatY.push(playerPos[1]); splatColor.push(plrFill); var randSize = (splatSizeMax - splatSizeMin) * Math.random(); splatSize.push(randSize + splatSizeMin); splatFrames.push(framesElapsed); } function splatGrow(i) { if (framesElapsed - splatFrames[i] <= 180) { var x = (framesElapsed - splatFrames[i]) / 60; return ( splatSize[i] - Math.abs((splatSize[i] / 2) * -(Math.pow(10, -x) + 1)) ); } else { return splatSize[i] / 2; } } function getRandomColor() { var letters = "0123456789ABCDEF"; var color = ""; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } function convertHexToRgbA(val, alpha) { var hexVal = "#" + val; let ret; // If the hex value is valid. if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hexVal)) { // Getting the content after '#', // eg. 'ffffff' in case of '#ffffff' ret = hexVal.slice(1); // Splitting each character ret = ret.split(""); // Checking if the length is 3 // then make that 6 if (ret.length == 3) { let ar = []; ar.push(ret[0]); ar.push(ret[0]); ar.push(ret[1]); ar.push(ret[1]); ar.push(ret[2]); ar.push(ret[2]); ret = ar; } // Starts with '0x'(in hexadecimal) ret = "0x" + ret.join(""); // Converting the first 2 characters // from hexadecimal to r value let r = (ret >> 16) & 255; // Converting the second 2 characters // to hexadecimal to g value let g = (ret >> 8) & 255; // Converting the last 2 characters // to hexadecimal to b value let b = ret & 255; // Appending all of them to make // the RGBA value return "rgba(" + [r, g, b].join(",") + "," + alpha + ")"; } } //Loop------------------------------------------------------------------------------------------------------ setInterval(function () { framesElapsed++; checkKeys(); if (!termOpen) { doPlayerPhys(); } draw(); }, 1000 / FPS);