godot-nim
godot-nim copied to clipboard
Example request
Can you elaborate an example like code in GDScript
and same code in godot-nim
.
I have a vague idea, how it would look like, but not quite sure i'm right. Of cource I may apply try and see approach, but i'm quite positive on that i'm not the only one with such problems.
For example:
From Jaynam tutorial https://www.youtube.com/watch?v=kc-zJnRvPUY
extends Camera
export var distance = 12.0
export var height = 4.0
func _ready():
# Called every time the node is added to the scene.
# Initialization here
set_physics_process(true)
set_as_toplevel(true) # Independant from the parent position
func _physics_process(delta):
var target_position = get_parent().get_global_transform().origin
var camera_position = get_global_transform().origin
var up = Vector3(0, 1, 0)
var camera_offset = camera_position - target_position
camera_offset = camera_offset.normalized()*distance
camera_offset.y = height
camera_position = target_position + camera_offset
look_at_from_position(camera_position, target_position, up)
will be transformed to
some code
And also you need to add script, choose NativeScript, choose class name from nim code, and (some other things)
This things are pretty simple, i'm almost sure it all revolves around gdobj
macro, but there are some unclear points.
Like name translation rules (CamelCase to underscore_delimited and back), using inherited procs (like look_at_from_position
in this ex.), using methods of GD core objects (like Input.is_action_pressed
) and so on. Then do i need to write custom toVariant/fromVariant/godotTypeInfo
and then it may be crated automatically (and is there any such case)?
All of this questions may be solved by simple but throughout example. Step-by-Step, from binding to the editor object till running scene.
This may be a little boring for you, but it will greatly help people who start their very first godot+nim project.
Found scripts in stub project doing in essence what what i'd asked. Beg you pardon on my sillyness, but docs are lacking info on there to look for nim godot scripts and on how it's tailored together (I mean i've found them, but it would be for the better to add something like: "Nim godot scripts sources can be found in /src doc. /src/stub.nim is considered the root of the project, it's compilation is added in nakefile.nim" to the readme of the stub project)
I would also love some more info on how the stub is structured and the workflow of Nim and Godot ala the readme of godot-go: https://github.com/ShadowApex/godot-go
Also, some parts of how the API works are a little hard to catch at a glance: for example, as NodeType constructs like
findNode("Stop") as BaseButton
They can be found in stub, yes, but a little inline comments would be welcome
And, of course, the most welcome addition will be a simple mapping like godot Class/method -> nim class/method (with module path) would be MOST WELCOME. Again: MOST WELCOME
I'm planning to make a very simple open source example game based on godot-nim to show how it can be used. Not sure when I will get to that though.
The mapping from GDScript to Nim is straightforward: modules are just class names in snake_case (TextureRect
-> texture_rect.nim
), methods are in lowerCamelCase (remove_child
-> removeChild
). If you use VSCode and it is correctly configured, you should get auto-complete suggestions. Also, the generated modules have all method declarations at the top so you can quickly observe what it contains. For example, if you would like to know what you can do with TextureRect, just open texture_rect.nim
and you'll see at the top:
const
STRETCH_SCALE_ON_EXPAND* = 0'i64
STRETCH_SCALE* = 1'i64
STRETCH_TILE* = 2'i64
STRETCH_KEEP* = 3'i64
STRETCH_KEEP_CENTERED* = 4'i64
STRETCH_KEEP_ASPECT* = 5'i64
STRETCH_KEEP_ASPECT_CENTERED* = 6'i64
STRETCH_KEEP_ASPECT_COVERED* = 7'i64
proc texture*(self: TextureRect): Texture {.gcsafe, locks: 0.}
proc `texture=`*(self: TextureRect; val: Texture) {.gcsafe, locks: 0.}
proc expand*(self: TextureRect): bool {.gcsafe, locks: 0.}
proc `expand=`*(self: TextureRect; val: bool) {.gcsafe, locks: 0.}
proc stretchMode*(self: TextureRect): int64 {.gcsafe, locks: 0.}
proc `stretchMode=`*(self: TextureRect; val: int64) {.gcsafe, locks: 0.}
That's great and all. But either you do it or i'll eventually try to build authomatic doc on top of godot's class descriptions. Like TextureButton methods Nim source package: texture_button
GoDot | Nim |
---|---|
is_pressed() | pressed() |
... | ... |
TextureButton properties
GoDot | Nim |
---|---|
disabled | disabled |
... | ... |
"pressed" is a property and so "is_pressed" and "set_pressed" are not generated to enforce consistent usage and brevity. button.pressed
works both in GDScript and Nim.
That's a complicated question. pressed()
- is not a property, though still named the same. And if GD policy for accessors is is_{key}
it shoud be mapped as is{Key} to nim, IMO. Otherwise it IS NOT consistent. And direct property usage in case of having accessors/mutators is an incapsulation breach. And should be discouraged, IMHO. But that's discussible.
Did you seen the other issue i've created? I think it's one of the things you may encounter trying to oversimplify api behaviour.
How did you derive it's not a property? If there are pressed
and pressed=
procedures generated, it means Godot reported it as a property. And you can see pressed
is listed as a member variable (property) here: http://docs.godotengine.org/en/3.0/classes/class_basebutton.html
Yes, I saw the issue, and that problem would not be avoided by adding is_pressed
and set_pressed
, because pressed
and pressed=
would still be there and would conflict with the method pressed
.
GDScript allows this:
button.pressed
button.is_pressed() # equivalent of above
button.pressed = true
button.set_pressed(true) # equivalent of above
Nim just removes is_pressed() and set_pressed(). The name clash problem appears because, unlike in GDScript, there is no separate concept of properties in Nim and properties are simulated with two procedures. So they may clash with other procedures in the same class. method
s are inteded for overriding behaviour, so the solution could be to add a suffix in case of a clash, such as Impl
, so that method pressed
would turn into method pressedImpl
.
I think the metod/proc clash resolution strategy you've given is right. Might be other suffix/or even prefix, but that's insignificant details. About class properties and accessors. Yes, GDScript do not impose you to use accessors, it's not strict. But even it supplies them. Nim is much more strict, and though you "throw the accessors away" I think it's a wrong way to do it. After all, i don't think OOP's accessor/mutator concept useless. Class properties should be considered private outside of the class. And you should have accessors/mutators (or only one of them) for accessing them from the outside. I think it's a sane idea, and the way you give looks more like a lazy way of doing things (no offence, i'm grateful for the godot-nim's existance, i just want it to be even better). Anyway - it's for you to decide, i may only explain my position.
I don't throw the accessors away, it's all about syntax. proc pressed
and proc pressed=
are a getter and a setter, working exactly the same as proc is_pressed
and proc set_pressed
would. So I don't see how removing the latter two affects anything, aside from enforcing consistency of your codebase (you cannot use is_pressed
in one place and pressed
in another).
The point is why accessor was named is_pressed in the first place. It's not about the inability to make a poc with pressed() name, it's more about distinguishing. It's a philosophical question, but I prefer to see that I do explicitly. Yes, i'm setting internal class property, but i'm using mutator for that. I'm SETTING it. Imagine
proc `pressed=`
got lost somethere on the way. Now, using your code scheme, you're not using mutator any more. And you still think you are. And what if, for example, mutator had some check inside, and was able to throw an exception? No check for you, no idea it is not made. After all, that's the point - cleaner and more explicit code is more predictable. (Yeah, i'm python's fan, don't blame me:))
Though you speaking of a more JS's kind of thinking. If there's 3 ways to do a thing, it doesn't mean all of them are correct ones :)
I still don't get your point. I'm avoiding 2 ways to do the exactly same thing in the first place, I don't see where there is "JS thinking" in that.
Now, using your code scheme, you're not using mutator any more. And you still think you are. And what if, for example, mutator had some check inside, and was able to throw an exception? No check for you, no idea it is not made.
It will be made if it's there. There is ZERO difference between pressed
and is_pressed
and GDScript allows both, and both work the same in every way.
And if pressed=
"gets lost", your code just stops compiling, because there is no such field in the type definition.
Okay, your way to go. So, you don't have properties on the nim's side at all? It's a little confusing, but viable. A minor problem is that you effectually "mask" the things you shoudn't. Cause nim's
x.pressed = true
is not similar to
x.pressed = True
it's effectually
x.set_pressed(True)
And i really don't see why are you so insistent on doing so. It's just confusing.
My point is - you may suppress the x.pressed
behaviour at all as it's non-OOP in godot. But the godot's x.set_pressed
is optimally translated to x.setPressed
as it's a way to go with the other functions. Why change that, why make special case for accessors/mutators. First of all - they are FUNCTIONS.
Anyway, i'd be happy with any decision, i just don't see a point in your logic.
It seems you don't realize that Godot's x.pressed = true
executes exactly as x.set_pressed(true)
, and so does Nim's x.pressed = true
. The concept of properties with custom getters/setters does exist in OOP languages (C# has it, for instance).
So what we are talking about here is selecting between:
Option 1. Add duplicates:
proc pressed*(self: BaseButton): bool
proc is_pressed*(self: BaseButton): bool
## Does the exact same thing as above, including any checks or side effects or anything.
proc `pressed=`*(self: BaseButton; val: bool)
proc set_pressed*(self: BaseButton; val: bool)
## Does the exact same thing as above, including any checks or side effects or anything.
Option 2. Only property-like procedures, this is implemented now:
proc pressed*(self: BaseButton): bool
proc `pressed=`*(self: BaseButton; val: bool)
Option 3. Only get/set procedures:
proc is_pressed*(self: BaseButton): bool
proc set_pressed*(self: BaseButton; val: bool)
I went with option 2 because: a) Unlike option 1, it enforces consistency of user codebase. b) It's more concise than option 3.
Looks like you're right, i didn't realise that in godot you may access/modify your property only via accessors/mutators. My bad. As of the other things... I think option 1 is off the table, because duplicates are rarely needed and that's certainly not the case. So distinguish is between 2 and 3. I better like 3, because it's more explicit and can't be mixed up with anything else, but that's really a matter of taste. So, i'll be happy if you'll fix the proc/method clash and that's all. And the 'transition' table, godot-to-nim, of course. But that one may wait :) In my defence, i may say it's rather hard to imagine that property direct access and access via mutators is essentially the same. And i think i'm now one of only the few of knowing it works that way in GoDot
@survivorm I know the conversation moved on passed this a bit, but I translated that script for you.
I did it exactly as-is (with the exception of moving the UP
vector out to show you this is still nim, and can benefit from nim features).
By the way you don't need set_physics_process(true)
in godot-nim nor in gdscript... I think people still do that as a remnant from Godot 2.x which just spreads misinformation, but I digress.
import
godot,
camera,
spatial
# I like putting these kinds of things in another file and importing them
const UP* = vec3(0, 1, 0)
gdobj CameraFollow of Camera:
var distance {.gdExport.} = 12.0
var height {.gdExport.} = 4.0
method ready() =
setAsToplevel(true)
method physicsProcess(dt: float) =
# I like to store these, already cast, as member variables so I don't need to cast on-demand
let targetPosition = (getParent() as Spatial).globalTransform.origin
var cameraPosition = self.globalTransform.origin
var cameraOffset = cameraPosition - targetPosition
cameraOffset = cameraOffset.normalized * distance
cameraOffset.y = height
cameraPosition = targetPosition + cameraOffset
lookAtFromPosition(cameraPosition, targetPosition, UP)
Thanks. Great example, maybe @endragor will include it into the doc. It's very illustrative, IMO Though i'm gone a little forward, it'll help someone else
It also only took around five minutes, which shows how easy it is to adapt code between them once you are familiar enough with gdscript, nim, and godot-nim.
Also worth noting in nim you can write things like getParent
as get_parent
. I didn't do that because I think snake_case is absolutely hideous, but if I had it would look a lot more like the original source in gdscript.
Yeah, great. Though i don't think nim gd scripts should be written in the gd style, better in nim's. Though - it's a point of view matter (what do you consider primary - GD or Nim). Sadly, ambiguity issue isn't closed yet
Hello community
I'm thinking of using Nim in Godot, but I have many doubts that are not clear to me.
The fact that there are no complete examples of code with a couple of simple games increase my doubts.
I also have doubts that the time I dedicate not worth it for the time necessary for their learning.
Certainly I could investigate by reading all the documentation, but this already takes a lot of time.
Currently I know C # and JavaScript very well, I earn a living with them by professionally programming.
My doubts are with respect to the necessary time regarding C #.
I am new to Godot. It took me a week, about 40 hours to learn it for a normal start a project, without being an expert in it.
I have seen GDScript, it is very easy to learn, but insufficient.
Now I was thinking about moving to C# with Godot, I imagine that handling C # with Godot will be another 40 hours.
I am aware that answering the question I am going to ask is difficult, but considering a normal intelligence.
How long can I take to learn Nim to an appropriate degree?
How long can I take to learn Nim with Godot?
I know of the best performance of Nim's language, also of its nice syntax, but I am afraid of its reduced community and if the necessary time will compensate for the project I want to do.
Sorry for my English, I defend reading but I write it very badly
Thank you
Hello. About learning the Nim - it depends on your background. I like to think of Nim as a Python-like syntax with strict type system. It's rather crude, yes, but it gives you a start. First of all, you're easier to learn Nim as much you're familiar with python-like syntax and with strict typed languages. Nim's rather easy to learn, you may start small and then discover features for you. Also, Nim has great community. It's rather small, but open and always ready to answer. You may just go to the IRC (gitter/matrix) channel or to TG group and just ask whatever you like, even post your program sample, and get tips on what you're doing wrong and/or what you need to do to achieve your goal. Don't be shy and ask whatever noob question you like. With godot itself... It's a bit more complicated. If you know how to do someth. in GDScript, you're likely easily implement it in Nim-godot. It's simple, really. And translation rules are quite clear. But if you're stuck... It's a little more complicated. You may ask in channel, but if question is godot-specific it's likely people here wouldn't be able to help. Not saying they wouldn't try. You may ask here and you'll get an answer. Eventually. But that means a duration between hours and days. Nim-godot society is quite specific and rather small. That's only my opinion and result may differ. But i advise you to take a shot on it. Go on and try Nim :)
Also, try asking nim beginner's guide in the society, depending on your background. People will give you links on the info best suits your level/background
Thanks for your answer.
I currently know that with C # in a week I am running Godot. I know C # from several years of experience. I am afraid that with Nim he does not master him well in two months of study. I have doubts that the advantages are so many to compensate for the learning time, especially if the community is so small.
You have encouraged me, which I sincerely appreciate, but I still have the doubt. ☹
Nim needs examples of small games in Godot as life needs water, a must.
Your choice. I think you're right about the examples, but with 1-2 people maintaining this project this will unlikely happen soon. On practical side, if you've experience with C#, it might be the best decision to take time-wise. But I'll be happy if you'll join the Nim community in your free time. It may be fun for you too.
Ok I'll try Nim. I have seen that there is a book. I suppose one way to achieve extended support is to donate a small amount per month, for example 10 or more. No abuse, but to respond to questions not found in the documentation
The book (Nim in Action) is a really good resource for learning. I read it after I had already learned Nim, but it was still a good read.
Im also new, only a few weeks into godot-nim and nim, learning both at the same time. More than often not the easiest task, but nevertheless fun! ;) I find the basics of Nim easy to learn , but struggle to go turbo on it. Right now im using it like GDScript, because i have problems understanding when to make use of generics, templates and macros. But i think it is worth to dig into Nim, for me it's GDScript on steroids. Anyway, for some reason im not getting answers on discord, so i will try it here, don't want to open a new issue only to ask some simple questions.
- How to Nim
Input.is_action_pressed
? i can only use event.* but i also need Input.* - How to use Signals? esp. connect()
- How to Nim
call_deferred("add_child, scene")
?