Skip to content

Commit

Permalink
feat(html): added ui interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
tsukinoko-kun committed Jul 23, 2024
1 parent 30aaaf5 commit 68c6981
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 10 deletions.
1 change: 1 addition & 0 deletions lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class App {
await system()
}

// cleanup builtins
{
const pb = this.world.getResourceSafe(PhysicalButtonInput)
if (pb) {
Expand Down
1 change: 1 addition & 0 deletions lib/builtin/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./uiButton"
export * from "./uiInteraction"
export * from "./uiNode"
export * from "./uiStyle"
export * from "./uiText"
15 changes: 15 additions & 0 deletions lib/builtin/components/uiInteraction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class UiInteraction {
private _pressed = false

public get pressed(): boolean {
return this._pressed
}

public triggerDown() {
this._pressed = true
}

public triggerUp() {
this._pressed = false
}
}
3 changes: 2 additions & 1 deletion lib/builtin/plugins/html.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { Plugin } from "../../plugin"
import { HtmlRoot } from "../resources"
import { Schedule } from "../../schedule"
import { renderHtmlRoot } from "../systems"
import { htmlInteraction, renderHtmlRoot } from "../systems"

export function HtmlPlugin(rootSelector: string): Plugin {
return (world) => {
world.insertResource(new HtmlRoot(rootSelector))
world.addSystem(Schedule.Update, renderHtmlRoot)
world.addSystem(Schedule.Start, htmlInteraction)
}
}
40 changes: 39 additions & 1 deletion lib/builtin/systems/html.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
import { res } from "../../resource"
import { HtmlRoot } from "../resources"
import { query } from "../../query"
import { UiButton, UiStyle, UiText } from "../components"
import { UiButton, UiInteraction, UiStyle, UiText } from "../components"
import { Entity } from "../../entity"
import { inWorld, useWorld } from "../../world"
import { Commands } from "../../commands"

export function htmlInteraction(): void {
const root = res(HtmlRoot)
const world = useWorld()

;(root.element as HTMLElement).addEventListener("mousedown", (ev) => {
inWorld(world, () => {
let target = ev.target as Node | null
while (target && !(target instanceof HTMLElement)) {
target = target.parentElement
}
while (target) {
let id = (target as HTMLElement).id
if (!id.startsWith("Entity(")) {
target = target.parentElement
continue
}
const e = Commands.getEntityById(id)
for (const c of Commands.components(e)) {
if (c instanceof UiInteraction) {
c.triggerDown()
}
}
target = target.parentElement
}
})
;(root.element as HTMLElement).addEventListener("mouseup", (ev) => {
inWorld(world, () => {
for (const [interaction] of query([UiInteraction])) {
interaction.triggerUp()
}
})
})
})
}

export function renderHtmlRoot(): void {
const root = res(HtmlRoot)

Expand All @@ -29,6 +65,8 @@ export function renderHtmlRoot(): void {
}
}

entityEl.id = e.toString()

el.appendChild(entityEl)

for (const child of e.children) {
Expand Down
4 changes: 4 additions & 0 deletions lib/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export const Commands = {
world.insertResource(resource)
},
trigger(event: Event) {},
getEntityById(id: number | string): Entity {
const world = useWorld()
return world.getEntityById(id)
},
components(entity: Entity): IterableIterator<Component> {
const world = useWorld()
return world.getEntityComponents(entity).values()
Expand Down
4 changes: 2 additions & 2 deletions lib/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useWorld } from "./world"
export class Entity {
private static current = 0
public readonly children = new Array<Entity>()
private readonly id: number
public readonly id: number

public constructor() {
this.id = Entity.current++
Expand All @@ -16,7 +16,7 @@ export class Entity {
}

public toString(): string {
return `Entity::${this.id}`
return `Entity(${this.id})`
}
}

Expand Down
20 changes: 20 additions & 0 deletions lib/world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ export function useWorld(): World {
return currentWorld
}

export function inWorld(world: World, fn: (world: World) => void): void {
const oldWorld = currentWorld
setCurrentWorld(world)
fn(world)
setCurrentWorld(oldWorld)
}

export class World {
private readonly entities = new Array<Entity>()
private readonly components = new Map<Entity, Map<Ident, Component>>()
Expand All @@ -41,6 +48,19 @@ export class World {
return this.entities
}

public getAllEntities(): IterableIterator<Entity> {
return this.components.keys()
}

public getEntityById(id: number | string): Entity {
for (const e of this.getAllEntities()) {
if (e.id === id || e.toString() === id) {
return e
}
}
throw new Error(`Entity with id ${id} not found in world`)
}

public getComponents(): ReadonlyMap<Entity, ReadonlyMap<Ident, Component>> {
return this.components
}
Expand Down
13 changes: 7 additions & 6 deletions test/src/counter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
Commands,
LogicalButtonInput,
query,
res,
Schedule,
UiButton,
UiInteraction,
UiNode,
UiStyle,
UiText,
Expand All @@ -31,14 +31,15 @@ function spawnUi() {
parent.spawn(new UiText("c"), new UiStyle().set("color", "green"))
})

Commands.spawn(new CounterMarker(), new UiButton(), new UiText("Click me!"))
Commands.spawn(new CounterMarker(), new UiButton(), new UiText("Click me!"), new UiInteraction())
}

function incrementCounter() {
const btn = res(LogicalButtonInput)
if (btn.pressed("b")) {
const counter = res(Counter)
counter.value++
for (const [btn] of query([UiInteraction], query.and(CounterMarker))) {
if (btn.pressed) {
const counter = res(Counter)
counter.value++
}
}
}

Expand Down

0 comments on commit 68c6981

Please sign in to comment.