Triky
May 14, 2025, 7:01pm
1
Godot Version
4.4
Question
I work with .net and have the following problem.
When I instantiate my player, all attached components remain null.
I instantiate via PlayerScene.Instantiate<Player.Player>(); a Player(RigidBody3D).tscn.
Player.tscn has Player.cs
All components are Node3D’s with their own script.
public override void _Ready() {
StatsComponent = GetNode<StatsComponent>(StatsComponentPath);
if (StatsComponent == null)
{
GD.PushError("Player: StatsComponent not found!");
}
}
In my opinion, the components are set correctly in the Insprector via NodePath.
Values seem to be available in the engine via remote, but not in the .net code.
Am I missing something or why are the child components in Player only initialized with null?
Hi,
That seems weird. Have you tried adding a breakpoint on the player instantiation code to debug in details the instantiated node?
Could you send your full class code? However it looks like Stats Component Path might just be the node that you are trying to get the path too
Triky
May 15, 2025, 10:29am
4
The code did not work because of another error, but what I noticed is that the components were never null, they are filled with data, it is just displayed incorrectly in Visual Studio.
Idk why this is, but my problem is fixed.
Here a part of the Player and one of the component classes, just to understand:
public partial class Player : CharacterBody3D
{
[ExportGroup("Components")]
[Export] public NodePath StatsComponentPath { get; set; }
[Export] public Array<NodePath> HurtboxComponentPaths { get; set; }
[Export] public NodePath EquipmentComponentPath { get; set; }
[Export] public NodePath InventoryComponentPath { get; set; }
[ExportGroup("Animation")]
[Export] public NodePath AnimationPlayerPath { get; set; }
[Export] public string IdleAnimationName { get; set; } = "Idle";
[Export] public string RunAnimationName { get; set; } = "Run";
[ExportGroup("Movement Control")]
[Export] public float MoveSpeed { get; set; } = 10.0f;
[Export] public float StopForceMultiplier { get; set; } = 5.0f;
[ExportGroup("Attack Control")]
[Export] public NodePath DefaultMeleeAttackAreaPath { get; set; }
[ExportGroup("Interaction")]
[Export] public float MaxPickupRange { get; set; } = 7.0f;
private const string INTERACT_ACTION = "interact";
// General values
public PlayerSpawnPointId LastPlayerSpawnPointId { get; set; }
public long Exp { get; set; }
private Camera3D _camera;
private readonly float _gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle();
private Vector3 _targetWorldDirection = Vector3.Zero;
private Vector3? _lookAtTarget;
private AnimationPlayer _animationPlayer;
public StatsComponent StatsComponent { get; private set; }
public EquipmentComponent EquipmentComponent { get; private set; }
public InventoryComponent InventoryComponent { get; private set; }
private VisualController _visualController;
private AttackComponent _activeMainHandAttackArea;
private AttackComponent _activeOffHandAttackArea;
private ItemInstance _currentMainHandWeapon;
private ItemInstance _currentOffHandItem;
private DroppedItem _currentlyHoveredItem;
private enum PlayerAnimState { Idle, Run, Attack }
private PlayerAnimState _currentAnimState = PlayerAnimState.Idle;
private const string DEFAULT_ATTACK_ANIM = "default_attack";
public override void _Ready()
{
StatsComponent = GetNodeOrNull<StatsComponent>(StatsComponentPath);
if (StatsComponent == null)
{
GD.PushError("Player: StatsComponent not found!");
}
EquipmentComponent = GetNodeOrNull<EquipmentComponent>(EquipmentComponentPath);
if (EquipmentComponent == null)
{
GD.PushError("Player: EquipmentComponent not found!");
}
InventoryComponent = GetNodeOrNull<InventoryComponent>(InventoryComponentPath);
if (InventoryComponent == null)
{
GD.PushError("Player: InventoryComponent not found!");
}
_animationPlayer = GetNodeOrNull<AnimationPlayer>(AnimationPlayerPath);
if (_animationPlayer == null)
{
GD.PushError("Player: AnimationPlayer not found at path: " + AnimationPlayerPath);
}
else
{
_animationPlayer.AnimationFinished += OnAttackAnimationFinished;
PlayAnimation(IdleAnimationName);
_currentAnimState = PlayerAnimState.Idle;
}
foreach (NodePath hurtboxComponentPath in HurtboxComponentPaths)
{
HurtboxComponent hurtboxComponent = GetNodeOrNull<HurtboxComponent>(hurtboxComponentPath);
hurtboxComponent.HitDetected += OnHitReceived;
}
}
public override void _Process(double delta)
{
PlayerInput();
_camera ??= GetViewport().GetCamera3D();
if (_camera != null)
{
CalculateAndEmitLookAtTarget();
}
}
public override void _PhysicsProcess(double delta)
{
Movement(delta);
UpdateAnimationState();
}
public override void _Input(InputEvent @event)
{
if (@event.IsActionPressed("attack"))
{
PerformMeleeAttack();
}
InteractAction();
}
#region Init
private void FinalizeSetup()
{
Global.Instance.SetPlayer(this);
}
public void Initialize(PlayerDto dto)
{
if (dto == null)
{
GD.PushError($"{Name}: Initialize called with null dto!");
return;
}
Name = dto.Name;
if (StatsComponent == null)
{
GD.PushError($"{Name}: StatsComponent is null!");
return;
}
Exp = dto.Exp;
LastPlayerSpawnPointId = dto.LastPlayerSpawnPointId;
StatsComponent.Armor = dto.Armor;
StatsComponent.Health = dto.Health;
StatsComponent.Heal(dto.Health.Max);
StatsComponent.Mana = dto.Mana;
StatsComponent.Stamina = dto.Stamina;
CallDeferred(nameof(FinalizeSetup));
}
}
[GlobalClass]
public partial class InventoryComponent : Node3D
{
[Signal]
public delegate void InventoryChangedEventHandler();
[Export] public int MaxSlots { get; set; } = 20;
[Export] public Array<InternalItemSlot> Items { get; private set; } = new();
private Player.Player _playerOwner;
public override void _Ready()
{
_playerOwner = GetOwner<Player.Player>();
if (_playerOwner == null)
{
GD.PushWarning($"{Name}: Could not get Player owner.");
}
}
#region Add item
public bool AddItem(ItemInstance instanceToAdd) {}
}
1 Like
system
Closed
June 14, 2025, 10:29am
5
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.