Game programming is hard. It consistently ranks among the most challenging domains due to realtime programming, many cross-cutting concerns, and the sheer number of systems that interact.
LunyScript reduces that complexity with high-level, declarative patterns. State machines and behavior trees instead of cargo cult coroutines. Fault-tolerant execution instead of null-references.
And then you also learned to program in two or more engines. That makes it all the more exciting!
True, AI coding assistants are powerful learning tools. But they work best with simple, consistent APIs.
When a learner asks AI for help with Unityâs GetComponent<AudioSource>().PlayOneShot() vs Godotâs $AudioStreamPlayer.play() vs Unrealâs audio system, the AI might suggest outdated methods, wrong engine conventions, or code that doesnât match what the learner sees in their editor.
With LunyScriptâs simple, fluent API, AI assistants give reliable, working code that learners can actually understand and reason about. Audio.Play("sound") reads like natural language, works in all engines, and helps beginners learn patterns instead of fighting syntax. AI becomes a learning amplifier instead of a source of confusion.
LunyScript is a novel training wheels API, not another re-inventing wheels framework.
Engine API semantics are needlessly disparate: BeginPlay, OnEnable, _enter_tree. Every engine has the same lifecycle events. Their semantics differ, their purpose is uniform.
And their behavior? Thereâs no contract. In which order children receive lifecycle events varies.
Recall how we used to put up with browser-specific code paths only to render content the same across browsers? Game engines are the same right now. The fragmented API landscape is entirely to their benefit, not ours.
LunyScript is the uniform API to help beginners get started and transition between engines. The Scratch for game engines.
General purpose frameworks are too abstract for beginners. They are loaded with CS jargon and concepts. LunyScript provides high-level, fluent gameplay APIs that read like game design intent.
Letâs compare with general-purpose (but Unity-only) UniRx:
this.OnCollisionEnterAsObservable()
.Where(c => c.gameObject.CompareTag("ball"))
.Do(_ => audioSource.Play())
.Subscribe();
this.OnCollisionExitAsObservable()
.Where(c => c.gameObject.CompareTag("ball"))
.SelectMany(_ => Observable.Timer(TimeSpan.FromSeconds(2.5)))
.Do(_ => Instantiate(sparkles, other.position))
.Subscribe(_ => sparkles.Despawn());
The same code in LunyScript:
When.Collision.With("ball")
.Begins(Audio.Play("ball_tagged_loop"))
.Ends(Spawn("sparkles").At(Other).Run(Wait.Seconds(2.5), Despawn()));
LunyScript code is 66% less verbose than UniRx and reads like intent.
CS jargon is loading semantics with assumptions, raising questions:
âHmm .. select many an observable timer?â
If you read it out loud it just makes no sense! Thatâs where beginners and designers walk away!
LunyScript is for ease of entry and productivity in pro-tier game engines, and perhaps contributes to popularizing emerging engines. Creating a custom âLunyâ game engine would defeat those purposes.
Currently, roughly 95% of Steam games published are made with Unity, Unreal, Godot, and proprietary engines. This is where the learning pains are felt most.
Building a custom engine means rebuilding:
LunyScript leverages all that existing infrastructure. Screw on those training wheels and start rolling with ease!
Visual scripting tools (PlayMaker, Blueprints, etc.) are a popular choice for many non-programmers. But they are currently the ONLY choice for users intimidated by conventional programming.
Visual tools are criticized for being:
LunyScript provides the same high-level expressiveness and simplicity with all the benefits of text-based code â a viable alternative for beginners & designers.
The shared engine features and behaviors have settled. They are so fundamental to every project that they resist change.
LunyScript will not chase fancy features. Anyone can add whatever they want however.
The engine adapters and observers are in separate, engine-specific repositories. I neednât manage and maintain every engine integration myself.
70% of LunyScript is fully portable, providing the behavioral guarantees. The engine-native code is just 30% â mostly automatable glue.
â Read the full maintenance strategy
They neednât. Close enough is good enough. The behavior contract is most important!
Even if you have to tweak every physics value once more, the logic itself is already running in the new engine, unchanged!
Thatâs a lot more productive than having to start with no code, or worse: having to verify and fix automatically converted code in a foreign environment.
Neither.
Itâs processing static graphs (FSMs, BTs) on engine heartbeat events via a central script runner.
Infrequent native events are observed and trapped for a single frame by handlers like Collision.Begins.
LunyScript handles âstructural changesâ (eg destroy object) gracefully by activating associated events (ie When.Self.Disables, When.Self.Destroys) while deferring native execution to the âend of frameâ event.
A simple source generator will be used to create the APIâs static language bindings (C# to Lua).
Weâre long past the days when we needed to count bytes and CPU cycles. Our games are already full of layers of abstractions.
Code we write in C# crosses the language boundary to C++ â this is rather costly. It still worked wonderfully for Unity. Same with Blueprints: we know itâs between 100x to 1,000x slower than C++ yet we use it extensively.
LunyScript, through its central processing concept and internal caching, may even prove to be faster when compared to ubiquitous uses of GameObject.Find("") or the commonplace copy-pasta trainwrecks:
if (gameObject.transform.GetComponent<Rigidbody>() != null)
{
gameObject.transform.GetComponent<Rigidbody>().linearVelocity = 0;
gameObject.transform.GetComponent<Rigidbody>().angularVelocity = 0;
gameObject.transform.GetComponent<Rigidbody>().Sleep();
}
As seen on a worryingly regular basis.
For LunyScriptâs target audience (simple games, learning projects, prototypes), performance is not a limiting factor.
Join the Discussions to ask questions, share feedback, or propose ideas!