selectable inventory items

main
Norman Köhring 1 year ago
parent c486c12283
commit e4e3953734

@ -15,6 +15,12 @@ const { player, direction, dx, dy } = usePlayer()
const { inputX, inputY, running, digging, paused, help, inventory } = useInput()
const level = createLevel(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
player.inventory.push(
{ name: 'Shovel', type: 'tool', icon: 'shovel', quality: 'bronze' },
{ name: 'Sword', type: 'weapon', icon: 'sword', quality: 'bronze' },
{ name: 'Pick Axe', type: 'tool', icon: 'pick', quality: 'bronze' },
)
let animationFrame = 0
let lastTick = 0
@ -27,6 +33,7 @@ const ty = computed(() => (y.value - floorY.value) * -BLOCK_SIZE)
const rows = computed(() => level.grid(floorX.value, floorY.value))
const walking = ref(false)
const inventorySelection = ref<InventoryItem | null>(null)
type Surroundings = {
at: Block,
@ -125,7 +132,7 @@ onMounted(() => {
</template>
</div>
<div id="player" :class="[direction, { walking }]">
<div id="player" :class="[direction, { walking }]" @click="inventory = !inventory">
<div class="head"></div>
<div class="body"></div>
<div class="legs">
@ -133,8 +140,9 @@ onMounted(() => {
<div class="right"></div>
</div>
<div class="arms">
<div class="left"></div>
<div class="right"></div>
<div v-if="inventorySelection"
:class="['item', `${inventorySelection.type}-${inventorySelection.icon}-${inventorySelection.quality}`]"
></div>
</div>
</div>
<div id="level-indicator">
@ -143,7 +151,10 @@ onMounted(() => {
<template v-else>({{ clock }})</template>
</div>
<Inventory :shown="inventory" :player="player" />
<Inventory :shown="inventory"
:items="player.inventory"
@selection="inventorySelection = $event"
/>
<Help v-show="help" />
</div>
</template>

@ -34,67 +34,6 @@
.night .block, .night #player { filter: brightness(0.3) saturate(30%); }
#player {
--player-width: 64px;
--player-height: 76px;
position: absolute;
left: calc(var(--field-width) / 2);
top: calc(var(--field-height) / 2 - 10px);
display: flex;
flex-flow: column nowrap;
width: var(--player-width);
height: var(--player-height);
}
#player > div {
margin: auto;
background: transparent center no-repeat;
background-size: cover;
}
#player.right {
transform: scaleX(-1);
}
#player > .head {
width: 46px;
height: 46px;
background-image: url(/Characters/Alien/alien_head.png);
z-index: 1;
}
#player > .body {
width: 22px;
height: 24px;
margin-top: -8px;
background-image: url(/Characters/Alien/alien_body.png);
}
#player > .legs {
position: relative;
width: 14px;
height: 18px;
}
#player > .legs > div {
position: absolute;
width: 14px;
height: 18px;
background-image: url(/Characters/Alien/alien_leg.png);
transform-origin: top center;
}
#player.walking > .legs > div.right {
animation: dingle .3s linear infinite alternate;
}
#player.walking > .legs > div.left {
animation: dangle .3s linear infinite alternate;
}
#player > .arms {
position: absolute;
width: 8px;
height: 16px;
top: 48px;
left: 30px;
background-image: url(/Characters/Alien/alien_arm.png);
transform-origin: top center;
}
#player.walking > .arms {
animation: dangle .3s linear infinite alternate;
}
.block {
flex: 0 0 auto;
width: var(--block-size);
@ -113,12 +52,3 @@
display: flex;
flex-flow: row wrap;
}
@keyframes dingle {
from { transform: rotate(20deg); }
to { transform: rotate(-20deg); }
}
@keyframes dangle {
from { transform: rotate(-20deg); }
to { transform: rotate(20deg); }
}

@ -0,0 +1,9 @@
.item.tool-shovel-bronze {
background-image: url("/Items/shovel_bronze.png");
}
.item.weapon-sword-bronze {
background-image: url("/Items/sword_bronze.png");
}
.item.tool-pick-bronze {
background-image: url("/Items/pick_bronze.png");
}

