From cf28b9a59096ad23f96cb940f54837c82573476a Mon Sep 17 00:00:00 2001 From: KeSuave Date: Sun, 15 Dec 2024 08:52:26 -0800 Subject: [PATCH] feat: inspect drawing for fixtures --- src/examples/SphereStack.ts | 47 ++++++++++++++++++++++++++++++ src/lib/components/BoxShape.ts | 18 +++++++++++- src/lib/components/ChainShape.ts | 25 +++++++++++++++- src/lib/components/CircleShape.ts | 23 ++++++++++++++- src/lib/components/EdgeShape.ts | 15 +++++++++- src/lib/components/Fixture.ts | 27 ++++++++++++++++- src/lib/components/PolygonShape.ts | 13 ++++++++- src/lib/components/Shape.ts | 15 ++++++++++ src/lib/internals.ts | 13 +++++++++ src/shared.ts | 2 ++ 10 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 src/examples/SphereStack.ts diff --git a/src/examples/SphereStack.ts b/src/examples/SphereStack.ts new file mode 100644 index 0000000..b02450d --- /dev/null +++ b/src/examples/SphereStack.ts @@ -0,0 +1,47 @@ +import { Vec2 } from "planck"; +import { addScenesButtons, type KAPLANCKCtx } from "../shared"; + +const sphereStackScene = (k: KAPLANCKCtx) => () => { + const scene = k.add([]); + + const worldContainer = scene.add([k.kpWorld(new Vec2(0, 10))]); + + const COUNT = 10; + + worldContainer.add([ + k.kpPos(k.kpCenter().add({ x: 0, y: 10 })), + k.kpRotate(), + k.kpBody(), + k.kpEdgeShape({ + v1: new Vec2(-40, 0), + v2: new Vec2(40, 0), + draw: false, + }), + k.kpFixture({ density: 0 }), + ]); + + for (let i = 0; i < COUNT; i++) { + const sphere = worldContainer.add([ + k.kpPos( + k.kpCenter().add({ + x: 0, + y: 4 - 3 * i, + }), + ), + k.kpRotate(), + k.kpCircleShape({ radius: 1, draw: true }), + k.kpBody({ type: "dynamic" }), + k.kpFixture({ density: 1 }), + ]); + + k.wait(10, () => { + sphere.setAwake(false); + }); + + sphere.setLinearVelocity({ x: 0, y: 50 }); + } + + addScenesButtons(k, scene); +}; + +export default sphereStackScene; diff --git a/src/lib/components/BoxShape.ts b/src/lib/components/BoxShape.ts index b2b538e..47456f3 100644 --- a/src/lib/components/BoxShape.ts +++ b/src/lib/components/BoxShape.ts @@ -1,5 +1,5 @@ import type { GameObj, KAPLAYCtx } from "kaplay"; -import { type KPShapeComp, type KPShapeOpt } from "./Shape"; +import type { KPShapeColor, KPShapeComp, KPShapeOpt } from "./Shape"; import { BoxShape, type Vec2Value } from "planck"; import { getRenderProps, m2p, p2kVec2 } from "../internals"; @@ -65,6 +65,22 @@ export default function boxShape( return _shape; }, + kpDrawInspect(color: KPShapeColor) { + const width = m2p(opt.width); + const height = m2p(opt.height); + const pos = k.vec2(p2kVec2(k, this.shape.m_centroid)); + + k.drawRect({ + width, + height, + pos, + anchor: "center", + fill: true, + color: k.rgb(color.r, color.g, color.b), + opacity: color.a, + }); + }, + add(this: BoxShapeCompThis) { _shape = new BoxShape( opt.width / 2, diff --git a/src/lib/components/ChainShape.ts b/src/lib/components/ChainShape.ts index f529938..2f430d9 100644 --- a/src/lib/components/ChainShape.ts +++ b/src/lib/components/ChainShape.ts @@ -1,5 +1,5 @@ import type { GameObj, KAPLAYCtx, Vec2 as KaVec2 } from "kaplay"; -import { type KPShapeComp, type KPShapeOpt } from "./Shape"; +import type { KPShapeColor, KPShapeComp, KPShapeOpt } from "./Shape"; import { ChainShape, type Vec2Value } from "planck"; import { getRenderProps, p2kVec2 } from "../internals"; @@ -38,6 +38,29 @@ export default function chainShape( return _shape; }, + kpDrawInspect(color: KPShapeColor) { + const vertices = this.shape.m_vertices; + + const pts: KaVec2[] = []; + for (let i = 0; i < vertices.length - 1; i++) { + pts.push(p2kVec2(k, vertices[i])); + + if (i === vertices.length - 2) { + pts.push(p2kVec2(k, vertices[i + 1])); + } + } + + if (opt?.loop) { + pts.push(pts[0]); + } + + k.drawLines({ + pts, + color: k.rgb(color.r, color.g, color.b), + opacity: color.a, + }); + }, + add() { _shape = new ChainShape(opt?.vertices, opt?.loop); }, diff --git a/src/lib/components/CircleShape.ts b/src/lib/components/CircleShape.ts index d24e746..c634623 100644 --- a/src/lib/components/CircleShape.ts +++ b/src/lib/components/CircleShape.ts @@ -1,5 +1,5 @@ import type { GameObj, KAPLAYCtx } from "kaplay"; -import { type KPShapeComp, type KPShapeOpt } from "./Shape"; +import type { KPShapeColor, KPShapeComp, KPShapeOpt } from "./Shape"; import { CircleShape, Vec2, type Vec2Value } from "planck"; import { getRenderProps, m2p, p2kVec2 } from "../internals"; @@ -39,6 +39,22 @@ export default function circleShape( return _shape; }, + kpDrawInspect(color: KPShapeColor) { + k.drawCircle({ + pos: p2kVec2(k, this.shape.getCenter()), + radius: m2p(this.shape.getRadius()), + fill: true, + color: k.rgb(color.r, color.g, color.b), + opacity: color.a, + }); + + k.drawLine({ + p1: k.vec2(), + p2: k.vec2(m2p(this.shape.getRadius()), 0), + color: k.rgb(color.r, color.g, color.b), + }); + }, + add() { _shape = new CircleShape(opt?.position ?? Vec2.zero(), opt?.radius); }, @@ -53,6 +69,11 @@ export default function circleShape( radius: m2p(this.shape.getRadius()), fill: opt?.fill, }); + + k.drawLine({ + p1: k.vec2(), + p2: k.vec2(m2p(this.shape.getRadius()), 0), + }); }, destroy() { _shape = null; diff --git a/src/lib/components/EdgeShape.ts b/src/lib/components/EdgeShape.ts index bd2727b..05d64bc 100644 --- a/src/lib/components/EdgeShape.ts +++ b/src/lib/components/EdgeShape.ts @@ -1,5 +1,5 @@ import type { GameObj, KAPLAYCtx } from "kaplay"; -import { type KPShapeComp, type KPShapeOpt } from "./Shape"; +import type { KPShapeColor, KPShapeComp, KPShapeOpt } from "./Shape"; import { EdgeShape, type Vec2Value } from "planck"; import { getRenderProps, p2kVec2 } from "../internals"; @@ -38,6 +38,19 @@ export default function edgeShape( return _shape; }, + kpDrawInspect(color: KPShapeColor) { + const p1 = p2kVec2(k, this.shape.m_vertex1); + const p2 = p2kVec2(k, this.shape.m_vertex2); + + k.drawLine({ + p1, + p2, + color: k.rgb(color.r, color.g, color.b), + opacity: color.a, + width: 1, + }); + }, + add() { _shape = new EdgeShape(opt?.v1, opt?.v2); }, diff --git a/src/lib/components/Fixture.ts b/src/lib/components/Fixture.ts index 42ef1e5..0e6a5c9 100644 --- a/src/lib/components/Fixture.ts +++ b/src/lib/components/Fixture.ts @@ -1,9 +1,9 @@ import type { Comp, GameObj } from "kaplay"; import type { Fixture, FixtureDef } from "planck"; +import type { KPShapeColor, KPShapeComp } from "./Shape"; import type { KPUserData } from "../types"; import type { KPBodyComp } from "./Body"; -import type { KPShapeComp } from "./Shape"; export type KPFixtureDef = Omit; @@ -145,7 +145,32 @@ export default function fixture(def?: KPFixtureDef): KPFixtureComp { }); }; }, + drawInspect(this: FixtureThis) { + const body = this.fixture.getBody(); + + const color: KPShapeColor = { + r: 200, + g: 200, + b: 200, + a: 1, + }; + + if (body.isDynamic()) { + color.r = 0; + color.g = 191; + color.b = 255; + } else if (body.isKinematic()) { + color.r = 238; + color.g = 130; + color.b = 238; + } + if (!body.isAwake()) { + color.a = 0.5; + } + + this.kpDrawInspect(color); + }, destroy(this: FixtureThis) { this.fixture.getBody().destroyFixture(this.fixture); diff --git a/src/lib/components/PolygonShape.ts b/src/lib/components/PolygonShape.ts index 5b5e704..5fa99e8 100644 --- a/src/lib/components/PolygonShape.ts +++ b/src/lib/components/PolygonShape.ts @@ -1,6 +1,6 @@ import type { GameObj, KAPLAYCtx } from "kaplay"; import { getRenderProps, p2kVec2 } from "../internals"; -import { KPShapeComp, KPShapeOpt } from "./Shape"; +import type { KPShapeColor, KPShapeComp, KPShapeOpt } from "./Shape"; import type { Vec2Value } from "planck"; import { PolygonShape } from "planck"; @@ -39,6 +39,17 @@ export default function polygonShape( return _shape; }, + kpDrawInspect(color: KPShapeColor) { + const pts = this.shape.m_vertices.map((v) => p2kVec2(k, v)); + + k.drawPolygon({ + pts, + fill: true, + color: k.rgb(color.r, color.g, color.b), + opacity: color.a, + }); + }, + add() { _shape = new PolygonShape(opt?.vertices); }, diff --git a/src/lib/components/Shape.ts b/src/lib/components/Shape.ts index daa0267..a90ca98 100644 --- a/src/lib/components/Shape.ts +++ b/src/lib/components/Shape.ts @@ -2,6 +2,13 @@ import type { Comp } from "kaplay"; import { type Shape } from "planck"; +export interface KPShapeColor { + r: number; + g: number; + b: number; + a: number; +} + export interface KPShapeComp extends Comp { /** * The Shape @@ -9,6 +16,14 @@ export interface KPShapeComp extends Comp { * @type {Shape} */ shape: Shape; + + /** + * @internal + * Draws the shape for debugging purposes. + * + * @param color - The color to use for drawing the shape. + */ + kpDrawInspect(color: KPShapeColor): void; } export interface KPShapeOpt { diff --git a/src/lib/internals.ts b/src/lib/internals.ts index 4324225..6daafb6 100644 --- a/src/lib/internals.ts +++ b/src/lib/internals.ts @@ -1,5 +1,6 @@ import type { GameObj, KAPLAYCtx, Vec2 as KaVec2, RenderProps } from "kaplay"; import { Settings, Vec2, type Vec2Value } from "planck"; +import { KPBodyComp } from "./components/Body"; export function m2p(m: number) { return m * Settings.lengthUnitsPerMeter; @@ -33,3 +34,15 @@ export function getRenderProps(obj: GameObj): RenderProps { uniform: obj.uniform, }; } + +export function hasKPBody(obj: GameObj): GameObj | null { + if (obj.c("kpBody")) { + return obj as unknown as GameObj; + } + + if (obj.parent && obj.parent.c("kpBody")) { + return obj.parent as unknown as GameObj; + } + + return null; +} diff --git a/src/shared.ts b/src/shared.ts index 90dc2d7..0b6494d 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -6,6 +6,7 @@ import addPairScene from "./examples/AddPair"; import applyForceScene from "./examples/ApplyForce"; import motorJointScene from "./examples/MotorJoint"; import sampleScene from "./examples/Sample"; +import sphereStackScene from "./examples/SphereStack"; import tumblerScene from "./examples/Tumbler"; import webScene from "./examples/Web"; import type { KaPlanckPluginCtx } from "./lib"; @@ -22,6 +23,7 @@ export const examples: [SceneName, ExampleCheckScene][] = [ ["addPair", addPairScene], ["applyForce", applyForceScene], ["motorJoint", motorJointScene], + ["sphereStack", sphereStackScene], ["tumbler", tumblerScene], ["web", webScene], ];