Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/examples/src/examples/platformer/entities/HUD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,10 @@ class UIContainer extends Container {
// Use screen coordinates
this.floating = true;

// make sure our object is always draw first
this.z = Number.POSITIVE_INFINITY;
// Draw order comes from the `addChild(child, z)` in `play.ts`.
// `renderable.z` is not a property — the accessor is `depth`, an alias
// for `pos.z` — so assigning it here only ever made an expando that
// nothing read, and the container was ordered by `autoDepth` instead.

// give a name
this.name = "HUD";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,10 @@ export class VirtualJoypad extends Container {
// Use screen coordinates
this.floating = true;

// make sure our object is always draw first
this.z = Number.POSITIVE_INFINITY;
// Draw order comes from the `addChild(child, z)` in `play.ts`.
// `renderable.z` is not a property — the accessor is `depth`, an alias
// for `pos.z` — so assigning it here only ever made an expando that
// nothing read, and the container was ordered by `autoDepth` instead.

// give a name
this.name = "VirtualJoypad";
Expand Down
8 changes: 6 additions & 2 deletions packages/examples/src/examples/platformer/play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import UIContainer from "./entities/HUD";
import { MinimapCamera } from "./entities/minimap";
import { gameState } from "./gameState";

/** draw order for the screen-space overlays — above every level layer */
const HUD_Z = 100;

export class PlayScreen extends Stage {
private virtualJoypad?: VirtualJoypad;
private HUD?: UIContainer;
Expand All @@ -40,14 +43,15 @@ export class PlayScreen extends Stage {
if (typeof this.HUD === "undefined") {
this.HUD = new UIContainer();
}
app.world.addChild(this.HUD);
// explicit z: the HUD draws over the level
app.world.addChild(this.HUD, HUD_Z);

// display if debugPanel is enabled or on mobile
if (plugin.cache.debugPanel?.panel.visible || device.touch) {
if (typeof this.virtualJoypad === "undefined") {
this.virtualJoypad = new VirtualJoypad();
}
app.world.addChild(this.virtualJoypad);
app.world.addChild(this.virtualJoypad, HUD_Z);
}

// vignette post-effect + built-in color grading (always applied last).
Expand Down
10 changes: 8 additions & 2 deletions packages/melonjs/skills/melonjs-performance/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,17 @@ Two rules that cause subtle bugs when missed:
successfully recycled object never sees it. Pair event subscriptions with
`onActivateEvent` / `onDeactivateEvent` instead, or you leak handlers.

Engine classes are poolable too: `pool.pull("Tween", target)`. The registered
names carry no `me.` prefix — `Entity`, `Collectable`, `Trigger`, `Light2d`,
Engine classes are poolable too: `pool.pull("Tween", target)`. The canonical
names are unprefixed — `Entity`, `Collectable`, `Trigger`, `Light2d`,
`Particle`, `Sprite`, `NineSliceSprite`, `Renderable`, `Text`, `BitmapText`,
`ImageLayer`, `Tween`, `ColorLayer`.

`pool.register` additionally aliases every name under an `me.` prefix, pointing
at the same entry, so `pool.pull("me.Tween")` resolves identically — and the
same alias is registered with the Tiled object factory, which is why a map
authored against melonJS 1.x still finds its classes. Prefer the unprefixed
name in new code; do not "correct" an `me.`-prefixed one, it is not broken.

## `scale()` is multiplicative

A pooled sprite arrives carrying its previous life's transform, and calling
Expand Down
13 changes: 13 additions & 0 deletions packages/melonjs/skills/melonjs-physics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ this.body.setVelocity(vx, vy);
this.body.force.x = this.body.maxVel.x;
```

`maxVel` is what turns a force into a speed, so the two are set together. Use
the setters rather than writing the vectors — both take an optional THIRD
argument for the depth axis, left unchanged when omitted, so a 2D call keeps
its behaviour:

```js
this.body.setMaxVelocity(3, 15); // walk speed, jump speed
this.body.setFriction(0.4, 0); // ground drag, none vertically
```

`friction` here is per-axis per-step velocity damping, not a surface
coefficient — see the built-in quirks below.

Under matter and planck, `syncFromPhysics()` copies the engine body's position
back onto `renderable.pos` after every step, so a direct write is simply erased
— no error. The built-in world integrates `pos` in place instead, so a write
Expand Down
34 changes: 34 additions & 0 deletions packages/melonjs/skills/melonjs-ui-and-text/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,40 @@ Three things matter here:
real accessor is `depth` (an alias for `pos.z`); `addChild(child, z)` sets it
for you.

### Buttons: extend the handlers, do not bind listeners

`UISpriteElement` is a `Sprite` that already registers itself for pointer
events, so a button is made by overriding methods rather than by wiring
`registerPointerEvent`:

| handler | fires | returns |
|---|---|---|
| `onClick(event)` | pressed | `false` to stop the event propagating |
| `onRelease(event)` | pressed and released | `false` to stop propagating |
| `onOver(event)` | pointer enters | — |
| `onOut(event)` | pointer leaves | — |
| `onHold()` | pressed and held | — |

```js
class MuteButton extends UISpriteElement {
constructor(x, y) {
super(x, y, { image: atlas, region: "speaker.png" });
this.setOpacity(0.5);
}
onOver() { this.setOpacity(1.0); }
onOut() { this.setOpacity(0.5); }
onClick() {
audio.muteAll();
return false; // consumed — do not fall through to the world
}
}
```

The pointer still has to reach it: a renderable with `isKinematic = true` — the
default on a plain `Renderable` — is skipped by the broadphase and receives
nothing. `UISpriteElement` and `UIBaseElement` clear it for you; anything else
you make clickable has to clear it itself.

### In a 3D scene, a HUD needs a SMALL depth

`floating` opts a renderable out of the camera transform. It does **not** opt it
Expand Down
Loading