1
0
forked from noxious/client

#96 - Renamed and refactored pointer handler composables in favor of arrow key movement.

This commit is contained in:
Dennis Postma 2025-01-31 22:26:23 +01:00
parent 0f46e3b6d2
commit 7d3946e274
11 changed files with 187 additions and 245 deletions

View File

@ -175,7 +175,7 @@ onMounted(async () => {
mapStore.setCharacterLoaded(true) mapStore.setCharacterLoaded(true)
// #146 : Set camera position to character, need to be improved still // #146 : Set camera position to character, need to be improved still
scene.cameras.main.startFollow(charSprite.value as Phaser.GameObjects.Sprite) // scene.cameras.main.startFollow(charSprite.value as Phaser.GameObjects.Sprite)
} }
updatePosition(character.positionX, character.positionY, character.rotation) updatePosition(character.positionX, character.positionY, character.rotation)

View File

@ -27,28 +27,20 @@ function handlePointer(pointer: Phaser.Input.Pointer) {
// Check if left mouse button is pressed // Check if left mouse button is pressed
if (!pointer.isDown) return if (!pointer.isDown) return
// Check if shift is not pressed, this means we are moving the camera // Check if shift is pressed or if we're in move mode, this means we are moving the camera
if (pointer.event.shiftKey) return if (pointer.event.shiftKey || mapEditor.tool.value === 'move') return
// Check if draw mode is tile // Check if draw mode is tile
switch (mapEditor.drawMode.value) { switch (mapEditor.drawMode.value) {
case 'tile': case 'tile':
mapTiles.value.handlePointer(pointer) mapTiles.value.handlePointer(pointer)
break
case 'object': case 'object':
mapObjects.value.handlePointer(pointer) mapObjects.value.handlePointer(pointer)
case 'teleport': break
case 'event':
eventTiles.value.handlePointer(pointer) eventTiles.value.handlePointer(pointer)
break
} }
} }
onMounted(() => {
scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointer)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointer)
})
onUnmounted(() => {
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointer)
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointer)
mapEditor.reset()
})
</script> </script>

View File

@ -3,8 +3,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useCameraControls } from '@/composables/useCameraControls' import { useControlsComposable } from '@/composables/useControlsComposable'
import { usePointerHandlers } from '@/composables/usePointerHandlers'
import { Image, useScene } from 'phavuer' import { Image, useScene } from 'phavuer'
import { onBeforeUnmount, ref } from 'vue' import { onBeforeUnmount, ref } from 'vue'
@ -14,45 +13,16 @@ type WayPoint = { visible: boolean; x: number; y: number }
// Props // Props
const props = defineProps<{ layer: Phaser.Tilemaps.TilemapLayer }>() const props = defineProps<{ layer: Phaser.Tilemaps.TilemapLayer }>()
// Constants
const ZOOM_SETTINGS = {
WHEEL_FACTOR: 0.005,
KEY_FACTOR: 0.3,
MIN: 1,
MAX: 3
} as const
// Setup // Setup
const scene = useScene() const scene = useScene()
const waypoint = ref<WayPoint>({ visible: false, x: 0, y: 0 }) const waypoint = ref<WayPoint>({ visible: false, x: 0, y: 0 })
const { camera } = useCameraControls(scene) const { setupControls, cleanupControls } = useControlsComposable(scene, props.layer, waypoint)
const { setupPointerHandlers, cleanupPointerHandlers } = usePointerHandlers(scene, props.layer, waypoint, camera)
// Handlers
function handleScrollZoom(pointer: Phaser.Input.Pointer) {
if (!(pointer.event instanceof WheelEvent && pointer.event.shiftKey)) return
const zoomLevel = Phaser.Math.Clamp(camera.zoom - pointer.event.deltaY * ZOOM_SETTINGS.WHEEL_FACTOR, ZOOM_SETTINGS.MIN, ZOOM_SETTINGS.MAX)
camera.setZoom(zoomLevel)
}
function handleKeyComboZoom(event: { keyCodes: number[] }) {
const deltaY = event.keyCodes[1] === 38 ? 1 : -1 // 38 is Up, 40 is Down
const zoomLevel = Phaser.Math.Clamp(camera.zoom + deltaY * ZOOM_SETTINGS.KEY_FACTOR, ZOOM_SETTINGS.MIN, ZOOM_SETTINGS.MAX)
camera.setZoom(zoomLevel)
}
// Event setup // Event setup
setupPointerHandlers() setupControls()
scene.input.keyboard?.createCombo([16, 38], { resetOnMatch: true }) // Shift + Up
scene.input.keyboard?.createCombo([16, 40], { resetOnMatch: true }) // Shift + Down
scene.input.keyboard?.on('keycombomatch', handleKeyComboZoom)
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleScrollZoom)
// Cleanup // Cleanup
onBeforeUnmount(() => { onBeforeUnmount(() => {
cleanupPointerHandlers() cleanupControls()
scene.input.keyboard?.off('keycombomatch')
scene.input.off(Phaser.Input.Events.POINTER_WHEEL, handleScrollZoom)
}) })
</script> </script>

