ruffle icon indicating copy to clipboard operation
ruffle copied to clipboard

Shape hit testing checks the last 2 frames

Open relrelb opened this issue 4 years ago • 2 comments

In Flash Player, it seems that hitTest with shapeFlag set to true returns true only when a hit occurs in both the current frame and the previous frame. However Ruffle accounts only for the current frame.

The attached test.zip traces in Flash Player false twice, then true repeatedly. In Ruffle it traces false just once, then true repeatedly. Also, test2.zip never traces true in Flash Player, but does once in Ruffle.

Without shapeFlag Flash Player behaves like Ruffle.

relrelb avatar Feb 14 '21 00:02 relrelb

This is reusing the previous frame's rendering in some way, as this only occurs when the object is in the visible area of the stage. If you do _root._x = 2000; to toss everything offscreen, the hitTest returns true on the first frame it collides instead of the one-frame-lag behavior, probably because the player has to redraw the object on demand. Also happens with _visible = false.

The question is what the exact behavior is; I suspect it will require some reverse engineering work to figure it out. Could be something like:

  • Caching the contour or scanline spans of the rendering?
  • Using an additional "picking" buffer storing object IDs along with the rendered frame, i.e. mouse picking via depth/stencil? (Maybe for mouse picking, but can't be for hitTest, because the hitTested object could be completely occluded.)

Herschel avatar Oct 18 '21 20:10 Herschel

It might also be that there's some cached value at play, that doesn't update in the way one might except.

var rect:Shape = new Shape();
// make a 100x100 square...
rect.x = 100;
trace(rect.hitTestPoint(150, 150, true));
rect.x = 200;
trace(rect.hitTestPoint(250, 150, true));

prints true false, but if the first hitTest is commented out, then the second becomes true!

adrian17 avatar Feb 14 '24 19:02 adrian17