Archived
4
1
Fork 0

Inital commit

This commit is contained in:
Simon Giesel 2018-04-24 20:56:07 +02:00
commit 74e6a11bce
18 changed files with 5044 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

2
TODO.md Normal file
View file

@ -0,0 +1,2 @@
* Fix collision while in air
* Fix jumping while in air (disallow)

BIN
assets/block_dirt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/block_dirt_x4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
assets/block_grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/block_grass_x4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
assets/char_luigi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/char_luigi_x4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
assets/char_mario.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/char_mario_x4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
assets/luigi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
assets/mario.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 KiB

4542
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

21
package.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "mario",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"dev": "nodemon server"
},
"author": "Simon Giesel",
"license": "ISC",
"dependencies": {
"babel-polyfill": "^6.26.0",
"branded-qr-code": "^1.3.0",
"express": "^4.16.3",
"express-handlebars": "^3.0.0",
"socket.io": "^2.1.0"
},
"devDependencies": {
"nodemon": "^1.17.3"
}
}

157
server.js Normal file
View file

@ -0,0 +1,157 @@
require('babel-polyfill');
const express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io')(server, {
// wsEngine: 'ws'
}),
exphbs = require('express-handlebars'),
qrCode = require('branded-qr-code');
/** CONSTANTS */
const HOST = 'http://192.168.0.105:8080/client/';
const players = [
{
type: 'mario',
id: guid(),
points: 0
},
{
type: 'luigi',
id: guid(),
points: 0
},
]
console.log(players);
app.set('views', 'src/views');
app.engine('.hbs', exphbs({
extname: '.hbs',
}));
app.set('view engine', '.hbs');
server.listen(8080, function () {
console.log('Listening on *:' + this.address().port);
});
app.get('/assets*', (req, res) => {
if (req.originalUrl.includes('qr.png')) {
const isMario = req.originalUrl.includes('mario');
qrCode.generate({
text: HOST + players[isMario ? 0 : 1].id,
path: __dirname + '/assets/' + (isMario ? 'mario.png' : 'luigi.png'),
ratio: 4,
opt: {
errorCorrectionLevel: 'H',
width: 500,
},
}).then(qr => {
res.send(qr);
});
}
else if (!req.originalUrl.includes('.map'))
res.sendFile(__dirname + req.originalUrl.split('?')[0]);
});
app.get(['/', '/index.html'], (req, res) => {
res.render('server', {
layout: false,
marioURL: HOST + players[0].id,
luigiURL: HOST + players[1].id,
});
});
app.get('/client/:id', (req, res) => {
console.log(req.params.id);
if (req.params.id == players[0].id || req.params.id == players[1].id)
res.render('client', {
layout: false,
id: getPlayerFromId(req.params.id).id,
type: getPlayerFromId(req.params.id).type,
});
else
res.render('client', { layout: false }); //TODO change to error
});
const monitorNSP = io.of('/monitor');
const clientNSP = io.of('/client');
clientNSP.on('connection', socket => {
let id = socket.request.headers.referer.split('/').slice(-1)[0];
if (!getPlayerFromId(id)) { console.error('Wrong ID'); return; }
console.log('Client connected.');
monitorNSP.emit('clientConnect', getPlayerFromId(id).type);
// monitorNSP.emit('updateGameState', 1);
socket.on('moveStart_left', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveStart_left: ' + pl.type);
monitorNSP.emit('moveStart_left', pl.type);
});
socket.on('moveStart_right', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveStart_right: ' + pl.type);
monitorNSP.emit('moveStart_right', pl.type);
});
socket.on('moveStart_jump', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveStart_jump: ' + pl.type);
monitorNSP.emit('moveStart_jump', pl.type)
});
socket.on('moveStart_crouch', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveStart_crouch: ' + pl.type);
});
socket.on('moveEnd_left', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveEnd_left: ' + pl.type);
monitorNSP.emit('moveEnd_left', pl.type);
});
socket.on('moveEnd_right', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveEnd_right: ' + pl.type);
monitorNSP.emit('moveEnd_right', pl.type);
});
socket.on('moveEnd_jump', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveEnd_jump: ' + pl.type);
});
socket.on('moveEnd_crouch', () => {
let pl = getPlayerFromId(socket.request.headers.referer.split('/').slice(-1)[0]);
console.log('moveEnd_crouch: ' + pl.type);
});
socket.on('disconnect', () => {
console.log('Client disconnected.');
monitorNSP.emit('clientDisconnect', getPlayerFromId(id).type);
});
});
monitorNSP.on('connection', socket => {
console.log('Monitor connected.');
socket.on('disconnect', () => {
console.log('Monitor disconnected.');
});
});
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
function getPlayerFromId(id) {
return players.filter(el => el.id == id)[0];
}