View File

@ -0,0 +1,69 @@
import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { ref, type Ref } from 'vue'
export function useBaseControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore()
const pointerStartPosition = ref({ x: 0, y: 0 })
const dragThreshold = 5 // pixels
function updateWaypoint(worldX: number, worldY: number) {
const pointerTile = getTile(layer, worldX, worldY)
if (!pointerTile) {
waypoint.value.visible = false
return
}
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.worldPositionX || !worldPoint.worldPositionX) return
waypoint.value = {
visible: true,
x: worldPoint.worldPositionX,
y: worldPoint.worldPositionY + config.tile_size.height + 15
}
}
function handleDragMap(pointer: Phaser.Input.Pointer) {
if (!gameStore.game.isPlayerDraggingCamera) return
const deltaX = pointer.x - pointerStartPosition.value.x
const deltaY = pointer.y - pointerStartPosition.value.y
if (Math.abs(deltaX) <= dragThreshold && Math.abs(deltaY) <= dragThreshold) return
const scrollX = camera.scrollX - (deltaX / camera.zoom)
const scrollY = camera.scrollY - (deltaY / camera.zoom)
camera.setScroll(scrollX, scrollY)
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
}
function startDragging(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
gameStore.setPlayerDraggingCamera(true)
}
function stopDragging() {
gameStore.setPlayerDraggingCamera(false)
}
function handleZoom(pointer: Phaser.Input.Pointer) {
if (pointer.event instanceof WheelEvent && pointer.event.shiftKey) {
const deltaY = pointer.event.deltaY
const zoomLevel = camera.zoom - deltaY * 0.005
if (zoomLevel > 0 && zoomLevel < 3) {
camera.setZoom(zoomLevel)
}
}
}
return {
updateWaypoint,
handleDragMap,
startDragging,
stopDragging,
handleZoom,
pointerStartPosition
}
}

View File

@ -0,0 +1,46 @@
import { getTile } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { useBaseControlsComposable } from './useBaseControlsComposable'
import type { Ref } from 'vue'
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 baseHandlers = useBaseControlsComposable(scene, layer, waypoint, camera)
function handlePointerDown(pointer: Phaser.Input.Pointer) {
baseHandlers.startDragging(pointer)
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
baseHandlers.updateWaypoint(pointer.worldX, pointer.worldY)
baseHandlers.handleDragMap(pointer)
}
function handlePointerUp(pointer: Phaser.Input.Pointer) {
baseHandlers.stopDragging()
const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
if (!pointerTile) return
gameStore.connection?.emit('map:character:move', {
positionX: pointerTile.x,
positionY: pointerTile.y
})
}
const setupControls = () => {
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_UP, handlePointerUp)
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
}
const cleanupControls = () => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
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_WHEEL, baseHandlers.handleZoom)
}
return { setupControls, cleanupControls }
}

