In the planning phase with friends to work on a game. For context I'm currently an iOS developer but has past experience making indie games, and interned at EA to make FIFA 11 back in 2010.
Tried out GDScript and did some research, and feel that it has certain limitations:
I propose Godot to switch to Swift as its core scripting language to connect with its underlying C++, and add GDScript on top of Swift for people who want to use GDScript. I feel this will address the followings:
Here I want to make a simple code snippet comparison, taking the Player.gd example from Platformer 2D:
class_name Player
extends Actor
const FLOOR_DETECT_DISTANCE = 20.0
export(String) var action_suffix = "" // This is already changed in Godot 4.0 to annotation
onready var platform_detector = $PlatformDetector
func _ready():
var camera: Camera2D = $Camera
if action_suffix == "_p1":
camera.custom_viewport = $"../.."
elif action_suffix == "_p2":
var viewport: Viewport = $"../../../../ViewportContainer2/Viewport"
viewport.world_2d = ($"../.." as Viewport).world_2d
camera.custom_viewport = viewport
func _physics_process(_delta):
var direction = get_direction()
var is_jump_interrupted = Input.is_action_just_released("jump" + action_suffix) and _velocity.y < 0.0
_velocity = calculate_move_velocity(_velocity, direction, speed, is_jump_interrupted)
# When the character鈥檚 direction changes, we want to to scale the Sprite accordingly to flip it.
# This will make Robi face left or right depending on the direction you move.
if direction.x != 0:
sprite.scale.x = 1 if direction.x > 0 else -1
var is_shooting = false
if Input.is_action_just_pressed("shoot" + action_suffix):
is_shooting = gun.shoot(sprite.scale.x)
var animation = get_new_animation(is_shooting)
if animation != animation_player.current_animation and shoot_timer.is_stopped():
if is_shooting:
shoot_timer.start()
animation_player.play(animation)
func get_direction():
return Vector2(
Input.get_action_strength("move_right" + action_suffix) - Input.get_action_strength("move_left" + action_suffix),
-1.5 if is_on_floor() and Input.is_action_just_pressed("jump" + action_suffix) else 0
)
func calculate_move_velocity(
linear_velocity,
direction,
speed,
is_jump_interrupted
):
var velocity = linear_velocity
if direction.y != 0.0:
velocity.y = speed.y * direction.y
if is_jump_interrupted:
velocity.y *= 0.6
return velocity
In Swift it would be more or less look like:
class Player: Actor {
let floorDetectDistance = 20.0
@export // or some other name like implemented in Godot 4.0's GDScript
private var actionSuffix = ""
lazy var platformDetector = PlatformDetector()
// override makes it clear this is overriding a super function
override func ready() {
var camera: Camera2D = .init() // or just `var camera = Camera2D() since it's equally clear`
if actionSuffix == "_p1" {
camera.customViewport = SomeViewport()
} else if actionSuffix == "_p2" {
var viewport = Viewport()
viewport.world2d = (SomeViewport as Viewport).world2d
camera.customViewport = viewport
}
}
override func physicsProcess(_ delta: Double) {
var direction = getDirection()
var isJumpInterrupted = Input.isActionJustReleased("jump" + actionSuffix) && velocity.y < 0.0
velocity = calculateMoveVelocity(velocity, direction, speed, isJumpInterrupted)
// When the character鈥檚 direction changes, we want to to scale the Sprite accordingly to flip it.
// This will make Robi face left or right depending on the direction you move.
if direction.x != 0 {
sprite.scale.x = direction.x > 0 ? 1 : -1
}
var isShooting = false
if Input.isActionJustPressed("shoot" + actionSuffix) {
isShooting = gun.shoot(sprite.scale.x)
}
var animation = getNewAnimation(isShooting)
if animation != animationPlayer.currentAnimation && shootTimer.isStopped() {
if isShooting {
shootTimer.start()
}
animationPlayer.play(animation)
}
}
func getDirection() {
return Vector2(
Input.getActionStrength("move_right" + actionSuffix) - Input.getActionStrength("move_left" + actionSuffix),
isOnFloor() && Input.isActionJustPressed("jump" + actionSuffix) ? -1.5 : 0
)
}
// More clear param types, and can either require name on callsites or use _ to avoid named params
func calculateMoveVelocity(_ linearVelocity: Vector2,
_ direction: Vector2,
_ speed: Vector2,
_ isJumpInterrupted: Bool)
{
var velocity = linearVelocity
if direction.y != 0.0 {
velocity.y = speed.y * direction.y
}
if isJumpInterrupted {
velocity.y *= 0.6
}
return velocity
}
Not applicable here.
This touches the engine core so I don't think it suits as an add-on.
Adding support for more scripting languages can be done with a third-party GDNative binding, but this won't be accepted in core. We're happy with GDScript as it's precisely designed to fit Godot's needs, and would prefer not splitting the maintenance effort too much. See this section of What is GDNative?:
There are no plans to support additional languages with GDNative officially. That said, the community offers several bindings for other languages (see below).
For context, Godot already officially supports no less than four "scripting" options:
- Lack of types in function parameters, which makes code hard to read and follow.
Are you sure about this? GDScript supports type hints for variables (member and local), function parameters and return types.
- Numerous sources claim GDScript is very slow in larger calculations - e.g. this says it's 9x slower than Java, 100x slower than C# (reddit.com/r/godot/comments/aisrey/i_have_created_a_minimal_benchmark_for_java_and).
Typed instructions are being implemented in Godot 4.0 to improve GDScript performance. Also, most of the time, you'll be calling methods that are implemented in C++ anyway.
Thank you @Calinou for the explanation! I think it makes sense to add things on top of GDNative as you pointed out, and it's great to hear the performance boost will be very significant.
As for my misunderstanding about types in function parameters, I guess we could improve the example projects with best practices for the upcoming 4.0 so newcomers won't be misguided.
I'll close this one and watch the Kotlin implementation for now as it's very close to Swift in many aspects, and hopefully someone more experienced with bindings could use the information here to create a Swift binding in the near future :)
As for my misunderstanding about types in function parameters, I guess we could improve the example projects with best practices for the upcoming 4.0 so newcomers won't be misguided.
We intentionally chose not to use type hints in demo projects and documentation to avoid confusing beginners. At the end of the day, type hinting in GDScript is optional and will remain so.
You can find a list of all the languages supported, including that one by the community, here: https://github.com/Vivraan/godot-lang-support/blob/master/README.md
Nim and Rust are two languages who are very similar to Swift, by being modern implementations who feature imperative and functional features with a strong type system.
Nim has actuallya pretty nifty documentation and amazing macro skills, plus you can compile it to C/C++ and ObjectiveC, which could help you to utilize it somewhere else.
https://pragmagic.github.io/godot-nim/v0.7.8/index.html
Much fun, what ever you choose 馃槡
Thanks for elaborating on the supported languages @ShalokShalom !
@Calinou I'm not sure if avoiding the type hints would help avoid confusing beginners. Was there a survey done on the subject? Maybe should have a discussion with other core members there? Just a suggestion from a newcomer's perspective :)
I'm not sure if avoiding the type hints would help avoid confusing beginners. Was there a survey done on the subject? Maybe should have a discussion with other core members there? Just a suggestion from a newcomer's perspective :)
Not really, but this is the consensus we settled on with @NathanLovato who's currently reworking the documentation.
I see @NathanLovato is a teacher from his GitHub profile - probably worth checking with a few students about their feelings about type hints.
There wasn't a consensus necessarily with or through me, but we just settled on dynamic types after multiple discussions and based on multiple persons' feedback. Godot's dev mostly works like that, we always make an effort to reach a good consensus and keep the project moving forward.
@hyouuu Here's what I can tell you after years teaching and working full-time around Godot.
I can confirm, as we teach exclusively with type hints in our courses at GDQuest, that it needs to be explained first, that I always need to do the pedagogy of why you'd want to use them, and the fact it's optional confuses beginners.
Also, people really like the "Python-like" syntax and the fact it looks and feels so simple. This includes professional developers. It's one of the aspects of GDScript that attracts so many users and that they love. I know that not only from many discussions but also market studies we've done. Even in my team, with professional developers, it's been hard to convince some teammates to use types over dynamic code.
Some more notes.
GDScript's been designed as a dynamic and duck-typed language for fast scripting. The type checker was added more recently and still has caveats until the GDScript "v2" in Godot 4.0. For many users, the fact it doesn't improve performance right now is a turn-off.
The Getting started series' in the official docs is getting a rewrite and with it, the intro explicitly tells the user that GDScript is gradually typed and has optional type hints. Hopefully, it'll help raise awareness about the feature with new users.
Thanks for the thorough explanation @NathanLovato - very interesting insights & contexts, and great to hear that type hints are encouraged!
I would add that it is a huge difference - for me at least - between type hints and type inference as I see this basically as two different forms of programming. Something in between dynamic typing and type annotations is programming with using types inherently and use only inference. GDScript can do that only for bindings, so its not really an option with it, but both Haskell and FSharp support that amongst the languages that are supported. Sorry for the slightly offtopic talk.
Most helpful comment
Adding support for more scripting languages can be done with a third-party GDNative binding, but this won't be accepted in core. We're happy with GDScript as it's precisely designed to fit Godot's needs, and would prefer not splitting the maintenance effort too much. See this section of What is GDNative?:
For context, Godot already officially supports no less than four "scripting" options:
Are you sure about this? GDScript supports type hints for variables (member and local), function parameters and return types.
Typed instructions are being implemented in Godot 4.0 to improve GDScript performance. Also, most of the time, you'll be calling methods that are implemented in C++ anyway.