Merge remote-tracking branch 'origin/main' into feature/#321
This commit is contained in:
commit
09b458eeef
@ -5,12 +5,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="absolute -bottom-3 left-1/2 -translate-x-1/2 flex gap-1">
|
<div class="absolute -bottom-3 left-1/2 -translate-x-1/2 flex gap-1">
|
||||||
<button class="w-6 h-6 relative p-0">
|
<button class="w-6 h-6 relative p-0">
|
||||||
<img class="w-3 h-3 center-element" src="/assets/icons/plus-icon.svg" alt="Zoom-in button icon"/>
|
<img class="w-3 h-3 center-element" src="/assets/icons/plus-icon.svg" alt="Zoom-in button icon" />
|
||||||
<img class="w-full h-full" src="/assets/ui-elements/button-ui-box-textured.svg" alt=""/>
|
<img class="w-full h-full" src="/assets/ui-elements/button-ui-box-textured.svg" alt="" />
|
||||||
</button>
|
</button>
|
||||||
<button class="w-6 h-6 relative p-0">
|
<button class="w-6 h-6 relative p-0">
|
||||||
<img class="w-3 h-3 center-element" src="/assets/icons/minus-icon.svg" alt="Zoom-out button icon"/>
|
<img class="w-3 h-3 center-element" src="/assets/icons/minus-icon.svg" alt="Zoom-out button icon" />
|
||||||
<img class="w-full h-full" src="/assets/ui-elements/button-ui-box-textured.svg" alt=""/>
|
<img class="w-full h-full" src="/assets/ui-elements/button-ui-box-textured.svg" alt="" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +34,12 @@ gameStore.connection?.on('map:character:leave', (characterId: UUID) => {
|
|||||||
|
|
||||||
gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
|
gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
|
||||||
mapStore.updateCharacterPosition(data)
|
mapStore.updateCharacterPosition(data)
|
||||||
|
// @TODO: Replace with universal class, composable or store
|
||||||
|
if (data.characterId === gameStore.character?.id) {
|
||||||
|
gameStore.character!.positionX = data.positionX
|
||||||
|
gameStore.character!.positionY = data.positionY
|
||||||
|
gameStore.character!.rotation = data.rotation
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
@ -48,10 +48,7 @@
|
|||||||
<input v-model.number="action.frameRate" class="input-field" type="number" step="any" name="frame-speed" placeholder="Frame rate" />
|
<input v-model.number="action.frameRate" class="input-field" type="number" step="any" name="frame-speed" placeholder="Frame rate" />
|
||||||
</div>
|
</div>
|
||||||
<div class="form-field-full">
|
<div class="form-field-full">
|
||||||
<SpriteActionsInput
|
<SpriteActionsInput v-model="action.sprites" @tempOffsetChange="(index, offset) => handleTempOffsetChange(action, index, offset)" />
|
||||||
v-model="action.sprites"
|
|
||||||
@tempOffsetChange="(index, offset) => handleTempOffsetChange(action, index, offset)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
<div class="flex flex-wrap gap-3">
|
<div class="flex flex-wrap gap-3">
|
||||||
<div v-for="(image, index) in modelValue" :key="index" class="h-20 w-20 p-4 bg-gray-300 bg-opacity-50 rounded text-center relative group cursor-move" draggable="true" @dragstart="dragStart($event, index)" @dragover.prevent @dragenter.prevent @drop="drop($event, index)">
|
<div v-for="(image, index) in modelValue" :key="index" class="h-20 w-20 p-4 bg-gray-300 bg-opacity-50 rounded text-center relative group cursor-move" draggable="true" @dragstart="dragStart($event, index)" @dragover.prevent @dragenter.prevent @drop="drop($event, index)">
|
||||||
<img :src="image.url" class="max-w-full max-h-full object-contain pointer-events-none" alt="Uploaded image" @load="updateImageDimensions($event, index)" />
|
<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="image.dimensions" class="absolute bottom-1 right-1 bg-black/50 text-white text-xs px-1 py-0.5 rounded transition-opacity font-default">
|
<div v-if="image.dimensions" class="absolute bottom-1 right-1 bg-black/50 text-white text-xs px-1 py-0.5 rounded transition-opacity font-default">{{ image.dimensions.width }}x{{ image.dimensions.height }}</div>
|
||||||
{{ image.dimensions.width }}x{{ image.dimensions.height }}
|
|
||||||
</div>
|
|
||||||
<div class="absolute top-1 left-1 flex-row space-y-1">
|
<div class="absolute top-1 left-1 flex-row space-y-1">
|
||||||
<button @click.stop="deleteImage(index)" class="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity" aria-label="Delete image">
|
<button @click.stop="deleteImage(index)" class="bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity" aria-label="Delete image">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
@ -78,7 +76,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:modelValue', value: SpriteImage[]): void
|
(e: 'update:modelValue', value: SpriteImage[]): void
|
||||||
(e: 'close'): void
|
(e: 'close'): void
|
||||||
(e: 'tempOffsetChange', index: number, offset: { x: number, y: number }): void
|
(e: 'tempOffsetChange', index: number, offset: { x: number; y: number }): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const fileInput = ref<HTMLInputElement | null>(null)
|
const fileInput = ref<HTMLInputElement | null>(null)
|
||||||
|
@ -39,15 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="block mb-2 text-white">Frame: {{ currentFrame + 1 }} of {{ sprites.length }}</label>
|
<label class="block mb-2 text-white">Frame: {{ currentFrame + 1 }} of {{ sprites.length }}</label>
|
||||||
<input
|
<input type="range" v-model.number="currentFrame" :min="0" :max="sprites.length - 1" step="1" class="w-full accent-cyan-500" @input="stopAnimation" />
|
||||||
type="range"
|
|
||||||
v-model.number="currentFrame"
|
|
||||||
:min="0"
|
|
||||||
:max="sprites.length - 1"
|
|
||||||
step="1"
|
|
||||||
class="w-full accent-cyan-500"
|
|
||||||
@input="stopAnimation"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="block mb-2 text-white">Zoom: {{ zoomLevel }}%</label>
|
<label class="block mb-2 text-white">Zoom: {{ zoomLevel }}%</label>
|
||||||
@ -69,7 +61,7 @@ const props = defineProps<{
|
|||||||
frameRate: number
|
frameRate: number
|
||||||
isModalOpen?: boolean
|
isModalOpen?: boolean
|
||||||
tempOffsetIndex?: number
|
tempOffsetIndex?: number
|
||||||
tempOffset?: { x: number, y: number }
|
tempOffset?: { x: number; y: number }
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
/>
|
/>
|
||||||
<MapList ref="mapModal" @open-create-map="mapSettingsModal?.open" />
|
<MapList ref="mapModal" @open-create-map="mapSettingsModal?.open" />
|
||||||
<TileList ref="tileList" />
|
<TileList ref="tileList" />
|
||||||
<ObjectList ref="objectList"/>
|
<ObjectList ref="objectList" />
|
||||||
<MapSettings ref="mapSettingsModal" />
|
<MapSettings ref="mapSettingsModal" />
|
||||||
<TeleportModal ref="teleportModal" />
|
<TeleportModal ref="teleportModal" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,8 +32,8 @@ export function useBaseControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
|
|||||||
|
|
||||||
if (Math.abs(deltaX) <= dragThreshold && Math.abs(deltaY) <= dragThreshold) return
|
if (Math.abs(deltaX) <= dragThreshold && Math.abs(deltaY) <= dragThreshold) return
|
||||||
|
|
||||||
const scrollX = camera.scrollX - (deltaX / camera.zoom)
|
const scrollX = camera.scrollX - deltaX / camera.zoom
|
||||||
const scrollY = camera.scrollY - (deltaY / camera.zoom)
|
const scrollY = camera.scrollY - deltaY / camera.zoom
|
||||||
|
|
||||||
camera.setScroll(scrollX, scrollY)
|
camera.setScroll(scrollX, scrollY)
|
||||||
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
|
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { getTile } from '@/composables/mapComposable'
|
import { getTile } from '@/composables/mapComposable'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useGameStore } from '@/stores/gameStore'
|
||||||
import { useBaseControlsComposable } from './useBaseControlsComposable'
|
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
|
import { useBaseControlsComposable } from './useBaseControlsComposable'
|
||||||
|
|
||||||
export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
|
export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
|
||||||
const gameStore = useGameStore()
|
const gameStore = useGameStore()
|
||||||
@ -28,11 +28,70 @@ export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pressedKeys = new Set<string>()
|
||||||
|
let moveInterval: number | null = null
|
||||||
|
|
||||||
|
function handleKeyDown(event: KeyboardEvent) {
|
||||||
|
if (!gameStore.character) return
|
||||||
|
|
||||||
|
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
|
||||||
|
pressedKeys.add(event.key)
|
||||||
|
|
||||||
|
// Start movement loop if not already running
|
||||||
|
if (!moveInterval) {
|
||||||
|
moveInterval = window.setInterval(moveCharacter, 250) // Adjust timing as needed
|
||||||
|
moveCharacter() // Move immediately on first press
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeyUp(event: KeyboardEvent) {
|
||||||
|
pressedKeys.delete(event.key)
|
||||||
|
|
||||||
|
// If no movement keys are pressed, clear the interval
|
||||||
|
if (pressedKeys.size === 0 && moveInterval) {
|
||||||
|
clearInterval(moveInterval)
|
||||||
|
moveInterval = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveCharacter() {
|
||||||
|
if (!gameStore.character) return
|
||||||
|
const { positionX, positionY } = gameStore.character
|
||||||
|
|
||||||
|
if (pressedKeys.has('ArrowLeft')) {
|
||||||
|
gameStore.connection?.emit('map:character:move', {
|
||||||
|
positionX: positionX - 1,
|
||||||
|
positionY: positionY
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (pressedKeys.has('ArrowRight')) {
|
||||||
|
gameStore.connection?.emit('map:character:move', {
|
||||||
|
positionX: positionX + 1,
|
||||||
|
positionY: positionY
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (pressedKeys.has('ArrowUp')) {
|
||||||
|
gameStore.connection?.emit('map:character:move', {
|
||||||
|
positionX: positionX,
|
||||||
|
positionY: positionY - 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (pressedKeys.has('ArrowDown')) {
|
||||||
|
gameStore.connection?.emit('map:character:move', {
|
||||||
|
positionX: positionX,
|
||||||
|
positionY: positionY + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const setupControls = () => {
|
const setupControls = () => {
|
||||||
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
|
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
|
||||||
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
|
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
|
||||||
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
|
scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
|
||||||
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
|
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
|
||||||
|
scene.input.keyboard!.on('keydown', handleKeyDown)
|
||||||
|
scene.input.keyboard!.on('keyup', handleKeyUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanupControls = () => {
|
const cleanupControls = () => {
|
||||||
@ -40,6 +99,8 @@ export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Til
|
|||||||
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
|
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
|
||||||
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
|
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
|
||||||
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
|
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
|
||||||
|
scene.input.keyboard!.off('keydown', handleKeyDown)
|
||||||
|
scene.input.keyboard!.off('keyup', handleKeyUp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { setupControls, cleanupControls }
|
return { setupControls, cleanupControls }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
|
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
|
||||||
import { useBaseControlsComposable } from './useBaseControlsComposable'
|
|
||||||
import { computed, type Ref } from 'vue'
|
import { computed, type Ref } from 'vue'
|
||||||
|
import { useBaseControlsComposable } from './useBaseControlsComposable'
|
||||||
|
|
||||||
export function useMapEditorControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
|
export function useMapEditorControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
|
||||||
const mapEditor = useMapEditorComposable()
|
const mapEditor = useMapEditorComposable()
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
|
|
||||||
import { computed, watch, type Ref } from 'vue'
|
|
||||||
import { useGameControlsComposable } from '@/composables/controls/useGameControlsComposable'
|
import { useGameControlsComposable } from '@/composables/controls/useGameControlsComposable'
|
||||||
import { useMapEditorControlsComposable } from '@/composables/controls/useMapEditorControlsComposable'
|
import { useMapEditorControlsComposable } from '@/composables/controls/useMapEditorControlsComposable'
|
||||||
import { useGameStore } from '@/stores/gameStore'
|
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
|
||||||
|
import { computed, type Ref } from 'vue'
|
||||||
|
|
||||||
export function useControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>) {
|
export function useControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>) {
|
||||||
const camera = scene.cameras.main
|
const camera = scene.cameras.main
|
||||||
const mapEditor = useMapEditorComposable()
|
|
||||||
const gameHandlers = useGameControlsComposable(scene, layer, waypoint, camera)
|
const gameHandlers = useGameControlsComposable(scene, layer, waypoint, camera)
|
||||||
const mapEditorHandlers = useMapEditorControlsComposable(scene, layer, waypoint, camera)
|
const mapEditorHandlers = useMapEditorControlsComposable(scene, layer, waypoint, camera)
|
||||||
|
|
||||||
|
const mapEditor = useMapEditorComposable()
|
||||||
const currentHandlers = computed(() => (mapEditor.active.value ? mapEditorHandlers : gameHandlers))
|
const currentHandlers = computed(() => (mapEditor.active.value ? mapEditorHandlers : gameHandlers))
|
||||||
|
|
||||||
const setupControls = () => currentHandlers.value.setupControls()
|
const setupControls = () => currentHandlers.value.setupControls()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user