Open telaviv opened 4 years ago
Note that you can create an enum to use globally, create an autoload singleton and put the enums in the singleton:
attacks_enum.gd
extends Node
enum Attacks {
Normal,
Special,
Aerial,
}
Usage:
var a = attacks_enum.Attacks.Special
Whether this works for classes too I'm not sure, never tried.
https://docs.godotengine.org/en/3.1/getting_started/step_by_step/singletons_autoload.html
@lawnjelly I'm fairly sure this works for classes too. The only issue is that you can't use enums as type hints, but this isn't specific to enums being local to a script somehow.
I don't think we need a local
/global
keyword for enums, as this proposal is purely related to static typing.
I do kind of also want to highlight how Enum
's in GDScript with the introduction of the class_name
keyword, are now second class citizens.
I mean consider all these types:
class_name
)For all these, there is a way to get an instance of that type globally. Every type in GDScript can be created/referenced globally. All types, except ones declared with the Enum
keyword.
var a = null
var b = Vector2(0, 0)
var c = Enemy() # declared with class_name
var d = Attacks.Special # this breaks, since Attacks, as an enum, can never be global
In fact an alternative, maybe more radical version of a solution could look something like this:
# attacks_enum.gd
extends Enum
class_name Attacks
_types = [
'Normal',
'Special',
'Aerial',
]
Where Enum
would be a sibling type of Object
. My goal with this is to hopefully get to some sort of feature parity with classes.
Using class_name
you can access inner classes and enums from other scripts, and you don't need a singleton nor do you need to instance the script. I don't think there needs to be a global keyword, because everything in a script is already global, you just have to specify the script you're getting it from.
test_script.gd
extends Object
class_name TestScript
enum Attacks {
Normal,
Special,
Aerial
}
class test_class:
var variable = 1
some_other_script.gd
extends Node
func _ready() -> void:
var attack_type = TestScript.Attacks.Normal
var my_class : = TestScript.test_class.new()
do_thing(my_class)
func do_thing(test : TestScript.test_class) -> void:
test.variable += 1
But it would be nice if enums could be used as types like other values can. At the moment enums are just a shorthand for making a constant dictionary on a class, so it can't be used as a type hint.
For all these, there is a way to get an instance of that type globally. Every type in GDScript can be created/referenced globally. All types, except ones declared with the Enum keyword.
This should work, no?
class_name Attacks # Or better yet, extends Node and make it a singleton
enum {
Normal,
Special,
Aerial
}
@telaviv Not sure if I understand correctly, but at least for enums I'm just doing this (no autoload or class_name required):
dialogue.gd:
enum ActionType { START_LEVEL, FINISH_LEVEL, OPEN_MAP, UI_INTERACTION }
script2.gd:
var Dialogue = load("res://ui/dialogue.gd")
...
someFunctionUsingEnum(Dialogue.ActionType.UI_INTERACTION)
This has always been possible:
extends Node
const MyEnum = preload("res://script_with_enum.gd").MyEnum
const MyClass = preload("res://script_with_class.gd").MyClass
export(MyEnum) var enum_val
func _ready():
var obj = MyClass.new()
obj.wow_cool()
obj.val = MyEnum.Woah
Ofc, nowadays you can use class_name for this purpose, which is functionally similar to preloading entire scripts in every other script. Anyhow, the points made about this being impossible in the proposal are incorrect; it may not be as convenient as, say, C#, but it's certainly not impossible. I think this proposal should be closed, and separate proposals opened for the various different features being asked for (registering enums in an enum database, registering inner classes in the class database, enums as types.)
Unless/until the proposals to address this are split into their own issues, I'd like to suggest another alternative: File level local scope import, kinda like importing a namespace. This makes it so you don't have to register a class (which can create issues with cyclic dependency), or require a named autoload before every invocation. import
or imports
would be fine for this.
/signed
I'm working on an RPG. Enemies can have elements, PCs can have elements, attacks can have elements. I try to use static typing everywhere because I'm used to statically-typed languages and I like both the extra checks and the guarantees that a certain variable will be of a certain type. Trying to work around this enum limitation is frustrating.
I don’t know, in this way or in some other way, but probably we should add the ability to declare global enums. Because when enums are used outside of a class, at least 3 name components are required: ClassName.EnumName.ELEMENT_NAME
. It's ok, but a little annoying for commonly used enums. Especially now, when autocompletion doesn't work very well.
class_name
, then we need to add the ability to do this for enums as well.Error
) can be global, then it should also be possible to declare custom enums as global.There are other options to achieve a similar effect, such as the use
/import
keyword (but I don't like that).
This should work, no?
class_name Attacks # Or better yet, extends Node and make it a singleton enum { Normal, Special, Aerial }
In this case, you will not be able to use Attacks
as a type hint.
const MyEnum = preload("res://script_with_enum.gd").MyEnum
Doesn't work in 4.0-dev.
To me this issue concerns more having something easy to iterate on and distribute. Defining your enum once is handy so everyone can work on the same base, and that same base can be easy to modify. I don't like the idea of something like that being global because not every script will need the enum. But that every script that needs the enum search it in the same place is cool!
Anyway thank everyone for the work arounds! Works well and I don't feel like it's a "dirty" solution!
This worked for me:
Describe the project you are working on: 2D Fighting Game.
Describe the problem or limitation you are having in your project: I'm writing my project using entirely static typing. Unfortunately, it's currently impossible to share something as simple as enum definition across multiple files. Let's say I have an enum definition in 1 file like so:
If I'd like to use this definition across files outside of
attacks_enum.gd
, I'm completely out of luck.The same goes for classes defined using the
class
keywordDescribe how this feature / enhancement will help you overcome this problem or limitation: The solution I propose will allow the use of the class name for both referencing the class as well as static typing for method definitions.
Show a mock up screenshots/video or a flow diagram explaining how your proposal will work: My solution would be to have both the
enum
andclass
keywords make their definitions global by default similar to how theclass_name
keyword works. This would be a breaking change to how things currently work since now there would be a possibility of global name conflict in existing projects.This suggestion makes the assumption that most of the time you want to enum/class definition, you really want to use it across your project. For use cases where you really want your enum/class definitions just in your file I propose a new keyword.
local
. It would work like this:Similarly if we don't want a breaking change, and if we believe that users would prefer a more explicit way of sharing enums/classes we can instead introduce a
global
keyword.If this enhancement will not be used often, can it be worked around with a few lines of script?: For the case of the
class
keyword, yes. You can create a new file and use the newclass_name
keyword to have a global reference to the class. Forenum
, the best you can do is copy and paste the definition every time you want to reference it.Is there a reason why this should be core and not an add-on in the asset library?: When it comes to implementation of things that involve scopes, that needs to be a language level detail.