107
src/views/client.hbs Normal file
View file

@ -0,0 +1,107 @@
<head>
<title>MARIO Controller</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="/socket.io/socket.io.js"></script>
<style>
* {
margin: 0;
padding: 0;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
html,
body {
height: 100%;
width: 100%;
overflow: hidden;
}
button {
display: inline-block;
position: absolute;
bottom: 35%;
width: 20%;
height: 30%;
}
button#left {
left: 5%;
}
button#right {
left: 30%;
}
button#crouch,
button#jump {
right: 5%;
}
button#jump {
top: calc(40% / 3);
}
button#crouch {
bottom: calc(40% / 3);
}
warning {
display: none;
}
@media screen and (orientation:portrait) {
warning {
display: block;
position: absolute;
width: 100%;
height: 100%;
background-color: black;
color: white;
top: 0;
left: 0;
z-index: 100;
font-size: 400%;
padding: 2%;
}
warning span {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
</style>
</head>
{{!--
<img src="/assets/{{type}}.png"> ID: '{{id}}' --}}
<body>
<warning>
<span>Bitte das Smartphone drehen!</span>
</warning>
<button id="left">Left</button>
<button id="right">Right</button>
<button id="jump">Jump</button>
<button id="crouch" disabled>Crouch</button>
<script>
document.body.addEventListener("contextmenu", e => e.preventDefault());
var socket = io('/client');
Array.from(document.querySelectorAll('button')).forEach(el => {
console.log(el.id);
el.addEventListener('touchstart', event => {
console.log('moveStart_' + el.id);
socket.emit('moveStart_' + el.id);
});
el.addEventListener('touchend', event => {
console.log('moveEnd_' + el.id);
socket.emit('moveEnd_' + el.id);
});
});
</script>
</body>

1
src/views/error.hbs Normal file
View file

@ -0,0 +1 @@
<h1>Fehler</h1>

213
src/views/server.hbs Normal file
View file

@ -0,0 +1,213 @@
<head>
<title>MARIO</title>
<script src="/socket.io/socket.io.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
body {}
img.check {
filter: blur(10px);
}
img.checkmark {
content: "";
display: block;
position: absolute;
width: 200px;
top: 180px;
left: 680px;
height: 200px;
z-index: 1;
}
img.checkmark.left {
left: 140px;
}
img.checkmark.hidden {
display: none;
}
game img {
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
}
</style>
</head>
<lobby>
<mario>
<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5NnB4IiBoZWlnaHQ9Ijk2cHgiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTYgOTYiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMyNkE5NjQiIGQ9Ik00OS44NDQsNjguMzI1Yy0xLjQxNiwwLTIuNzQ4LTAuNTU0LTMuNzUtMS41NTdMMjcuNTIzLDQ4LjE5MWMtMS4wMDMtMS4wMDItMS41NTUtMi4zMzQtMS41NTUtMy43NXMwLjU1Mi0yLjc0OSwxLjU1NS0zLjc1YzEuMDAxLTEuMDAxLDIuMzMzLTEuNTUyLDMuNzUtMS41NTJzMi43NSwwLjU1MSwzLjc1MywxLjU1M2wxNC4wMTksMTQuMDE3TDgyLjE0LDUuNTA0YzAuOTg5LTEuNDY4LDIuNjM5LTIuMzQ1LDQuNDEyLTIuMzQ1YzEuMDU0LDAsMi4wNzUsMC4zMTIsMi45NTYsMC45MDJjMi40MjQsMS42MzEsMy4wNyw0LjkzNCwxLjQzOSw3LjM2MUw1NC4yNSw2NS45OGMtMC44OTIsMS4zMTYtMi4zMTIsMi4xNjItMy44OTUsMi4zMTRDNTAuMTcsNjguMzE1LDUwLjAxLDY4LjMyNSw0OS44NDQsNjguMzI1eiIvPjwvZz48L3N2Zz4="
class="checkmark left hidden">
<img src="assets/mario.qr.png">
<a href="{{marioURL}}">Mario</a>
</mario>
<luigi>
<img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5NnB4IiBoZWlnaHQ9Ijk2cHgiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTYgOTYiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMyNkE5NjQiIGQ9Ik00OS44NDQsNjguMzI1Yy0xLjQxNiwwLTIuNzQ4LTAuNTU0LTMuNzUtMS41NTdMMjcuNTIzLDQ4LjE5MWMtMS4wMDMtMS4wMDItMS41NTUtMi4zMzQtMS41NTUtMy43NXMwLjU1Mi0yLjc0OSwxLjU1NS0zLjc1YzEuMDAxLTEuMDAxLDIuMzMzLTEuNTUyLDMuNzUtMS41NTJzMi43NSwwLjU1MSwzLjc1MywxLjU1M2wxNC4wMTksMTQuMDE3TDgyLjE0LDUuNTA0YzAuOTg5LTEuNDY4LDIuNjM5LTIuMzQ1LDQuNDEyLTIuMzQ1YzEuMDU0LDAsMi4wNzUsMC4zMTIsMi45NTYsMC45MDJjMi40MjQsMS42MzEsMy4wNyw0LjkzNCwxLjQzOSw3LjM2MUw1NC4yNSw2NS45OGMtMC44OTIsMS4zMTYtMi4zMTIsMi4xNjItMy44OTUsMi4zMTRDNTAuMTcsNjguMzE1LDUwLjAxLDY4LjMyNSw0OS44NDQsNjguMzI1eiIvPjwvZz48L3N2Zz4="
class="checkmark hidden">
<img src="assets/luigi.qr.png">
<a href="{{luigiURL}}">Luigi</a>
</luigi>
</lobby>
<game>
<assets style="display:none;">
<img id="char_mario" src="/assets/char_mario_x4.png">
<img id="char_luigi" src="/assets/char_luigi_x4.png">
<img id="block_dirt" src="/assets/block_dirt_x4.png">
<img id="block_grass" src="/assets/block_grass_x4.png">
</assets>
<canvas id="canvas"></canvas>
</game>
<script>
const lobbyDOM = document.querySelector('lobby'),
gameDOM = document.querySelector('game');
let gameState = 0;
var socket = io('/monitor');
socket.on('updateGameState', gs => {
gameState = gs;
switch (gameState) {
case 0: lobbyDOM.style.display = 'inline'; gameDOM.style.display = 'none'; break;
case 1: lobbyDOM.style.display = 'none'; gameDOM.style.display = 'inline'; initGame(); break;
}
});
socket.on('clientConnect', type => {
if (type == 'mario') {
document.querySelector('mario img.checkmark').classList.remove('hidden');
document.querySelector('mario img:not(.checkmark)').classList.add('check');
} else if (type == 'luigi') {
document.querySelector('luigi img.checkmark').classList.remove('hidden');
document.querySelector('luigi img:not(.checkmark)').classList.add('check');
}
});
socket.on('clientDisconnect', type => {
if (type == 'mario') {
document.querySelector('mario img.checkmark').classList.add('hidden');
document.querySelector('mario img:not(.checkmark)').classList.remove('check');
} else if (type == 'luigi') {
document.querySelector('luigi img.checkmark').classList.add('hidden');
document.querySelector('luigi img:not(.checkmark)').classList.remove('check');
}
});
let lastBtn;
socket.on('moveStart_right', type => {
if (type == 'mario') {
player.vel = 3;
lastBtn = 'right';
}
})
socket.on('moveEnd_right', type => {
if (type == 'mario' && lastBtn == 'right') {
player.vel = 0;
}
})
socket.on('moveStart_left', type => {
if (type == 'mario') {
player.vel = -3;
lastBtn = 'left';
}
})
socket.on('moveEnd_left', type => {
if (type == 'mario' && lastBtn == 'left') {
player.vel = 0;
}
})
socket.on('moveStart_jump', type => {
if (type == 'mario') {
if (player.velUp == 0)
player.velUp = 14;
console.log(player.velUp)
}
})
/** CANVAS VARS **/
const BLOCK_SIZE = 128,
canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
right = window.innerWidth,
bottom = window.innerHeight,
char_mario = document.getElementById('char_mario'),
char_luigi = document.getElementById('char_luigi'),
block_dirt = document.getElementById('block_dirt'),
block_grass = document.getElementById('block_grass');
initGame();
function initGame() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
window.requestAnimationFrame(draw);
}
let player = new Player('char_mario');
let colliders = [];
const grav = 5;
function draw() {
colliders = [];
ctx.clearRect(0, 0, right, bottom);
for (let y = bottom / BLOCK_SIZE - 2; y < bottom / BLOCK_SIZE; y++)
for (let x = 0; x < right / BLOCK_SIZE; x++) {
ctx.drawImage(block_dirt, x * BLOCK_SIZE, y * BLOCK_SIZE);
colliders.push({ x: x * BLOCK_SIZE, y: y * BLOCK_SIZE });
}
for (let x = 0; x < right / BLOCK_SIZE; x++) {
if (x === 4 || x === 5) continue;
ctx.drawImage(block_grass, x * BLOCK_SIZE, bottom - 3 * BLOCK_SIZE);
colliders.push({ x: x * BLOCK_SIZE, y: bottom - 3 * BLOCK_SIZE });
}
// ctx.drawImage(char_mario, 6 * BLOCK_SIZE, bottom - 5 * BLOCK_SIZE + 76); // 76 == offest to full block
// ctx.drawImage(char_luigi, 5 * BLOCK_SIZE, bottom - 5 * BLOCK_SIZE + 48); // 48 == offest to full block
ctx.drawImage(char_mario, player.x, player.y);
player.move();
player.gravity();
window.requestAnimationFrame(draw);
}
function Player(type) {
this.x = 4 * BLOCK_SIZE;
this.y = 300;
this.vel = 0;
this.height = 180;
this.width = 72;
this.type = type;
this.velUp = 0;
Player.prototype.gravity = () => {
if (this.y >= bottom - this.height) return;
if (this.velUp > 0) return;
if (this.vel >= 0 && colliders.filter(el => this.y + this.height >= el.y && this.y + this.height <= el.y + BLOCK_SIZE && this.x >= el.x && this.x <= el.x + BLOCK_SIZE).length)
return;
if (this.vel < 0 && colliders.filter(el => this.y + this.height >= el.y && this.y + this.height <= el.y + BLOCK_SIZE && this.x + this.width >= el.x && this.x + this.width <= el.x + BLOCK_SIZE).length)
return;
this.y = this.y + grav;
};
Player.prototype.move = () => {
if (this.velUp > 5)
this.y = this.y - 20;
if (this.velUp > 0)
this.velUp--;
if (this.x <= 0 && this.vel < 0)
return;
if (this.x >= right - this.width)
return;
if (this.vel >= 0 && colliders.filter(el => this.x + this.width >= el.x && this.x + this.width <= el.x + BLOCK_SIZE && this.y + this.height - 10 >= el.y && this.y + this.height - 10 <= el.y + BLOCK_SIZE).length)
return;
if (this.vel < 0 && colliders.filter(el => this.x >= el.x && this.x <= el.x + BLOCK_SIZE && this.y + this.height - 10 >= el.y && this.y + this.height - 10 <= el.y + BLOCK_SIZE).length)
return;
this.x = this.x + this.vel;
}
}
</script>