I have a game idea there one of the most integral part is to let the player write code.
Are there any good examples how to do that? searching for this is quite difficult.
I do not want to make a own interpreter but would like to integrate a real language like python or typescript. But the user also should not be able to import random modules other than the one provided by the game or the user itself. I imaging it a bit like in Bitburner.
GDScript is compiled to bytecode and run by an interpreter, and that compiler is available at runtime, so you can build a script from a string and load it on the fly:
extends Node2D
class_name script_executer
var helloScript
func _init():
helloScript = GDScript.new()
# take the source where ever you want
helloScript.source_code = """
func run():
print("Hello")
""".dedent()
helloScript.reload()
func SayHello():
var s = helloScript.new()
s.run()
func _ready() -> void:
SayHello()
something like this should’ve work. But if you want to interact with the engine, you should’ve implement own engine bridge
If you just need to evaluate one expression (a formula, a condition) rather than a whole script, you can use the Expression class
var e := Expression.new()
e.parse("2 + pow(x, 2)", ["x"])
print(e.execute([5])) # 27
And of course bring your own, write your own lexer / parser / evaluator in GDScript and also again some godot glue code if you want to interact with the engine and interpret whatever DSL you want.
I wrote an interpreter in GDScript for my own little scripting language. I followed the (very good) Crafting Interpreters book for that, to a degree. My language is pretty simple, so maybe it’s something you could be interested in. I’m open for ideas too.
I do not recommend Kerim’s idea to use GDScript. I looked into that and refrained from it. For example, you can’t put your user’s script in a try…catch block (as GDScript does not have that), so errors in the player’s script are automatically bugs in your own game.
I do not recommend Kerim’s idea to use GDScript. I looked into that and refrained from it. For example, you can’t put your user’s script in a try…catch block (as GDScript does not have that), so errors in the player’s script are automatically bugs in your own game.
Yeah, agreed on the try/catch point — that’s exactly why I listed three possible solution rather than recommending just one. Each has its own trade-offs.
Dynamic GDScript is only meant for trusted runtime codegen; for untrusted/moddable input the
third option was to do exactly what you did
write your own lexer/parser/evaluator (+ some engine glue).
So we’re on the same page: custom interpreter is the right call for user-facing scripting.
gompl looks lovely
I think a common language to use in games is LUA, since it has a relative standalone library. as far as I know, it’s only available in C/C++, so you’d need to create a godot extension.
I recently started to implement a compiler/vm for javascript using a port of pegjs to gdscript. I think using your own script, inventing the syntax and the API to your game is a fun undertaking. handling the interaction with your game is a different beast, and it depends on what the “computing bits” of your game is (multiple “computers” (like else.heartbreak), or puzzles like zachtronlcs games, etc.
I would start by identifying what the user would program and how the code interacts with your game world. and you can maybe hack a prototype in one of the languages you want to target, like a mini simulation of your game.
(I need to cleanup my JS project, once I’m finished I can share it here)
thanks for input. but writing everything completely by my own was something I would like to avoid.
I mean designing a own language definitely is fun - I’ve done that in past for educational reasons - but to make it really usable is an enormous efford. As well for the player that has to learn a language that is of no other use to him.
I was thinking about something like Qt’s QJSEnginewhere you set up the engine. Add “bridge classes” (that expose application-interfaces to the script) to the engine and load a script into it.
The game I have in mind is a bit of a mix of 1988’s Neuromancer’s Matrix vibes and the 2002 Shawn Overcashs Decker but with some kind of automation by user written code like in Bitburner.
So at the end where will be many simultanously running user scripts that may do complex things, so a classic handcrafted interpreter based approach may not fit.
To be honest. The projects concept is not very far atm and its completely unsure if will lead anywhere. But thinking about it and doing little experiments, currently is fun to me.
You can use GDScript. You can write a custom Logger to catch the errors and report them back to the user if needed.
More info about logging:
This will log any error the moment you add it with OS.add_logger() so you’ll need to filter them to the user’s script.
You’ll also need to disable error breaks in the Debugger -> Stack Trace tab while working on it or the errors in the user script will also cause a break in the editor. It’s the red bell in the top-right.
Simple example:
extends Node
@onready var code_edit: CodeEdit = %CodeEdit
@onready var run_button: Button = %RunButton
var user_script := GDScript.new()
var my_logger := MyLogger.new()
func _ready() -> void:
OS.add_logger(my_logger)
run_button.pressed.connect(func():
user_script.source_code = code_edit.text
if user_script.reload(false) == OK:
var obj = user_script.new()
if obj.has_method("run"):
obj.call("run")
)
class MyLogger extends Logger:
func _log_error(function: String, file: String, line: int, code: String, rationale: String, editor_notify: bool, error_type: int, script_backtraces: Array[ScriptBacktrace]) -> void:
printt("error!", function, file, line, code, rationale, editor_notify, error_type)
How about making a very simple visual scripting language? This can take any form you want. (For example, I once created a visual programming language in 3D for a game.)
No - every time I play a game with a visual language, I get frustrated and I am glad if its possible to switch to a text representation or export/import works via text that can be edited externally
Also I think the scripts will get to complex for this.
this does not seem to be desireble to me, as the player will have access to the whole Godot API, hasn’t? So it would be possible to manipulate the game itself.
This may be okay for a games level or scenario editor or so but not for the game itself.
DinoSourceis quite a good key word. That looks like that I was imagening from the developer perspective. I definitely will try it and will keep this in mind.
however I would prefer something more like python or typescript.
that’s also what Else.Heartbreak is using; and the ComputerCraft mod for minecraft.
I recently played “The Farmer Was Replaced”, where they use a very reduced python syntax. I think they did a good job to expose a the “game api” there.
Btw, I would also consider how the execution of your scripts work. The ability to limit the speed is crucial. I.e. it should not just run off some thread in the background, but you should be able to sync with a custom (clock) tick (this also avoid the endless-loop kills the game problem). For example in Else.Heartbreak the computers have different CPU speeds; this also offers certain upgrade paths.
Also, offering a debugger to the user is usually simpler, when you run your own VM / script.
You’re having trouble (and getting lots of answer on here) because your question is very generic.
Why?
I would recommend taking a step back and describing in detail the kind of gameplay you imagine, and what kinds of things you want the player to be able to write. Is your imagined player base already coders? Are you going to be teaching players how to learn this language? Python and Typescript have a lot of differences. What’s the common ground between them that you are envisioning? Is the player editing this code in-game, or through an external editor? Is it for modding, or part of the primary gameplay expereince?
Some effort into describing your envisioned end product would go a long way towards helping you figure out what you want to do.
I can’t imagine this being much fun as game, usually there is simple puzzle in pseudo code ,some fake hex code in Cyberpunk, but can’t recall any game with serious take on programming.
Maybe it’s rather some educational app or IDE made here.
I think there are plenty of games where “coding” is the primary theme. but I think those are separated into 3 categories:
a) coding is the primary puzzle. eg exapunks, “the farmer was replaced”, TIS-100, microhard, shenzen.io
b) coding is used to interact with the world but needed in order to advance: Else.heartbreak, screeps
c) learn to code games…
From @vladtepesch description, his idea goes rather towards b). and I agree with @dragonforge-dev , that you should revise your goals and think how the “code” interacts with the world and what would be a good “api” / “mechanism” to express this in code (function calls, RPC, events, I/O ports).
getting braod and generic answers is very fine at this state since it gives better overview.
The common ground between these two languages is accessiblity to online ressources and algorithms the player may want to research. And maybe familiarity to them already. And from my Point the chance that there maybe already some integration.
the code should be written ingame but exporting/editing it outside should be possible (in a comfortable way).
those are definitively good points. Killing the game with a user-code endlessloops and a forgotten await sleep is a weak side of Bitburner allthough its not a huge problem.
Yep B.
The idea so far is that most things can be explored manually to get an idea how things work. then to write code to exploit them. automate manual steps. For example write crawler that finds new targets while user does other stuff. or other tools that try to crack these targets by credential stuff them from bought lists of credentials or test agains vulnerabilities bought on black markets. with further progression to completely automate the runs on weaker targets for a basic income stream to buy better hardware, better software and to aquire “throw-away”-proxys for identity-protection.
I really like the way programming in Bitburner works. But there the actual intrusion and hacking is largely abstracted in calling few functions there. But I imagine to be more focus on the fight how to get into the systems, fight the ICE, steal data, take over the system. So the player can buy Hardware and Software that adds certain features or APIs that can be used in his programs to either autonomously do stuff in the game world or assist the player while he is on a manual run within some system.
The way I currently imagine the interaction of the code with the environment is that the script (or the hardware it runs on) is some kind of entity with capabilities (virutal sensors, actors) defined by the the hardware and the owned software components. It can monitor the simulated environment and interact with other entities (access gates, ICE, Data stores, … whatever).
I think your ideas sound like fun, albeit ambitious.
But what do you mean by not wanting to build your own interpreter? Don’t you mean you need an interpreter that is out there already? In that case you may just have to work with what you can get. I can’t really point you to anything concrete, but to say: “wasn’t there a plugin called Godot mod or something that shipped a Lua interpreter or something?” (Super vague and probably not true)
But here’s a suggestion that may appeal to you.
I once built a domain specific Scratch interpreter (of the xml serialization of the language) in a top down level editor type of game engine. Things like timers, following a target, opening and closing doors, that type of domain. User just programmed with scratch blocks; coding GUI I got from the Github repos.
This is all open source stuff and scratch is a perfectly valid programming language. Why is it a good fit (imho)? User can’t easily make syntax errors and run into mysterious bugs (without doing their best).
Scratch.mit.edu used to have a huge user base of young enthusiastic people.
Enough about scratch.
Making a domain specific subset of functions based on an existing language’s syntax and just exposing your DSL keeps the threshold for learning to play your game feasible and makes it doable for you to build content.
Just another general idea for you to consider, I guess?