diff --git a/README.md b/README.md index 3945c152..96eb9e48 100755 --- a/README.md +++ b/README.md @@ -1,93 +1,21 @@ -Assignment 2 - Short Stack: Basic Two-tier Web Application using HTML/CSS/JS and Node.js -=== +## AccuMouse - The Mouse Accuracy Game +# By Truman Larson +https://a2-trumanlarson.glitch.me/ +AccuMouse is a mouse accuracy game that seeks to improve the user's clicking accuracy. A leaderboard is provided so the best of the best can rise to the top. To play, all you need to do is press the start button and start clicking as many circles as you can! Note: sometimes it may feel like the circles are broken and don't actually get click, but I assure you they are not broken! -Due: September 16th, by 11:59 PM. - -This assignment aims to introduce you to the concepts and practice involved in creating a prototype (i.e. not deployment ready) two-tiered web application. The baseline aims of this assignment involve creating an application that demonstrates the use of several specific pieces of HTML, CSS, JavaScript, and Node.js functionality. - -Baseline Requirements ---- - -Note that there is a very large range of application areas and possibilities that meet these baseline requirements. Make your application do something useful! A todo list, storing / retrieving high scores for a very simple game, have a little fun with it. - -Your application is required to implement the following functionalities: - -- a `Server` which not only serves files, but also maintains a tabular dataset with 3 or more fields related to your application -- a `Results` functionality which shows the entire dataset residing in the server's memory -- a `Form/Entry` functionality which allows a user to add, modify, or delete data items residing in the server's memory -- a `Server Logic` which, upon receiving new or modified "incoming" data, includes and uses a function that adds at least one additional derived field to this incoming data before integrating it with the existing dataset -- the `Derived field` for a new row of data must be computed based on fields already existing in the row. For example, a `todo` dataset with `task`, `priority`, and `creation_date` may generate a new field `deadline` by looking at `creation_date` and `priority` - -Your application is required to demonstrate the use of the following concepts: - -HTML: -- One or more [HTML Forms](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms), with any combination of form tags appropriate for the user input portion of the application -- A results page displaying all data currently available on the server. You will most likely use a `` tag for this, but `
+ + + + + + + + + + + + +
RankNameScoreDateGame LengthScore per Second
- + diff --git a/public/js/scripts.js b/public/js/scripts.js index de052eae..82ce50b0 100755 --- a/public/js/scripts.js +++ b/public/js/scripts.js @@ -1,3 +1,286 @@ // Add some Javascript code here, to run on the front end. -console.log("Welcome to assignment 2!") \ No newline at end of file +console.log("Welcome to assignment 2!") + +let gw = document.getElementById("gameWindow"), + gwStyle = window.getComputedStyle(gw); + + +let gameState = { + metaData : { + width : document.querySelector("#gameWindow").clientWidth, + height : document.querySelector("#gameWindow").clientHeight, + score : 0, + maxID : 2, + startTimeMillis : -1, + endTimeMillis : -1, + }, + isRunning : true, + entities : [ + { id : "0", x : 50, y : 50, dx : 1, dy : -1, life : 3 , element : null}, + { id : "1", x : 100, y : 100, dx : -1, dy : 1, life : 3 , element : null}, + ], + ticks : 0, + +} + + +const submit = function( e ) { + // prevent default form action from being carried out + e.preventDefault(); + + const input = document.querySelector( '#yourname' ), + json = { yourname: input.value, FinalScore : gameState.metaData.score, + date : (new Date()).toJSON(), + gameLength : gameState.metaData.endTimeMillis - gameState.metaData.startTimeMillis}, + body = JSON.stringify( json ); + + fetch( '/submit', { + method:'POST', + body + }) + .then( async function( response ) { + let appdata = await response.json() + displayLeaderboard(appdata) + console.log( appdata ); + }); + + return false; + } + + + + + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +const playGame = async function ( ) { + score = 0; + gameState.metaData.startTimeMillis = (new Date()).getTime(); + console.log(gameState); + while (stillRunning(gameState)){ + gameState = stepGame(gameState); + updateDisplay(gameState); + + await sleep(9); + } + document.getElementById("score").innerHTML = "TIMES UP!!! Final Score = "+ gameState.metaData.score; + gameState.metaData.endTimeMillis = (new Date()).getTime(); + +} + + +function stillRunning(gs){ + if (gs.ticks > 1000){ + gs.isRunning = false; + } + // TODO stop the game based on a time limit as opposed to tick limit + return gs.isRunning; +} + +function stepGame(gs){ + gs.ticks++; + + + // step all entity movement + for (i=0; i= gs.metaData.width - 50 || e.x + e.dx <= 0) { // check X collisions + e.dx = -increaseSpeed(e.dx, 2); + e.life--; + } + else if (e.y + e.dy >= gs.metaData.height - 50 || e.y + e.dy <= 0) { // check Y collisions + e.dy = -increaseSpeed(e.dy, 2); + e.life--; + } + + // move the shapes + e.x += e.dx; + e.y += e.dy; + } + + // TODO functionality of adding circles + + if ((gs.ticks % 200) === 0){ + spawnNewCircle(randNum(gameState.metaData.width - 100, 50), randNum(gameState.metaData.height - 100, 50), randPosOrNeg(), randPosOrNeg(), gameState); + } + + + return gs; +} + +function randNum(range, min){ + return Math.floor(Math.random() * range) + min; +} + +function randPosOrNeg(){ + let r = Math.floor(Math.random() * 2) // 0 or 1 + + let out = -1; + if (r === 1){ + out = 1; + } + + return out; +} + +function spawnNewCircle(_x, _y, _dx, _dy, gs){ + // give circle correct id and proper fields and increment max id + let newC = { id : (++gs.metaData.maxID)+"", x : _x, y : _y, dx : _dx, dy : _dy, life : 3 , element : null}; + + //console.log(newC); + // add circle to entities + gs.entities.push(newC); + + +} + + +function increaseSpeed(velocity, mag){ + if (velocity <= 0) { + return velocity-mag; + } + else return velocity+mag; +} + +function updateDisplay(gs){ + let gw = document.getElementById("gameWindow"); + + for (i=0; i=0; j--){ + let key = Object.keys(appdata[i])[j]; + nCell = nRow.insertCell(0); + row = appdata[i][key] + let nText = document.createTextNode(row); + nCell.appendChild(nText); + } + + + nCell = nRow.insertCell(0); + row = (i+1) + let nText = document.createTextNode(row); + nCell.appendChild(nText); + + } + + + console.log(row); + +} + + + + window.onload = function() { + const button = document.querySelector( '#form' ); + button.onclick = submit; + score = 0; + + pullLeaderboard(); + } + + function load(){ + const button = document.querySelector( '#form' ); + button.onclick = submit; + score = 0; + + pullLeaderboard(); + } \ No newline at end of file diff --git a/server.improved.js b/server.improved.js index 26673fc0..974b064c 100644 --- a/server.improved.js +++ b/server.improved.js @@ -7,9 +7,7 @@ const http = require( 'http' ), port = 3000 const appdata = [ - { 'model': 'toyota', 'year': 1999, 'mpg': 23 }, - { 'model': 'honda', 'year': 2004, 'mpg': 30 }, - { 'model': 'ford', 'year': 1987, 'mpg': 14} + ] const server = http.createServer( function( request,response ) { @@ -25,6 +23,8 @@ const handleGet = function( request, response ) { if( request.url === '/' ) { sendFile( response, 'public/index.html' ) + }else if ( request.url === '/db'){ + sendAppdata( response ) }else{ sendFile( response, filename ) } @@ -38,13 +38,39 @@ const handlePost = function( request, response ) { }) request.on( 'end', function() { - console.log( JSON.parse( dataString ) ) + let jsonData = JSON.parse(dataString) + jsonData.scorePerSecond = ((jsonData.FinalScore) / (jsonData.gameLength/1000)).toPrecision(4) // ... do something with the data here!!! + appdata.push(jsonData) + console.log( appdata ) + + sendAppdata( response ) + }) +} - response.writeHead( 200, "OK", {'Content-Type': 'text/plain' }) - response.end() +function sortAppdata() { // sorts the app data by the highest score + appdata.sort(function(a, b){ + console.log(a); + if (parseFloat(a['FinalScore'])parseFloat(b['FinalScore'])){ + return -1; + } + + return 0; }) + + +} + + +const sendAppdata = function(response) { + + sortAppdata(); + response.writeHead( 200, "Ok", {'Content-Type': 'application/json' }) + response.end(JSON.stringify(appdata, null, 3)) } const sendFile = function( response, filename ) {