View File

@ -0,0 +1,42 @@
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useBaseControlsComposable } from './useBaseControlsComposable'
import { computed, type Ref } from 'vue'
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 baseHandlers = useBaseControlsComposable(scene, layer, waypoint, camera)
const isMoveTool = computed(() => mapEditor.tool.value === 'move')
function handlePointerDown(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) {
baseHandlers.startDragging(pointer)
}
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) {
baseHandlers.handleDragMap(pointer)
}
baseHandlers.updateWaypoint(pointer.worldX, pointer.worldY)
}
function handlePointerUp(pointer: Phaser.Input.Pointer) {
baseHandlers.stopDragging()
}
const setupControls = () => {
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_UP, handlePointerUp)
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
}
const cleanupControls = () => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
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_WHEEL, baseHandlers.handleZoom)
}
return { setupControls, cleanupControls }
}

View File

@ -1,70 +0,0 @@
import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useGameStore } from '@/stores/gameStore'
import { ref, type Ref } from 'vue'
export function useGamePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore()
const pointerStartPosition = ref({ x: 0, y: 0 })
const dragThreshold = 5 // pixels
function updateWaypoint(worldX: number, worldY: number) {
const pointerTile = getTile(layer, worldX, worldY)
if (!pointerTile) {
waypoint.value.visible = false
return
}
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.worldPositionX || !worldPoint.worldPositionX) return
waypoint.value = {
visible: true,
x: worldPoint.worldPositionX,
y: worldPoint.worldPositionY + config.tile_size.height + 15
}
}
function handlePointerDown(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = pointer.position
gameStore.setPlayerDraggingCamera(true)
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
updateWaypoint(pointer.worldX, pointer.worldY)
if (!gameStore.game.isPlayerDraggingCamera) return
// If the distance is less than the drag threshold, return
// We do this to prevent the camera from scrolling too quickly
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
if (distance <= dragThreshold) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
}
function handlePointerUp(pointer: Phaser.Input.Pointer) {
gameStore.setPlayerDraggingCamera(false)
const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
if (!pointerTile) return
gameStore.connection?.emit('map:character:move', {
positionX: pointerTile.x,
positionY: pointerTile.y
})
}
const setupPointerHandlers = () => {
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_UP, handlePointerUp)
}
const cleanupPointerHandlers = () => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
}
return { setupPointerHandlers, cleanupPointerHandlers }
}

View File

@ -1,86 +0,0 @@
import config from '@/application/config'
import { getTile, tileToWorldXY } from '@/composables/mapComposable'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useGameStore } from '@/stores/gameStore'
import { computed, ref, type Ref } from 'vue'
export function useMapEditorPointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const gameStore = useGameStore()
const mapEditor = useMapEditorComposable()
const isMoveTool = computed(() => mapEditor.tool.value === 'move')
const pointerStartPosition = ref({ x: 0, y: 0 })
const dragThreshold = 5 // pixels
function updateWaypoint(worldX: number, worldY: number) {
const pointerTile = getTile(layer, worldX, worldY)
if (!pointerTile) {
waypoint.value.visible = false
return
}
const worldPoint = tileToWorldXY(layer, pointerTile.x, pointerTile.y)
if (!worldPoint.worldPositionX || !worldPoint.worldPositionX) return
waypoint.value = {
visible: true,
x: worldPoint.worldPositionX,
y: worldPoint.worldPositionY + config.tile_size.height + 15
}
}
function handlePointerDown(pointer: Phaser.Input.Pointer) {
pointerStartPosition.value = { x: pointer.x, y: pointer.y }
if (isMoveTool.value || pointer.event.shiftKey) {
gameStore.setPlayerDraggingCamera(true)
}
}
function dragMap(pointer: Phaser.Input.Pointer) {
if (!gameStore.game.isPlayerDraggingCamera) return
const distance = Phaser.Math.Distance.Between(pointerStartPosition.value.x, pointerStartPosition.value.y, pointer.x, pointer.y)
// If the distance is less than the drag threshold, return
// We do this to prevent the camera from scrolling too quickly
if (distance <= dragThreshold) return
camera.setScroll(camera.scrollX - (pointer.x - pointer.prevPosition.x) / camera.zoom, camera.scrollY - (pointer.y - pointer.prevPosition.y) / camera.zoom)
}
function handlePointerMove(pointer: Phaser.Input.Pointer) {
if (isMoveTool.value || pointer.event.shiftKey) {
dragMap(pointer)
}
updateWaypoint(pointer.worldX, pointer.worldY)
}
function handlePointerUp(pointer: Phaser.Input.Pointer) {
gameStore.setPlayerDraggingCamera(false)
}
function handleZoom(pointer: Phaser.Input.Pointer) {
if (pointer.event instanceof WheelEvent && pointer.event.shiftKey) {
const deltaY = pointer.event.deltaY
const zoomLevel = camera.zoom - deltaY * 0.005
if (zoomLevel > 0 && zoomLevel < 3) {
camera.setZoom(zoomLevel)
}
}
}
const setupPointerHandlers = () => {
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_UP, handlePointerUp)
scene.input.on(Phaser.Input.Events.POINTER_WHEEL, handleZoom)
}
const cleanupPointerHandlers = () => {
scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
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_WHEEL, handleZoom)
}
return { setupPointerHandlers, cleanupPointerHandlers }
}

