Godot: centralized proxy strategy for once-only type-checking …
Goal: use node.transform.position across entire API without worrying about whether the underlying object is Node2D, Node3D, or logical (Node).
using Godot;
using System;
public class NodeProxy { // <== GodotNode (LunyObject subclass)
private readonly Node _node;
public TransformProxy transform { get; } // <== LunyTransform + NodeTransform
public NodeProxy(Node node) {
_node = node;
transform = new TransformProxy(node);
}
public class TransformProxy {
// Centralized delegates for get/set logic
private readonly Func<Vector3> _getPos;
private readonly Action<Vector3> _setPos;
public TransformProxy(Node node) {
// TYPE CHECKING HAPPENS ONLY ONCE HERE
if (node is Node3D n3) {
_getPos = () => n3.Position; // make lambdas static, alloc only once?
_setPos = (v) => n3.Position = v;
}
else if (node is Node2D n2) {
_getPos = () => new Vector3(n2.Position.X, n2.Position.Y, 0);
_setPos = (v) => n2.Position = new Vector2(v.X, v.Y);
}
else {
// Default "Safe" behavior for base Nodes
_getPos = () => Vector3.Zero;
_setPos = (v) => { };
}
}
// Clean properties with zero logic/type-checks
public Vector3 position {
get => _getPos();
set => _setPos(value);
}
}
}
// Static lambda pattern
public class NodeProxy {
// 1. Static Accessor Definitions (Shared by all instances)
private static readonly Func<Node, Vector3> Get3D = (n) => ((Node3D)n).Position;
private static readonly Action<Node, Vector3> Set3D = (n, v) => ((Node3D)n).Position = v;
private static readonly Func<Node, Vector3> Get2D = (n) => {
var p = ((Node2D)n).Position;
return new Vector3(p.X, p.Y, 0);
};
private static readonly Action<Node, Vector3> Set2D = (n, v) => ((Node2D)n).Position = new Vector2(v.X, v.Y);
private static readonly Func<Node, Vector3> GetNone = (n) => Vector3.Zero;
private static readonly Action<Node, Vector3> SetNone = (n, v) => { };
private readonly Node _node;
private readonly Func<Node, Vector3> _getter;
private readonly Action<Node, Vector3> _setter;
public NodeProxy(Node node) {
_node = node;
// 2. Assign the shared static reference ONCE
if (node is Node3D) { _getter = Get3D; _setter = Set3D; }
else if (node is Node2D) { _getter = Get2D; _setter = Set2D; }
else { _getter = GetNone; _setter = SetNone; }
}
public Vector3 Position {
get => _getter(_node); // No new allocation here
set => _setter(_node, value);
}
}