Bullet Destruction on Collision not working
Asked Answered
H

16

0

I'm making a 3D FPS game where i am also in the making of a shooting mechanic. I want to make so when bullets collide with something they self_destruct. But, when said bullet is fired and actually collides with, a wall, for example, it just passes through and that's it, but the code seems to be working fine on the tutorial i'm seeing. All the code below is in the script of the bullet and i'm actually detecting when the RayCast collides with something. Any questions to be asked about more details will be answered gladly

@onready var ray = $RayCast3D

func _process(delta):
...
if ray.is_colliding():
mesh.visible = false
await get_tree().create_timer(1.0).timeout
queue_free()

Hydrangea answered 30/1 at 1:4 Comment(0)
I
0

Try commenting-out the "await" line.

Irritated answered 30/1 at 1:23 Comment(0)
H
0

Irritated
No, that actually does nothing different.

Hydrangea answered 30/1 at 3:46 Comment(0)
I
0

If you change the code to the below, does it print anything?

if ray.is_colliding():
    print("ray is colliding") # add this line
    mesh.visible = false
    await get_tree().create_timer(1.0).timeout
    queue_free()

Worth checking everything against the reference material if it works as you stated.

Ironbark answered 30/1 at 12:23 Comment(0)
H
0

Ironbark you know what's funny? not only it actually prints something (although it only prints the message when the bullets collide with the ground but not the wall, maybe because the wall is too thin?) i got to actually see that some bullets don't pass through the ground, like most die when colliding but some still get to live to see the other side, get it? To get matters worse, the faster it is, the more likely it's going to survive and not destroy when colliding.

The problem is, obviously, bullets are meant to be fast and not always there will be too much collision for it to be destroyed, as the example of the wall. A bullet in the speed of 10.0, which is really slow, already passes through a wall, so imagine a bullet in the speed of 100.0, the intended for my bullets. There'll be almost nothing to stop them, but i want them to be colliding and destroying on impact...

Is there anymore that can be done?

Hydrangea answered 30/1 at 21:19 Comment(0)
F
0

Hello again. In FPS there are two methods of firing: hitscan and projectiles.
hitscan is the simplest, you put a raycast on the player and whatever it hits when pressing the fire button will take damage, then you spawn a decal of a bullet hole and particles.
the second depends on physics, it can be used for rocket launchers, or to create realistic weapon firing, but it's only worth at long distances or for things like rocket launchers and blasters.
there is virtually no difference between the two, hitscan is better for games that need to run on low end devices, require fast accurate response, or for games where you don't care about bullet drop and delay.
projectiles I would only use whenever needed (rocket launcher) or if the game is trying to be some kind of simulator like Arma3.
projectile is much more difficult. you can use a physics object, but too fast and it will always pass through walls. An alternative I kind of invented is to shoot a raycast. the raycast has a range equal to the distance the bullet has to move the next frame (it runs in the physics_process which is locked to 60 frames), then the bullet teleports to the next position (I think it was basis * speed + global_position). if the raycast hits, just do the same as with hitscan: particle effects, bullet hole decal, damage.
So, the first question is, which one is it? are you making an arcade or a simulation game?

@onready var ray = $RayCast3D

func _process(delta):
...
     if ray.is_colliding():
          mesh.visible = false
          await get_tree().create_timer(1.0).timeout
          queue_free()

first there's no need for await. second, you are running this in process, which is tied to your game's framerate. it should run on physics_process which is locked at 60 FPS.

I should probably post some of the code from my FPS, here, you will have to figure a few things out though. This is C_Projectile:

extends RayCast3D

@onready var assetmang : Asset_manager = get_node("/root/AssetManager")#ignore this
var tim : float = 0.0
@export var lifetime : float = 10.0
@export var weaponPower : float = 0.2#also ignore this

func _physics_process(delta):
	#projectile self destructs after lifetime ends
	if tim < lifetime:
		tim += delta
	else:
		selfDestruct()
	#projectile hits something
	if self.is_colliding():
		SpawnFX(self.get_collision_point()) #here you spawn particles, decals, etc
		selfDestruct()
	#projectile DOESN'T hit something
	else:
		self.translate_object_local(self.target_position * delta) #move the projectile

func selfDestruct():
	queue_free()

