#"Issue with "angle_to_point". Please, help?

17 messages · Page 1 of 1 (latest)

gaunt fractal
#

I have a function where I attempt to make sure the player can only stomp enemies if they are coming from a specific angle.

The code for the function is on the first screenshot. In the second screenshot, you can see the variables holding the minimum and maximum angles.

I made sure collisions are working via printing silly things like "hi" and "bye". But, if you need me to share screenshots of how player and enemy collisions are set up, I can share them.

Anyway, sadly, no matter the angle the player approaches the enemy, only the code in the "else" section of the function runs. I will admit stuff like "rad_to_deg" and "angle_to_point" are WAY above my level of GDscript knowledge, but I could not find a different way of setting up a stomp mechanic that does not let the player stomp the enemies when coming from all sorts of directions.*

Please, I really want to fix this so I can start building levels and making interesting enemies for this little project of mine. Everything else related to the player works, this is all there is left.

*I tried having so stomping only worked if the player was in the "on_air" state and if the velicity was > 0, meaning the player was falling down and not rising up, but it was VERY janky...

gaunt fractal
#

While I would still love to get some help on this matter, this works for now (though, the player can still stomp the enemy when coming from below them, somehow).

gaunt fractal
#

Bump

kind iron
# gaunt fractal While I would still love to get some help on this matter, this works for now (th...

From what i see here in the last picture, you only check if the player is on the right site of the enemy, so it doesn't really matter if the player is above or below.

Do you call that function on collision?
Can you show where enemy and player are in the scene tree and maybe how they look in their scene?
Did you try printing the returned angle and if yes what does it return? If your player is right on top of the enemies origin it should return 90° ( in case it has a square collisionshape).
What collisionshape does your enemy have?

There are few reasons i can think of, why the condition could be false for you:

  • Enemy and Player have different positioned parents, so comparing their local positions will not result in anything that helps you. Their positions would be relative to their parent so angle_to_point wouldn't result in the value you want. So just to be safe id change position to global_position for both of them.

  • It could be that your sprite/collision is offset from the actual enemy ( i attached 2 pics that show what i mean).

I recreated your code and the conditions work for me.
In the clip /screenshot that i attached, the players origin is at the center bottom of the sprite and the origin of the enemy is in the middle of the rectangle. The green line connects those and the red angle i drew is the one what will return from angle_to_point. So your initial idea should work!

#

Also something additional (Just ignore this if you´re not interested^^):

I just thought of smth else. If you want to try an alternative using the collision features of your Characterbody2D, so you´re not dependent on the origin of the enemy, but only the location of the collision.
The idea is to compare the collision normal with the Vector that points up, and decide if a stomp is valid depending on the angle between those.

var max_collision_angle_deg = 30
move_and_slide()
for i in get_slide_collision_count():
    var collision = get_slide_collision(i)
    if collision.get_collider() == enemy and Vector2.UP.dot(collision.get_normal()) > cos(deg_to_rad(max_collision_angle_deg)):
        do_your_stuff()

