Godot Version
4.2.1
Question
I followed the official 3D gizmo guide to make my own gizmo, but during the process I kept receiving an Invalid Call
error in the _redraw
function.
The error is specifically:
res://addons/sky_light_3d_gizmo/plugin.gd:20 - Invalid call. Nonexistent function 'calculate' in base 'DirectionalLight3D (SkyLight3D)'.
Here is my entire SkyLight3D
class:
extends DirectionalLight3D
class_name SkyLight3D
@export_group("Orbit Properties")
@export_range(-180.0, 180.0) var orbit_offset := 0.0
@export var orbit_period := 0.0
@export var pertubation_period := 0.0
@export_range(-90.0, 90.0) var incline := 0.0
@export_group("Wobble Incline")
@export var wobble_incline := false
@export var wobble_period := 0.0
var _seconds := 0.0
var _tick := 0
var _days := 0.0
func _process(delta: float) -> void:
position = calculate(delta)
look_at(Vector3.ZERO)
func calculate(delta: float) -> Vector3:
# calculate current time
_seconds += delta * 3600
if _seconds > 1.0:
_tick += roundi(_seconds)
_seconds = 0.0
_days = _tick / float(86400)
# calculate position in orbit
var cycle := _cycle_angle(_days, orbit_period)
var final_position := _circle(fmod(orbit_offset + cycle, 360.0))
if not wobble_incline:
final_position = final_position.rotated(Vector3.RIGHT, incline)
var pertube_cycle := _cycle_angle(_days, pertubation_period)
final_position = final_position.rotated(Vector3.UP, pertube_cycle)
if wobble_incline:
var wobble_cycle := _cycle_angle(_days, wobble_period)
wobble_cycle = sin(deg_to_rad(wobble_cycle)) * incline
final_position = final_position.rotated(Vector3.RIGHT, wobble_cycle)
return final_position
func _cycle_angle(current: float, max: float) -> float:
if is_equal_approx(current, 0.0) || is_equal_approx(max, 0.0):
return 0.0
return fmod(current, max) / max * 360.0
func _circle(f: float, r := 1.0) -> Vector3:
return Vector3(r * sin(f), 0.0, r * cos(f))
And here is my entire plugin
script:
extends EditorNode3DGizmoPlugin
const default_icon := preload("res://gizmo_icons/earth_icon.png")
func _get_gizmo_name() -> String:
return "SkyLight3D Gizmo"
func _has_gizmo(for_node_3d: Node3D) -> bool:
return for_node_3d is SkyLight3D
func _init() -> void:
create_material("main", Color(0, 0, 1))
create_icon_material("icon", default_icon)
func _redraw(gizmo: EditorNode3DGizmo) -> void:
gizmo.clear()
var node := gizmo.get_node_3d() as SkyLight3D
var lines := PackedVector3Array()
print(node.calculate(23.0))
var icon_material := get_material("icon", gizmo)
icon_material.albedo_texture = load("res://gizmo_icons/" + node.name.to_lower() + "_icon.png")
gizmo.add_unscaled_billboard(get_material("icon", gizmo), 0.05)
It’s that print(node.calculate(23.0))
line that causes the error. No idea why. The function absolutely exists, it even appears in the autocompletion menu.
Edit
I have found that not only do I get this error for functions but also for properties. The plugin only seems to recognize exported variables. Is this intentional?
Here’s the error for the properties:
res://addons/sky_light_3d_gizmo/plugin.gd:34 - Invalid get index '_seconds' (on base: 'DirectionalLight3D (SkyLight3D)').
It seems like my only option is to have my plugin store its own data.