Tumgik
leo173-blog · 5 years
Text
Final Project Documentation
Final Project Documentation
This is a write up for my final project, a multiplayer shooting game called 'Space'. It is a rework and touch of my previous project. I added better graphics to my game and added a settings menu, where players can change their name and color. The most significant change is the server-client relationship. Before, my system was a hybrid, as my server handled synchronization and the clients handled collision and movement. Now, it's primarily server-sided. Collision handling and synchronization is being handled by the server while the play can only control movement.
Server Code
const express = require('express') const routes = require('routes') const app = express() var server = app.listen(8080) var io = require('socket.io')(server); const canvas_size = 1500; const port = 3000 var players = {} var bullets = {} var shadows = {}
I first imported libraries that are necessary to work with websockets and servers. I also included global variables that will contain player information and basic server/game information. The server will listen on port 8080 for any websocket packets.
io.on('connection', function(socket) {  socket.on('player_new', function(data) {    let player_id = data['id'];    players[player_id] = data;  });  socket.on('sync', function() {    socket.emit('sync', {'players': players, 'bullets': bullets, 'shadows': shadows});  })  socket.on('player_move', function(data) {    let player_id = data['id']    players[player_id] = data;  })  socket.on('player_shoot', function(data) {    let player = players[data['id']]    let bid = data['bid']    let id = data['id'];    let direction = data['direction']    let offset = 35;    let x_offset = 0;    let y_offset = 0;    if (direction === 'up') {        y_offset -= offset;        x_offset += 0;    } else if (direction === 'down') {        y_offset += offset;        x_offset += 0;    } else if (direction === 'left') {        x_offset -= offset;        y_offset += 0;    } else {        x_offset += offset;        y_offset += 0;    }    bullets[bid] = {'x': player['x'] + x_offset, 'y': player['y'] + y_offset, 'direction': direction, 'bid': bid, 'color': data['color'], 'id': id}  })  socket.on('player_color_change', function(data) {    let player_id = data['id']    players[player_id]['color'] = data['color']    console.log('changing colors')  })  socket.on('disconnect', function(data) {    console.log('player has disconnected')  }); });
Next, I created functions that react to websocket events. When somebody loads the webpage, it calls the main function and find which function to call next. Based on the event name, the server either creates a new player, syncs the data, etc.
The first function handles player creation. It adds the player's information to the players data structure. The sync function packages the global variables of the server and sends it to the client. The next function updates the player's information if they made any movement. The shooting function is a more complicated function because it handles the bullets. Based off of the direction the player is going, the bullet will travel that same direction. This can be seen in the four conditional statements. The x and y coordinates of the bullet will depend on the direction. For example, if the player is going up, the x coordinate of the bullet will stay the same, but the y coordinate will be increased so that it appears above the player. This is done by adding an offset to the specified coordinate. The bullet is now packaged into a dictionary and added the bullets data structure. The second to last function handles player color change. It updates the player's color to the players data structure. The disconnect function currently does nothing, which is intended. Disconnected players should still exist in the game, so if somebody kills them, then the player will die and the scores will be updated.
function collideCircleCircle(p1x, p1y, r1, p2x, p2y, r2) {  let a;  let x;  let y;  a = r1 + r2;  x = p1x - p2x;  y = p1y - p2y;  if (a > Math.sqrt((x * x) + (y * y))) {    return true;  } else {    return false;  } }
This function returns whether two circles have collided.
function tick() {  for (let key in bullets) {    let offset = 5;    let bullet = bullets[key];    let direction = bullet['direction'];    if (direction === 'up') {        bullet['y'] -= offset;    } else if (direction === 'down') {        bullet['y'] += offset;    } else if (direction === 'left') {        bullet['x'] -= offset;    } else {        bullet['x'] += offset;    }    if (bullet['x'] > canvas_size || bullet['x'] < 0) {        delete bullets[key]    }    if (bullet['y'] > canvas_size || bullet['y'] < 0) {        delete bullets[key]    }    for (let p_key in players) {      let player = players[p_key]      let player_x = player['x']      let player_y = player['y']      let killer_score = players[bullet['id']]['score']      let x = bullet['x']      let y = bullet['y']      let hit = collideCircleCircle(x, y, 15, player_x, player_y, 15);      if (hit && bullet['id'] != p_key) {        player['health'] -= 20        delete bullets[key]        if (player['health'] <= 0) {          player['alive'] = false          players[bullet['id']]['score'] += 10          shadows[Math.round(Math.random() * 10000)] = {'x': player_x,                            'y': player_y, 'r1': 15 + (killer_score / 10) * 2,                            'r2': 35 + (killer_score / 10) * 2,                            'rgb': player['rgb'],                            'duration': 2000                          }          io.sockets.emit('player_death', player)          delete players[p_key]        }      }    }  }  for (let key in shadows) {    let shadow = shadows[key]    shadow['duration'] -= 1    shadow['rgb'] = [shadow['rgb'][0] + 0.2, shadow['rgb'][1] + 0.2, shadow['rgb'][2] + 0.2]    if (shadow['duration'] <= 0) {      delete shadows[key]    }  }  io.sockets.emit('sync', {'players': players, 'bullets': bullets, 'shadows': shadows}) }
The tick function is a complicated function because it handles what happens to the data at every tick. First of all, it updates each bullet that was created. Depending on the direction it was shot in, the x or y coordinate will be updated so that it travels in that direction. It also checks if any bullet is outside the canvas because those bullets will become 'lost' and just use up precious memory. After that, I handled player an bullet collision. Using the function I created earlier, I check if any players have collided with any bullets. If so, the player's health is reduced and if the player's health is below 0, the player is killed. Dead players will leave behind a star. Stars are also updated every tick. Its color will slowly increase until it become white and it eventually dies after the its duration reaches 0.
setInterval(function() {  try {    tick()  } catch(err) {    console.log(err)  } }, 10); app.use('/maze/', express.static('maze'))
The last part of this code causes the tick function to run every 10 ms. This creates a smooth experience for players because the data will be rapidly updating. The last line is to serve the client side code, which I will explain now.
Client Code
const speed = 5; const player_size = 50; const canvas_w = 1200; const canvas_h = 800; const naturalKeyNames = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; const ip = 'localhost'; var socket = io.connect(ip + ':8080'); var words; var bg, start, button, red, green, blue, menu, canvas; // Player Info var player_name, player_id, player_id, player_rgb, player_x, player_y, player_info; var player_score = 0; var player_health = 100; var player_direction = 'up'; var player_alive = true; var in_game = false; var players = {}; var bullets = {}; var shadows = []; var sounds = [];
I first created global variables to store player information and basic game information. The constants hold canvas information and sound file names. The last block of variables will contain information sent from the server.
function preload() {    bg = loadImage('assets/bg3.jpg')    start = loadImage('assets/start.png')    words = loadJSON('assets/words.json')    for (let i = 0; i < naturalKeyNames.length; i++) {      sounds.push(loadSound(String('assets/reg-' + naturalKeyNames[i] + '.mp3')));    } }
I first preloaded game assets, which includes the background image, the center lobby image, a list of random nouns, and piano sounds. The words will form random names for players and the sounds will play if the player dies.
function setup() {  canvas = createCanvas(canvas_w, canvas_h);  let menu = select('.drop')  let dropdown = select('.dropdown')  let input_name = select('#name_i')  let input_red = select('#red_i')  let input_green = select('#green_i')  let input_blue = select('#blue_i')  let sub_name = select('#name_s')  let sub_color = select('#color_s')  menu.mouseOver(function() { dropdown.show(300) })  menu.mouseOut(function() { dropdown.hide(300) })  sub_name.mousePressed(function() { player_name = input_name.value() })  sub_color.mousePressed(function() {    player_rgb = [clean_color_input(input_red.value()),                  clean_color_input(input_green.value()),                  clean_color_input(input_blue.value())                 ]  })  lobby()  socket.on('sync', sync)  socket.on('player_score', increment_score)  socket.on('player_death', death) } function lobby() {  player_id = Math.round(random(100000));  player_x = 50 + random(canvas_w - 50);  player_y = 35 + random(canvas_h/2 - 175);  let r = random(255);  let g = random(255);  let b = random(255);  player_name = words.words[Math.floor(Math.random()*words.words.length)] + ' ' + words.words[Math.floor(Math.random()*words.words.length)];  player_rgb = [r, g, b];  draw_player(player_name, player_x, player_y, player_rgb, player_health)  console.log(player_name) } function draw_player(name, x, y, rgb, health) {      fill('white');      text(name, x - (25 + name.length), y - 30);      fill(rgb);      ellipse(x, y, player_size, player_size);      fill('white')      text(String(health), x - 9, y + 4) } function clean_color_input(color) {  color = parseInt(color);  if (isNaN(color)) {    return random(255);  }  return color; } function changeColor() {    if (player_alive) {        player_rgb = [red.value(), green.value(), blue.value()]        socket.emit('player_color_change', {'color': player_rgb, 'id': player_id})    } }
The setup function creates the canvas with the specified global dimensions. It also creates the settings menu for players and defines functions that allows the player to change their name or color. There are helper functions that clean the color input, if the player enters invalid values and sends it to the server. As an important note, there should be one for name too, but I forgot to include it. The lobby function creates the player at a random location that is not in the middle, and gives a random name. The draw_player function draws the player on the canvas, with their color, health, and name.
function check_player_movement() {    if (keyIsDown(UP_ARROW) && player_y >= 0) {        move(-speed, 0, 'up')    }    if (keyIsDown(DOWN_ARROW) && player_y <= canvas_h) {        move(speed, 0, 'down')    }    if (keyIsDown(RIGHT_ARROW) && player_x <= canvas_w) {        move(0, speed, 'right')    }    if (keyIsDown(LEFT_ARROW) && player_x >= 0) {        move(0, -speed, 'left')    } } function move(v, h, d) {    player_direction = d    player_x += h    player_y += v    package_player()    if (player_alive) {      socket.emit('player_move', player_info)    } } function keyPressed() {  if (keyCode === 32 && player_alive && in_game) {      shoot()  } } function shoot() {    console.log('shoot')    socket.emit('player_shoot', {'direction': player_direction, 'id': player_id, 'bid': Math.round(random(1000)), 'color': player_rgb}) } function package_player() {  player_info = {'id': player_id,                   'x': player_x,                   'y': player_y,                   'name': player_name,                   'rgb': player_rgb,                   'score': player_score,                   'health': player_health,                   'alive': player_alive,                  } } function update_player() {  if (player_info != undefined) {    player_name = player_info['name']    player_rgb = player_info['rgb']    player_score = player_info['score']    player_health = player_info['health']    player_alive = player_info['alive']  } } function check_start() {  let start_x_left = canvas_w/2 - 50  let start_x_right = canvas_w/2 + 50  let start_y_top = canvas_h/2 - 50  let start_y_bottom = canvas_h/2 + 50  if (player_x >= start_x_left &&      player_x <= start_x_right &&      player_y <= start_y_bottom &&      player_y >= start_y_top) {    player_alive = true;    in_game = true;    player_health = 100;    player_score = 0;    package_player()    socket.emit('player_new', player_info)    socket.emit('sync')  } }
This next block of code performs basic checking and server packaging. The first function checks if the player has pressed any arrow keys. It also checks if the player is inbounds, so they won't disappear from the screen. Also, if the player presses the space button, they will shoot a bullet. Any successful movements will be passed down to the next function, where it updates the player's x and y coordinates and sends it to the server. Player data packaging is handled by the update_player function. It updates the global variable that holds the player's attributes. The last function checks if the player wants to enter the multiplayer game. If the player enters the middle circle, the packaged player information is sent to the server and requests a sync from the server.
function draw() {    background(bg)    if (!in_game) {      image(start, canvas_w/2 - 100, canvas_h/2 - 100, 200, 200)      check_player_movement()      check_start()    } else {      socket.emit('sync')      tick()    }    draw_player(player_name, player_x, player_y, player_rgb, player_health) } function tick() {  update_player()  if (!player_alive) {    text("YOU ARE DEAD", 500, 150, 100, 100)    in_game = false  }  if (player_alive) {    check_player_movement()  }  for (let key in players) {    let player = players[key]    let id = player['id']    if (id != player_id) {      let name = player['name']      let x = player['x']      let y = player['y']      let rgb = player['rgb']      let health = player['health']      draw_player(name, x, y, rgb, health)    }  }  for (let key in bullets) {    let bullet = bullets[key]    let x = bullet['x']    let y = bullet['y']    let color = bullet['color']    let id = bullet['id']    let bid = bullet['bid']    fill(color)    ellipse(x, y, 15, 15)  }  for (let key in shadows) {    let shadow = shadows[key]    let x = shadow['x']    let y = shadow['y']    let r1 = shadow['r1']    let r2 = shadow['r2']    fill(shadow['rgb'])    star(x, y, r1, r2, 5);  } }
The draw function draws on the canvas. If the user is still in the lobby, the game will keep on checking if the player has entered the the middle of the circle, using the previously defined functions. Also, there will be no server communication until the game has started. If the user is in game, it will sync the information from the server to the client. The player is always drawn so they can see where they are. The tick function is called from the draw function. It handles drawing all of the data that the server sends and checks for player movement. It first renders all of the other players in the game. Then it renders all bullets that were fired. Last of all, it renders the shadows or 'stars' of dead players.
function sync(data) {    players = data['players']    bullets = data['bullets']    shadows = data['shadows']    if (player_alive) {      player_info = players[player_id]    } } function star(x, y, radius1, radius2, npoints) {  var angle = TWO_PI / npoints;  var halfAngle = angle/2.0;  beginShape();  for (var a = 0; a < TWO_PI; a += angle) {    var sx = x + cos(a) * radius2;    var sy = y + sin(a) * radius2;    vertex(sx, sy);    sx = x + cos(a+halfAngle) * radius1;    sy = y + sin(a+halfAngle) * radius1;    vertex(sx, sy);  }  endShape(CLOSE); }
The sync function is the key method for client-server communication. When the client receives data from the server, it updates global variables that were created at the start. The client will use the data to draw and perform everything else. The last function just forms a star when it is called.
<!DOCTYPE html> <html>  <head>    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.dom.min.js"></script>    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/addons/p5.sound.min.js"></script>    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script>    <script src="assets/p5.collide2d.js"></script>    <link rel="stylesheet" type="text/css" href="style.css">    <meta charset="utf-8" />  </head>  <body>    <script src="sketch.js"></script>    <nav class="nav">      <ul>        <li>        <li class="drop"><a href="#">Settings</a>          <ul class="dropdown">            <li><a href="#">              <label for="inp" class="inp">                <input type="text" id="name_i" placeholder="Insert Name">                <button id="name_s"> Submit </button>                <span class="border"></span>              </label>            </a></li>            <li><a href="#">              <label for="inp" class="inp">                <input type="text" id="red_i" placeholder="Change Red">                <input type="text" id="green_i" placeholder="Change Green">                <input type="text" id="blue_i" placeholder="Change Blue">                <button id="color_s"> Submit </button>                <span class="border"></span>              </label>              </a></li>          </ul>        </li>      </ul>    </nav>  </body> </html>
This contains the html for everything. It contains the elements that holds the settings menu and libraries for p5.
@import url(https://fonts.googleapis.com/css?family=Montserrat:300&subset=latin-ext); body { -moz-osx-font-smoothing:grayscale; -ms-flex-direction:column; -webkit-box-direction:normal; -webkit-box-orient:vertical; -webkit-font-smoothing:antialiased; background:#f5f5f5; color:#777; display:flex; flex-direction:column; font-family:Montserrat, sans-serif; font-size: 1em; font-weight:300; margin:0; min-height:100vh; padding:0%; overflow: hidden; } h1 {    font-weight: 200;    font-size: 2.2rem;    color: #222;    text-align: center; } nav {    margin: 0 auto;    max-width: 800px;    background: #008FEA;    box-shadow:0 3px 15px rgba(0,0,0,.15);    position: fixed;    right: 100px; } nav::after {    display: block;    content: '';    clear: both; } nav ul {    padding: 0;    margin: 0;    list-style: none; } nav ul li {    float: left;    position: relative; } nav ul li a {    display: block;    color: rgba(255, 255, 255, .9);    text-decoration: none;    padding: 1rem 2rem;    border-top: 2px solid transparent;    border-bottom: 2px solid transparent;    transition: all .3s ease-in-out; } nav ul li a:hover, nav ul li a:focus {    background: rgba(0, 0, 0, .15); } nav ul li a:focus {    color: white; } nav ul li a:not(:only-child)::after {    padding-left: 4px;    content: ' ▾'; } nav ul li ul li {    min-width: 190px; } nav ul li ul li a {    background: transparent;    color: #555;    border-bottom: 1px solid #DDE0E7; } nav ul li ul li a:hover, nav ul li ul li a:focus {    background: #eee;    color: #111; } .dropdown {    display: none;    position: absolute;    background: #fff;    box-shadow: 0 4px 10px rgba(10, 20, 30, .4); } footer { color: #555; font-size:12px; margin-top:5em; text-align:center; } footer a { color:#008FEA; text-decoration:none; }
This is the CSS for the html. It basically updates the graphical properties of specific elements.
As a final note, this documentation code is a cleaned version of my Github code. My code on Github might contain old functions and other lines of code that are no longer useful. The webserver is hosted on Digitalocean. I am using Nginx as the primary web framework and pm2 to create a process to host the server code. The client code is delivered with Nginx.
1 note · View note
leo173-blog · 5 years
Text
Art 173 Final Code
https://github.com/le-sun/art173-final/tree/master/game
http://178.128.70.190
0 notes
leo173-blog · 6 years
Text
Midterm Documentation
Introduction
This write up is for my midterm project. The goal of this project was to create interactive art using an "air piano" and computers.
"Air piano" is similar to an "air guitar", in the sense that users will be playing keys in the air to create sound. This is established by using a Pi and a laser range finder (LRF). The LRF can determine the distance from the source to the object, which act as the range for determining which key is pressed. For example, if the set maximum range is 1000, and there are 10 keys, a measured distance of 50 will result in the first key being "pressed". This is because the bins range from 0 to 1000, in intervals of 100. Each bin corresponds to a key. The distance will fall in one of the bins, which can then activate the key.
The second part is audience interactivity. Since only one person can use the LRF, it is difficult for the whole audience to participate. This can be fixed by allowing participants to use their personal computers to interact with the piece. A webserver is used to show the pressed keys, and allows others to use their keyboards and also create music. Their keystrokes are shared among all users, so everybody can create sound together.
The rest of the this writeup will discuss how I setup all of the components. Any mistakes that I have made will be explained at the end.
Components
Raspberry Pi
Electronics Starter Kit
Parallax Laser Range Finder
Private Webserver
Setting up the Webserver
The first step is purchasing private server. This is necessary because interactivity can be established by allowing all clients to interact with a central host, which is my webserver.
I personally bought the cheapest droplet because this project does not need a lot of computing power. I selected Ubuntu with NodeJS as the system image, so that less setup is required. Then, I selected the SF location server because it is the closest one to me, which will result in lower latency.
Next, I had to login to my private server.
There were a few of methods I used to login. I used ssh, the online console. Both methods are nearly identical, but I prefer using ssh. I also used PuTTY on my Windows machine to ssh in. On my Macbook, I used console/terminal to ssh.
I entered the following commands to setup the extreme basics of Nginx (webserver). Pm2 is an easy to use process manager, which will be useful for forking processes.
sudo apt update sudo apt install nginx sudo ufw allow 'Nginx HTTP' sudo npm install pm2 -g
After that, I organized my webserver because organization is always very important!
cd /var/www/html mkdir public
This will create a new folder called public, where I stored client sided files. That means that vistors will be shown the files inside public.
Now, I modified the configuration of Nginx so that it knows what to display.
nano /etc/nginx/sites-available/default
I changed the line containg root /var/www/html; to root /var/www/html/public;. This basically changes which directory is the root or public directory of the website. Anything in the public directory can be displayed or found by visitors.
Setting up the Server
As a side note, this whole section is a mistake that I will explain at the end of this write up. After navigating to /var/www/html, I created a new file called server.js and installed some necessary libraries.
cd /var/www/html npm install express npm install socket.io nano server.js
I'm using Express to create the server because it requires very little setup. The following code block will load in the necessary libraries and initialze Express.
const http = require('http'); const express = require('express'); var app = express();
The following block initializes the server on localhost port 8080. Any connections to that port will establish a connection between the client and server. It includes a callback function that includes callbacks whenever data is transmitted from the client to server and when the client disconnects. When it recieves a signal post, it broadcasts the casted data to everybody that is connected. The client will handle the incoming data.
var server = app.listen(8080); var io = require('socket.io')(server); io.sockets.on('connection', function (socket) { console.log("We have a new client: " + socket.id); socket.on('post', function(data) { io.sockets.emit('post', parseInt(data)); } ); socket.on('disconnect', function() { console.log("Client has disconnected"); }); } );
This next block basically creates another server on port 3000 that handle POST requests.
var restServer = http.createServer((req, res) => { if (req.method === 'POST') { var body = ''; req.on('data', function (data) { body += data; }); req.on('end', function () { io.sockets.emit('post', parseInt(body)); }); res.writeHead(200, {'Content-Type': 'text/html'}); res.end('POST received'); } else { response.end('Not POST'); } }); restServer.listen(3000);
I saved the file and started it as a background process using pm2.
pm2 start server.js
This will start server.js as a process in the background, so it will be able to listen on ports 8080 and 3000.
Setting up the Client
I created a new folder in /var/www/html/public called assets to store my piano sounds. Next, I made a new file called sketch.js, which holds the client code.
const naturalKeyNames = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; // Keep track of our socket1 connection var socket1; var keys = {1: keyA, 2: keyB, 3: keyC, 4: keyD, 5: keyE, 6: keyF, 7: keyG}; var sounds = []; //5x3 letters var currentRow = 0; var currentColumn = 0; var w; var columns; var rows; var board; var next; function preload() { for (let i = 0; i < naturalKeyNames.length; i++) { sounds.push(loadSound(String('assets/reg-' + naturalKeyNames[i] + '.mp3'))); } console.log(sounds) } function setup() { createCanvas(1872, 1024); frameRate(30); w = 20; // Calculate columns and rows columns = floor(width/w); rows = floor(height/w); // Wacky way to make a 2D array is JS board = new Array(columns); for (var i = 0; i < columns; i++) { board[i] = new Array(rows); } // Going to use multiple 2D arrays and swap them next = new Array(columns); for (i = 0; i < columns; i++) { next[i] = new Array(rows); } socket1 = io.connect('http://178.128.70.190:8080'); socket1.on('post', function(data) { console.log(currentColumn, currentRow); keys[data](currentColumn, currentRow, 255); currentColumn += 4; if (currentColumn + 3 > columns) { currentRow += 6; currentColumn = 0; } if (currentRow + 5 > rows) { currentRow = 0; currentColumn = 0; } sounds[data - 1].play(); } ); console.log(columns, rows); }
This block of code splits the canvas into blocks, depending on the set width and height and connects to the websocket. It also contains a function that handles socket packets. Whenever the server sends a packet with a key 'post', this function will run. It basically sets the row and column of where the next letter will be placed and also plays the corresponding sound.
The next block of code allows limited keyboard input.
function keyPressed() { if (key <= '7' && key !== '0') { socket1.emit('post', key); } }
Basically, whenever a key number key from 0 to 7 is pressed, it sends a packet to the server with the key number as its data. The server will transmit the data recieved from the client to all clients, so everybody else can see what is played.
This next part contains functions that draw the letters. Based on the current row and column, it sets the block the color white. The getValue function is not needed, but was there because of an idea that I wanted but decided it would not be in the final version. There are also functions between keyA and keyG, but most of the code is the same, and to save space, I'm not including it here.
function draw() { background(255); for ( var i = 0; i < columns;i++) { for ( var j = 0; j < rows;j++) { if (!isNaN(board[i][j])) { board[i][j] -= 1.5; fill(board[i][j]); } else { fill(0); } stroke(0); rect(i*w, j*w, w-1, w-1); } } } function getValue(mode) { if (mode === true) { return floor(random(2)); } return mode; } // TODO: Modularize this function keyA(x=0, y=0, value=false) { board[0 + x][0 + y] = getValue(value); board[0 + x][1 + y] = getValue(value); board[0 + x][2 + y] = getValue(value); board[0 + x][3 + y] = getValue(value); board[0 + x][4 + y] = getValue(value); board[2 + x][0 + y] = getValue(value); board[2 + x][1 + y] = getValue(value); board[2 + x][2 + y] = getValue(value); board[2 + x][3 + y] = getValue(value); board[2 + x][4 + y] = getValue(value); board[1 + x][0 + y] = getValue(value); board[1 + x][2 + y] = getValue(value); } ... function keyG(x=0, y=0, value=false) { board[0 + x][0 + y] = getValue(value); board[0 + x][1 + y] = getValue(value); board[0 + x][2 + y] = getValue(value); board[0 + x][3 + y] = getValue(value); board[0 + x][4 + y] = getValue(value); board[1 + x][0 + y] = getValue(value); board[1 + x][2 + y] = getValue(value); board[1 + x][4 + y] = getValue(value); board[2 + x][0 + y] = getValue(value); board[2 + x][2 + y] = getValue(value); board[2 + x][3 + y] = getValue(value); board[2 + x][4 + y] = getValue(value); }
After coding all of that, I ran sudo systemctl restart nginx to restart the webserver. Going to my website now loads the sketch.
The Raspberry Pi and LRF
This section will be completed in the following days.
Mistakes
So, the main mistake is that this whole project is not the correct way to setup a webserver. Due to a lack of sleep, I misunderstood some documentation, which confused my view on a webserver.
The fix for this mistake is to just use ExpressJS for the whole thing. The whole public file system and pm2 is not necessary because Express can serve static files. Instead of having pm2 host server.js in the background, and Nginx serving index.html, sketch.js, and assets/, Nginx can just serve one javascript file that contains code that uses Express to deliver sketch.js and handle websockets.
The code might something like this:
var express = require('express') , routes = require('./routes') , http = require('http'); var app = express(); var server = app.listen(3000); var io = require('socket.io').listen(server); // this tells socket.io to use our express server app.configure(function(){ app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.static(__dirname + '/public')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); }); app.configure('development', function(){ app.use(express.errorHandler()); }); app.get('/', routes.index);
This allows Express to handle everything. When going to the default webaddress, the public files will be served. It also starts a websocket, so clients can connect.
A short summary is that I basically complicated my delivery of files by using pm2 with Nginx, while the whole server can be hosted just using Nginx. In other words, I was using pm2 to host the server and Nginx to deliver the client. In reality, Nginx should have hosted the server and client using Express.
0 notes
leo173-blog · 6 years
Link
0 notes
leo173-blog · 6 years
Text
Code Haiku
JS not Java
JSON is never PSON
JS not Python
0 notes
leo173-blog · 6 years
Link
youtube
youtube
Sounds from throat singing is incredible!
0 notes
leo173-blog · 6 years
Link
Banksy’s painting becoming somewhat of a meme.
0 notes
leo173-blog · 6 years
Link
Interesting video that deals with the sounds of the English language.
0 notes
leo173-blog · 6 years
Link
0 notes
leo173-blog · 6 years
Link
Trump singing parodies 
0 notes
leo173-blog · 6 years
Link
This reminded me of what we discussed in class.
0 notes
leo173-blog · 6 years
Link
“Background sounds” of Never Gonna Give You Up
0 notes
leo173-blog · 6 years
Link
0 notes
leo173-blog · 6 years
Text
https://le-sun.github.io/art173-proj-1/
src: https://github.com/le-sun/art173-proj-1
0 notes
leo173-blog · 6 years
Text
https://editor.p5js.org/le-sun/sketches/S1XLutHOQ
0 notes
leo173-blog · 6 years
Text
Test
Hello world
0 notes