selectable inventory items
This commit is contained in:
parent
c486c12283
commit
e4e3953734
7 changed files with 146 additions and 109 deletions
19
src/App.vue
19
src/App.vue
|
@ -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); }
|
||||
}
|
||||
|
|
9
src/assets/items.css
Normal file
9
src/assets/items.css
Normal file
|
@ -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");
|
||||
}
|
80
src/assets/player.css
Normal file
80
src/assets/player.css
Normal file
|
@ -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…
Reference in a new issue