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
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
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
Hi, for next time - including the whole error stack would be super helpful
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
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
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
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.
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