pythonarcade / arcade

Easy to use Python library for creating 2D arcade games.
http://arcade.academy
Other
1.71k stars 323 forks source link

Collision detection for points outside the image not happening due to early AABB check #832

Open thomai-d opened 3 years ago

thomai-d commented 3 years ago

Big hitbox areas are very inaccurate.

hit1

hit2

Tested with version: arcade==2.5.5 Shapely==1.7.1

Small repro-code (you can switch hitboxes in player.py): repro-code.zip

Related: #753

thomai-d commented 3 years ago

Explanation After debugging arcade code, I found out, that to improve performance, a quick collision check is made before the 'real' collision detection algorithm is run.

This quick check relies on the sprites width/height properties, which in my case are zero for the invisible sprite. Therefore, the collision only works within the monkey height's radius.

Solution To make it work, I have to set the invisible sprite's width/height manually to the hitbox's bounding box width/height.

Suggestion Not sure if using a sprite for collision detection is considered 'hacky', but if this is the officially supported method, I would have expected that by using set_hit_box() the sprite's collision radius should be calculated based on the hitbox points and not the sprite's width / height.

pvcraven commented 3 years ago

Agreed, I think we need to hook into set_hit_box so it also will reset height/width. Thanks for the very detailed report.

einarf commented 2 years ago

Doing invisible collision with sprite like that is kind of hacky yes, but it's not too unreasonable.

Some random thoughts: 1) It's probably not reasonable that a sprite doesn't have a texture (adds complexity). It can have a dummy texture for sure, and those are easy to make. 2) If the dummy texture needs to be scaled it will also scale the hit box points. That can be a hit weird. 3) Possibly a sprite type could be added for this kind of use.

pvcraven commented 1 year ago

This is still a issue with current development, the width/height of the image is used, and if the hitbox extends past that, it is going to be ignored.

einarf commented 1 year ago

I looked at his brifely. When it comes to performance it's alll about the cost of calling left, right, top and bottom. These might need to be cached in the sprite to make it viable, but no idea if this reasonable.

Is it even reasonable that points extend past the texture area?

pushfoo commented 1 year ago

Is it even reasonable that points extend past the texture area?

Things like the anomalies from the STALKER series might do something like this to save on texture space: small sprite, large hitbox to set it off.

einarf commented 1 year ago

We now have arcade.get_sprites_in_rect((l, r, b, t), spritelist) that can used instead of dummy sprite. Still, this doesn't solve the core issue.

alejcas commented 1 year ago

This quick check relies on the sprites width/height properties, which in my case are zero for the invisible sprite. Therefore, the collision only works within the monkey height's radius.

This quick check also makes the collision detection to fail if the hitbox is set to something bigger than the sprite itself.

See https://discord.com/channels/458662222697070613/696054878593744946/1038023494946017320

Cleptomania commented 1 year ago

So we have had a big hitbox re-work very recently, and this problem still exists, however we've had a lot of performance improvements, and are able to achieve greater than 20x speedups to the are_polygons_intersecting check that this bounding box check tries to ignore via the upcoming arcade-accelerate package. Given all of this, I'm tempted to say that we can just remove the check altogether, and always use the full are_polygons_intersecting check which will stay true to the hitbox.

DragonMoffon commented 1 year ago

Using the new super stripped back Sprite, could we not provide a BlankSprite class to solve this issue? Give it a 2x2 invisible texture that can't be changed, just the hitbox and sprite size.

pushfoo commented 6 months ago

EDIT: might not be the same issue, refiled here https://github.com/pythonarcade/arcade/issues/2255

TL;DR: It's still happening, and it isn't just big sprites

One of our users appears to have run into this on Discord today. Their sprite tiles appear to be 48x48 and the hitbox appears to be clean. See the video below (Converted with ffmepg -i file.avi file.mp4):

https://github.com/pythonarcade/arcade/assets/36696816/d0b054f7-e0f2-41db-a8fe-0aaa704ad62b