collision.get_normal() is the normal, that points away from your enemies collisionshape at the point where the collision occured.
It is perpendicular to the collisionshapes surface. I attached a pic.
So for a rectangle:

  • if you hit the top, it points up (Vector2.UP or Vector2(0, -1))
  • if you hit the site, it points right or left (Vector2.RIGHT or Vector2.LEFT)
  • if you hit the bottom, it points down(Vector2.DOWN (Vector2(0,1))

Vector2.UP.dot(collision.get_normal()) is the dot product between the normal and the Vector2.UP.
Both vectors have the length 1, so the dot product is only the cosine between the angle of those vectors.

If you hit it from the top in the rectangle case collision.get_normal() is (0,-1) and Vector2.UP is also (0,-1).
The angle between them is 0 so the cos(0) is 1 and therefore the expression is 1.
In that case you want that expression to be 1 if it is a valid stomp for example.

From the side you would get 0 and from the bottom you would get -1

If you have a curved surface you can check the angle between the collision and the up direction like this if you defined a max angle:
Vector2.UP.dot(collision.get_normal()) > cos(deg_to_rad(max_collision_angle_deg))

gaunt fractal
#

Thank you so much. I will put your advice and suggestions to use, and get back to you in a few hours. There is a lot here for me to digest. Thanks a lot!!

gaunt fractal
#

Hi! So, I have been finally trying to implement your suggestion, and I am struggling a little. This function is being called in the _physics_process() function, by the way.

So, I tried it with "collision.get_collider() == BasicEnemy", as well as "collision.get_collider() == EnemyBounceCollision", but it was not working. I am currently trying it with BreakableBrick, because the object does not deal damage to the player character.

Anyways...

"print(collision.get_collider())" confirms the function is being called, and that the player is colliding with things. Yet, the code in lines 281 and 282 are never called. I understand that in my code, I am not calling "move_and_slide()" in the "collision_shenanigans()" function, but that is because it is already being called in "physics_process()". Besides, even if I call "move_and_slide()" again in the collision function, nothing really changes (other than the player becoming twice as fast, and jumping twice as high).

I am just a bit lost. In the second screenshot, you can see something I was trying out, that shows my level of confusion.

Sorry for asking for help again :( I am just really dumb.

kind iron
#

Also what does printing collision.get_collider() or collision.get_collider() == BreakableBrick or Vector2.UP.dot.(collision.get_normal()) before the if statement output? As you described it it seem like the statement is never true

kind iron
#

Now that i read your code and mine again i think i know what is wrong.
In my if statement i check if the collider is the same object as my enemy variable. So i used == which checks if the value of the two variables is the same.
In your statement you want to check if your collider is of the type or extends BreakableBrick.

So that statement should look like this instead then

if collision.get_collider() is BreakableBrick ...
gaunt fractal
#

Thank you so much, Sniffi. It is now working with the brick object, but not with the enemy objects. The brick is a Static2D object, while the enemies are CharacterBody2D, so maybe there are a few more things I need to get right before it works properly.

gaunt fractal
#

So, I added a StaticBody2D node as a child of the enemy node, and now it works. Should I be worried about having a StaticBody2D node as a child of a CharacterBody2D node?

kind iron
#

StaticBody2D should ususally not be moved at all and only being used for completely static objects like walls or similar.
If i understood you correctly you want the breakable brick and enemy to be stomped.
Couldnt you just do this, where you also just check if the collider is from type Enemy:

var collider := collision.get_collider()
var is_valid_collider:bool = (collider is BreakableBrick or collider is Enemy)
if is_valid_collider and Vector2. ...
    ...

and in the enemy script you have this:

class_name Enemy
extends Characterbody2D

How is your enemy set up that you need another Staticbody2D and what purpose does it have?

gaunt fractal
#

Understood. Thanks for letting me know. I removed the StaticBody2D node from the enemy.

The problem is the player does not detect collision when, well, colliding with enemies and as such, the stomping never triggers. The player just phases through the enemy. The one time I was able to make the player collide with an enemy, the player actually pushed the enemy into the tiles (screenshot #1).

I played around with collision layers and masks for a good while, to no avail. So, I decided to try the StaticBody2D route, because well, the stomping was working with the brick (which is a StaticBody2D object).

In the second screenshot, you can see how an enemy node tree is structured. I have different Area2Ds for different purposes, so I can enable and disable them based on the enemy's current state. And, in the third screenshot, you can see I have a base enemy script set up, with other enemies extending the BasicEnemy class.

kind iron
gaunt fractal
#

Thank you, Sniffi!

That makes things simpler as I no longer need to play around with the Area2Ds. Though, I will have to figure out how to stop the player from pushing the enemies, but that is probably no longer relevant to the original question I asked.

wispy mortar
#

wow.. this should be made into a tutorial