diff options
Diffstat (limited to 'server/web/game')
| -rw-r--r-- | server/web/game/game.js | 67 | ||||
| -rw-r--r-- | server/web/game/index.html | 69 | ||||
| -rw-r--r-- | server/web/game/style.css | 160 |
3 files changed, 229 insertions, 67 deletions
diff --git a/server/web/game/game.js b/server/web/game/game.js index 78e5547..05756fc 100644 --- a/server/web/game/game.js +++ b/server/web/game/game.js @@ -1,24 +1,59 @@ "use strict"; -const showGame = (g) => { + +var cloned = false + +const cloneGame = (g) => { const tmpl = document.querySelector("template#tmpl"); const disp = document.querySelector("#game"); const clone = document.importNode(tmpl.content, true); - doDistance(clone, g.Distance.Value); - doActions(clone, g.Actions); - disp.replaceChildren(clone); + const localPlayer = clone.querySelector("#player").content.cloneNode(true) + localPlayer.querySelector("div").setAttribute("id", "local-player") + const remotePlayer = clone.querySelector("#player").content.cloneNode(true) + remotePlayer.querySelector("div").setAttribute("id", "remote-player") + + disp.replaceChildren(remotePlayer, clone, localPlayer); + showGame(disp, g) +} + +const showGame = (n, g) => { + console.debug(g) + doDistance(n, g.Distance.Value); + doActions(n, g.Actions); + doPlayer(n.querySelector("#local-player"), g[g.You]) + doPlayer(n.querySelector("#remote-player"), g[g.Them]) }; -const doDistance = (clone, value) => { - clone.querySelector("#distance").setAttribute("data-value", value); - [...clone.querySelectorAll("#distance .content .sakura")].map((n, i) => { - n.checked = i < value; - }); - clone.querySelector("#distance .pool-value").innerText = value +const doPlayer = (n, p) => { + doPool(n.querySelector(".life"), p.Life.Value) + doPool(n.querySelector(".aura"), p.Life.Value) + +} + +const doPool = (node, value) => { + node.setAttribute("data-value", value); + node.querySelectorAll(".sakura").forEach((n, i) => { + const shouldCheck = (n.getAttribute("data-ordering") ?? i) < value + n.checked = shouldCheck + n.setAttribute("checked", shouldCheck) + }) + const valueNode = node.querySelector(".pool-value") + if (valueNode) + valueNode.innerText = value +} + +const doDistance = (node, value) => { + const distance = node.querySelector("#distance") + doPool(distance, value) }; + +let actionTemplate + const doActions = (g, actions) => { - const actionList = g.querySelector(".actions"); - const actionTemplate = actionList.querySelector(".action").cloneNode(true); + const actionList = g.querySelector("#actions"); + if (!actionTemplate) { + actionTemplate = document.importNode(actionList.querySelector("template").content.querySelector(".action"), true) + } if (actions) { actionList.replaceChildren( ...actions.map((a, i) => { @@ -42,8 +77,12 @@ const connect = (gameId) => { window.socket = connection; connection.addEventListener("message", (ev) => { const game = JSON.parse(ev.data); - console.debug(game); - showGame(game); + if (cloned) { + showGame(document.querySelector("#game"), game) + } else { + cloneGame(game) + cloned = true + } document.querySelector("#game-json").innerText = JSON.stringify( ev.data, null, diff --git a/server/web/game/index.html b/server/web/game/index.html index 04e85d2..f022c64 100644 --- a/server/web/game/index.html +++ b/server/web/game/index.html @@ -18,32 +18,61 @@ <code id="game-json"></code> </details> </header> +<img class="background" src="/game/assets/sea-water-texture-seamless.jpg"> <main id="game"></main> <template id="tmpl"> - <div id="distance"> - <div class="content"> - <input type="checkbox" class="sakura" style="animation-delay: 0.7s"/> - <input type="checkbox" class="sakura" style="animation-delay: 1.4s"/> - <input type="checkbox" class="sakura" style="animation-delay: 2.1s"/> - <input type="checkbox" class="sakura" style="animation-delay: 2.8s"/> - <input type="checkbox" class="sakura" style="animation-delay: 3.5s"/> - <input type="checkbox" class="sakura" style="animation-delay: 4.2s"/> - <input type="checkbox" class="sakura" style="animation-delay: 4.9s"/> - <input type="checkbox" class="sakura" style="animation-delay: 5.6s"/> - <input type="checkbox" class="sakura" style="animation-delay: 6.3s"/> - <input type="checkbox" class="sakura" style="animation-delay: 7s"/> + <div id="arena"> + <div id="shadow" class="pool"> + <input type="checkbox" data-ordering="8" class="sakura" style="animation-delay: 0.7s"/> + </div> + <div id="distance" class="pool"> + <div class="content"> + <input type="checkbox" data-ordering="8" class="sakura" style="animation-delay: 0.7s"/> + <input type="checkbox" data-ordering="6" class="sakura" style="animation-delay: 1.4s"/> + <input type="checkbox" data-ordering="4" class="sakura" style="animation-delay: 2.1s"/> + <input type="checkbox" data-ordering="2" class="sakura" style="animation-delay: 2.8s"/> + <input type="checkbox" data-ordering="0" class="sakura" style="animation-delay: 3.5s"/> + <input type="checkbox" data-ordering="1" class="sakura" style="animation-delay: 4.2s"/> + <input type="checkbox" data-ordering="3" class="sakura" style="animation-delay: 4.9s"/> + <input type="checkbox" data-ordering="5" class="sakura" style="animation-delay: 5.6s"/> + <input type="checkbox" data-ordering="7" class="sakura" style="animation-delay: 6.3s"/> + <input type="checkbox" data-ordering="9" class="sakura" style="animation-delay: 7s"/> + </div> </div> - <label class="label pool-name">Distance</label> - <label class="label pool-value">10</label> </div> - <ul class="actions"> - <li class="action" data-index=""> - <button type="button" class="description" - onclick="window.socket.send(closest('.action').getAttribute('data-index'))">Do - </button> - </li> + <ul id="actions"> + <template> + <li class="action" data-index=""> + <button type="button" class="description" + onclick="window.socket.send(closest('.action').getAttribute('data-index'))">Do + </button> + </li> + </template> </ul> + <template id="player"> + <div class="player"> + <div class="pool aura" data-value="3"> + <input type="checkbox" data-ordering="0" class="sakura"/> + <input type="checkbox" data-ordering="1" class="sakura"/> + <input type="checkbox" data-ordering="2" class="sakura"/> + <input type="checkbox" data-ordering="3" class="sakura"/> + <input type="checkbox" data-ordering="4" class="sakura"/> + </div> + <div class="pool life" data-value="3"> + <input type="checkbox" data-ordering="0" class="sakura"/> + <input type="checkbox" data-ordering="1" class="sakura"/> + <input type="checkbox" data-ordering="2" class="sakura"/> + <input type="checkbox" data-ordering="3" class="sakura"/> + <input type="checkbox" data-ordering="4" class="sakura"/> + <input type="checkbox" data-ordering="5" class="sakura"/> + <input type="checkbox" data-ordering="6" class="sakura"/> + <input type="checkbox" data-ordering="7" class="sakura"/> + <input type="checkbox" data-ordering="8" class="sakura"/> + <input type="checkbox" data-ordering="9" class="sakura"/> + </div> + </div> + </template> </template> <script src="/game/game.js"></script> diff --git a/server/web/game/style.css b/server/web/game/style.css index 83f06ad..d7baa20 100644 --- a/server/web/game/style.css +++ b/server/web/game/style.css @@ -2,58 +2,152 @@ display: none; } -#distance { +#actions { + position: absolute; + bottom: 0; + width: 80%; + margin: 0 auto 0 auto; + transform: translateY(80%); + transition: transform 0.2s ease-in-out; + padding: 1em; + border: solid 2px black; + border-bottom: none; + border-radius: 1em 1em 0 0; + background-color: slategray; - & .label { - position: relative; + &:hover { + transform: translateY(0); + } +} + +.action button { + border-color: lightpink; + background-color: rgba(41, 24, 24, 0.4); + color: floralwhite; +} - bottom: 0; - margin-bottom: 4px; +.sakura { + transition-property: opacity; + transition-duration: 0.5s; + opacity: 1; - &.pool-name { - left: 0; - } + /* noninteractive and style override */ + pointer-events: none; + -webkit-appearance: none; + appearance: none; + background-color: transparent; - &.pool-value { - right: 0; - } + &::before { + content: "🌸" } - & .content { - display: flex; - justify-content: center; + font-size: 2em; + @starting-style{ + opacity: 0; + } +} - & input[type=checkbox] { - pointer-events: none; - -webkit-appearance: none; - appearance: none; - background-color: transparent; - margin: 4px; - font-size: 2em; +body { + overflow: hidden; +} - @media (prefers-reduced-motion: no-preference) { - animation: 5s shake ease-in-out alternate infinite; +.background { + position: absolute; + top: 0; + height: 100%; + background-image: url("/game/assets/sea-water-texture-seamless.jpg"); + animation: alternate scroll 60s infinite ease-in-out; + z-index: -1; + filter: contrast(10%); + width: 200vw; + +} + +#arena { + + margin: 0 2em; + + display: flex; + flex-direction: row-reverse; + justify-content: left; + + & #distance { + & .label { + position: relative; + + bottom: 0; + + &.pool-name { + left: 0; } - &::before { - color: lightseagreen; - content: "" + &.pool-value { + right: 0; + } + } + + & .sakura { + height: 0.6em; + + text-shadow: 0 0 0.5em #70b8da; + + @media (prefers-reduced-motion: no-preference) { + animation: 1s sway ease-in-out alternate infinite; } - &:checked { - &::before { - content: "🌸" - } + &:not(:checked) { + filter: grayscale(85%) contrast(25%); } } + + & .content { + display: flex; + justify-content: center; + flex-direction: column; + } + } +} + +@keyframes sway { + from { + transform: translateY(6%) rotateX(-5deg) + } + to { + transform: translateY(-6%) rotateX(5deg) } } -@keyframes shake { +@keyframes scroll { from { - transform: translateY(0) rotateZ(0deg) + transform: translateX(-30%) rotateX(5deg) } to { - transform: translateY(12%) rotateZ(60deg) + transform: translateX(-60%) rotateX(-5deg) } +} + +#remote-player { + transform: rotateX(180deg); +} + +.pool { + display: flex; + flex-wrap: wrap; + justify-content: space-around; + + &.life { + background-color: rgba(139, 0, 0, 0.57); + border: solid 0.2em indianred; + border-top: none; + } + + &.aura { + background-color: rgba(173, 216, 230, 0.6); + border-radius: 1em 1em 0 0; + box-shadow: 0 0 0.4em lightskyblue; + } +} + +#shadow { + flex-basis: 50%; }
\ No newline at end of file |
