#Is there an alternate way to have enemies check for legeds that doesn't involve raycasts?

13 messages · Page 1 of 1 (latest)

mild kiln
#

Or if not, please help figure out what I am doing wrong here. I have been trying to debug the first basic enemy I made for my game for hours, but it always get stuck

I have tried changing the horizontal position of the raycasts, placing them further away from the sprite, as well as closer, but it didn't help. I tried using a CapsuleShape2D instead, but it only made the enemy get stuck more often.

I tried using only one raycast and flipping the entire enemy around with the scale method (I honestly much prefer it over flip_h since it flips the collisions as well), but even with only one raycast, the enemy still gets stuck. It seems like once the enemy finds the ledge and turns around, it interprets the tilemaps as ledges as well? Maybe the tilemap collisions aren't properly configured?

The problem seems to be with the raycasts, I am likely missing something/doing something wrong, because even after disabling the CollisionShape2Ds, one by one, the enemy still gets stuck sometimes. I added a few screenshots, including one of the enemy code, the collision layer and mask for the tilemap and the enemy's collisions as well. Thanks in advance!

ornate juniper
# mild kiln Or if not, please help figure out what I am doing wrong here. I have been trying...

I'm going to sound a bit rumbly on this but hear me out.

What I'm curious about is the script that you have, I think you should have 2 different checks to differentiate between floor & wall: one set of Raycasts pointing down (which in your case I would make a bit longer than normal) & another set of Raycast that are pointing in front of your "enemy".

In general, I think that you should consider using RayCasts that checks for different things (but does the same thing), meaning for example that you have 2 different RayCasts that are pointing to the Left/Right but have If-statements that does different things.

For Walls
In your case I would consider to have separate if-checks for your Raycasts, meaning that if your for example CheckForWallToTheLeft Raycast is true, flip the enemy direction movement, it could look like this:

if check_for_wall_left.is_colliding() and !check_for_wall_right.is_colliding():
  *Flip the direction of the enemy's movement here*
elif check_for_wall_right.is_colliding() and !check_for_wall_left.is_colliding():
  *Flip the direction again*

For Floor
This one is a theory but it could function similar to your "Wall" Rays. They would be similar to your "Wall" rays but would be slightly in front of the enemy on either side & slightly longer than normal.
Then you could create a similar series of if/elif statement as above but have the condition be that if the "floor" ray isn't true, then that probably means that there's no floor below & we're supposed to move in the other direction.

But I think this method would only work on flat surfaces depending on how long the "floor" rays are.

Also check the screenshot from my own project for example on how I do it (for me it works for my project, just because it works for me & suit my needs, doesn't necessarily means it will work for you)

ornate juniper
#

You just have to make sure that the Rays are updated properly

mild kiln
#

Hey, I am going to give your suggestion a try in a bit, but I have to ask, what is the purpose of updating rays? Sorry if it is too silly of a question!

ornate juniper
# mild kiln Hey, I am going to give your suggestion a try in a bit, but I have to ask, what ...

Well like I said, this worked for my project.
For me, I'm forcing the update because I want to do it right then & there, instead of waiting for the next _physics_process call, you can read more about "force_raycast_update" here: https://docs.godotengine.org/en/stable/classes/class_raycast2d.html#class-raycast2d-method-force-raycast-update

For your issue, I can't say for sure if forcing the raycast update will be necessary, in my case, I needed a solution that "just" works & it did. The project I'm currently working on is supposed to serve more as a concept instead of a complete product.

To be completely honest, I have no idea if my implementation is the right way to do it, but it works?

mild kiln
#

Oh sorry, I wasn't questioning your reasoning behind choosing to update the raycasts, I was curious about the purpose of updating them. As in, each piece of code has a purpose and such.

ornate juniper
# mild kiln Oh sorry, I wasn't questioning your reasoning behind choosing to update the rayc...

In my case, I just want to make 100% sure that the update happens but for my project, I'm not really sure if force_raycast_update is 100% necessary & it's likely that I've misunderstood it's function.

But if you want to check for collisions (in this case the walls for your project), you want to do that in _physics_process, from there the raycasts are should be "updated".

To me, Raycast are the 2nd (with Signals in Godot coming 1st) aspect of Godot that I don't understand perfectly well.

mild kiln
#

Thanks, I went and read the documentation on force_raycast_update. Interesting stuff.

Could I ask you to show me how you set up the raycasts? A visual would help.

ornate juniper
#

Sure thing!

  • For my project, I created a separate scene that's of the type "Position2D" that I call "RoofDetector.
  • I add 4 RayCast2D as children pointing up.
  • I attach a script to "RoofDetector" that I call, well, "RoofDetector".
  • Because "RoofDetector" is a child of the player, after my series of if-statements where I check if any of my Rays are colliding, I do the thing I want to do by using the keyword "owner" first (owner being my "Player").

The way I did it might be overkill for your project, in your case, I would focus on making it do what you want it do do first.

#

By "Roof Detector" position, I mean where the Rays are starting from

ornate juniper
mild kiln
#

Thank you! I was able to finally make it work.