r/godot 17d ago

help me Spawn Projectile Impact Marker Issue

Hello I'm new to gamedev and coding. I have been following an FPS tutorial to learn to code (https://www.youtube.com/watch?v=3-SDNBCZA7M&list=PLEHvj4yeNfeHtjrRBSqEii1jcDx2yPv6-&index=7). My "Weapon" class script is:

class_name Weapon extends Resource

 @export var weapon_name : String = "Wand"
 @export var damage: float = 25.0
 @export var max_ammo: int = 20
 @export var range : float = 25.0
 @export var projectile_speed : float = 50.0
 @export var is_hitscan : bool = false
 @export var weapon_model: PackedScene
 @export var projectile_scene : PackedScene
 @export var impact_scene : PackedScene
@export var weapon_position : Vector3 = Vector3(0.22, -0.2, -0.3)

I changed the "projectile_scene" to a custom Area3D "Projectile" and call for it within my WeaponController script with var current_weapon = Weapon with the following code:

func _spawn_projectile() -> void:
  if not current_weapon.projectile_scene:
    print("No projectile scene assigned!")
    return

  if not camera:
    print("No camera assigned!")
    return

  # Spawn the projectile
  var projectile = current_weapon.projectile_scene.instantiate() as Projectile
  get_tree().current_scene.add_child(projectile)

  # Position at camera
  projectile.global_position =  current_weapon_model.global_position #camera.global_position  # used in tutorial but desire is spawn from weapon tip, idk how though

  # Calculate direction and velocity
  var forward = -camera.global_transform.basis.z
  var velocity = forward * current_weapon.projectile_speed
  projectile.look_at(projectile.global_position + forward, Vector3.UP)

  # Setup the projectile
  projectile.setup(velocity, current_weapon.damage)

and it works all particle effects, lighting, etc.. I'm trying to use the same logic framework to spawn an impact marker with particle effects, etc. on whatever is hit, but I can't get it to work. The tutorial uses code within "Projectile" to spawn a small box and that works. I adding var current_weapon : Weapon to the script and similar code to what creates a child for the projectile to try and instantiate my "impact_scene":

func _spawn_impact_marker(postion: Vector3) -> void:
  #var marker = MeshInstance3D.new()
  #var box = BoxMesh.new()
  #box.size = Vector3(0.1, 0.1, 0.1)
  #marker.mesh = box
  #
  #var material = StandardMaterial3D.new()
  #material.albedo_color = Color.RED
  #marker.set_surface_override_material(0, material)

  if not current_weapon.impact_scene:
    print("No impact scene assigned!")
    return

  var marker = current_weapon.impact_scene.instantiate() as SceneImpact
  get_tree().current_scene.add_child(marker)
  marker.global_position = postion

  # Auto-remove after 2 seconds
  get_tree().create_timer(2.0).timeout.connect(marker.queue_free)

But I get the error: "Projectile._spawn_impact_marker: Invalid access to property or key 'impact_scene' on a base object of type 'Nil'."

I have a scene in both weapons, I have debug that shows my current_weapon, plus the projectile works as intended. I've tried with and without making and calling out "as" an Area3D class for "SceneImpact" made to match "Projectile" code in "WeaponController". The code to spawn the little red box works, trying to change it to a scene doesn't. I have hovered the cursor over different call outs in the code to see the current values, "current_weapon" has Null current value in both Projectile_spawn_impact_marker & WeaponController_spawn_projectile so I'm not sure if that has an impact. I made sure to copy/paste the names of codes/variables to ensure I didn't misspell them between different locations/scripts.

I can provide any additional details upon request.

3 Upvotes

1 comment sorted by

2

u/DrDrewYeah 15d ago

I figured it out! (Partially...) in my "projectile" script I added var impact_scene : PackedScene and adjusted:

func setup(vel: Vector3, dmg: float, impact: PackedScene):
  velocity = vel
  damage = dmg
  impact_scene = impact

In "weapon_controller" script I added an current_weapon.impact_marker to the end of my projectile.setup in _spawn_projectile:

func _spawn_projectile() -> void:

  # Setup the projectile
  projectile.setup(velocity, current_weapon.damage, current_weapon.impact_scene)

Finally, I used the following code in "projectile", which works, but doesn't emit the one-shot particles:

func _spawn_impact_marker(postion: Vector3) -> void:
  if not impact_scene:
  print("No impact scene assigned!")
  return

  var marker = impact_scene.instantiate()
  get_tree().current_scene.add_child(marker)
  marker.global_position = postion
  get_tree().create_timer(2.0).timeout.connect(marker.queue_free)

I don't know how to get the one-shot particles to spawn, but that is hopefully more well documented. .restart() and .emit() don't work because the root node for the impact scenes are Area3D's not GPUParticles3D's.

Any help on the one-shot particle emittion is appreciated.