Skip to content

Commit

Permalink
fix(gui): don't propagate events
Browse files Browse the repository at this point in the history
  • Loading branch information
RSamaium committed Oct 30, 2023
1 parent cc4ff8d commit 1439e0f
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 43 deletions.
21 changes: 1 addition & 20 deletions packages/client/src/Gui/Gui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,10 @@ export class Gui {
COMPONENT_LIBRARIES.push(await import('./React').then(m => m.ReactGui))
}

const propagateEvents = (el: HTMLElement) => {
const eventMap = {
MouseEvent: ['click', 'mousedown', 'mouseup', 'mousemove', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout', 'contextmenu', 'wheel'],
KeyboardEvent: ['keydown', 'keyup', 'keypress', 'keydownoutside', 'keyupoutside', 'keypressoutside'],
PointerEvent: ['pointerdown', 'pointerup', 'pointermove', 'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'pointercancel'],
TouchEvent: ['touchstart', 'touchend', 'touchmove', 'touchcancel']
};

for (let [_Constructor, events] of Object.entries(eventMap)) {
for (let type of events) {
el.addEventListener(type, (e) => {
const _class = window[_Constructor] ?? MouseEvent
this.renderer.canvas.dispatchEvent(new _class(type, e))
});
}
}
}

for (let componentClass of COMPONENT_LIBRARIES) {
const el = document.createElement('div')
elementToPositionAbsolute(el)
el.style['pointer-events'] = 'auto'
propagateEvents(el)
el.style['pointer-events'] = 'none'
guiEl.appendChild(el)
this.librariesInstances.push(new componentClass(el, this))
}
Expand Down
12 changes: 8 additions & 4 deletions packages/client/src/Gui/React.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,19 @@ export class ReactGui {
useEffect(() => {
this._gui.subscribe(gui => setGui(gui))
}, [])

return createElement(RpgReactContext.Provider, {
value: parentGui.getInjectObject()
},
..._gui.filter(ui => ui.display && !ui.attachToSprite).map(ui => createElement(ui.gui, {
..._gui.filter(ui => ui.display && !ui.attachToSprite).map(ui => createElement('div', {
key: ui.name,
...(ui.data || {})
})),
style: { 'pointerEvents': 'auto' },
},
createElement(ui.gui, ui.data || {})
)),
..._gui.filter(ui => ui.display && ui.attachToSprite).map(ui => createElement('div', {
key: ui.name
key: ui.name,
style: { 'pointerEvents': 'auto' },
}, createElement(GuiTooltip(ui)))),
)
}
Expand Down
10 changes: 5 additions & 5 deletions packages/client/src/Gui/Vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ const _hoisted_1 = {
style: { "position": "absolute", "top": "0", "left": "0" }
}
function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {}, [
return (_openBlock(), _createElementBlock("div", { }, [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.fixedGui, (ui) => {
return (_openBlock(), _createElementBlock(_Fragment, null, [
(ui.display)
? (_openBlock(), _createBlock(_resolveDynamicComponent(ui.name), _normalizeProps(_mergeProps({ key: 0 }, ui.data)), null, 16 /* FULL_PROPS */))
? (_openBlock(), _createBlock(_resolveDynamicComponent(ui.name), _normalizeProps(_mergeProps({ key: 0, style: { pointerEvents: 'auto' } }, ui.data)), null, 16 /* FULL_PROPS */))
: _createCommentVNode("v-if", true)
], 64 /* STABLE_FRAGMENT */))
}), 256 /* UNKEYED_FRAGMENT */)),
Expand All @@ -49,7 +49,7 @@ function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock("div", {
style: _normalizeStyle(_ctx.tooltipPosition(tooltip.position))
}, [
(_openBlock(), _createBlock(_resolveDynamicComponent(ui.name), _mergeProps({ ...ui.data, spriteData: tooltip }, {
(_openBlock(), _createBlock(_resolveDynamicComponent(ui.name), _mergeProps({ ...ui.data, spriteData: tooltip, style: { pointerEvents: 'auto' } }, {
ref_for: true,
ref: ui.name
}), null, 16 /* FULL_PROPS */))
Expand All @@ -76,7 +76,7 @@ export class VueGui {
this.renderer = this.clientEngine.renderer
this.gameEngine = this.clientEngine.gameEngine
const { gui } = parentGui

const obj = {
render,
data() {
Expand All @@ -101,7 +101,7 @@ export class VueGui {
tooltipFilter: parentGui.tooltipFilter.bind(parentGui)
},
mounted() {

}
}

Expand Down
44 changes: 43 additions & 1 deletion packages/client/src/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TransitionScene } from './Effects/TransitionScene'
import { Subject, forkJoin } from 'rxjs'
import { GameEngineClient } from './GameEngine'
import { SpinnerGraphic } from './Effects/Spinner'
import { autoDetectRenderer, Container, Graphics, ICanvas, IRenderer } from 'pixi.js'
import { autoDetectRenderer, Container, EventBoundary, FederatedEvent, FederatedPointerEvent, Graphics, ICanvas, IRenderer } from 'pixi.js'

const { elementToPositionAbsolute } = Utils

Expand Down Expand Up @@ -264,4 +264,46 @@ export class RpgRenderer {
this.scene = null
this.sceneContainer.removeChildren()
}

/**
* @title Propagate mouse event to Viewport
* @method propagateEvent(ev)
* @stability 1
* @memberof RpgRenderer
* @returns {void}
*/
propagateEvent(ev: MouseEvent) {
const boundary = new EventBoundary(this.stage);
const event = new FederatedPointerEvent(boundary)
event.global.set(ev.clientX, ev.clientY);
event.type = ev.type;
this.getScene<SceneMap>()?.viewport?.emit(event.type as any, event)
}

/***
* Propagate events from an HTMLElement to the canvas
*
* @title Propagate events
* @method addPropagateEventsFrom(el)
* @stability 1
* @memberof RpgRenderer
* @returns {void}
*/
addPropagateEventsFrom(el: HTMLElement) {
const eventMap = {
MouseEvent: ['click', 'mousedown', 'mouseup', 'mousemove', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout', 'contextmenu', 'wheel'],
KeyboardEvent: ['keydown', 'keyup', 'keypress', 'keydownoutside', 'keyupoutside', 'keypressoutside'],
PointerEvent: ['pointerdown', 'pointerup', 'pointermove', 'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'pointercancel'],
TouchEvent: ['touchstart', 'touchend', 'touchmove', 'touchcancel']
};

for (let [_Constructor, events] of Object.entries(eventMap)) {
for (let type of events) {
el.addEventListener(type, (e) => {
const _class = window[_Constructor] ?? MouseEvent
this.canvas.dispatchEvent(new _class(type, e))
});
}
}
}
}
3 changes: 0 additions & 3 deletions packages/client/src/Scene/Map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,6 @@ export class SceneMap extends Scene {
on(eventName: keyof DisplayObjectEvents, cb: (position: { x: number, y: number }, ev?: any) => any) {
if (!this.viewport) return
this.viewport.eventMode = 'static'
if (eventName == 'click') {
eventName = 'pointerdown'
}
this.viewport.on(eventName, (...args) => {
const ev: FederatedPointerEvent = args[0] as any
const pos = ev.getLocalPosition(this.viewport as Viewport)
Expand Down
5 changes: 4 additions & 1 deletion packages/plugins/mobile-gui/src/controls/main.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="controls">
<div class="controls" @click="propagate">
<div class="d-pad" ref="dPad"></div>
<div class="actions">
<div class="action" @click="action"></div>
Expand Down Expand Up @@ -92,6 +92,9 @@ export default {
},
action() {
this.rpgEngine.controls.applyControl(Control.Action)
},
propagate(evt) {
this.rpgEngine.renderer.propagateEvent(evt)
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion packages/sample2/main/scene-map.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { RpgSceneMapHooks, RpgSceneMap, RpgGui } from '@rpgjs/client'

const sceneMap: RpgSceneMapHooks = {

onAfterLoading(scene) {
scene.on('click', (scene) => {
console.log(scene)
})
},
}

export default sceneMap;
10 changes: 2 additions & 8 deletions tests/unit-tests/specs/scene.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import { RpgClientEngine, RpgModule, RpgClient, RpgSceneMap } from '@rpgjs/clien
import { clear } from '@rpgjs/testing'
import { beforeEach, test, afterEach, expect, describe, vi, afterAll } from 'vitest'

let client: RpgClientEngine,
player: RpgPlayer

beforeEach(async () => {
clear()
})
Expand Down Expand Up @@ -38,15 +35,14 @@ describe('Hooks called', () => {
})
})

// TODO: can't make this test work, because PIXI doesn't propagate the event (only for the test).
test('Scene Click', async () => {
const onClick = vi.fn()

@RpgModule<RpgClient>({
scenes: {
map: {
onAfterLoading(scene) {
scene.on('pointerdown', onClick)
expect(scene).toBeInstanceOf(RpgSceneMap)
}
}
}
Expand All @@ -57,7 +53,5 @@ test('Scene Click', async () => {
client: RpgClientModule
}])

const guiEl = document.getElementById('rpg')?.children[1].children[0]
guiEl?.dispatchEvent(new MouseEvent('pointerdown'))
//expect(onClick).toHaveBeenCalled()
client.renderer.propagateEvent(new MouseEvent('click'))
})

0 comments on commit 1439e0f

Please sign in to comment.