Your first Luny Script in Godot
Goal: You want to create a controllable capsule as your first "Player" in a blank scene. This time you'll try Godot.
Status Quo: Godot 4.6
If you're already familiar with the Godot editor workflows, skip to the GDScript.
Everyone else: brace yourselves.
Create the 3D Scene
To create a usable 3D scene in Godot, you will have to perform these steps:
- FileSystem:
Right-click -> New Scene.- In the modal dialog: Select
3D Scene, enter scene name. - Click
OK.
- In the modal dialog: Select
- Scene:
Right-click: Add Child Node.- Node Dialog: Select
Camera3D. - Click
Create.
- Node Dialog: Select
- Scene: Select root node.
- Scene:
Right-click: Add Child Node.- Node Dialog: Select
DirectionalLight3D. - Click
Create.
- Node Dialog: Select
- Scene: Select root node.
- Scene:
Right-click: Add Child Node.- Node Dialog: Select
WorldEnvironment. - Click
Create.
- Node Dialog: Select
- Inspector, with
WorldEnvironmentselected:Environment -> New Environment.- Click
Environment.Background -> Mode -> Sky.Sky -> New Sky.- Click
Sky. Sky Material -> New ProceduralSkyMaterial.
- Click
This accomplishes three things Godot doesn't provide out of the box:
- The 3D scene renders via the
Camera3D. Without it you'd just get a solid color window. - The objects will be lit and will cast shadows via the
DirectionalLight3D. Without it, everything would look dim and flat. - A color gradient resembles the horizon via the
WorldEnvironmentsky. Without it, it wouldn't feel three-dimensional due to a solid-color backdrop.
Create the Player Object
To create a player capsule character with a script in the 3D scene, you will need to perfom these steps:
- Scene: Select root node.
- Scene:
Right-click: Add Child Node.- Node Dialog: Select
CharacterBody3D. - Click
Create.
- Node Dialog: Select
- Scene:
Right-click: CharacterBody3D -> Add Child Node.- Node Dialog: Select
CollisionShape3D. - Click
Create.
- Node Dialog: Select
- Inspector with
CollisionShape3Dselected:- Click
Shape -> CapsuleShape3D.
- Click
- Scene:
Right-click: CharacterBody3D -> Add Child Node.- Node Dialog: Select
MeshInstance3D. - Click
Create.
- Node Dialog: Select
- Inspector with
MeshInstance3Dselected:- Click
Mesh -> CapsuleMesh.
- Click
- Scene:
Right-click: CharacterBody3D -> Attach Script.- Attach Node Script Dialog: Browse or enter path and file name.
- Click
Create.
Now you have a capsule character with a GDScript attached.
Create the Input Map
Godot projects start with an empty Input Map. You will have to set it up yourself:
- Menu:
Project -> Project Settings. - Project Settings: Click the
Input Maptab. - Input Map, in the
Actionfield:- Type "MoveLeft".
- Click
Add. - Click the
+icon next to "MoveLeft" action -> Event Configuration for..:- Press the desired key or mouse button (or select it from the list).
- Click
OK.
- Click the
+icon next to "MoveLeft" action -> Event Configuration for..:- Press the desired gamepad button (or select it from the list).
- Click
OK.
- Click the
+icon next to "MoveLeft" action -> Event Configuration for..:- Press the desired joystick button (or select it from the list).
- Click
OK.
- Repeat the above steps five additional times:
- .. for the "MoveRight", "MoveUp", "MoveDown", "Jump", and "Crouch" input actions.
Now you can use these input mappings in your code.
You could skip the gamepad and joystick setup for now if you prefer, but keep in mind: players do expect common input devices to be supported!
Why So Many Extra Steps?
Compared to Unity, there's an egregious amount of extra steps to be done in the Godot editor before you even get to scripting.
Godot deliberately provides clean slates for everything, no meaningful templates, and lacks sensible defaults. Its user experience centers on deeply hierarchical (procedural) user interfaces and an abundance of modal dialogs. This results in higher-than-usual UI interactions.
While Unreal editor's highly complex UI with many uniquely designed windows will shock beginners and challenges even experienced developers, Godot's design provides a consistent UI experience that's easy to pick up. Thanks to the higher number of successful interactions it is rewarding and it feels productive.
The GDScript
With all those editor setup steps out of the way, at least now you need to write much less code in GDScript:
extends Node3D
func _process(delta: float):
var move_input = Input.get_vector("MoveLeft", "MoveRight", "MoveDown", "MoveUp")
var jump_input_value = Input.get_action_strength("Jump")
var crouch_input_value = Input.get_action_strength("Crouch")
var moveX = move_input.x
var moveZ = move_input.y
var movementDirection = Vector3(0, 0, 0)
movementDirection.x = moveX
movementDirection.z = moveZ
if jump_input_value > 0.1:
movementDirection.y = 1.0
else:
if crouch_input_value > 0.1:
movementDirection.y = -1.0
else:
movementDirection.y = 0.0
var movementSpeed = 4.0
var finalMovement = movementDirection * delta * movementSpeed
translate(finalMovement)
That's ten lines you're saving compared to the Unity MonoBehaviour implementation.
However, the savings derive solely from inlining the Input map strings, thus avoiding field declarations (instance variables). The code looks strikingly familiar: its complexity remains exactly the same, with only minor syntax reduction (braces, semicolons).
Note
| 🤔 Hey, wait! This GDScript is 26 lines but Unity's code snippet was 52 lines!
Correct, but in all fairness we should stop counting empty lines and structural lines with only a { or } character.
That makes Unity's solution 30 and the GDScript version 20 actual lines of code.
With LunyScript
Here's the LunyScript C# implementation once again for reference - identical to its Unity version since Luny scripts represent portable code:
using LunyScript;
public partial class Player : Script
{
public override void Build(ScriptBuildContext context)
{
On.FrameUpdate(
Transform.MoveBy(Input.Direction("Move"), 4),
Transform.MoveUp(Input.Button("Jump").Strength, 4),
Transform.MoveDown(Input.Button("Crouch").Strength, 4)
);
}
}
At 7 actual lines of code it is merely a third of the GDScript! 😎
Note
LunyScript, when ported to Godot, will remain in C#. GDScript is a proprietary language that entrenches lock-in - a polar opposite of LunyScript's vision.