Colliders take a frame's outline and tiles have their own surface (#193)
Issue #193 asked where friction, bounciness and density of a tile live. Tiles had a fixed surface (friction 0.5, bounciness 0) and a collider could not use the outline drawn on a texture frame (#141). Both gaps are closed here. - A collider has a fifth shape "Frame collision" with a Frame row. The frame is picked like a sprite's texture and stored as the value 'frame'. - The shape is linked, not copied. Redrawing the outline in the texture tab changes every collider using that frame, in the editor and on the next play. - The frame centre sits on the collider origin, one image pixel is one unit. The shape turns, scales and mirrors like any other. - Every outline ring blocks. Each ring is split into convex parts the same way a polygon is. - Without a frame, with a whole texture or with a frame that has no outline, the collider is drawn red as a box and blocks nothing. - Move, Rapier, raycast, detection, hit test, drawing and footprint all resolve the frame. At runtime an entity looks the frame up live in the current project. - A tile has Friction and Bounciness next to Solid and One-way. The rows only show when Solid is on. Defaults and mixing rules match the collider. Density is left out because a tilemap never moves. - Tilemap cells are grouped by surface as well as by one-way angle. Ice and stone never merge into one rectangle, and every cell brings its surface to Move and Rapier. Findings: - A tile with a collision scale below 1 is no longer flush with a neighbour of another surface. It is inset there like at an open side, the same as next to one-way tiles today. - A bounce test first measured 0.84. The ball had landed on the hero at the origin, not on the tile. On the tile it measures 0.993. Tests: - ./check.sh: 130 files, 1931 tests, exit 0 (was 129 / 1917). - 14 new unit tests in tests/core/surface.test.ts. The Move tests run against the editor run and the physics system. - 3 new e2e checks: 40l (surface rows follow Solid), 42e (collider has frame size, a walker climbs the slope in the frame). - GM_STEPS=1-8,39-43 freshly seeded: ALL PASSED, 376 checks. - Three counter-probes bite: Move ignores the tile surface (2 fail), Rapier ignores it (1 fails), frame shape falls back to a box (5 fail). - Check sum 1198 is computed (1195 + 3), the full run belongs to CI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3ff7e91dbf
commit
f4ec23d3d3
20 files changed
+729
-83
No files matched your search
@@ -22,10 +22,12 @@ import {
|
||||
import { findAssetOf, type Project } from '../model/Project';
|
||||
import { ALL_LAYERS, COLLIDES_WITH_KEY, COLLISION_LAYER_KEY } from '../model/collisionLayers';
|
||||
import {
|
||||
TILE_BOUNCINESS_KEY,
|
||||
TILE_COLLISION_SCALE_KEY,
|
||||
TILE_COLLISION_SCALE_MAX,
|
||||
TILE_COLLISION_SCALE_MIN,
|
||||
TILE_FPS_KEY,
|
||||
TILE_FRICTION_KEY,
|
||||
TILE_KIND_KEY,
|
||||
TILE_ONE_WAY_ANGLE_KEY,
|
||||
TILE_ONE_WAY_KEY,
|
||||
@@ -105,6 +107,25 @@ const ONE_WAY_ANGLE_ROW: FlatDef<'number'> = {
|
||||
shownWith: 'oneWay',
|
||||
};
|
||||
|
||||
/** The surface a collider or a solid tile (#193) offers, read by the physics engine and by `Move` (#146, #150). */
|
||||
const FRICTION_ROW: FlatDef<'number'> = {
|
||||
key: 'friction',
|
||||
label: 'Friction',
|
||||
kind: 'number',
|
||||
default: 0.5,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
};
|
||||
const BOUNCINESS_ROW: FlatDef<'number'> = {
|
||||
key: 'bounciness',
|
||||
label: 'Bounciness',
|
||||
kind: 'number',
|
||||
default: 0,
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.05,
|
||||
};
|
||||
|
||||
/**
|
||||
* Which colliders may meet (#152). Both rows sit on colliders and on tilemaps, so a map can be
|
||||
* ground that only some things walk on. The defaults are layer 0 against every layer, which is
|
||||
@@ -343,6 +364,9 @@ const ASSET_SCHEMAS: Record<AssetType, PropertySchema> = {
|
||||
// A solid tile that only blocks from above, like a platform one jumps through (#155).
|
||||
{ key: TILE_ONE_WAY_KEY, label: 'One-way (from above)', kind: 'boolean', default: false },
|
||||
{ ...ONE_WAY_ANGLE_ROW, key: TILE_ONE_WAY_ANGLE_KEY, shownWith: TILE_ONE_WAY_KEY },
|
||||
// No density: a map never moves, so what its cells would weigh counts for nothing.
|
||||
{ ...FRICTION_ROW, key: TILE_FRICTION_KEY, shownWith: TILE_SOLID_KEY },
|
||||
{ ...BOUNCINESS_ROW, key: TILE_BOUNCINESS_KEY, shownWith: TILE_SOLID_KEY },
|
||||
// Below 1 a cell blocks less than its square, above 1 more – but only on the sides without a
|
||||
// blocking neighbour, so a wall of such cells stays closed (#140).
|
||||
{
|
||||
@@ -433,6 +457,7 @@ const ASSET_SCHEMAS: Record<AssetType, PropertySchema> = {
|
||||
{ value: 'circle', label: 'Circle' },
|
||||
{ value: 'capsule', label: 'Capsule' },
|
||||
{ value: 'polygon', label: 'Polygon' },
|
||||
{ value: 'frame', label: 'Frame collision' },
|
||||
],
|
||||
},
|
||||
// A box and a capsule fill width × height; the capsule is rounded along the longer side.
|
||||
@@ -450,10 +475,12 @@ const ASSET_SCHEMAS: Record<AssetType, PropertySchema> = {
|
||||
{ x: -50, y: 50 },
|
||||
],
|
||||
},
|
||||
// The frame whose collision outlines (#141) the "Frame collision" shape wears, kept linked (#193).
|
||||
{ key: 'frame', label: 'Frame', kind: 'texture', default: '' },
|
||||
{ key: 'isTrigger', label: 'Trigger (no blocking)', kind: 'boolean', default: false },
|
||||
// The material, read by the physics engine where a rigidbody takes part (#146).
|
||||
{ key: 'friction', label: 'Friction', kind: 'number', default: 0.5, min: 0, step: 0.05 },
|
||||
{ key: 'bounciness', label: 'Bounciness', kind: 'number', default: 0, min: 0, max: 1, step: 0.05 },
|
||||
FRICTION_ROW,
|
||||
BOUNCINESS_ROW,
|
||||
{ key: 'density', label: 'Density', kind: 'number', default: 1, min: 0, step: 0.1 },
|
||||
// Blocks only what comes from that side, turned with the object; the rest passes through (#155).
|
||||
{ key: 'oneWay', label: 'One-way', kind: 'boolean', default: false },
|
||||
|
||||
Reference in new issue
Block a user