calling on null value and a ton of other newbie struggles

Godot Version

4

Question

new to scripting and game making. have been looking for any answers

Paste your code or whatever is giving your problems here, so we can help you

1 Like

If you want to check if value is null and do something try that:

if value==null: on_null_value()

sorry i forgot to add the code. so i have my scene in the image provided

in my knight node i have:

extends CharacterBody3D

Constants

const SPEED = 10.0
const JUMP_VELOCITY = 7.0
const DODGE_DISTANCE = 3.0
const DODGE_TIME = 0.5

@onready var player = get_node_or_null(“Player/PlayerC”)
@onready var animation = get_node_or_null(“Player/AnimationC”)
@onready var combat = get_node_or_null(“Player/CombatC”)

func _physics_process(delta: float) → void:
player.handle_movement(delta)
combat.handle_combat(delta)

move_and_slide()

On my AnimationC node i have:

extends Node3D
class_name AnimationC

@onready var animation_player: AnimationPlayer = $AnimationPlayer

signal animation_finished

func _ready() → void:
animation_player.connect(“animation_finished”, Callable(self, “_on_animation_finished”))

func play_animation(animation_name: String) → void:
if animation_player == null:
print(“Error: AnimationPlayer is null in AnimationC!”)
return

if not animation_player.is_playing() or animation_player.current_animation != animation_name:
	animation_player.play(animation_name)

func _on_animation_finished(anim_name: String) → void:
emit_signal(“animation_finished”)

in my PlayerC node i have:

extends Node3D

@onready var knight: CharacterBody3D = get_node_or_null(“…/…”) as CharacterBody3D
@onready var animation_controller: AnimationC = get_node(“…/AnimationC”)

const SPEED = 10.0
const JUMP_VELOCITY = 7.0

var was_on_floor = true
var has_jumped = false
var action_animation_playing = false

func _ready() → void:
animation_controller.connect(“animation_finished”, Callable(self, “_on_animation_finished”))

func _physics_process(delta: float) → void:
if knight == null:
return

handle_movement(delta)

if not knight.is_on_floor():
	knight.velocity.y += knight.get_gravity().y * delta

if Input.is_action_just_pressed("Jump") and knight.is_on_floor() and not has_jumped:
	knight.velocity.y = JUMP_VELOCITY
	play_action_animation("Jump_Full_Long")
	has_jumped = true

if knight.is_on_floor():
	if has_jumped and not was_on_floor:
		play_action_animation("Jump_Land")
		has_jumped = false
	elif not action_animation_playing:
		animation_controller.play_animation("Idle")

was_on_floor = knight.is_on_floor()

knight.move_and_slide()

func handle_movement(delta: float) → void:
if knight == null:
print(“Error: knight is null when trying to access velocity.”)
return

var input_dir = Input.get_vector("Left", "Right", "Forward", "Back")
var move_direction = Vector3(-input_dir.x, 0, -input_dir.y).normalized()

if move_direction.length() > 0:
	knight.velocity.x = move_direction.x * SPEED
	knight.velocity.z = move_direction.z * SPEED
	knight.rotation.y = atan2(move_direction.x, move_direction.z)
	if not action_animation_playing:
		animation_controller.play_animation("Running_A")
else:
	knight.velocity.x = 0
	knight.velocity.z = 0
	if not action_animation_playing:
		animation_controller.play_animation("Idle")

func play_action_animation(animation_name: String) → void:
action_animation_playing = true
animation_controller.play_animation(animation_name)

func _on_animation_finished() → void:
action_animation_playing = false

and lastly in my CimbatC node:

extends Node3D

@onready var animation_controller: AnimationC = get_node(“…/AnimationC”)
@onready var knight: CharacterBody3D = get_parent().get_parent() as CharacterBody3D

var is_attacking = false
var is_dodging = false
var dodge_timer = 0.0
var dodge_offset = Vector3.ZERO

const DODGE_DISTANCE = 3.0
const DODGE_TIME = 0.5

func _physics_process(delta: float) → void:
handle_combat(delta)

func attack() → void:
if not is_attacking and not is_dodging:
is_attacking = true
animation_controller.play_animation(“1H_Melee_Attack_Slice_Diagonal”)

func end_attack() → void:
if is_attacking:
is_attacking = false

