Physics stage 2: colliders gain the shapes capsule and polygon, a polygon keeps its corners in the property points, turns, scales and mirrors with its object and is edited in the scene view (drag a corner, click an edge to insert one, double-click to delete, at least three stay, each step one undo step), a concave polygon is split into convex parts, a self-intersecting one is drawn red and collides with nothing, Rapier gets a capsule and one convex collider per part on the same body, and Move and the editor run use our own f64 geometry for the new shapes, where on a tie between two normals the one that blocks the move least wins, so a box no longer stops at the foot of a slope (#151); first version of a collision outline per texture frame, edited in the texture tab with the new Collision toggle, which a plain tile blocks with instead of its rectangle (#141, to be reworked)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1b5e386b60
commit
32057a96fc
25 files changed
+2341
-122
No files matched your search
@@ -2,7 +2,14 @@ import { isHandleEnabled, worldMatrixOf } from '../../core/graph';
|
||||
import { applyVector, determinant, IDENTITY, invert, linearOf, type Mat } from '../../core/model/matrix';
|
||||
import type { Vec2 } from '../../core/model/Properties';
|
||||
import { findAssetOf } from '../../core/model/Project';
|
||||
import { type CellRect, cellRectShape, solidRects } from '../../core/model/tilemapCollision';
|
||||
import {
|
||||
type CellPolygon,
|
||||
cellPolygonShape,
|
||||
type CellRect,
|
||||
cellRectShape,
|
||||
solidPolygons,
|
||||
solidRects,
|
||||
} from '../../core/model/tilemapCollision';
|
||||
import { parentChain } from '../../core/model/walk';
|
||||
import {
|
||||
type ColliderShape,
|
||||
@@ -97,35 +104,45 @@ export interface CollisionSource {
|
||||
*/
|
||||
export class Solids {
|
||||
/**
|
||||
* The blocking rectangles of each tilemap, in cells. Worked out once per tick – painting, or a
|
||||
* behavior changing the map, is picked up by the next one – and turned into world shapes only
|
||||
* when asked, since the map may move in between.
|
||||
* The blocking rectangles and outlined cells of each tilemap, in cells. Worked out once per tick –
|
||||
* painting, or a behavior changing the map, is picked up by the next one – and turned into world
|
||||
* shapes only when asked, since the map may move in between.
|
||||
*/
|
||||
private rects = new Map<Entity, CellRect[]>();
|
||||
private blocks = new Map<Entity, { rects: CellRect[]; polygons: CellPolygon[] }>();
|
||||
|
||||
/** Forgets the rectangles, so the next tick works them out afresh. */
|
||||
/** Forgets the cells, so the next tick works them out afresh. */
|
||||
reset(): void {
|
||||
this.rects = new Map();
|
||||
this.blocks = new Map();
|
||||
}
|
||||
|
||||
rectsOf(world: World, tilemap: Entity): CellRect[] {
|
||||
let rects = this.rects.get(tilemap);
|
||||
if (!rects) {
|
||||
private blocksOf(world: World, tilemap: Entity): { rects: CellRect[]; polygons: CellPolygon[] } {
|
||||
let blocks = this.blocks.get(tilemap);
|
||||
if (!blocks) {
|
||||
const asset = findAssetOf(world.project, tilemap.assetId, 'tilemap');
|
||||
rects = asset ? solidRects(world.project, tilemap.props, asset) : [];
|
||||
this.rects.set(tilemap, rects);
|
||||
blocks = asset
|
||||
? {
|
||||
rects: solidRects(world.project, tilemap.props, asset),
|
||||
polygons: solidPolygons(world.project, tilemap.props, asset),
|
||||
}
|
||||
: { rects: [], polygons: [] };
|
||||
this.blocks.set(tilemap, blocks);
|
||||
}
|
||||
return rects;
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* The shapes a body occupies in the world: one for a collider, one box per merged rectangle
|
||||
* for a tilemap. A tilemap placed before the first tick is worked out on the spot.
|
||||
* The shapes a body occupies in the world: one for a collider; for a tilemap one box per merged
|
||||
* rectangle and one polygon per outlined cell (#141). A tilemap placed before the first tick is
|
||||
* worked out on the spot.
|
||||
*/
|
||||
shapesOf(world: World, body: Entity): ColliderShape[] {
|
||||
if (body.type !== 'tilemap') return [shapeOf(body)];
|
||||
const m = worldMatrixOf(body);
|
||||
return this.rectsOf(world, body).map((rect) => cellRectShape(body.props, rect, m));
|
||||
const { rects, polygons } = this.blocksOf(world, body);
|
||||
return [
|
||||
...rects.map((rect) => cellRectShape(body.props, rect, m)),
|
||||
...polygons.map((polygon) => cellPolygonShape(body.props, polygon, m)),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user