Attempt to call function 'interact' in base 'null instance' on a null instance

Godot Version

4.5

Question

Hello :3

Im trying to make an interactable object. Almost everything has worked, except now it has given me the error message “Attempt to call function ‘interact’ in base ‘null instance’ on a null instance.”

Heres my code:

(player)

extends CharacterBody3D

@onready var raycast = $Camera3D/RayCast3D
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
@onready var target = raycast.get_collider()



func _physics_process(delta: float) -> void:
	_update_camera(delta)
	if raycast.is_colliding():
		print("target")
		$CanvasLayer/BoxContainer/Label.show()
		print("interactable")
	if Input.is_action_just_pressed:
		target.interact()
		

	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta



	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var input_dir := Input.get_vector("Left", "Right", "Up", "Down")
	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if 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 _input(event):
	if event.is_action_pressed("Exit"):
		get_tree().quit()

func _ready():
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

var _mouse_input : bool = false
var _mouse_rotation : Vector3
var _rotation_input : float
var _tilt_input : float
var _player_rotation : Vector3
var _camera_rotation : Vector3


func _unhandled_input(event):
	_mouse_input = event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED
	if _mouse_input :
		_rotation_input = -event.relative.x * MOUSE_SENSITIVITY
		_tilt_input = -event.relative.y * MOUSE_SENSITIVITY
		print(Vector2(_rotation_input,_tilt_input))

@export var TILT_LOWER_LIMIT := deg_to_rad(-90.0)
@export var TILT_UPPER_LIMIT := deg_to_rad(90.0)
@export var CAMERA_CONTROLLER : Camera3D
@export var MOUSE_SENSITIVITY : float = 0.5 




func _update_camera(delta):
	
	_mouse_rotation.x += _tilt_input * delta
	_mouse_rotation.x = clamp(_mouse_rotation.x, TILT_LOWER_LIMIT, TILT_UPPER_LIMIT)
	_mouse_rotation.y += _rotation_input * delta
	
	_player_rotation = Vector3(0.0,_mouse_rotation.y,0.0)
	_camera_rotation = Vector3(_mouse_rotation.x,0.0,0.0)
	
	CAMERA_CONTROLLER.transform.basis = Basis.from_euler(_camera_rotation)
	CAMERA_CONTROLLER.rotation.z = 0.0
	
	global_transform.basis = Basis.from_euler(_player_rotation)
	
	_rotation_input = 0.0
	_tilt_input = 0.0

although it says the problem is this exact line:

if Input.is_action_just_pressed:
		target.interact()

and heres my object, which is also set in the group “Interactables”:

extends Node3D

func interact():
	print("interacted")
	queue_free()

How do i fix this error?

When you write …

if Input.is_action_just_pressed:

	target.interact()

… you dont specify which action.

It should look more like:

if event.is_action_pressed(“Exit”):

	get_tree().quit()

Also, the code assumes that there is a target and that it can be interacted with. Its not certain there will be. I would add a check to make sure there is a target and that target .has_method(“interact”) after Input.is_action_just_pressed(“your action’s name“).

Also if you want better help, try to avoid pasting in entire scripts. Like jumping, camera logic etc. Here, the problem is with the targeting. It just makes it easier to find the problem!

1 Like

okay :DD thank you!! the game runs now, but when i press interact (e), it doesnt print ‘interacted’ or free the queue

@onready var target = raycast.get_collider()



func _physics_process(delta: float) -> void:
	_update_camera(delta)
	if raycast.is_colliding():
		print("target")
		$CanvasLayer/BoxContainer/Label.show()
		print("interactable")
	if Input.is_action_just_pressed("Interact"):
		target.interact()
		

OK!

I would add a print statement just to make sure the target.interact() part of the code is reached.

`
	if Input.is_action_just_pressed("Interact"):
                print(“Interact is pressed”) 
                print(target)  
                if target.has_method(“Interact”): 
                     target.Interact()
                elif target.has_method("Interact") == false:
                     print("Target doesn't have method Interact")

I would also double check that “Interact” should be written with a capital i.

The print(target) will print to target, just to check there is one.

What is the target? Is it always the same thing?

1 Like

Thanks ^^

now when i play the game, it kicks me out saying ‘E 0:00:03:533 _physics_process: Attempt to call function ‘has_method’ in base ‘null instance’ on a null instance.”

Also, for now its only one interactable, but I was going to put the same code onto different collectables. For now, its only one VHS tape.

func _physics_process(delta: float) -> void:
	_update_camera(delta)
	if raycast.is_colliding():
		print("target")
		$CanvasLayer/BoxContainer/Label.show()
		print("interactable")
	if Input.is_action_just_pressed("interact"):
		target.interact()
	elif target.has_method("Interact") == false:
		print("Target doesn't have method Interact")
		

raycast.get_collider() should not be called @onready, but when the button is pressed. Otherwise target will always be the one thing hit by the raycast at the beginning (or null, if it didn’t hit anything in that moment).

I would remove this line:

@onready var target = raycast.get_collider()

And change the other code to:

	if Input.is_action_just_pressed("interact") and raycast.is_colliding():
		var target = raycast.get_collider()
		if target.has_method("interact"):
			target.interact()
		else:
			print("Target doesn't have method Interact")
1 Like

Thank you!!! :smiley:

I only have one more quiestion (genuinely thank you ive been at this for DAYS)

This is my objects code:

extends Node3D

func interact():
	print("interacted")
	queue_free()

How do i make it have the method interact? Right now its saying it doesnt have it

This object already has the method “interact”, but since it’s a Node3D I guess it won’t be the one detected from the raycast.

Does it have any child nodes (like a StaticBody3D or an Area3D) that the raycast can hit?

1 Like

That was my other problem :DDDD (i changed the root node to a staticbody3d)

thank you so so much!!!<3333333333333 I can finally get started fully :DDDDD!!

(can i set multiple solutions or no?)

1 Like