#how do we implement explosions in Godot 2d that do stuff(eg. damage)
174 messages · Page 1 of 1 (latest)
no but i cant do that
because then you would be able to do damage through walls and stuff
thats what i thought of too actually
what i usually do is add a raycast at the center thats the same length as the radius of the explosion, and have it loop through every overlapping body and check if the raycast result is that body, if it is apply damage. if its not, do nothing
basically what I was about to say
ahh thats pretty smart, i was thinking of just doing raycasts in 8 directions and seeing if they hit anything 💀
ty
yea its a useful thing to learn, good for not letting players pick up objects through walls, and for vision cones not seeing thru stuff
trust me, I went down a path like that for a game I made (for light detection not explosions) and it's far better to just do a raycast per target
(I stuck with the alternative because it provided better results for light detection, but it's heavy on performance)
you can create a new raycast per target, or reuse the same raycast and call force_raycast_update() every time it gets_collider()
before it gets_collider(), rather
im not too familiar with ray casts (i havent used them yet), but how would this matter if we qeue free the explosion at the end anyway
btw do we use autoloads for functions we want to use through the code, so say i want to use the explosion function, i would pass in coords and radius and i want to use it anywhere in the code
i would use globals right
i dont think it would matter, its just different ways of doing the same thing. i think reusing the raycast might be a little more performant, though its probably not too big a deal
fair
yeah
so its like Global.create_explosion(radius, position) which can be called from anywhere
the actual script name doesent matter when we use globals right
yeah you can set it to be anything
you could also store the explosion in the player itself, as a child of a Node so it doesn't inherit the player's transform
reduces the messiness of needing to do lots of things through an external node
but wouldnt i have to re write the code every time i wanted an explosion then
like say i made a grenade
also how do we make global nodes for the area2d and ray casts required
plus i might qufree it after i explode it, so its prolly better to have it externally
if you're queue freeing it, then you'd still need to instantiate it, and can do so in the player
get_tree().current_scene.add_child()
is how you'd put it in the scene
then that also puts the preload in the player, which is pretty sensible
or you could even export a packed scene
can't do that with an autoload
I think the idea is that several things may want to do explosions, so they want to implement it in an autoload to make life as easy as possible
yes exactly
but i still need to add it as a child of something for it to work right
i added it as a child of the autoload but that doesent work
What's the issue?
i made an explosion class and am testing it rn
func explode():
print("called explode")
get_node("Explosion area").get_node("explosion radius").get_node("Shape2D").radius = radius
var bodies = get_node("Explosion Area").get_overlapping_bodies()
print(str(bodies))
i put the explosion radius really high (50 pixels), the game is pixel art so that should be enough. i make a new explosion every time a player dies
so i killed on of the players, but it doesent print anything
Oh, a quick tip. Often a better way to get child nodes like that is with an @onready variable:
oh nvm, it seems the method isnt getting called at all
@onready explosion_shape = $Explosion area/explosion radius/Shape2D
oh yeah, that makes sense
Then you can just refer to explosion_shape instead of the big string of .get_node() calls
i forgot about that 💀
But anyway, onto the actual problem, what's the code that the player uses to create the explosion
func die():
print(name + " died")
Global.explosion(position, 30)
And you're seeing it print the died message?
Okay, so let's look at the function in the Global autoload
@onready var explosion_class = preload("res://explosion.tscn")
func explosion(position: Vector2, radius: float):
var explosion = explosion_class.instantiate()
explosion.radius = radius
explosion.position = position
Mhm. So, does the explosion script call the explode() function at any point?
Or does that need to be called from outside?
oh lol
wait i added it lemme see if it works
atleast it calls it now
explosion_shape.radius = radius
its claiming that the object is of type nil
What's the tree structure of the explosion scene?
Ah, right
You can use a shapecast that does not change its position and checks for anything, if found then it damages the enemy
Knowing that, you actually want to do the following:
@onready explosion_shape = $Explosion Area/explosion radius
And then:
explosion_shape.shape.radius = radius
I'm not really good at explaining
Why use a shapecast instead of an area?
personally an area did not work for me
oh thats how it works
What issue did you encounter?
brain issues, i have low intelligence stat when i was born (obvious skill issue) so i had to do what i could
you dont need the string marks?
it gives me an error if i dont use quotation marks
Mhm! Notice how the Radius property is inside the Shape property, so that's how it has to be accessed
Ah, right, yes, you do need quotes in your case. That's because your node names contain spaces.
I'm, uh.. Sorry for your loss?
is godot case sensitive?
anyway its still showing nil
Hm. Could be an issue with order? What does your explosion() function inside the autoload look like now?
func explosion(position: Vector2, radius: float):
var explosion = explosion_class.instantiate()
explosion.radius = radius
explosion.position = position
explosion.explode()
Oh, you haven't actually added it to the tree
You'll need to use add_child somewhere to do that
If you don't add it to the tree, then it never actually readies itself
so do i explode it after using add_child or before
After
but since its an autoload, what will it be a child of
The explosion could be a child of the autoload itself (that's totally fine, since an autoload is just a node)
There are other options, but for now that should work
I think the ideal is probably adding it as a child of the current level, so that it'd be removed when the level is unloaded
You can get the current scene using get_tree().current_scene
its going to be removed by itself anyway after i add the particle effects ( since i can only remove it after the particles are over )
but it still doesent add my tank in the bodies hit
P2 died
bodies hit []
Check the collision layers?
all are on 1
You can tick "Visible Collision Shapes" so you can see the area's shape appear
That might help with debugging?
ohh, i didnt know that was an option
ill go ahead and do that
yep its quite big
bigger than the screen infact
As an alternative to using .get_overlapping_bodies(), you could use the body_entered signal?
It might be the case that you're asking the area for overlapping bodies before it's gotten a chance to check for them
is that even possible?
Yeah, that kind of thing can happen in some cases
how would i impliment it with the body entered signal, have an array and append it for every time the signal is called?
You could, or you could just apply the effect inside the on_body_entered implementation
oh right
No need to maintain a list in most cases
oh ok nice it lists the bodies now
:D
wierd, i implimented the damage function in it
func _on_explosion_area_body_entered(body: Node2D) -> void:
print(str(body))
if(body is TANK):
body.damage()
and it just drains all the hp and destroys the game
like literally hangs it
ahh
i got it
since i do damage but dont delete the tanks when they die
they just keep killing each other using explosions
Oop
oh yeah, i havent implimented that yet, since i dont really have any objects in my game, im implimenting explosion particles first. but that should be easy enough (famous last words)
tbh i feel like i should have started with either using unity or godot with C#, since i aldready knew java and C# is apparently just microsoft flavor java
yeah i think now that ive started with GDscript im just going to continue
I know there's issues with web builds when using C#, for instance
oof, still godot better than unity cuz open source
Which, for me, was an instant massive issue.
GDScript is a perfectly good language
And not hard to learn
I think it fits Godot well
true
For me, until Godot C# has support for web builds, I can't even consider using it. Web builds are just too important for the things I do (almost entirely game jams)
i think over time GD script might get some of the features of C#
That and, I've become really comfortable with GDScript at this point
so it might be worth holding out
seriously though interfaces are like quite a common thing
weird that they arent in godot
I get what you mean, but they're kind of unnecessary because of the philosophy of the language.
wdym
Kind of. They'd still have uses, of course.
In GDScript, the idea is that you don't care so much whether a certain object implements an interface or is of a certain class, you care about what it can do. If you want to damage it, just check if it can be damaged, no need to check if it's a player or an enemy or what have you. That's why you have stuff like the has_method() function
Of course, that's not the entirety of the language's philosophy.
oh nice
tbh thats kinda janky
cuz you might name it slightly different accidentally in some classes
or might forget to impliment the function
but ig it works
Godot really isn't meant for huge games
Stuff like that becomes more important as scale increases
But with smaller games and smaller teams, stuff like that is much easier to just go in and fix
fair ig, but you shouldnt be needing to fix it in the first place
With an interface, you can still forget to implement the interface, or one of the functions
If the argument is "you could forget to do something", then that can always happen
I'm not saying it's a perfect system. Interfaces would have uses.
But you honestly get used to it
fair
the problem now is how to set the explosion's targets and stuff like collision layers. which could be solved by simply having different packed scenes
Or including them as parameters (probably with default values)
ig i could, just have an explosion scene and duplicate it and put the explosion function in the scene itself
but atp idc, i aldready implimented the global so i might as well use it
im new to godot so some of my structuring decisions do end up a bit weird
but we improve with time
👍
just wanted to share some ideas, but yea, anything works if it works
this is the main advantage