Basic playmat stuff: deck/discard, hand, card movement

This commit is contained in:
Adam Goldsmith 2017-09-18 12:04:55 -04:00
parent 1c9bda694d
commit 802f76db8a
5 changed files with 6264 additions and 0 deletions

5978
interact.js Normal file

File diff suppressed because it is too large Load Diff

12
package.json Normal file
View File

@ -0,0 +1,12 @@
{
"name": "final",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC"
}

141
script.js Normal file
View File

@ -0,0 +1,141 @@
let deckName, deckJSON, cardCount, deckWidth, deckHeight,
piles = {'deck': [], discard: []};
window.addEventListener('load', () => {
deckName = document.querySelector('#card-container').getAttribute("data-deckName");
let xhr = new XMLHttpRequest();
xhr.addEventListener("load", () => {
deckJSON = JSON.parse(xhr.responseText);
piles['deck'] = deckJSON.ObjectStates[0].DeckIDs.map(c => c - 100);
cardCount = piles['deck'].length;
shuffle(piles['deck']);
deckWidth = deckJSON.ObjectStates[0].CustomDeck["1"].NumWidth;
deckHeight = deckJSON.ObjectStates[0].CustomDeck["1"].NumHeight;
console.log(deckName);
});
xhr.open("GET", "/" + deckName + ".json");
xhr.send();
});
let cardInteract = interact('.card')
.draggable({
restrict: {
restriction: "parent",
endOnly: true,
elementRect: { top: 0, left: 0, bottom: 1, right: 1 }
},
snap: {
targets: [() => {
// TODO: maybe change to dropzone?
let pos = document.body.getBoundingClientRect(),
style = window.getComputedStyle(hand),
handHeight = parseInt(style.getPropertyValue("height"));
return {y: pos.bottom,
range: handHeight/2};
}],
relativePoints: [{x: 0.5 , y: 1}]
},
onmove: dragMoveListener
})
.on('hold', event => {
let target = event.target,
transform = target.style.transform;
// Scale up for visibility
if (transform.includes("scale(2)")) {
// translate the element
target.style.webkitTransform =
target.style.transform = transform.replace(" scale(2)", "");
}
else {
target.style.webkitTransform =
target.style.transform = transform + ' scale(2)';
}
});
interact('.card-pile')
.dropzone({
accept: '.card',
ondrop: event => {
let pile = piles[event.target.getAttribute('data-pile')];
pile.push(event.relatedTarget.getAttribute('data-num'));
event.relatedTarget.parentElement.removeChild(event.relatedTarget);
// update deck text
event.target.innerHTML = `DECK<br>${pile.length}/${cardCount}`;
}
})
.draggable({manualStart: true})
.on('move', event => {
let interaction = event.interaction;
let pile = piles[event.target.getAttribute('data-pile')];
// if the pointer was moved while being held down
// and an interaction hasn't started yet
if (interaction.pointerIsDown &&
!interaction.interacting() &&
pile.length > 0) {
// draw a new card
let newCard = document.createElement('div');
newCard.className = "card";
let style = window.getComputedStyle(newCard);
let cardNum = pile.pop();
newCard.setAttribute('data-num', cardNum);
newCard.style.backgroundPosition = `
${(cardNum % deckWidth) * parseInt(style.getPropertyValue("width"))}px
${Math.floor(cardNum/deckHeight) * parseInt(style.getPropertyValue("height"))}px`;
newCard.style.backgroundImage = `url('${deckName}.png')`;
newCard.style.backgroundSize = `${deckWidth * 100}% ${deckHeight * 100}%`;
// insert the card to the page
document.querySelector("#card-container").appendChild(newCard);
// update deck text
event.target.innerHTML = `DECK<br>${pile.length}/${cardCount}`;
// start a drag interaction targeting the clone
interaction.start({name: 'drag'}, cardInteract, newCard);
}
});
// Fisher-Yates shuffle from https://bost.ocks.org/mike/shuffle/
function shuffle(array) {
let m = array.length, t, i;
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
i = Math.floor(Math.random() * m--);
// And swap it with the current element.
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
function dragMoveListener (event) {
let interaction = event.interaction;
let target = event.target,
// keep the dragged position in the data-x/data-y attributes
x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx,
y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
// translate the element
target.style.webkitTransform =
target.style.transform =
'translate(' + x + 'px, ' + y + 'px)';
// raise to top
target.parentElement.removeChild(target);
document.querySelector("#card-container").appendChild(target);
// update the posiion attributes
target.setAttribute('data-x', x);
target.setAttribute('data-y', y);
}

91
server.js Normal file
View File

@ -0,0 +1,91 @@
// jshint node:true
// jshint esversion:6
"use strict";
const http = require('http'),
qs = require('querystring'),
fs = require('fs'),
url = require('url'),
https = require('https'),
port = 8080;
const deckName = "the_Unholy_Priest_update_2";
const server = http.createServer((req, res) => {
const uri = url.parse(req.url);
if (req.method === 'POST') {
handlePost(res, req, uri);
}
else {
switch( uri.pathname ) {
case '/':
case '/index.html':
sendIndex(res, "");
break;
case '/style.css':
sendFile(res, 'style.css', 'text/css');
break;
case '/script.js':
sendFile(res, 'script.js', 'application/javascript');
break;
case '/interact.js':
sendFile(res, 'interact.js', 'application/javascript');
break;
case '/' + deckName + '.png':
sendFile(res, deckName + '.png', 'image/png');
break;
case '/' + deckName + '.json':
sendFile(res, deckName + '.json', 'application/json');
break;
default:
res.writeHead(404, {'Content-type': "text/html; charset=utf-8"});
const html = `
<head>
<title>404 Not Found</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Error 404: Path ${uri.pathname} not found</h1>
You seem to have gone to the wrong place, would you like to go
back to the <a href="/">main page</a>?
</body>`;
res.end(html, 'utf-8');
}
}
});
server.listen(process.env.PORT || port);
console.log('listening on 8080');
function sendIndex(res) {
let cards = [];
const html = `
<html>
<head>
<script src="interact.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="card-container" data-deckName="${deckName}">
<div class="card-pile deck" data-pile="deck">DECK</div>
<div class="card-pile discard" data-pile="discard"></div>
<div id="hand"></div>
</div>
</body>
</html>`;
res.writeHead(200, {'contentType': 'text/html; charset=utf-8'});
res.end(html, 'utf-8');
}
function sendFile(res, filename, contentType='text/html; charset=utf-8') {
fs.readFile(filename, (error, content) => {
res.writeHead(200, {'Content-type': contentType});
res.end(content, 'utf-8');
if (error) {
console.error(error);
}
});
}

42
style.css Normal file
View File

@ -0,0 +1,42 @@
body {
margin: 0 0 0 0;
}
.card {
position: absolute;
border-radius: 5px;
width: 142px;
height: 200px;
}
#card-container {
width: 100%;
height: 100%;
}
#hand {
position: absolute;
bottom: 0px;
width: 100%;
height: 20%;
background-color: #ccc;
}
.card-pile {
width: 100px;
height: 100px;
color: #eee;
display: flex;
justify-content: center;
align-items: center;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.deck {
background-color: blue;
}
.discard {
background-color: red;
}