target position of the raycast is then the distance the projectile must travel in a frame. at 60 FPS, a muzzle velocity of, say 600 m/s, would be a target_position of, say, Vector3(0.0, 0.0, -10.0).

Filia answered 30/1 at 23:2 Comment(0)
H
0

Filia thank you for replying and getting to help me solve another issue man, but, i don't know if i did something wrong, probably did, but it didn't do much really, maybe it was more accurate, but i cant really put my finger there. Before i put the code, just wanna clarify some things that i may have left out the picture.

The first is my answer if it's an arcade or simulation, and i guess it's really inclined for an arcade, so i don't actually expect something really accurate to reality. The second is that all of this is done on the script of the bullet, maybe i should do it somewhere else? Third is that, even if it actually destroys the bullet, my main problem is that a bullet travels really far and really quick, so the speed should be high, but if the speed is high, the chances of destroying on collision is really low because it just phases everything.

extends Node3D

const SPEED = 100.0

var tim : float = 0.0
var lifetime : float = 10.0

@onready var mesh = $MeshInstance3D
@onready var ray = $RayCast3D

func _process(delta):
position += transform.basis * Vector3(0,0, -SPEED) * delta

func _ready():
pass # Replace with function body.

func _physics_process(delta):
#projectile self destructs after lifetime ends
if tim < lifetime:
tim += delta
else:
selfDestruct()
#projectile hits something
if ray.is_colliding():
print ("ray is colliding")
get_tree().create_timer(0.0).timeout
selfDestruct()
else:
ray.translate_object_local(ray.target_position * delta) #move the projectile

func _on_timer_timeout():
queue_free()

func selfDestruct():
queue_free()

Hydrangea answered 31/1 at 23:54 Comment(0)
H
0

