diff --git a/src/Player.js b/src/Player.js index d78b635..e6f1526 100644 --- a/src/Player.js +++ b/src/Player.js @@ -3,8 +3,9 @@ import skull from 'data-url:./assets/img/skull.png'; import { getPointer, Sprite, on } from 'kontra'; import { PlayerControls } from './PlayerControls'; import { fgc2 } from './constants'; -import { ARCADIAN_ADDED, CUT_ROPE, GOAL_COLLISION } from './gameEvents'; +import { ARCADIAN_HEAD_SELECTED, CUT_ROPE, GOAL_COLLISION } from './gameEvents'; import { Rope } from './Rope'; +import { getSelectedArcadian } from './store'; export class Player { game; @@ -26,6 +27,8 @@ export class Player { const startY = levelData.p.y; this.createRope({ startX, startY, ropeLength }); this.createSprite(); + this.headImg = getSelectedArcadian().img; + this.createHeadSprite(this.headImg); this.playerControls = new PlayerControls(this); this.listenForGameEvents(); } @@ -60,6 +63,7 @@ export class Player { }; } createHeadSprite(img) { + if (!img) return; const scale = this.scale / 2; let scaleX = scale; if (this.isLeft) scaleX = scaleX * -1; @@ -167,7 +171,7 @@ export class Player { listenForGameEvents() { on(GOAL_COLLISION, this.onGoalCollision); - on(ARCADIAN_ADDED, this.onArcadianAdded); + on(ARCADIAN_HEAD_SELECTED, this.onArcadianAdded); on(CUT_ROPE, this.onCutRope); } onGoalCollision = () => { diff --git a/src/arcadianApi.js b/src/arcadianApi.js index 7b86baf..f861ce8 100644 --- a/src/arcadianApi.js +++ b/src/arcadianApi.js @@ -1,4 +1,6 @@ -export const arcadianHeadImages = []; +import { emit } from 'kontra'; +import { ARCADIAN_ADDED, ARCADIAN_HEAD_SELECTED } from './gameEvents'; +import { setArcadianData } from './store'; export async function queryArcadian(id) { const partsUrl = @@ -29,9 +31,9 @@ export async function queryArcadian(id) { img.addEventListener( 'load', () => { - localStorage.setItem('Arcadian #' + id, xhr.response); - arcadianHeadImages.push(img); - resolve(img); + localStorage.setItem('Arcadian #' + id, img); + setArcadianData({ id, data, img }); + resolve({ id, data, img }); }, false ); @@ -41,3 +43,17 @@ export async function queryArcadian(id) { xhr.send(); }); } + +export const fetchArcadianHeads = () => { + return new Promise((resolve) => { + const promises = []; + for (let i = 1; i < 6; i++) { + const promise = queryArcadian(i); + promises.push(promise); + } + Promise.allSettled(promises).then((res) => { + emit(ARCADIAN_HEAD_SELECTED, { img: res[0].value }); + resolve(res); + }); + }); +}; diff --git a/src/gameEvents.js b/src/gameEvents.js index beb7c3e..4901b4a 100644 --- a/src/gameEvents.js +++ b/src/gameEvents.js @@ -5,3 +5,4 @@ export const HEART_PICKUP = 'hp'; export const CUT_ROPE = 'cr'; export const START_LEVEL = 'sl'; export const RESTART_LEVEL = 'r'; +export const ARCADIAN_HEAD_SELECTED = 'ahs'; diff --git a/src/index.html b/src/index.html index fc2831b..19b698e 100644 --- a/src/index.html +++ b/src/index.html @@ -19,6 +19,7 @@
+
diff --git a/src/index.js b/src/index.js index 41f4b13..5785f60 100644 --- a/src/index.js +++ b/src/index.js @@ -3,8 +3,6 @@ import { emit } from 'kontra'; import cssText from 'bundle-text:./styles.css'; import { Game } from './Game'; -import { ARCADIAN_ADDED } from './gameEvents'; -import { queryArcadian } from './arcadianApi'; import { initLoginLogout } from './near/nearLogin'; import { NearConnection } from './near/nearConnection'; import { initMenu } from './menu'; @@ -46,14 +44,4 @@ const loadNearApi = () => { }); }; -const fetchArcadianHeads = () => { - // TODO (johnedvard) get from localStorage so we don't call the api too much - // get many headpices - for (let i = 0; i < 60; i += 5) - queryArcadian(i).then((img) => { - if (img) { - emit(ARCADIAN_ADDED, { img }); - } - }); -}; init(); diff --git a/src/menu.js b/src/menu.js index 8d5a84d..e05f69a 100644 --- a/src/menu.js +++ b/src/menu.js @@ -1,6 +1,11 @@ +import { emit, Sprite } from 'kontra'; + import closeIcon from 'data-url:./assets/img/close icon.svg'; -import { emit } from 'kontra'; -import { START_LEVEL } from './gameEvents'; +import skull from 'data-url:./assets/img/skull.png'; + +import { ARCADIAN_HEAD_SELECTED, START_LEVEL } from './gameEvents'; +import { arcadianHeadImages, fetchArcadianHeads } from './arcadianApi'; +import { setSelectedArcadian } from './store'; const overlayIds = ['main', 'bonus', 'levels']; const levels = 20; @@ -20,7 +25,34 @@ const initLevels = () => { levelsGridEl.appendChild(levelEl); } }; -const initBonusContent = () => {}; +const initBonusContent = () => { + const bonusGridEl = document.getElementById('bonus-grid'); + const skullImg = new Image(); + skullImg.src = skull; + fetchArcadianHeads().then((res) => { + for (let i = 0; i < res.length; i++) { + const img = res[i].value.img; + const bonusEl = document.createElement('canvas'); + bonusEl.setAttribute('height', img.height * 4); + bonusEl.setAttribute('width', img.width * 4); + bonusEl.classList.add('bonus-item'); + bonusEl.setAttribute('arcadian', res[i].value.id); + const ctx = bonusEl.getContext('2d'); + ctx.imageSmoothingEnabled = false; + ctx.scale(8, 8); + ctx.drawImage(skullImg, img.width / 4 - 4, img.height / 4 - 12); + ctx.scale(1 / 2, 1 / 2); + ctx.drawImage(img, 0, 0); + bonusGridEl.appendChild(bonusEl); + } + }); + bonusGridEl.addEventListener('click', (e) => { + if (e.target.classList.contains('bonus-item')) { + setSelectedArcadian(e.target.getAttribute('arcadian')); + showOverlay('main'); + } + }); +}; const addButtonListeners = () => { const containerEl = document.getElementById('container'); diff --git a/src/store.js b/src/store.js index 6a4e7d0..22f23fa 100644 --- a/src/store.js +++ b/src/store.js @@ -1,8 +1,28 @@ +import { emit } from 'kontra'; +import { ARCADIAN_HEAD_SELECTED } from './gameEvents'; + export let gameWidth = 0; export let gameHeight = 0; +const arcadianData = {}; +let selectedArcadian = {}; + export const setGameWidth = (width) => { gameWidth = width; }; + export const setGameHeight = (height) => { gameHeight = height; }; + +export const setArcadianData = ({ id, data, img }) => { + arcadianData[id] = { data, img }; +}; + +export const setSelectedArcadian = (id) => { + selectedArcadian = arcadianData[id]; + emit(ARCADIAN_HEAD_SELECTED, { img: selectedArcadian.img }); +}; + +export const getSelectedArcadian = () => { + return selectedArcadian; +}; diff --git a/src/styles.css b/src/styles.css index 6884e86..2a3a21f 100644 --- a/src/styles.css +++ b/src/styles.css @@ -116,9 +116,24 @@ button:disabled { display: grid; justify-items: center; } -#levels-grid::-webkit-scrollbar { +#levels-grid::-webkit-scrollbar, +#bonus-grid::-webkit-scrollbar { display: none; } +.bonus-item { + cursor: pointer; + background: none; + border-radius: 4px; +} +.bonus-item:hover { + box-shadow: inset 0px 0px 100px -50px var(--acc); +} +#bonus-grid { +} +#bonus-grid > canvas { + width: 200px; + height: 200px; +} .hide { display: none !important; /* XXX Override any other display settings on the element */ }