@ -0,0 +1,80 @@
#player {
--player-width: 64px;
--player-height: 76px;
position: absolute;
left: calc(var(--field-width) / 2);
top: calc(var(--field-height) / 2 - 10px);
display: flex;
flex-flow: column nowrap;
width: var(--player-width);
height: var(--player-height);
}
#player > div {
margin: auto;
background: transparent center no-repeat;
background-size: cover;
}
#player.right {
transform: scaleX(-1);
}
#player > .head {
width: 46px;
height: 46px;
background-image: url(/Characters/Alien/alien_head.png);
z-index: 1;
}
#player > .body {
width: 22px;
height: 24px;
margin-top: -8px;
background-image: url(/Characters/Alien/alien_body.png);
}
#player > .legs {
position: relative;
width: 14px;
height: 18px;
}
#player > .legs > div {
position: absolute;
width: 14px;
height: 18px;
background-image: url(/Characters/Alien/alien_leg.png);
transform-origin: top center;
}
#player.walking > .legs > div.right {
animation: dingle .3s linear infinite alternate;
}
#player.walking > .legs > div.left {
animation: dangle .3s linear infinite alternate;
}
#player > .arms {
position: absolute;
width: 8px;
height: 16px;
top: 48px;
left: 30px;
background-image: url(/Characters/Alien/alien_arm.png);
transform-origin: top center;
}
#player.walking > .arms {
animation: dangle .3s linear infinite alternate;
}
#player > .arms > .item {
width: 32px;
height: 32px;
margin: -10px 0 0 -25px;
background-color: transparent;
background-position: center;
background-repeat: no-repeat;
background-size: contain;
transform: rotate(-90deg);
}
@keyframes dingle {
from { transform: rotate(20deg); }
to { transform: rotate(-20deg); }
}
@keyframes dangle {
from { transform: rotate(-20deg); }
to { transform: rotate(20deg); }
}

@ -1,5 +1,7 @@
import { createApp } from "vue";
import "./assets/field.css";
import "./assets/player.css";
import "./assets/items.css";
import App from "./App.vue";
createApp(App).mount("#app");

@ -1,27 +1,29 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ref, computed } from 'vue'
export interface Props {
player: Player
items: InventoryItem[]
shown: boolean
}
defineProps<Props>();
const props = defineProps<Props>();
const emit = defineEmits<{
(event: 'selection', value: InventoryItem | null): void
}>()
// inventory size is 12, and it is so empty
const slots = ref([
{ name: 'Shovel', type: 'tool', icon: 'shovel', quality: 'bronze' },
{ name: 'Sword', type: 'weapon', icon: 'sword', quality: 'bronze' },
{ name: 'Pick Axe', type: 'tool', icon: 'pick', quality: 'bronze' },
null,
null,
null,
null,
null,
null,
null,
null,
null,
])
// inventory size is 15
const slots = Array(15)
const selectedIndex = ref(0)
const inventory = computed(() => {
const inventory = [...props.items, ...slots]
inventory.length = slots.length
return inventory
})
function setSelection(i: number) {
selectedIndex.value = i
emit('selection', inventory.value[i])
}
</script>
<template>
@ -31,14 +33,19 @@ const slots = ref([
</header>
<ol>
<li v-for="item in slots"
:class="[item?.type, item?.icon, item?.quality]"
>
<i v-if="item === null">(empty)</i>
<template v-else>
<template v-for="(item,i) in inventory">
<li v-if="!item" class="empty">
<i>(empty)</i>
</li>
<li v-else
:class="['item', `${item.type}-${item.icon}-${item.quality}`, {
selected: selectedIndex === i
}]"
@click="setSelection(i)"
>
<b>{{ item.name }}</b>
</template>
</li>
</li>
</template>
</ol>
</section>
@ -71,6 +78,13 @@ li {
border-radius: 6px;
background: transparent center no-repeat;
background-size: contain;
cursor: pointer;
}
li:not(.empty):hover, li.selected {
background-color: #FFCA;
}
li.empty {
cursor: not-allowed;
}
li > i, li > b {
position: absolute;
@ -80,13 +94,4 @@ li > i, li > b {
background: black;
font-size: .8em;
}
.tool.shovel.bronze {
background-image: url("/Items/shovel_bronze.png");
}
.weapon.sword.bronze {
background-image: url("/Items/sword_bronze.png");
}
.tool.pick.bronze {
background-image: url("/Items/pick_bronze.png");
}
</style>

@ -7,7 +7,7 @@ const player: Player = reactive({
lastDir: 0,
vx: 0,
vy: 1, // always falling, because of gravity
inventory: {}, // not yet in use
inventory: [], // not yet in use
})
export default function usePlayer() {

Loading…
Cancel
Save