From 469121e18ae8c23e4c97a66de0df8f5261c2e8a9 Mon Sep 17 00:00:00 2001 From: asraelite Date: Mon, 5 Mar 2018 15:05:55 +0000 Subject: [PATCH] Add inventory --- js/game/control.mjs | 8 +++- js/game/events.mjs | 2 + js/game/index.mjs | 9 +++-- js/game/inventory.mjs | 62 +++++++++++++++++++++++++++++ js/graphics/gui.mjs | 37 ++++++++++-------- js/gui/inventory.mjs | 90 +++++++++++++++++++++++++++++++++++++++++++ js/gui/item.mjs | 7 +++- js/gui/modules.mjs | 7 ++++ 8 files changed, 200 insertions(+), 22 deletions(-) diff --git a/js/game/control.mjs b/js/game/control.mjs index b99ce3b..7aa216e 100644 --- a/js/game/control.mjs +++ b/js/game/control.mjs @@ -2,13 +2,15 @@ import * as input from '../input.mjs'; import * as events from './events.mjs'; import * as player from './player.mjs'; import * as graphics from '../graphics/index.mjs'; +import * as inventory from './inventory.mjs'; import {state} from './index.mjs'; export const mapping = { thrust: 'KeyW', left: 'KeyA', right: 'KeyD', - exitEdit: 'Escape' + exitEdit: 'Escape', + inventory: 'KeyE', }; let held, pressed; @@ -42,6 +44,10 @@ function tickPlaying() { if (held[mapping.right]) { player.ship.applyThrust({ turnRight: 1 }); } + + if (pressed[mapping.inventory]) { + state.inventory = !state.inventory; + } } function tickEditing() { diff --git a/js/game/events.mjs b/js/game/events.mjs index 281571d..7d44d94 100644 --- a/js/game/events.mjs +++ b/js/game/events.mjs @@ -23,12 +23,14 @@ export function launchShip() { export function editShip() { game.state.editing = true; + game.state.inventory = true; edit.init(); } export function endEditing() { graphics.changePerspective('universe'); game.state.editing = false; + game.state.inventory = false; edit.end(); } diff --git a/js/game/index.mjs b/js/game/index.mjs index 7532d33..b088914 100644 --- a/js/game/index.mjs +++ b/js/game/index.mjs @@ -2,6 +2,7 @@ import * as graphics from '../graphics/index.mjs'; import * as gui from '../gui/index.mjs'; import * as assets from '../assets.mjs'; import * as input from '../input.mjs'; +import * as inventory from './inventory.mjs'; import * as world from '../world/index.mjs'; import * as events from './events.mjs'; import * as control from './control.mjs'; @@ -15,7 +16,8 @@ export async function init() { view: 'menu', playing: false, editing: false, - paused: false + paused: false, + inventory: false }; graphics.init(); @@ -29,7 +31,7 @@ export async function init() { // Recursive `requestAnimationFrame` can cause problems with Parcel. while(true) { - await tick(); + tick(); await new Promise(res => requestAnimationFrame(res)); } } @@ -44,10 +46,11 @@ export function changeView(view) { state.paused = false; world.init(); player.init(); + inventory.init(); } } -async function tick() { +function tick() { if (state.view == 'game') { world.tick(); control.tick(); diff --git a/js/game/inventory.mjs b/js/game/inventory.mjs index e69de29..8f070bf 100644 --- a/js/game/inventory.mjs +++ b/js/game/inventory.mjs @@ -0,0 +1,62 @@ +import {modules} from '../data.mjs'; +import {images as assets} from '../assets.mjs'; + +export const items = new Map(); +export let currentItem = null; + +export function init() { + items.clear(); + addItem('capsule', 'small'); + addItem('thruster', 'light'); +} + +export function getTiles() { + let list = Array.from(items.values()); + list.sort((a, b) => toId(...a.ident) < toId(...b.ident)); + return list; +} + +export function addItem(type, id) { + let mapId = toId(type, id); + if (!items.has(mapId)) items.set(mapId, new Tile(type, id)); + let tile = items.get(mapId); + tile.increase(); +} + +export function removeItem(type, id) { + let mapId = toId(type, id); + if (!items.has(mapId)) return; + let tile = items.get(mapId); + tile.decrease(); +} + +export function selectItem(type, id) { + currentItem = items.get(toId(type, id)); +} + +function toId(type, id) { + return `${type}.${id}`; +} + +class Tile { + constructor(type, id, q = 0) { + this.type = type; + this.id = id; + this.mapId = toId(type, id); + this.quantity = q; + this.image = assets.modules[type][id]; + if (type === 'thruster') this.image = this.image.off; + } + + get ident() { + return [this.type, this.id]; + } + + increase() { + this.quantity++; + } + + decrease() { + this.quantity = Math.max(0, this.quantity - 1); + } +} diff --git a/js/graphics/gui.mjs b/js/graphics/gui.mjs index 3f7cf2f..331f8c0 100644 --- a/js/graphics/gui.mjs +++ b/js/graphics/gui.mjs @@ -14,6 +14,7 @@ function renderElement(element) { if (element.type == 'button') renderButton(element); if (element.type == 'edit') renderEdit(element); if (element.type == 'itemButton') renderItemButton(element); + if (element.type == 'inventory') renderInventory(element); } if (element.options.drawChildren) @@ -56,30 +57,32 @@ function renderItemButton(element) { } context.fillRect(...element.shape); - context.strokeStyle = '#333'; - context.strokeWidth = 4; + if (element.selected) { + context.strokeStyle = '#fff'; + context.lineWidth = 2; + } else { + context.strokeStyle = '#333'; + context.lineWidth = 1; + } context.strokeRect(...element.shape); context.globalAlpha = 1; if (element.image) { - context.drawImage(element.image, ...element.shape); + let p = element.padding; + let ox = element.x + (p / 2 * element.w); + let oy = element.y + (p / 2 * element.h); + let [dw, dh] = [element.w * (1 - p), element.h * (1 - p)]; + context.drawImage(element.image, ox, oy, dw, dh); } } function renderEdit(element) { - /* - element.tiles.forEach(t => { - let tile = edit.getTile(x, y); - let [dx, dy] = tile.drawPos; - context.globalAlpha = 0.5; - context.fillStyle = '#000'; - context.fillRect(dx, dy, 1, 1); - context.globalAlpha = 1; - let module = tile.module; - if (module !== null) { - context.drawImage(module.currentImage, dx, dy, 1, 1); - } - }); - */ +} + +function renderInventory(element) { + context.globalAlpha = 0.1; + context.fillStyle = '#541'; + context.fillRect(...element.shape); + context.globalAlpha = 1; } diff --git a/js/gui/inventory.mjs b/js/gui/inventory.mjs index e69de29..489b80a 100644 --- a/js/gui/inventory.mjs +++ b/js/gui/inventory.mjs @@ -0,0 +1,90 @@ +import * as gui from './index.mjs'; +import GuiElement from './element.mjs'; +import GuiItemButton from './item.mjs'; +import {state} from '../game/index.mjs'; +import * as inventory from '../game/inventory.mjs'; + +export default class GuiInventory extends GuiElement { + constructor(x, y, w = 100, h = 30) { + super(x, y, w, h); + this.type = 'inventory'; + this.tileWidth = 4; + this.tileHeight = 5; + this.currentPage = 0; + } + + updateTiles() { + this.children.clear(); + + let tileRatio = this.tileWidth / this.tileHeight; + let rectRatio = this.w / this.h; + let tileSize; + let [ox, oy] = [0, 0]; + + if (tileRatio < rectRatio) { + tileSize = this.h / this.tileHeight; + ox = (this.w - (tileSize * this.tileWidth)) / 2; + } else { + tileSize = this.w / this.tileWidth; + oy = (this.h - (tileSize * this.tileHeight)) / 2; + } + + let spacing = 0.15 * tileSize; + let pageSize = this.tileWidth * this.tileHeight; + let offset = pageSize * this.currentPage; + let tiles = inventory.getTiles().slice(offset); + let tile; + + for (let y = 0; y < this.tileHeight; y++) + for (let x = 0; x < this.tileWidth && tiles.length; x++) { + let i = y * this.tileWidth + (x % this.tileWidth) + offset; + tile = tiles.shift(); + + let ex = x * tileSize + spacing / 2 + ox + this.x; + let ey = y * tileSize + spacing / 2 + oy + this.y; + let [ew, eh] = [tileSize - spacing, tileSize - spacing]; + + let ident = tile.ident; + + let onclick = (button) => { + this.tileClicked(...ident, button); + }; + + let cur = inventory.currentItem; + let selected = cur !== null && tile.type === cur.type + && tile.id === cur.id; + + let el = new GuiItemButton(tile, onclick, ex, ey, ew, eh, { + padding: 0.1, + selected: selected + }); + + this.append(el); + } + } + + tick() { + if (state.inventory && !this.active) this.updateTiles(); + this.active = state.inventory; + this.options.draw = this.options.drawChildren = this.active; + if (!this.active) return; + } + + getTile(x, y) { + return this.getTile(x + px, y + py); + } + + tileClicked(type, id, button) { + if (button == 'left') inventory.selectItem(type, id); + + if (!state.editing) { + if (button == 'left') { + inventory.addItem(type, id); + } else if (button == 'right') { + inventory.removeitem(type, id); + } + } + + this.updateTiles(); + } +} diff --git a/js/gui/item.mjs b/js/gui/item.mjs index f1525aa..fa8ea86 100644 --- a/js/gui/item.mjs +++ b/js/gui/item.mjs @@ -2,11 +2,16 @@ import * as gui from './index.mjs'; import GuiButton from './button.mjs'; export default class GuiItemButton extends GuiButton { - constructor(tile, onclick, x, y, w = 50, h = 50) { + constructor(tile, onclick, x, y, w = 50, h = 50, { padding, selected } = { + padding: 0, + selected: false + }) { super(null, onclick, x, y, w, h); this.module = tile.module; this.image = tile.image; this.type = 'itemButton'; + this.padding = padding; + this.selected = selected; } click() { diff --git a/js/gui/modules.mjs b/js/gui/modules.mjs index 94343df..5f50e6c 100644 --- a/js/gui/modules.mjs +++ b/js/gui/modules.mjs @@ -5,6 +5,7 @@ import GuiFrame from './frame.mjs'; import GuiImage from './image.mjs'; import GuiButton from './button.mjs'; import GuiEdit from './edit.mjs'; +import GuiInventory from './inventory.mjs'; import * as events from '../game/events.mjs'; import {state} from '../game/index.mjs'; @@ -53,5 +54,11 @@ export function game() { edit.x -= 10; edit.y += 10; + let inventory = new GuiInventory(0, 0, 0, 0); + shadow.append(inventory); + inventory.posRelative({x: 0, y: 0, w: 0.4, h: 0.6}); + inventory.x += 10; + inventory.y += 10; + return shadow; }