How to make Collision shape 2D match current frame in Animated Sprite 2D

Godot Version

v4.2.1.stable.official [b09f793f5]

Question

Hi, Im currently making a simple 2d game for my school project, and recently I decided to add animated textures to some stuff, and I have been wandering if there is a way to animate my CollisionShape2D to match current frame of my AnimatedSprite2D.

In theory I could set a timer for frame changes (every frame is exactly 0.25 seconds for me) and make a signal to function that would cycle different collision shapes (turning all, but the necessary one off), but I think if animation starts from any frame but first (or 0th as you will), my hitboxes will break, as I am not making an instance of animated sprite, but just having it spawn randomly on my map

Personally I try to limit myself to single collision shapes for animated sprites, with the only exception being when some of my actors change modes (e.g. my octopus boss goes from floating mode to spinning mode) I give them a collision shape for each mode and then disable the shapes accordingly.

That said, I try to stick to rectangles wherever possible, and I guess because the shapes are roughly aligned with my actor’s central masses, they tend to work across the sprites’ various frames.

However, each collision shape I use tends to need testing against all the relevant collisions it interacts with, so the more shapes I give an actor, the more effort it is to test it.

If your game needs precision, or if the frames are significantly different from each other, then you could have shapes for the different frames and enable them accordingly, possibly listening to the frame_changed signal. I guess an alternative would be to change the shape’s dimensions and position, once again by listening to frame_changed, or maybe using an AnimationPlayer, but that sounds like a lot of work.

Keen to hear others thoughts on this, though, as it’d be good to know what’s a normal approach to changing collision shapes.

2 Likes

image
Got this working only with this messy (aka Yandere_dev) method, was trying for 2 hours to get this working with Arrays, but couldnt manage to

Im very open to suggestions on how to redo this piece of code

If I understand correctly, your Area2D has 8 CollisionPolygon2Ds, and you’re using the current frame to copy the polygons from 1-7 into.

Based on your current approach, I’d be tempted to ditch the polygon copy, and instead have a loop, disabling all the polygons except for the one related to the current frame, along these lines:

var frame_count = ...
for x in frame_count:
    get_node("$Area2D/hitbox_" + str(x)).disabled = (x != C_frame)

I’d probably then swap out those get_node calls, instead using something like _ready to store those nodes in an array, and then reference the array in the above for loop.

The key advantage would be the code would be resilient to changes in the frame count.

1 Like

yea, thats what I was initially going for, but I couldnt figure out how to add C_frame var to my node_path string

I was also going to use for loop, but also couldnt figure out how to implement it

Also about this part of the code:

.disabled = (x == C_frame)

wouldnt that disable node with needed polygon? Condition is true when frame and hitbox are the same, and it should be inverted I think

Still much thanks for your answer, Ill try to understand all your code before adding it tho, no point just blindly copying solutions from web

Ah, I got the condition wrong on disabled. It should read:

.disabled = (x != C_frame)

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.