Open Feniks-Gaming opened 4 years ago
I believe you could implement something similar by overriding a method that returns a constant value. I think it's done this way in some other programming languages.
You can just export the variable if your bricks are scenes. Or overwrite it in _ready()
.
This may actually be helpful!
For example, if a script inherits from the Node class, then it can be added to the scene. But at the same time, the inherited properties will have default values from the base class. It would be nice to be able to override default values something like this:
extends RichTextLabel
class_name TypeWriter
default rect_size = Vector2(128, 64) # only constant values
default bbcode_enabled = true
default visible_characters = 0
default scroll_active = false
default scroll_following = true
# ...
(I know that you can use the tool
keyword.)
ADD. I mean that in the editor (if you do not use the tool
keyword), the inherited properties by default have some values, and in _ready()
they will be assigned different values.
@KoBeWi I know I can but this doesn't solve my problem as exactly as I would like it to be.
For example say I have a scene Bullet it has const SPEED = 400 I want it to be always 400 on run time in parent. But I would like the SPEED to be always 800 in it's child FastBullet I can't change it in _ready() function because you can't change constants
However I don't want to change constant to var. Because it will no longer act as constant during runtime. Even tho this is exactly what I want it to do.
Ability to override variables rather than just change them will solve situations like this.
Ability to override variables rather than just change them will solve situations like this.
But still, constants aren't variables.
Also, what's the problem with changing const to var? Keeping them UPPERCASE should be enough, there aren't any performance differences.
You can have a multiplier
variable, defaulted to 1. Then just use BASE_SPEED * multiplier
in _physics_process
and change multiplier
in inherited scenes. Say multiplier = 2
in your FastBullet
.
Difference is that is I accidentally change constantly SPEED somewhere in a game I will get an error knowing that it was a mistake I intended to avoid if I call my var SPEED I can change it by accident and not know about it.
@Feniks-Gaming Would https://github.com/godotengine/godot/issues/23695 solve this particular use case?
Yes that would solve my issue. I would be able to create a parent with empty variable and let SPEED
and then assign it on other children like to whatever I want and it would act like a constant otherwise.
Problem with this is that it allows for potential mistakes on the other end (when you override the parent variable without realizing). Maybe with ahem annotations we could have a tag to allow an explicit override:
@override
var name = "New Node Name"
Can be a keyword but I don't want to introduce yet another one.
Still, doing that for constants may not be possible. After all, they are supposed to be constants, and they are (or should be) optimized based on this assumption.
I would like to bring another point that this would enable to provide different defaults for custom SubClasses from Standard Nodes. Similar to the ToolButton
when you open the Documentation it actually says [override: true]
for the flat
property:
This is something currently impossible to do via GDScript, because when you change a default via a tool script (in _init
or _ready
etc.) you wont be able to change the default in the Inspector afterwards, because it will always reset to the value set in script on reloading the scene.
Please correct the title: "override" instead of "overwrite".
I also run into this issue a lot when working with inherited classes. Using _init()
works well enough for changing the default values of non-exported variables, but if there is a way to make it work with exported variables it seems like it would need to involve @tool
scripts, which themselves can interact unintuitively with the inheritance structure, and require a lot more care throughout the script to make sure only the right code is being executed in the editor. Assuming that one of the main advantages of inheritance is to avoid duplicating work, and the main advantage of changing a default value is the same, implementing a workaround that involves duplicating work and opening code to difficult-to-foresee errors seems undesirable.
Problem with this is that it allows for potential mistakes on the other end (when you override the parent variable without realizing). Maybe with ahem annotations we could have a tag to allow an explicit override:
@override var name = "New Node Name"
Can be a keyword but I don't want to introduce yet another one.
...
I'm self-taught in GDScript (and a couple other high level scripting languages), so my programming fundamentals are pretty lacking and I don't know how hard any of this would be to implement under the hood, but I was wondering if the implementation of annotations in GDScript 2.0 makes the above proposal any more workable/worth revisiting?
If I'm not mistaken it's possible to do this in Godot3 overriding getset methods in inherited classes. It seems that this particular issue is where GDscript2.0 is somewhat lacking when compared to old system.
Does this @override
means the property still have same type?
@override
is needed. I suggest simply not to use var
keyword to indicate that the member value is overridden:class A:
var x:int= 1
class B:
extends A
x = 2 # ok
class C:
extends A
var x = 2 # should still give the error "the variable exists in parent class"
If no, I think this is a bad idea to implement
Of course not, this contradicts the Liskov substitution principle. We are talking about overriding the default value, which is already used in the engine.
suggest simply not to use
var
keyword to indicate that the member value is overridden
It's confusing. Users may think that it is allowed to write code outside of a function, but this is not true.
What about allowing child classes to change variable types if the type specified is a child. For example:
class MyResource
extends Resource
class A:
var x: Resource
class B:
extends A
@override var x: MyResource
class C:
extends B
@override var x: Resource # Give error because it isn't a child of MyResource
Edit: I suppose it's similar to a generic parameter in C#. Without the generics. Edit2: You can override functions without a special attribute. Why would it be different for variables wouldn't that make it more confusing. Why not add an icon in the editor next to overridden variables and functions?
What about allowing child classes to change variable types if the type specified is a child.
This contradicts Liskov substitution principle. Covariance and contravariance do not work for properties:
class A:
var x: Node
var y: Node
class B extends A:
@override var x: Node2D
@override var y: Object
func _ready() -> void:
var b: B = B.new()
var a: A = b
a.x = Node3D.new() # Valid.
print(b.x) # Invalid.
b.y = Resource.new() # Valid.
print(a.y) # Invalid.
Covariance and contravariance do not work for properties
Technically your 'y' wouldn't be allowed as Object is a parent of Node not a child. But yes I do see your point. I suppose that's why generics exist in the first place.
I just wanted a way to get more specific type hints/limit inspector selection in child classes.
Some use case for this proposal. Now I'm working on addon where I use different resources to specify node behavior. So for some extended resources I need to redefine base resource values defaults for user now I'm using some sort of workaround (tool script):
func _init() -> void:
if not Engine.is_editor_hint() or _lock:
return
_lock = preload("res://addons/fast_ui/triggers/ui_trigger_lock.tres")
But it's work not ideal because it's not actually change defaults but override on start (restore to default button shown):
Is this suggestion still actively being considered? Apologies for the duplicate feature request submission, for some reason neither this one nor #10020 showed up when I did a cursory search earlier.
I'm currently working on one Godot project and another UE4-based one & was reminded how nice (and extremely quick) this workflow is in UE4:
Conversely in Godot this is the sort of "seemingly trivial" thing that often trips me up or otherwise slows me down at unexpected times & leads to that (imho) "death by a thousand papercuts" feeling when using the engine for anything non-trivial...
I'm new to GDScript so take my suggestion with a grain of salt... However, if you're trying to market GDScript as an OOP programming language then it makes no sense to not provide a means of abstraction.. abstraction is a fundamental concept in Object-Oriented Programming (OOP) and by your own documentation: "Still, many best practices using Godot involve applying object-oriented programming principles to the scripts and scenes that compose your game."
Consider the following: abstract_example.gd
class_name AbstractClassExample
extends Node
@export var example_boolean: bool = false
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
child_example.gd
extends AbstractClassExample
#var example_boolean = true
#@export var example_boolean = true
#@override var example_boolean = true
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass
It's clear what I'd like to do. I understand that this can be accomplished in within the _ready
function, however, that's not good enough as:
It seems to me that this is an oversight, and experienced developers will not enjoy this as it layers the truth behind function calls when, simply put, the solution could be more elegant, clean and user friendly.
Describe the project you are working on:
Arcanoid Clone for learning
Describe the problem or limitation you are having in your project:
I have a scene BrickParent that has behaviours for all my bricks in a game. I then want multiple inherited scenes of that scene to be different colour bricks. Each brick is worth different amount of points in the game
In my BrickParent scene I have var points = 0 I then want this var points to be different in each inherited scene. So In my inherited scene I created a inherited script that inherits from BrickParent.gd if I type var points = 50 U will get error Member 'points' already exists in parent class. I would like to be able to override this just how I can override some of the functions in parent class that already exist.
Describe how this feature / enhancement will help you overcome this problem or limitation:
This will will make code easier to follow across different inherited scenes. And allow for faste rprototyping
Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:
N/A
Describe implementation detail for your proposal (in code), if possible:
I can't help here I have no idea how to do it.
If this enhancement will not be used often, can it be worked around with a few lines of script?:
I would expect it to be used every time people create inherited scripts. Work around for now is to add all the variables we want to change in _ready() function it works but for example you can't override constants in that way.
Is there a reason why this should be core and not an add-on in the asset library?:
It's pretty much part of the way core