Components not properly working on CharacterBody3D?

Godot Version

4.6.2

Question

I recently followed this tutorial to learn Godot composition. I’m working on a new project now and using the system implemented for basic movement, however no movement is registering. I feel extremely lost as to why it won’t work as expected when InputComponent does indeed get updated properly each frame (at least looking at the debug message I added.) There are 3 component scripts: Player (where the other two components get initiated), Input, and Movement.

class_name Player extends CharacterBody3D

@onready var input_component: InputComponent = %InputComponent
@onready var movement_component: MovementComponent = %MovementComponent



# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta: float) -> void:
	input_component.update()
	
	movement_component.direction = input_component.move_dir
	movement_component.jump_counter = input_component.jump_pressed
	movement_component.tick(delta)
class_name MovementComponent extends Node

@onready var body : CharacterBody3D

#variables for movement and physics

const RUN_SPEED : float = 20.0
const SPEED : float = 10.0
@export var current_speed : float = SPEED
@export var jump_velocity : float = 12.0
@export var gravity_multiplier : float = 3.0

@onready var input_component: InputComponent = %InputComponent

var direction: Vector2 = Vector2.ZERO
var jump_counter := false

func tick(delta: float) -> void:
	if body == null:
		return
		
	#Move
	body.velocity.x = direction.x*current_speed
	body.velocity.z = direction.y*current_speed

	#Gravity
	if not body.is_on_floor():
		body.velocity += body.get_gravity() * delta * gravity_multiplier
		
		#Jump
	if jump_counter and body.is_on_floor():
		body.velocity.y = jump_velocity
		jump_counter = false
	
	body.move_and_slide()

class_name InputComponent extends Node

var move_dir : Vector2 = Vector2.ZERO
var jump_pressed : bool = false


func update() -> void:
	move_dir = Input.get_vector("left", "right", "up", "down")
	jump_pressed = Input.is_action_just_pressed("jump")
	
	print(move_dir)
	print(jump_pressed)

As you can see, both are referred to in the Player script, however when running the game, nothing in tick() is applied; I’m unable to use WASD to move and gravity is not applied. Also to note, the first project I implemented this in, it did work. I tried to see if I missed anything but I couldn’t find any differences in node organization or anything as such, I could be missing something though. I just really don’t know what it is exactly after hours of re-writing and analyzing. I also intend to add more components, so I’d like to be secure in using this method further without things not getting updated. I can send node trees etc. if this is unclear/unhelpful.

Any errors in the debugger?

Where do you initialize MovementComponent’s body property?

Have you mapped the keys? There is any error message on the console window? WASD is not the default mapping in Godot.

I did map keys. There are no error messages besides warnings (not errors) for something unrelated, about assets I have in the game, but currently nothing.

In Player if you print move_dir do you get a proper Vector2 when you press the keys?

If I’m understanding correctly, its initialized at the top of the script? sorry, I think I’m half-confused. The player itself is in the main scene, where the components are called in the player’s script.

Yes. I believe so.

but should change when press the keys to 1,0, 1,1 or 01

My bad, to I forgot to send a screenshot of the numbers changing. They did change when I did input.

Can you add a print at:
if body == null:
return

before the return to be sure is set?

@onready var body : CharacterBody3D
^ this doesn’t initialize it, it merely declares its type, so the check if body == null in tick() likely never passes.

Interesting. When doing this, it did print the inputs correctly when I pressed them in the tick() function.

As @normalized states, @onready var body : CharacterBody3D is never initialized so the tick method leaves after checking the body null condition

I see. How do I initialize it then? Not sure if this is a dumb question or not

-Nevermind. I had an idea to just get_parent() and it worked.. it seems, that is.

@onready var body : CharacterBody3D =

similar to:

@onready var input_component: InputComponent = %InputComponent

I see. I did try that I think. getting the parent instead fixed it, Though, I think I didn’t initially think of this because when ctrl and dragging the Player into the script, I get $”..”, which had me thinking there was already a reference to it if I just put CharacterBody3D, I guess not though. get_parent() worked though.

1 Like

$”..” is a get_parent() call.