Repository navigation
Fix isometric collision bounds, anchored raycasts and zoomed cameras - #1762
Merged
Merged
Conversation
Tiled: - a collision object whose shape reaches left of or above its position, like every rectangle on an isometric map, now has bounds covering its shape, so collision checks, queryAABB and raycast find it wherever the shape is. Its pos becomes the top left corner of the shape (point objects keep theirs). Parts of it were missed, so a character could walk through walls - a tile object on an isometric map collides over its image; its default body was the image box projected onto the map grid Physics: - the builtin raycast measures a body from the frame its renderable draws in, using the same anchor offsets as SAT (now exported from sat.js). On a body anchored anywhere but its top left, such as a Sprite's default centre, a ray hit half the body's size away from it, or missed it Camera: - a zoomed camera follows its target, honours its deadzone, stays within its bounds and centres on focusOn in world units - localToWorld and worldToLocal take zoom and screenX/screenY into account, so a pointer on a zoomed camera, or on one drawn in a corner of the screen, hits what it points at Text: an empty or blank label gets a canvas at least one bucket wide, since WebGPU refuses a zero-sized upload and blanked the whole frame. Typings: TextureAtlas#getAnimationSettings() is typed as the settings it returns, and Sprite3d accepts named animations. Skills: the tilemaps skill covers what the y-sort can and cannot sort and the default bodies of class-less tile objects; the drawing skill says to create a CanvasRenderTarget once and invalidate() it after repainting; the lighting skill no longer claims an unmapped sprite is lit flatly. Line of Sight example: round pillars as Ellipse bodies anchored at their centre, and patrolling intruders the cone spots with a raycast check. Verified: every new spec fails with its fix reverted (each half of the conversion fix caught separately); full suite 8,304 passed; lint clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SeWCkETjW35ZbXDRswV1hx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Engine fixes found while building a new isometric example (coming in its own PR), plus the skill updates and a Line of Sight example that shows the raycast fix.
Tiled
pos .. pos + size, sogetBounds()(what the quadtree files it by, and whatqueryAABBandraycastprefilter on) sat beside the drawn wall, and a character could walk through it wherever the quadtree split differently. The object now starts at its shapes' top left corner and the shapes are translated back, so the vertices are unchanged. Such an object'sposchanges; point objects keep theirs.parseTMXShapesran the isometric projection on a tile object's image box, which Tiled already draws upright, giving a slanted body hanging off the image.Physics
raycasthonours the anchor, as collisions have since 20.7 (Physics: collision shapes follow the renderable, and segments collide as segments #1693). It placed each shape atpos + shape.pos, so on a body anchored anywhere but its top left (aSpritedefaults to its centre) a ray hit half the body's size away from where it collides, or missed it. It now uses the same anchor offsets as SAT (anchorOffsetX/anchorOffsetY, exported fromsat.js), honouringapplyAnchorTransform = false. The 3D raycast already did this.Camera
follow(deadzone and clamps),moveTo's bounds clamp andfocusOnused the on-screenwidth/height, while a zoomed camera showswidth / zoomof the world: zoomed out, a followed target sat off centre and the view scrolled past its bounds; zoomed in, it stopped short of them.localToWorld/worldToLocaltakezoomandscreenX/screenYinto account, so a pointer on a zoomed camera, or on a second camera drawn in a corner, hits what it points at.world = pos + (screen - screenOffset) / zoom, then the existing world offset and camera transform steps;worldToLocalis the exact inverse.Also
TextureAtlas#getAnimationSettings()is typed as the settings it returns, andSprite3daccepts named animations (as an aseprite atlas carries them).sortOn = "y"can and cannot sort, and the default bodies of class-less tile objects), drawing (create aCanvasRenderTargetonce, since its GPU texture lives as long as the renderer, andinvalidate()it after repainting), lighting (a sprite without a normal map is not shaded at all, not "lit flatly").Ellipsebodies anchored at their centre, and patrolling intruders the cone spots with a raycast check.Verification
tmx-shape-factory,tmxtilemap,raycast,camera,pointer-world-offsetandtext_bucket; every one fails with its fix reverted, and each half of the conversion fix (zoom, screen offset) is caught separately.follow()with a zoom of 0.1.🤖 Generated with Claude Code
https://claude.ai/code/session_01SeWCkETjW35ZbXDRswV1hx