Hydrangea (also i don't know how to put the code in the "black screen" like everyone does)

Hydrangea answered 31/1 at 23:55 Comment(0)
I
0

Hydrangea i don't know how to put the code in the "black screen"

``` 
code 
``` 
Interradial answered 1/2 at 0:0 Comment(0)
F
0

Hydrangea

Hydrangea The first is my answer if it's an arcade or simulation, and i guess it's really inclined for an arcade, so i don't actually expect something really accurate to reality.

If it's an arcade you should use a hitscan, the code is similar, simpler. Parent a raycast to the camera, when you press the fire button it checks if it hits, and then it deals damage and spawns particles on the collision point. No need to destroy the raycast. For other things like grenades you can use physics objects because they tend to move slower. I used the projectiles for the shotgun and misiles.

The second is that all of this is done on the script of the bullet, maybe i should do it somewhere else?

On the bullet is correct. But have it be a raycast with a graphic parented to it, like a meshinstance3D. Look at my code.

Third is that, even if it actually destroys the bullet, my main problem is that a bullet travels really far and really quick, so the speed should be high, but if the speed is high, the chances of destroying on collision is really low because it just phases everything.

With my script the raycast checks for collisions in the frame and then moves, there should be NO phasing, unless its some problem with the physics engine, like a bug or bad colliders.

Let's look at your code:

extends Node3D #use a raycast instead

const SPEED = 100.0

var tim : float = 0.0
var lifetime : float = 10.0

#you don't need these
@onready var mesh = $MeshInstance3D
@onready var ray = $RayCast3D

#this should be in physics process. Might be why it phases. But it's not needed because you are doing it again in physics process. Just delete it.
#func _process(delta):
#	position += transform.basis * Vector3(0,0, -SPEED) * delta

func _physics_process(delta):
	#projectile self destructs after lifetime ends
	if tim < lifetime:
		tim += delta
	else:
		selfDestruct()
	#projectile hits something
	if ray.is_colliding():
		print ("ray is colliding")
		#Create particles with add_sibling() (instead of add_child()) and put scripts on them to self destruct. Keep it simple, keep it separate. There's no effect on performance.
		get_tree().create_timer(0.0).timeout
		selfDestruct()
	else:
		ray.translate_object_local(ray.target_position * delta) #move the projectile

func _on_timer_timeout():
	#No need for this
	queue_free()

func selfDestruct():
	queue_free()
Filia answered 1/2 at 6:51 Comment(0)
H
0

look, i followed almost 100% of your code (where i'll specify what i changed) but still, i am met with no changes. Firstly, i will say that i moved the script to the RayCast of the bullet, where i maybe did the wrong thing to do, but in defense, extending RayCast3D while the script is in the bullet it gives an error stating that this is not possible as the script is in a Node3D

( I will beforehand say that, i apologise if maybe i'm following things wrong or not getting some lol i'm new to all this, but i'm grateful that you are helping me with all this. )

And now, here's the code with the things i changed:

extends RayCast3D #explained my problem

const SPEED = 100.0

var tim : float = 0.0
var lifetime : float = 10.0

func _process(delta):
	position += transform.basis * Vector3(0,0, -SPEED) * delta #i can't remove this, nor from _process
	#the bullet simply doesn't go foward if not for this, so i actually have to have them both in this exact form

func _ready():
	pass # Replace with function body.

func _physics_process(delta):

	if tim < lifetime:
		tim += delta
	else:
		selfDestruct()
	#projectile hits something
	if self.is_colliding():
		print ("ray is colliding")
		#i do not have any effect ou particle right now so no need to think about this
		get_tree().create_timer(0.1).timeout
		selfDestruct()
	else:
		self.translate_object_local(self.target_position * delta) #as of now, i am yet to see this do anything

#oh, and having no timer makes the bullet not disappear, i think i actually have to have a timer

func selfDestruct():
	queue_free() 
Hydrangea answered 1/2 at 23:39 Comment(0)
F
0

Hydrangea maybe it's my fault for not explaining well enough, I'll try to go slower.
This is what you are going to do:
1 - Click on BulletMusket, right click change type and make it a RayCast3D. It HAS to be a raycast.
2 - I don't understand what you are trying to do with Timers, forget about Timers, delete all of them, disconnect them, you DON'T NEED THEM.
3 - you will be left with TWO nodes: BulletMusket, which will be a RayCast3D, and your MeshInstance3D.
4 - Yes, the script that extends RayCast3D must be on a RayCast3D, this is VERY important.
5 - delete const SPEED, you don't need it.
6 - delete process, don't add it again. code should go in physics_process anyway. process is dependent on you PCs framerate, physics is locked at 60 FPS. this means it will always run 60 times per second.

We use the target_position of the raycast3D for speed and movement. This is a property on the RayCast3D node that determines both the direction and reach of the raycast. make sure it's pointing forward.
the way the projectile works is this:

  • during the frame, the raycast detects if it hits something.
  • if it doesn't, it moves in the direction and distance covered by the ray.
  • repeat on next frame.

so the target_position of raycast is also the SPEED of the projectile.

7 - if tim < lifetime: time += delta else: selfDestruct() destroys the node after lifetime is reached. No Timers required.
8 - remove create timer. I don't think it's doing anything. If you need some special effect to happen, you do it on a different scene with code and spawn it with add_sibling. We keep the code separate which makes it easier to debug and extend, it is modular.
9 -
self.translate_object_local(self.target_position * delta) #as of now, i am yet to see this do anything
that's because your raycast must be the root of the instanced scene, not a children. The raycast moves, the mesh moves with it.

Hydrangea #oh, and having no timer makes the bullet not disappear, i think i actually have to have a timer

you don't need timers. the code should selfDestruct the projectile after 10 seconds.

code should look like this:

extends RayCast3D

var tim : float = 0.0 #this is our Timer. do not touch it.
var lifetime : float = 10.0 #this is the lifetime of the projectile. it will selfDestruct after 10.0 seconds. you can export it if you want.

func _physics_process(delta):

	if tim < lifetime:
		tim += delta
	else:
		selfDestruct()
	#projectile hits something
	if self.is_colliding():
		print ("ray is colliding")
		selfDestruct()
	else:
		self.translate_object_local(self.target_position * delta) 

func selfDestruct():
	queue_free() 
Filia answered 2/2 at 1:49 Comment(0)
H
0

Filia So, i did as you said, and now i have interesting results. First is that although the appearence of "BulletMusket" is that of what indicates a Node3D, so the script should be giving errors, it doesn't give any. Yes i have altered the type of BulletMusket to a Raycast so it should be that, but it's a little confusing as you can see. So it's a raycast, that is why it's not giving any errors, but it doesn't appear so. (Also, should i delete RayCast3D that is the children of the now Raycast3D, that is, BulletMusket? I think not, but tell me what you think, and if so, what should i do once i delete raycast3d child))

So, to the results. It actually works really well, i can't see it travelling because of the logic that we are using now, so i don't know if it's going in the same direction of where i'm looking (but that should be a problem with the alignment of the raycast maybe, although before it was going forward as intended), but the message "ray is colliding" appears instantly 99/100 times for sure. So that is really good. But, that 1 time where it does not appear, the bullet just spawns and slowly but surely goes down very awkwardly.

I have tested where are the times that this can happen, but they are not so accurate. First is that it happens often when i'm looking somewhere where its just void, so there's nothing the bullet can hit ever, so it just spawns and goes down as i have said, but also sometimes it doesn't, the message appears normally. And even when i'm facing a object with collision, there's a small chance the bullet does that same awkward bug.

So now, i'm guessing it probably has to do with the fact the raycast is pointing downwards, so there are majority of times where it meets the ground but also there are times it doesn't. But, before, it was going forward normally to where i was pointing, so i don't really understand why now it's going down. Again, the code most surely is going well and we have something here that it's working, but there's still something to be solved, but i think i'm quite close to closing this problem.

Hydrangea answered 2/2 at 3:13 Comment(0)
F
0

Hydrangea should i delete RayCast3D that is the children of the now Raycast3D, that is, BulletMusket? I think not, but tell me what you think, and if so, what should i do once i delete raycast3d child)

Yes. BulletMusket is the raycast now.

Hydrangea so i don't know if it's going in the same direction of where i'm looking

Bullets are fast, you will only notice them at long distances or if they are moving slow. At short distances they will not move at all, just hit.

Hydrangea that 1 time where it does not appear, the bullet just spawns and slowly but surely goes down very awkwardly.

Weird. Make sure:
1 - it's pointing forward. In my case it's negative Z.
2 - check a property in transform so that it doesn't inherit parent transforms. It's called top level.
3 - set your collision layers. Put player, world and bullets on different layers, make sure the bullets can't interact with player.
4 - clear rotations for BulletMusket.

Filia answered 2/2 at 4:0 Comment(0)
H
0

Filia I think, now that we have done everything, we are very close to closing this one. All of the bullets when they collide with an object checks the message "ray is colliding" but i have a new problem. They are now going reaaaally slow, like really slow. They ARE going directly to where i'm pointing, they are just going at the same speed of a turtle. And i'm not even worried that's going to end the same as previously ( slower = more accurate collision/faster = less accurate collision ) because we are now using a different logic so i'm in hopes of it going well, we just need to make the bullet go faster.

I have not done anything to the code, it's the same, i have just done what you told now:

Filia 1 - it's pointing forward. In my case it's negative Z.
2 - check a property in transform so that it doesn't inherit parent transforms. It's called top level.
3 - set your collision layers. Put player, world and bullets on different layers, make sure the bullets can't interact with player.
4 - clear rotations for BulletMusket.

Minus the part of the collision layer, not because i thought it wasn't needed, it was more that when i changed layers nothing changed really and if now that the problem is speed, if you think i should keep pressing this key.

Hydrangea answered 2/2 at 21:43 Comment(0)
F
0

Hydrangea I had the same problem, just increase target position until they are going fast enough. It has something to do with delta.
My projectile has a target positon of (0.0, 0.0, -40.0).

Filia answered 2/2 at 23:18 Comment(0)
H
0

Filia Well, now i'm pretty sure it's 99% complete. But, it seems to have a limit on how quickly the bullet travels. Like, for me -40 was a little slow, so i upped it to -100, got a little fast, but i wanted faster, then i was testing and then i got to -1000 and it doesn't really seem to have gone faster than -100. Also, when i'm close to a object of collision, the message instantly appears, but as i got further, the bullet actually takes waay longer to actually collide, like, within 10 meters of a collision the bullet instantly collides, but if i get to like 50 meters the bullet actually has to really touch the collision for the message to appear. Not really a problem obviously, the rest is working confortably and i'm happy that i could solve this issue once and for all (at least for now, if anything i will make another post detailing my problem).

(Also, thank you very much for basically carrying me through everything lol i learned a lot of things and the results really paid off)

Hydrangea answered 3/2 at 0:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.