1
0
forked from noxious/client
2024-06-14 21:17:45 +02:00

250 lines
7.1 KiB
Vue

<template>
<div class="wrapper">
<div class="toolbar">
<div class="tools">
<button class="tool move" :class="{ active: zoneEditorStore.tool === 'move' }" @click="zoneEditorStore.setTool('move')">
<img src="/assets/icons/zoneEditor/move.svg" alt="Move camera" />
</button>
<div class="divider"></div>
<button class="tool pencil" :class="{ active: zoneEditorStore.tool === 'pencil' }" @click="zoneEditorStore.setTool('pencil')">
<img src="/assets/icons/zoneEditor/pencil.svg" alt="Pencil" />
<div class="select" v-if="zoneEditorStore.tool === 'pencil'">
<div class="select-trigger" :class="{ open: selectPencilOpen }" @click="selectPencilOpen = !selectPencilOpen">
{{ zoneEditorStore.drawMode }}
<img src="/assets/icons/zoneEditor/chevron.svg"/>
</div>
<div class="options" v-show="selectPencilOpen && zoneEditorStore.tool === 'pencil'">
<span class="option" @click="setDrawMode('tile')">Tile</span>
<span class="option" @click="setDrawMode('wall')">Wall</span>
<span class="option" @click="setDrawMode('decoration')">Decoration</span>
<span class="option" @click="setDrawMode('teleport')">Teleport</span>
<span class="option" @click="setDrawMode('blocking tile')">Blocking tile</span>
</div>
</div>
</button>
<div class="divider"></div>
<button class="tool eraser" :class="{ active: zoneEditorStore.tool === 'eraser' }" @click="zoneEditorStore.setTool('eraser')">
<img src="/assets/icons/zoneEditor/eraser.svg" alt="Eraser" />
<div class="select" v-if="zoneEditorStore.tool === 'eraser'">
<div class="select-trigger" :class="{ open: selectEraserOpen }" @click="selectEraserOpen = !selectEraserOpen">
{{ zoneEditorStore.drawMode }}
<img src="/assets/icons/zoneEditor/chevron.svg"/>
</div>
<div class="options" v-show="selectEraserOpen">
<span class="option" @click="setDrawMode('tile')">Tile</span>
<span class="option" @click="setDrawMode('wall')">Wall</span>
<span class="option" @click="setDrawMode('decoration')">Decoration</span>
<span class="option" @click="setDrawMode('teleport')">Teleport</span>
<span class="option" @click="setDrawMode('blocking tile')">Blocking tile</span>
</div>
</div>
</button>
<div class="divider"></div>
<button class="tool settings" @click="() => zoneEditorStore.toggleSettingsModal()">
<img src="/assets/icons/zoneEditor/gear.svg" alt="Zone settings" />
</button>
</div>
<div class="buttons">
<button class="btn-cyan">Load</button>
<button class="btn-cyan" @click="() => emit('save')">Save</button>
<button class="btn-cyan" @click="clear">Clear</button>
<button class="btn-cyan" @click="() => zoneEditorStore.toggleActive()">Exit</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from 'vue'
import { useScene } from 'phavuer'
import { getTile, tileToWorldXY } from '@/services/zone'
import config from '@/config'
import { useZoneStore } from '@/stores/zone'
import { useZoneEditorStore } from '@/stores/zoneEditor'
const zoneEditorStore = useZoneEditorStore()
const props = defineProps({
layer: Phaser.Tilemaps.TilemapLayer
})
const scene = useScene()
const emit = defineEmits(['move', 'eraser', 'pencil', 'save'])
// track select state
let selectPencilOpen = ref(false);
let selectEraserOpen = ref(false);
// drawMode
function setDrawMode(value: string) {
zoneEditorStore.setDrawMode(value)
selectPencilOpen.value = false
selectEraserOpen.value = false
}
function drawTile(pointer: Phaser.Input.Pointer) {
if (zoneEditorStore.tool !== 'eraser' && zoneEditorStore.tool !== 'pencil') {
return
}
const px = scene.cameras.main.worldView.x + pointer.x
const py = scene.cameras.main.worldView.y + pointer.y
const pointer_tile = getTile(px, py, props.layer) as Phaser.Tilemaps.Tile
if (!pointer_tile) {
return
}
if (zoneEditorStore.tool === 'eraser') {
emit('eraser', pointer_tile)
}
if (zoneEditorStore.tool === 'pencil') {
emit('pencil', pointer_tile)
}
}
function drawTiles(pointer: Phaser.Input.Pointer) {
if (!pointer.isDown) return
drawTile(pointer)
}
scene.input.on(Phaser.Input.Events.POINTER_UP, drawTile)
scene.input.on(Phaser.Input.Events.POINTER_MOVE, drawTiles)
onBeforeUnmount(() => {
scene.input.off(Phaser.Input.Events.POINTER_UP, drawTile)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, drawTiles)
})
function clear() {
zoneEditorStore.setTiles(Array.from({ length: zoneEditorStore.width ?? 10 }, () => Array.from({ length: zoneEditorStore.height ?? 10 }, () => 0)))
}
</script>
<style scoped lang="scss">
@import '@/assets/scss/main';
.wrapper {
display: flex;
justify-content: center;
margin: 10px;
}
.toolbar {
position: fixed;
top: 20px;
border-radius: 5px;
display: flex;
background: rgba($dark-gray, 0.8);
border: 2px solid $cyan;
color: $light-gray;
padding: 5px 5px 5px 10px;
min-width: 90%;
height: 40px;
.tools {
display: flex;
gap: 10px;
.divider {
width: 1px;
background: $cyan;
}
// vertical center
.tool {
display: flex;
justify-content: center;
align-items: center;
min-width: 40px;
padding: 0;
position: relative;
select {
display: none;
}
&.active {
border-bottom: 3px solid $light-cyan;
gap: 10px;
}
.select {
.select-trigger {
text-transform: capitalize;
display: flex;
gap: 15px;
img {
transform: rotate(0);
transition: ease-in-out 0.2s;
}
&.open {
img {
transform: rotate(180deg);
}
}
}
.options {
display: flex;
flex-direction: column;
position: absolute;
top: calc(100% + 20px);
left: 50%;
transform: translateX(-50%);
background: rgba($dark-gray, 0.8);
border-radius: 5px;
min-width: 100px;
border: 1px solid $cyan;
text-align: left;
.option {
padding: 8px 10px;
position: relative;
&:hover {
background-color: rgba($cyan, 0.5);
}
&::after {
content: '';
position: absolute;
width: 80%;
left: 50%;
transform: translateX(-50%);
bottom: 0;
height: 1px;
background-color: $cyan;
}
&:last-child::after {
display: none;
}
}
}
}
}
img {
filter: invert(1);
width: 20px;
height: 20px;
}
}
.buttons {
display: flex;
gap: 10px;
margin-left: auto;
button {
padding-left: 15px;
padding-right: 15px;
}
}
}
</style>