View File

@ -1,15 +0,0 @@
import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore'
export function useCameraControls(scene: Phaser.Scene) {
const gameStore = useGameStore()
const camera = scene.cameras.main
const onPointerDown = () => gameStore.setPlayerDraggingCamera(true)
const onPointerUp = () => gameStore.setPlayerDraggingCamera(false)
scene.input.on(Phaser.Input.Events.POINTER_DOWN, onPointerDown)
scene.input.on(Phaser.Input.Events.POINTER_UP, onPointerUp)
return { camera }
}

View File

@ -0,0 +1,19 @@
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { computed, watch, type Ref } from 'vue'
import { useGameControlsComposable } from '@/composables/controls/useGameControlsComposable'
import { useMapEditorControlsComposable } from '@/composables/controls/useMapEditorControlsComposable'
import { useGameStore } from '@/stores/gameStore'
export function useControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>) {
const camera = scene.cameras.main
const mapEditor = useMapEditorComposable()
const gameHandlers = useGameControlsComposable(scene, layer, waypoint, camera)
const mapEditorHandlers = useMapEditorControlsComposable(scene, layer, waypoint, camera)
const currentHandlers = computed(() => (mapEditor.active.value ? mapEditorHandlers : gameHandlers))
const setupControls = () => currentHandlers.value.setupControls()
const cleanupControls = () => currentHandlers.value.cleanupControls()
return { setupControls, cleanupControls, camera }
}

View File

@ -1,25 +0,0 @@
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { computed, watch, type Ref } from 'vue'
import { useGamePointerHandlers } from './pointerHandlers/useGamePointerHandlers'
import { useMapEditorPointerHandlers } from './pointerHandlers/useMapEditorPointerHandlers'
export function usePointerHandlers(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
const mapEditor = useMapEditorComposable()
const gameHandlers = useGamePointerHandlers(scene, layer, waypoint, camera)
const mapEditorHandlers = useMapEditorPointerHandlers(scene, layer, waypoint, camera)
const currentHandlers = computed(() => (mapEditor.active.value ? mapEditorHandlers : gameHandlers))
const setupPointerHandlers = () => currentHandlers.value.setupPointerHandlers()
const cleanupPointerHandlers = () => currentHandlers.value.cleanupPointerHandlers()
watch(
() => mapEditor.active.value,
() => {
cleanupPointerHandlers()
setupPointerHandlers()
}
)
return { setupPointerHandlers, cleanupPointerHandlers }
}