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”:
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!
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.
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")