forked from noxious/client
Sprite editor changes
This commit is contained in:
parent
32ca61cc50
commit
ba3ed8c099
@ -17,20 +17,24 @@
|
|||||||
<button class="btn-cyan px-4" type="button" @click.prevent="addNewImage">New action</button>
|
<button class="btn-cyan px-4" type="button" @click.prevent="addNewImage">New action</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Accordion v-for="action in spriteActions" :key="action.id">
|
<div v-for="action in spriteActions" :key="action.id">
|
||||||
<template #header>
|
<div class="flex flex-wrap gap-3 mb-3">
|
||||||
<div class="flex items-center">
|
<div v-for="(image, index) in action.sprites" :key="index" class="h-20 w-20 p-4 bg-gray-300 bg-opacity-50 rounded text-center relative group">
|
||||||
{{ action.action }}
|
<img :src="image.url" class="max-w-full max-h-full object-contain pointer-events-none" alt="Uploaded image" @load="updateImageDimensions($event, index)" />
|
||||||
<div class="ml-auto space-x-2">
|
<div v-if="imageDimensions[index]" class="absolute bottom-1 right-1 bg-black/50 text-white text-xs px-1 py-0.5 rounded transition-opacity font-default">{{ imageDimensions[index].width }}x{{ imageDimensions[index].height }}</div>
|
||||||
<button class="btn-cyan px-4 py-1.5 min-w-24" type="button" @click.stop.prevent="openEditorModal(action)">Editor</button>
|
</div>
|
||||||
<button class="btn-red px-4 py-1.5 min-w-24" type="button" @click.stop.prevent="() => spriteActions.splice(spriteActions.indexOf(action), 1)">Delete</button>
|
</div>
|
||||||
|
<div class="flex items-center mb-3 hidden">
|
||||||
|
<div class="mr-3 space-x-2">
|
||||||
|
<button class="btn-cyan px-4 py-1.5 min-w-24 text-left" type="button" @click.stop.prevent="openEditorModal(action)">
|
||||||
|
Editor
|
||||||
|
<div class="flex">
|
||||||
|
<small class="text-xs font-default">{{ action.action }}</small>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
<template #content>
|
|
||||||
<SpriteImagesPreview :spriteActionImages="action.sprites" @tempOffsetChange="(index, offset) => handleTempOffsetChange(action, index, offset)" />
|
|
||||||
</template>
|
|
||||||
</Accordion>
|
|
||||||
<SpriteEditor
|
<SpriteEditor
|
||||||
v-for="[actionId, editorData] in Array.from(openEditors.entries())"
|
v-for="[actionId, editorData] in Array.from(openEditors.entries())"
|
||||||
:key="actionId"
|
:key="actionId"
|
||||||
@ -52,8 +56,6 @@ import { SocketEvent } from '@/application/enums'
|
|||||||
import type { Sprite, SpriteAction } from '@/application/types'
|
import type { Sprite, SpriteAction } from '@/application/types'
|
||||||
import { downloadCache, uuidv4 } from '@/application/utilities'
|
import { downloadCache, uuidv4 } from '@/application/utilities'
|
||||||
import SpriteEditor from '@/components/gameMaster/assetManager/partials/sprite/partials/SpriteEditor.vue'
|
import SpriteEditor from '@/components/gameMaster/assetManager/partials/sprite/partials/SpriteEditor.vue'
|
||||||
import SpriteImagesPreview from '@/components/gameMaster/assetManager/partials/sprite/partials/SpriteImagesPreview.vue'
|
|
||||||
import Accordion from '@/components/utilities/Accordion.vue'
|
|
||||||
import { socketManager } from '@/managers/SocketManager'
|
import { socketManager } from '@/managers/SocketManager'
|
||||||
import { SpriteStorage } from '@/storage/storages'
|
import { SpriteStorage } from '@/storage/storages'
|
||||||
import { useAssetManagerStore } from '@/stores/assetManagerStore'
|
import { useAssetManagerStore } from '@/stores/assetManagerStore'
|
||||||
@ -210,6 +212,24 @@ watch(selectedSprite, (sprite: Sprite | null) => {
|
|||||||
openEditors.value = new Map()
|
openEditors.value = new Map()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
interface SpriteImage {
|
||||||
|
url: string
|
||||||
|
offset: {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageDimensions = ref<{ [key: number]: { width: number; height: number } }>({})
|
||||||
|
|
||||||
|
const updateImageDimensions = (event: Event, index: number) => {
|
||||||
|
const img = event.target as HTMLImageElement
|
||||||
|
imageDimensions.value[index] = {
|
||||||
|
width: img.naturalWidth,
|
||||||
|
height: img.naturalHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (!selectedSprite.value) return
|
if (!selectedSprite.value) return
|
||||||
})
|
})
|
||||||
|
@ -32,8 +32,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-6">
|
<div class="mt-6">
|
||||||
<form class="flex gap-2.5 flex-wrap" @submit.prevent="">
|
<form class="flex gap-2.5 flex-wrap" @submit.prevent="">
|
||||||
|
<div class="relative flex py-5 items-center">
|
||||||
|
<div class="flex-grow border-t border-gray-400"></div>
|
||||||
|
<span class="flex-shrink mx-4 text-gray-400">Sprite action</span>
|
||||||
|
<div class="flex-grow border-solid border-gray-200"></div>
|
||||||
|
</div>
|
||||||
<div class="form-field-full">
|
<div class="form-field-full">
|
||||||
<label for="action">Action</label>
|
<label for="action">Name</label>
|
||||||
<input class="input-field" type="text" name="action" placeholder="Action" />
|
<input class="input-field" type="text" name="action" placeholder="Action" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-field-half">
|
<div class="form-field-half">
|
||||||
@ -44,6 +49,11 @@
|
|||||||
<label for="origin-y">Origin Y</label>
|
<label for="origin-y">Origin Y</label>
|
||||||
<input class="input-field" type="number" step="any" name="origin-y" placeholder="Origin Y" />
|
<input class="input-field" type="number" step="any" name="origin-y" placeholder="Origin Y" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="relative flex py-5 items-center">
|
||||||
|
<div class="flex-grow border-t border-gray-400"></div>
|
||||||
|
<span class="flex-shrink mx-4 text-gray-400">Sprite action image</span>
|
||||||
|
<div class="flex-grow border-t border-gray-400"></div>
|
||||||
|
</div>
|
||||||
<div class="form-field-half">
|
<div class="form-field-half">
|
||||||
<label for="offset-x">Offset X</label>
|
<label for="offset-x">Offset X</label>
|
||||||
<input class="input-field" type="number" step="1" :value="currentSprite?.offset?.x || 0" @input="updateOffset($event, 'x')" :disabled="isAnimating" />
|
<input class="input-field" type="number" step="1" :value="currentSprite?.offset?.x || 0" @input="updateOffset($event, 'x')" :disabled="isAnimating" />
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="flex flex-wrap gap-3">
|
|
||||||
<div v-for="(image, index) in spriteActionImages" :key="index" class="h-20 w-20 p-4 bg-gray-300 bg-opacity-50 rounded text-center relative group">
|
|
||||||
<img :src="image.url" class="max-w-full max-h-full object-contain pointer-events-none" alt="Uploaded image" @load="updateImageDimensions($event, index)" />
|
|
||||||
<div v-if="imageDimensions[index]" class="absolute bottom-1 right-1 bg-black/50 text-white text-xs px-1 py-0.5 rounded transition-opacity font-default">{{ imageDimensions[index].width }}x{{ imageDimensions[index].height }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
interface SpriteImage {
|
|
||||||
url: string
|
|
||||||
offset: {
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
spriteActionImages: SpriteImage[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
spriteActionImages: () => []
|
|
||||||
})
|
|
||||||
|
|
||||||
const imageDimensions = ref<{ [key: number]: { width: number; height: number } }>({})
|
|
||||||
|
|
||||||
const updateImageDimensions = (event: Event, index: number) => {
|
|
||||||
const img = event.target as HTMLImageElement
|
|
||||||
imageDimensions.value[index] = {
|
|
||||||
width: img.naturalWidth,
|
|
||||||
height: img.naturalHeight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,22 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="mb-4 flex flex-col gap-3">
|
|
||||||
<div @click="toggle" class="p-3 bg-gray-300 bg-opacity-50 rounded hover:bg-gray-400 text-white font-default cursor-pointer">
|
|
||||||
<slot name="header" />
|
|
||||||
</div>
|
|
||||||
<transition enter-active-class="transition-all duration-300 ease-in-out" leave-active-class="transition-all duration-300 ease-in-out" enter-from-class="opacity-0 max-h-0" enter-to-class="opacity-100 max-h-96" leave-from-class="opacity-100 max-h-96" leave-to-class="opacity-0 max-h-0">
|
|
||||||
<div v-if="isOpen" class="overflow-hidden">
|
|
||||||
<slot name="content" />
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
|
|
||||||
const isOpen = ref(false)
|
|
||||||
|
|
||||||
const toggle = () => {
|
|
||||||
isOpen.value = !isOpen.value
|
|
||||||
}
|
|
||||||
</script>
|
|
Loading…
x
Reference in New Issue
Block a user