Godot入门2D游戏教程中GetNode<Timer>抛出类型转换异常求助
Godot C# 教程中GetNode抛出InvalidCastException的问题
我是Godot新手,正在跟随官方《你的第一个2D游戏》教程用C#开发。调用GetNode<Timer>("/root/Main/StartTimer")时抛出System.InvalidCastException: Specified cast is not valid异常,但已确认StartTimer确实是Timer类型。当前处于教程的主游戏场景章节。
报错相关代码片段
public void New_Game() { Score = 0; var player = GetNode<Player>("/root/Main/Player"); var startPosition = GetNode<Position2D>("/root/Main/StartPosition"); player.Start(startPosition.Position); GetNode<Timer>("/root/Main/StartTimer").Start(); }
完整脚本
Main.cs
using Godot; using System; public class Main : Node { #pragma warning disable 649 [Export] public PackedScene MobScene; #pragma warning restore 649 public int Score; public override void _Ready() { GD.Randomize(); New_Game(); } public void Game_Over() { GetNode<Timer>("MobTimer").Stop(); GetNode<Timer>("ScoreTimer").Stop(); } public void New_Game() { Score = 0; var player = GetNode<Player>("/root/Main/Player"); var startPosition = GetNode<Position2D>("/root/Main/StartPosition"); player.Start(startPosition.Position); GetNode<Timer>("/root/Main/StartTimer").Start(); } public void OnScoreTimerTimeout() { Score++; } public void OnStartTimerTimeout() { GetNode<Timer>("MobTimer").Start(); GetNode<Timer>("ScoreTimer").Start(); } public void OnMobTimerTimeout() { var mob = (Mob)MobScene.Instance(); var mobSpawnLocation = GetNode<PathFollow2D>("MobPath/MobSpawnLocation"); mobSpawnLocation.Offset = GD.Randi(); float direction = mobSpawnLocation.Rotation + Mathf.Pi / 2; mob.Position = mobSpawnLocation.Position; direction += (float)GD.RandRange(-Mathf.Pi / 4, Mathf.Pi / 4); mob.Rotation = direction; var velocity = new Vector2((float)GD.RandRange(150.0, 250.0), 0); mob.LinearVelocity = velocity.Rotated(direction); AddChild(mob); } }
Mob.cs
using Godot; using System; public class Mob : RigidBody2D { public override void _Ready() { var animSprite = GetNode<AnimatedSprite>("AnimatedSprite"); animSprite.Playing = true; string[] mobTypes = animSprite.Frames.GetAnimationNames(); animSprite.Animation = mobTypes[GD.Randi() % mobTypes.Length]; } public void OnVisibilityNotifier2DScreenExited() { QueueFree(); } }
Player.cs
using Godot; using System; public class Player : Area2D { [Export] public int Speed = 400; [Signal] public delegate void Hit(); public Vector2 ScreenSize; public override void _Ready() { ScreenSize = GetViewportRect().Size; Hide(); } public override void _Process(float delta) { var velocity = Vector2.Zero; if (Input.IsActionPressed("move_right")) { velocity.x += 1; } if (Input.IsActionPressed("move_left")) { velocity.x -= 1; } if (Input.IsActionPressed("move_down")) { velocity.y += 1; } if (Input.IsActionPressed("move_up")) { velocity.y -= 1; } var animatedSprite = GetNode<AnimatedSprite>("AnimatedSprite"); if (velocity.Length() > 0) { velocity = velocity.Normalized() * Speed; animatedSprite.Play(); } else { animatedSprite.Stop(); } Position += velocity * delta; Position = new Vector2( x: Mathf.Clamp(Position.x, 0, ScreenSize.x), y: Mathf.Clamp(Position.y, 0, ScreenSize.y) ); if (velocity.x != 0) { animatedSprite.Animation = "walk"; animatedSprite.FlipV = false; animatedSprite.FlipH = velocity.x < 0; } else if (velocity.y != 0) { animatedSprite.Animation = "up"; animatedSprite.FlipV = velocity.y > 0; } } public void On_Player_Body_Entered(PhysicsBody2D body) { Hide(); EmitSignal(nameof(Hit)); GetNode<CollisionShape2D>("CollisionShape2D").SetDeferred("disabled", true); } public void Start(Vector2 pos) { Position = pos; Show(); GetNode<CollisionShape2D>("CollisionShape2D").Disabled = false; } }
解决步骤
校验节点路径与命名
- 确认场景树中
StartTimer的路径确实是/root/Main/StartTimer,注意Godot节点名区分大小写,避免拼写错误。 - 尝试用相对路径替代绝对路径,比如从Main节点出发调用
GetNode<Timer>("StartTimer"),减少层级定位错误概率。
- 确认场景树中
检查节点脚本绑定
- 确认
StartTimer节点未错误附加自定义脚本,若有附加脚本,必须确保该脚本继承自Timer类,否则会导致类型转换失败。
- 确认
延迟节点初始化
- 在
_Ready()中直接调用New_Game()时,部分节点可能未完成初始化。将调用改为延迟执行:public override void _Ready() { GD.Randomize(); CallDeferred(nameof(New_Game)); }
- 在
调试节点实际类型
- 先获取无类型节点,打印其实际类型定位问题:
var node = GetNode("/root/Main/StartTimer"); GD.Print("Node type: ", node.GetType().FullName); var startTimer = node as Timer; if (startTimer != null) { startTimer.Start(); } else { GD.Print("Failed to cast node to Timer"); }
- 先获取无类型节点,打印其实际类型定位问题:
内容的提问来源于stack exchange,提问作者Alex Cunha
相关产品推荐
相关产品推荐

