Can someone help me with this error?

Does anyone know why I’m getting an error at line 28 in hitscan_weapon.gd(*) script saying “Could not find type “Enemy” in the current scope.”

Here is the code:

extends Node3D

@export var fire_rate := 14.0
@export var recoil := 0.05
@export var weapon_mesh: Node3D
@export var weapon_damage := 15
@export var muzzle_flash: GPUParticles3D
@export var sparks: PackedScene

@onready var cooldown_timer: Timer = $CooldownTimer
@onready var weapon_position: Vector3 = weapon_mesh.position
@onready var ray_cast_3d: RayCast3D = $RayCast3D

Called every frame. ‘delta’ is the elapsed time since the previous frame.

func _process(delta: float) → void:
if Input.is_action_pressed(“fire”):
if cooldown_timer.is_stopped():
shoot()

weapon_mesh.position = weapon_mesh.position.lerp(weapon_position, delta * 10.0)

func shoot() → void:
muzzle_flash.restart()
cooldown_timer.start(1.0 / fire_rate)
var collider = ray_cast_3d.get_collider()
printt(“weapon fired!”, collider)
weapon_mesh.position.z += recoil
if collider is Enemy:
collider.hitpoints -= weapon_damage
var spark = sparks.instantiate()
add_child(spark)
spark.global_position = ray_cast_3d.get_collision_point()

Hi Reluxi, you should make this an Ask topic and tag it with the code from the video you are on. That way the correct TA will be notified. They might not see this otherwise.

2 Likes

Okay, thank you!

hi,

it sounds like the Enemy class hasnt been defined anywhere, so godot doesn’t know about it.

can you have a look at your enemy.gd script please and check if you have the class name declaration at the top of the script like below.

extends CharacterBody3D
class_name Enemy  #need this to declare the Enemy that we compare later

see if that was there and let us know please.

cheers
Darren

1 Like

I still get an error after trying to run the game saying “Invalid get index ’position’ (on base: ’null_instance’).” And it’s showing this line in hitscan_weapon.gd script:

@onready var weapon_position: Vector3 = weapon_mesh.position

Hi,

If that cleared the last error, cool.

For this one it’s saying that it can’t find a value for weapon_mesh.

As we have this as an @export, can you double check that you have assigned it in the inspector please.

Let us know how you get on.

Darren

1 Like

Thank you! Now I can run the game, but there seems to be another problem. Whenever I try to shoot with my smg, the game crashes and another error appears saying “Cannot call method ‘restart’ on a null value.” And it’s showing this line in hitscan_weapon.gd script:

muzzle_flash.restart()

If you can double check that all the exported variables that are in the inspector have been assigned and see if that works.

The muzzle flash is another one the same as you done with the weapon_mesh previously. Need to ensure there’s something assigned, otherwise it will be null.

Check those and let us know.

Darren

1 Like

Thanks, that error also got cleared and I moved to the next lecture (Game Over), but I realized that when the enemy attacks, I don’t get a message in the output saying “Enemy attack!”, I just see the attack animation. I think the attacks should be like “Enemy attack!” 100 “Enemy attack!” 80 “Enemy attack!” 60 or something like that, and I also don’t get the Game Over screen because of that.

Here’s my enemy.gd(*) code if that’s needed

extends CharacterBody3D

class_name Enemy

const SPEED = 5.0
const JUMP_VELOCITY = 4.5

@export var max_hitpoints := 100
@export var attack_range := 1.5
@export var attack_damage := 20

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
@onready var navigation_agent_3d: NavigationAgent3D = $NavigationAgent3D
@onready var animation_player: AnimationPlayer = $AnimationPlayer

var player
var provoked := false
var aggro_range := 12.0
var hitpoints: int = max_hitpoints:
	set(value):
		hitpoints = value
		if hitpoints <= 0:
			queue_free()
		provoked = true

func _ready() -> void:
	player = get_tree().get_first_node_in_group("player")

func _process(_delta: float) -> void:
	if provoked:
		navigation_agent_3d.target_position = player.global_position

func _physics_process(delta: float) -> void:
	var next_position = navigation_agent_3d.get_next_path_position()
	# Add the gravity.
	if not is_on_floor():
		velocity.y -= gravity * delta

	var direction = global_position.direction_to(next_position)
	var distance = global_position.distance_to(player.global_position)
	
	if distance <= aggro_range:
		provoked = true
		
	if provoked:
		if distance <= attack_range:
			animation_player.play("Attack")
	
	if direction:
		look_at_target(direction)
		velocity.x = direction.x * SPEED
		velocity.z = direction.z * SPEED
	else:
		velocity.x = move_toward(velocity.x, 0, SPEED)
		velocity.z = move_toward(velocity.z, 0, SPEED)

	move_and_slide()

func look_at_target(direction: Vector3) -> void:
	var adjusted_direction = direction
	adjusted_direction.y = 0
	look_at(global_position + adjusted_direction, Vector3.UP, true)
	
func attack() -> void:
	print("Enemy Attack!")
	player.hitpoints -= attack_damage

You’ve declared the attack() function but haven’t actually called it anywhere.

I like Bram’s idea of keyframing the function call in the attack animation, but even before doing that or similar, you can also just temporarily call attack() where you play the animation. Then you can confirm that the function works, which will help you debug if there are any problems with keyframing it.

2 Likes

Thank you! :pray: Now all the errors and bugs are fixed! :+1:

3 Likes

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms