Seed the saved demo scene (crate colliders) and make collider symbols grabbable only at their outline
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
b0860ca07f
commit
cb8885359f
3 files changed
+49
-17
No files matched your search
@@ -5,7 +5,7 @@ import { type Position, type PropertyBag, sortByZ, type Vec2 } from '../core/mod
|
||||
import { treeOrder, worldPosition } from '../core/model/hierarchy';
|
||||
import { findAsset } from '../core/model/Project';
|
||||
import { cameraFrame, rectAround, rectsIntersect, type WorldRect } from '../core/properties/camera';
|
||||
import { colliderShape, colliderSize, isTrigger } from '../core/properties/collider';
|
||||
import { type ColliderShape, colliderShape, colliderSize, isTrigger } from '../core/properties/collider';
|
||||
import { resolveSceneObjectProps } from '../core/properties/resolve';
|
||||
import type { World } from '../runtime/World';
|
||||
import { Theme, textStyle, Widget, type Size } from '../ui';
|
||||
@@ -27,6 +27,22 @@ interface DrawItem {
|
||||
|
||||
/** World-unit size of the behavior symbol (a diamond). */
|
||||
const BEHAVIOR_SYMBOL = 28;
|
||||
/** Screen-pixel half-width of the band along a collider's outline that grabs the collider. */
|
||||
const COLLIDER_GRAB_BAND = 6;
|
||||
|
||||
/** Hit area covering only the outline band of a collider shape (local coordinates, world units). */
|
||||
function colliderOutlineHitArea(shape: ColliderShape, band: number): { contains(x: number, y: number): boolean } {
|
||||
if (shape.kind === 'circle') return { contains: (x, y) => Math.abs(Math.hypot(x, y) - shape.r) <= band };
|
||||
const hw = shape.w / 2;
|
||||
const hh = shape.h / 2;
|
||||
return {
|
||||
contains: (x, y) => {
|
||||
const ax = Math.abs(x);
|
||||
const ay = Math.abs(y);
|
||||
return ax <= hw + band && ay <= hh + band && (ax >= hw - band || ay >= hh - band);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* How world coordinates map onto the viewport: the world point (`x`, `y`) sits at the
|
||||
@@ -301,12 +317,15 @@ export class Viewport extends Widget {
|
||||
node.circle(-6, -3, 2).fill(Theme.colors.accentText);
|
||||
node.circle(6, 3, 2).fill(Theme.colors.accentText);
|
||||
} else if (item.type === 'collider') {
|
||||
// Outline plus a faint fill: the fill keeps the shape hit-testable and reads as "area".
|
||||
// Outline plus a faint fill so the shape reads as "area". Colliders usually sit right on
|
||||
// top of their body, so only the outline band is hit-testable: clicks inside still reach
|
||||
// the sprite underneath, the edge grabs the collider.
|
||||
const shape = colliderShape(item.props, { x: 0, y: 0 });
|
||||
if (shape.kind === 'circle') node.circle(0, 0, shape.r);
|
||||
else node.rect(-shape.w / 2, -shape.h / 2, shape.w, shape.h);
|
||||
const color = isTrigger(item.props) ? Theme.colors.trigger : Theme.colors.collider;
|
||||
node.fill({ color, alpha: 0.12 }).stroke({ width: 2 / view.scale, color });
|
||||
node.hitArea = colliderOutlineHitArea(shape, COLLIDER_GRAB_BAND / view.scale);
|
||||
}
|
||||
}
|
||||
this.drawParentLinks(items, editing, view.scale);
|
||||
|
||||
Reference in new issue
Block a user