Skip to content

Commit

Permalink
feat: fixture events
Browse files Browse the repository at this point in the history
  • Loading branch information
KeSuave committed Nov 20, 2024
1 parent 728100e commit 1f38211
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 5 deletions.
79 changes: 77 additions & 2 deletions src/lib/components/Fixture.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,100 @@
import type { Comp, GameObj } from "kaplay";
import type {
Comp,
GameObj,
KAPLAYCtx,
KEventController,
MouseButton,
} from "kaplay";
import type { Fixture, FixtureDef } from "planck";

import type { KPBodyComp } from "./Body";
import type { KPShapeComp } from "./Shape";
import { k2pVec2 } from "../utils";

export interface KPFixtureUserData {
gameObj: GameObj;
[key: string]: unknown;
}

export interface KPFixtureDef extends Omit<FixtureDef, "shape"> {
userData?: Record<string, unknown>;
}

export interface KPFixtureComp extends Comp {
fixture: Fixture | null;

isHovering(): boolean;
isClicked(): boolean;
onHover(action: () => void): KEventController;
onHoverUpdate(action: () => void): KEventController;
onHoverEnd(action: () => void): KEventController;
onClick(action: () => void, btn?: MouseButton): KEventController;
}

type FixtureThis = GameObj<KPFixtureComp & KPBodyComp & KPShapeComp>;

export default function fixture(def?: KPFixtureDef): KPFixtureComp {
export default function fixture(
k: KAPLAYCtx,
def?: KPFixtureDef,
): KPFixtureComp {
return {
id: "kpFixture",
require: ["kpBody", "kpShape"],
fixture: null,

isHovering() {
if (!this.fixture) return false;

return this.fixture.testPoint(k2pVec2(k.mousePos()));
},
isClicked() {
return k.isMousePressed() && this.isHovering();
},
onHover(this: FixtureThis, action: () => void) {
let hovering = false;

return this.onUpdate(() => {
if (!hovering) {
if (this.isHovering()) {
hovering = true;

action();
}
} else {
hovering = this.isHovering();
}
});
},
onHoverUpdate(this: FixtureThis, action: () => void) {
return this.onUpdate(() => {
if (this.isHovering()) action();
});
},
onHoverEnd(this: FixtureThis, action: () => void) {
let hovering = false;

return this.onUpdate(() => {
if (hovering) {
if (!this.isHovering()) {
hovering = false;

action();
}
} else {
hovering = this.isHovering();
}
});
},
onClick(this: FixtureThis, action: () => void, btn = "left") {
const evt = k.onMousePress(btn, () => {
if (this.isHovering()) action();
});

this.onDestroy(() => evt.cancel());

return evt;
},

add(this: FixtureThis) {
if (!this.body) throw new Error("kpBody is required");

Expand Down
11 changes: 9 additions & 2 deletions src/lib/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {
} from "./utils";

interface KaPlanckPlugin {
// mimicked transform components
// transform components

/**
* Sets the position of a body.
Expand Down Expand Up @@ -305,6 +305,13 @@ interface KaPlanckPluginOpts {
/**
* A plugin to allows to use PlanckJS seamlessly with KaPlay.
*
* **IMPORTANT**
*
* Vec2 from KaPlay and Vec2 from PlanckJS are different, please use them accordingly.
*
* PlanckJS uses radians for angles while KaPlay uses degrees, please make use of KaPlay's
* tools to convert between them.
*
* @param {KaPlanckPluginOpts} opt
*/
const KaPlanckPlugin =
Expand All @@ -327,7 +334,7 @@ const KaPlanckPlugin =
return body(bodyDef);
},
kpFixture(def?: KPFixtureDef) {
return fixture(def);
return fixture(k, def);
},
kpFixtures(defs: KPFixtureDef[]) {
return fixtures(defs);
Expand Down
20 changes: 19 additions & 1 deletion src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { GameObj, KAPLAYCtx, Vec2 as KaVec2, RenderProps } from "kaplay";
import { Settings, Vec2, type World } from "planck";

import { KPWorldComp } from "./components/World";
import type { KPWorldComp } from "./components/World";

export function u2p(u: number) {
return u * Settings.lengthUnitsPerMeter;
Expand Down Expand Up @@ -54,3 +54,21 @@ export function getRenderProps(obj: GameObj): RenderProps {
uniform: obj.uniform,
};
}

export function findWorldContainer(k: KAPLAYCtx): GameObj<KPWorldComp> | null {
let obj: GameObj<KPWorldComp> | null = null;

const objs = k.get("*");

for (const currentObj of objs) {
const possibleWorldComp = currentObj.c("kpWorld") as KPWorldComp | null;

if (possibleWorldComp) {
obj = currentObj as GameObj<KPWorldComp>;

break;
}
}

return obj;
}

0 comments on commit 1f38211

Please sign in to comment.