func dodge() → void:
if not is_attacking and not is_dodging:
is_dodging = true
dodge_timer = DODGE_TIME
dodge_offset = -knight.transform.basis.z * DODGE_DISTANCE
animation_controller.play_animation(“Dodge_Backward”)

func apply_dodge(delta: float, position: Vector3) → Vector3:
if is_dodging:
dodge_timer -= delta
position += dodge_offset / DODGE_TIME * delta
if dodge_timer <= 0:
is_dodging = false
dodge_offset = Vector3.ZERO
return position

func handle_combat(delta: float) → void:
if is_attacking:
pass
if is_dodging:
pass

okay so my current error when i try to run is “Cannot call method ‘connect’ on a null value.”

i will say i had been using tons of tutorials and chat gpt to help since i know absolutely nothing about code in general. but gpt can take me so far. i did have a working code in 1 script but i thought it would be smarter to split my code in there own nodes. if i should just keep it all together in 1 script then ill revert and use that.
any and all help is appreciated and don’t burn me to hard for using chat gpt :joy: :joy:

Hi, for next time - including the whole error stack would be super helpful :slight_smile:

What that error tells me is that the object “connect” is being called from doesn’t exist or is unreachable.

Based on the code pasted above its either var animation_controller can’t find AnimationC or var animation_player can’t find $AnimationPlayer so I’d start there!

Whole stack? Like all the text in the error or debug tab? I can provide that later when im back home at the project.

And man seriously it cant find the controller again. I just had that fixed. Well once i get that working again my next thing is just trying to make certain animations play. I habe idle and run work but once i jump it wants to try and play the animation but stops after 1 frame and plays idle. Im guessing that idle has priority or that once “jump” is pressed it only plays for that frame instead of while in the air. So maybe i need to add an “in_air” or whatever on that animation?

Preciate the help

1 Like

I can give you advice when something not found on nodepath when expected to be there.
Signals is good thing but better try to use getters/setters on properties. So when something is ready, it self sets in get_parent() and then in parent node runs related to child code.
in child node:

func _ready():
	get_parent().animation_player=self

in parent node:

var animation_player:
	set(value):
		animation_player=value
		animation_player.connect(whatever connect)

it will be connected

one extra way to do advanced stuff call lambdas on signals to make them connected like
this is required to be run from _enter_tree():
$animation_player.ready(func(): self.animation_player=$animation_player, 4)
“,4” flag means one time action, callable will be removed from memory after it was used

1 Like

Yup yup! The stack contains information like the order of the code executed as it reached the error and stuff like that.

Hmm code is always hard to debug in a forum so apologies if I’m off the mark but if I were to guess it’d be something like the code enters the section below, which sets the animation and the has_jumped variables

if Input.is_action_just_pressed("Jump") and knight.is_on_floor():
   # jump is set

but then either directly or the frame after, it enters this code

if knight.is_on_floor():
   #jump is unset

But thats just a guess

thanks ill give that a go. i do have 1 question, is it smart or better to be splitting up my codes like this? or just throwing it all in 1 script? and if it is good to split it up how many scripts should i even have?

thanks everyone for the advice n help its awesome!

It’s usually smart to split code into smaller self-contained parts - but as it sounds like you’re new to programming, I would just focus on getting it working then splitting out modules when it feels like it’s grown too big or when you’ve found a reason to separate it into its own script or module.

There are hundreds of techniques out there to architecture code for performance, or maintainability and it can be bit overwhelming :sweat_smile:

But if you are keen on learning why-when to split, you can search up godot design patterns. I found this one and it looks promising.

2 Likes

okay so ill just leave it in a single line since that worked as intended. i just have a final question and i appreciate all the assistance from everyone. so my question what would be considered to long? is that just a preference or is like 1000+ lines to much just so i know for future projects. this game i am making is just so i get familiar with godot.

thanks everyone

personally I dont think its worth measuring code by number of lines.

Generally its all about how many responsibilities a single script/class does.

E.g. I’d rather have a 1000 line script if its all story text

var story1 = """
Once upon a time...

...800 lines later

The end
"""
	

Than a 20 line script that does 10 different things like control gravity,and inventory, and player movement.

The aim is to segregate code into related-logical chunks instead of just chunking it length wise

1 Like