Godot Version
4.2.1
Question
I am following along a tutorial for a simple 2D game.
I am now at the part of adding code with GDScript for movement to my scene and i wanted to have the 2D Sprites flip when i walk to the left, so that the character is actually facing into the right direction.
I have googled around and i found a lot of examples that seemingly work for other people, but they do not work for my specific case. (Or i just don’t understand the solutions)
I have a CharacterBody2D with a Node2D Child from another scene and the CollisionShape2D.
The other scene has all the individual parts of the character as child-sprites of the parent Node2D since it seems to be animated in engine there.
I have found a dirty solution to this now from other threads which checks for the mouse position relative to the character and flips the Node2D and the CollisionShape2D individually:
var mouse_position = get_global_mouse_position()
if mouse_position.x > position.x:
$Player.scale = Vector2(1,1)
$CollisionShape2D.scale = Vector2(1,1)
elif mouse_position.x < position.x:
$Player.scale = Vector2(-1,1)
$CollisionShape2D.scale = Vector2(-1,1)
But i am not quite happy with this.
Once i start adding even more nodes to the scene, this would become really messy and i am wondering if there is a way to just adress the root node, in this case the CharacterBody2D and have everything flip, rotate etc with it?
Alternatively i assume i could create a new Node2D and have it act as the parent to the other nodes i have in that scene, but this of course does not work for the CollisionShape2D since it needs to be a direct child of the CharacterBody2D.
Is there something else that i am missing or do i really have to rotate, move, scale etc both nodes individually each time?
Also how would i have to change my code to have the character flip when moving to the left via WASD instead of checking for the mouse position?
I found a post that talks about checking for the speed in the -x direction, but i want the animation to play and the char to flip when pressing the movement button even if the character isnt actually moving and, for example, is stuck on a wall.
I also saw a lot of people mention that the engine will keep flipping back the sprite with each frame, so if thats the case, how would i actually keep it flipped until i move in the other direction again?
I think that what you’re running into is that physics bodies/collisions often don’t work correctly when scaled, and you run into unsupported behaviors. In general, you want to apply scale to the visual representations only (the Sprite2D) and, if needed, use other methods to alter the physics nodes (rotation, swapping between multiple collision shapes, etc). In your case, if your collision shape is symmetric, you don’t need to worry about it.
If you have multiple visual nodes, you can give them a shared parent Node2D and scale that node. This also works for a Skeleton2D but, for reference, IK will not work when scaled.
1 Like
Oh interesting, so its best practice to have multiple preset CollisionShapes and swap between them when needed?
But that just kind of opens up an entirely new rabbithole for me…
There must also be a way to generate a CollisionShape based on geometry in 3D or shape of a sprite right?
Or how else would you handle it when you have a character that gets, for example, upgraded with new parts and changes it shape? Having a preset for every possible combination would seem like a waste.
1 Like
If you select your sprite node and click the Sprite2D menu at the top of the main viewport, there’s an option to automatically generate collision shapes. There are also many different options for automatically generating 3d colliders from meshes.
However, it depends on your specific game whether a high fidelity collision shape is needed or even wanted. Simpler shapes are more performant and less likely to get stuck in cracks or angles of the ground colliders. You also may want to control the difficulty of your game by making smaller hurtboxes for the player or larger ones for enemies, for example.
If it’s a sidescroller character turning around, I usually just rotate or reposition colliders rather than having multiple to swap between. With raycasts you can also just reverse the x-direction. But, yes, if your character changes in a way that you need a new shape for gameplay, that’s something you’ll need to find a way to do other than scaling, unfortunately.
2 Likes
Oh thats super neat and good to know.
And yeah i don’t need anything super complex. What i plan to do is have the player be upgradeable with new parts, which of course change the visuals and shapes, but keep everything relatively boxy. So if i add another turret on the side, i would of course like it to also have a hitbox, same with if i add a part that makes the player longer.
Do you know if the same “rules” also apply to Area2D’s?
I unfortunately can’t seem to find an Edit button so i have to make a new post.
Regarding flipping my sprite, i have approached it way more complicated than i had to and solved flipping the sprite without flip.h or raycasts by simply doing this:
if velocity.x < 0:
$Player.scale = Vector2(-1,1)
elif velocity.x > 0:
$Player.scale = Vector2(1,1)
Since my collision shape is just a box, i have not changed it in this case.
I also found out how i can play the walk animation even if the character is not actually moving, for example if he is blocked by a wall or similar:
if direction != Vector2.ZERO:
$Player.play_walk_animation()
else:
$Player.play_idle_animation()
It was simpler than i thought but Google has not been very helpful lately. Found a lot of scripts that wanted me to make a new variable and write the inputs into it and then do a for loop etc which just seems unnecessary complex.