Open Xrayez opened 3 years ago
Hmm, this seems like a trivial thing to do. It would make sense to make it a part of a core if there are some non-obvious optimizations that can be done to render it more efficiently. Otherwise, it's not complex to make this with a regular control and _draw()
.
Also, I've actually done grids several times at this point and there have always been details that made "just grids" impractical, always requiring a specialized solution. So I'm not sure how scalable it would be.
Also, I've actually done grids several times at this point and there have always been details that made "just grids" impractical, always requiring a specialized solution. So I'm not sure how scalable it would be.
Can you give a concrete example? I fail to understand how and why you'd need a more specialized grid. I mean, sure, there are always specific use cases, but it's not the task to cater to specific use cases here. We're mostly talking about developing games and tools for them.
It's similar to having existing ColorRect
node in core: should it have an outline, or filled with a texture modulated by specified color, or should it have rounded corners? None of these features are part of ColorRect
node. Some of these properties may not even make sense in ColorRect
node, that's why you shouldn't expect it to do more than it supposed to do out of the box. Same for suggested Grid
node here.
Godot is seen useful for prototyping purposes by many developers as well, so I'd expect this feature to be useful for those use cases as well.
Also, please, lets make the discussion more on topic and suggest solutions to make the node useful for at least 70% of use cases. As I said, I'm not even proposing to have this in core. At most, this could be a first-party plugin. At least, we can have a productive discussion to make a third-party plugin out of this proposal.
It's similar to having existing ColorRect node in core: should it have an outline, or filled with a texture modulated by specified color, or should it have rounded corners? None of these features are part of ColorRect node. Some of these properties may not even make sense in ColorRect node, that's why you shouldn't expect it to do more than it supposed to do out of the box.
Yeah, which is why there is almost no reason to use it, except to give some background to something in a lazy way. And a grid is even more particular.
How many projects require a grid for prototyping? I even feel like a generalized solution will be good only for prototyping, unlike the ColorRect you've mentioned which has its limited use in finished projects. You ask for concrete examples, but the problem is that it's very game specific. It's rarely that it's just a grid you want. You may want to work with one of the two coordinate systems (cross point or a center of a cell). You may want to skip some lines, to draw background behind some cells. Arbitrary thickness may be required for specific lines, and also non-square grids are useful. You never want just grids. You want to do something with them. Even your proposed "limitlessness" is an arbitrary requirement.
If we stop at just drawing the lines, then I see no point in it. Not for the majority, not for the 70% or 50% of Godot users. Unless, again, there is some way to optimize it in a way that is not accessible to an average user. Then, maybe, there is a reason to add it.
Also, please, lets make the discussion more on topic and suggest solutions to make the node useful for at least 70% of use cases. As I said, I'm not even proposing to have this in core. At most, this could be a first-party plugin. At least, we can have a productive discussion to make a third-party plugin out of this proposal.
Well, as you are aware discussing if it's worth adding this to the core is the purpose of this repository, so it's as on-topic as it gets.
@pycbouh you completely miss the point here. You talk about use cases which are specific to games in general. It's not the main goal of this proposal. The goal of this proposal is to help plugin creators to create tools for making games. If such a node is useful for in-game needs, it's only a nice byproduct.
What I've said is valid for tools too. You seem to want it for a very specific case of infinite grids like in some of our editor tools. In that case, we can probably make it an editor control by refactoring existing tools and exposing it to the plugin API. But even then, drawing such simple grid is maybe too trivial to make it a control instead of just directly drawing it.
I understand that you'd like to continue the discussion, but unfortunately your arguments are not convincing to me, no matter how harsh that could sound, so I suggest ending our discussion.
Lets keep this open for others who may be actually interested in this discussion.
If a grid was just a grid, then yes, it can be done (fairly) easily with draw() but I imagine most use cases will want at least the red/green axis lines and origin point just like in OP's last screenshot - and that is more complex to make sure it all lines up.
I can tell you I would definitely find a use for this grid in two out of three projects I have (a 3D racer and a 2D space game)
BTW "too trivial" argument strikes me as funny when we have Panel and ColorRect controls that are, well, colored rectangles so even more trivial
This actually sounds like a good plugin idea.
BTW "too trivial" argument strikes me as funny when we have Panel and ColorRect controls that are, well, colored rectangles so even more trivial
Colored rectangles are very common, and panels are just a Control node with a StyleBox, which is even more common. Grids on the other hand are not as common.
We already have grid-drawing code within GraphEdit, so I don't think it would be too unreasonable to suggest that we might extract that code into its own separate node.
BTW "too trivial" argument strikes me as funny when we have Panel and ColorRect controls that are, well, colored rectangles so even more trivial
Colored rectangles are very common, and panels are just a Control node with a StyleBox, which is even more common. Grids on the other hand are not as common.
I think you're misunderstanding Zireael here. They're not arguing whether Panel or ColorRect are commonly used. Rather, they're saying that making a Panel-like or ColorRect-like control from scratch would arguably be just as easy as making a Grid control from scratch. Therefore, they're saying that arguing a node is "trivial to make" as a reason for not including it makes no sense, when considering the engine already contains "trivial to make" nodes.
I've already addressed why ColorRect may be an exception from the "too trivial" argument in the same comments I've made the "too trivial" argument, and even then I agreed that even ColorRects are too trivial, but are just a little bit more widespread. That's what Jummit is talking about.
As for extracting code from other controls, as I've brought up before we can make an editor only control for plugins based on what we have for other controls (and it's not just GraphEdit btw), but the task of drawing grids may still be too trivial, and would complicate built-in controls for no reason with such refactoring.
I'd like to point out that refactoring did occur for editor stuff in the past, like with polygon editing: godotengine/godot#11019, and I have a similar proposal for other stuff: #1157.
So, if we can do this in a way which can cover all those editor use cases in Godot in a general-purpose way, then I think it's worth it. We can also save a bunch of kilobytes from the Godot editor executables by eliminating duplicate code.
But if we also can make it as a node accessible to users outside the editor, then that would also be nice in my opinion. The usefulness of the node would only be limited by your own imagination. 😏
People do report that they lack basic editor controls to be available via script in general: #300.
I've already addressed why ColorRect may be an exception from the "too trivial" argument in the same comments I've made the "too trivial" argument, and even then I agreed that even ColorRects are too trivial, but are just a little bit more widespread. That's what Jummit is talking about.
I actually don't see how you address it and exempt it from the "too trivial" argument. I mean, there's this line:
Yeah, which is why there is almost no reason to use it, except to give some background to something in a lazy way. And a grid is even more particular.
which seems close enough? But it hardly explains why ColorRect is an exception, only that it somehow is. Unless you're considering it an exception because it's a little more widespread already -- in which case, I would say that any node within the engine is already going to be widespread, by nature of being in the engine.
While I'm here, and have read your previous comments, I want to comment on this part:
How many projects require a grid for prototyping? I even feel like a generalized solution will be good only for prototyping, unlike the ColorRect you've mentioned which has its limited use in finished projects. You ask for concrete examples, but the problem is that it's very game specific. It's rarely that it's just a grid you want. You may want to work with one of the two coordinate systems (cross point or a center of a cell). You may want to skip some lines, to draw background behind some cells. Arbitrary thickness may be required for specific lines, and also non-square grids are useful. You never want just grids. You want to do something with them. Even your proposed "limitlessness" is an arbitrary requirement.
You seem to be over-complicating this whole grid-drawing control. One of Xrayez's comments sums up how I want to respond to this:
I fail to understand how and why you'd need a more specialized grid. I mean, sure, there are always specific use cases, but it's not the task to cater to specific use cases here. We're mostly talking about developing games and tools for them.
But if you still feel concerned about those use cases, please take some time to drum up a solution. Complaining about those issues will get us nowhere, whereas making suggestions for how to improve this proposal will inch us forward to a better result.
I actually don't see how you address it and exempt it from the "too trivial" argument. I mean, there's this line <...> which seems close enough? But it hardly explains why ColorRect is an exception, only that it somehow is. Unless you're considering it an exception because it's a little more widespread already -- in which case, I would say that any node within the engine is already going to be widespread, by nature of being in the engine.
I may not have been very clear, but it's the line you've quoted and the continuation here:
I even feel like a generalized solution will be good only for prototyping, unlike the ColorRect you've mentioned which has its limited use in finished projects.
ColorRect
s have some general purpose use as a lazy way to add a background to something. Same with Panel
control btw. This is a more common problem (hence, widespreadness) than a grid. Oh, and ColorRect
is a good place to start with a screenspace shader, especially for transitions. Of course there are other ways to achieve this, but you can't deny all of this is way more prevalent in gamedev than simple infinite grids.
Like I've said, when you actually want grid in games, you likely want way more customization than we can fit in a generalized solution.
You seem to be over-complicating this whole grid-drawing control.
Like I've said, I'm talking from experience of implementing various grid structures while making actual games. These were actual work requirements for tasks and issues at hand. These are not hypotheticals that I imagine on the spot.
And I'm not "complaining". I'm saying that there is very limited usefulness to the proposed addition, and actual tasks require way more customization than it's reasonable to add to a core component. I'm saying that we don't need this in core and developers are capable of implementing this themselves within the spec they have. I don't understand why you want me to improve this proposal when I say it's useless as a part of the Engine.
A grid can also serve as a background, especially for graphs (cf. Thrive, which seems to use a LOT of graphs)
I don't understand why you want me to improve this proposal when I say it's useless as a part of the Engine.
I want you to improve this proposal, because you say this node is useless.
You've been very clear that you think it's useless because it doesn't support your game-specific use cases. We all agree: It can't do every single thing that you might want. But at the same time, it's not meant to be a one-size-fits-all solution. Godot's built-in nodes are meant to provide foundations with some commonly-used settings, to make it easier to implement your own use case with an attached script.
Which is why I'm suggesting you take some time to drum up some solutions, even if such a solution might require an attached script. Your solutions don't have to be perfect, or even fit all of the use cases that you want. It just needs to get a conversation going so we know how we might want to fix the issue.
P.S. I took some time to drum up my own solution to your problem, because I do think your problem is one worth solving:
I propose
_draw_line()
. This is a virtual function onGrid
that will be called during_draw()
, and is called once per line. It will provide parameters related to the line being drawn, such as start and end points.When overriding this, the user is expected to return a
bool
, representing whetherGrid
should draw the line or not. Iffalse
, the node assumes that the user has drawn the line themselves (even if no draw call actually took place), and avoids drawing that line again.As this is called from
_draw()
, anydraw_*()
functions called will be cached. Additionally, if the user exports their own variables meant to change how certain lines are handled within_draw_line()
, they are expected to callupdate()
whenever these variables change so that their settings will take effect.Here is an example, where the user makes the lines draw at double the normal width:
func _draw_line(from: Vector2, to: Vector2) -> bool: draw_line(from, to, self.grid_color, 2.0) return false
It's not a perfect solution, but I'm not looking to start off with one. In fact, I bring up my proposed solution in hopes of starting a conversation on how we can improve and iterate upon my idea, if people feel my idea is promising. Hopefully my idea can lead to this Grid node coming out of the oven in an even more delicious state.
func _draw_line(from: Vector2, to: Vector2) -> bool: draw_line(from, to, self.grid_color, 2.0) return false
I think being able to override drawing per call is a nice idea. Perhaps the callback can also provide additional contextual state information to determine things such as whether a line is odd or even etc.
By the way, I've been looking at the source code and stumbled upon this method:
One can clearly see the amount of code needed to make it work in a general-purpose way, so this definitely requires some design work before programming such a thing yourself! I think we could take this as a base implementation and see how it goes. The viewport
node is basically the Grid
node here.
There are probably two largely approaches:
Both methods could be implemented and the type could be switched if those approaches do significantly differ. The per-cell approach may be more universal in comparison.
I took some time to drum up my own solution to your problem, because I do think your problem is one worth solving
I don't have a problem, and it's not up to me to improve this proposal, because it's not my proposal and I'm not in favor of it at all. But your idea is a nice addition to it nonetheless. Though I expect that this will ruin any chance for drawing optimizations, therefore making the whole idea lacking the point of implementing it in the first place.
At any rate, if you really want this proposal to be improved, this all can already be implemented as an addon to prove the concept and to polish the API.
@pycbouh Then I would suggest spending your time on other proposals, specifically ones that you think are worthwhile. You've already made it clear (multiple times, might I add) that you're not in favor, so I don't understand why you feel the need to continue commenting here.
@LikeLakers2 I only reply to the points made against my arguments and direct responses to me, like yours. Otherwise, indeed, I have nothing else to add here at this point. Please keep your suggestions to yourself, this is offtopic.
From reading the discussion, there seems to be a need to clarify: the proposals workflow is first and foremost to discuss additions to the core. @Xrayez's OP actually suggests that this would probably be best-suited as a plugin, and then there seems to be misunderstanding of @pycbouh's comments with regard to implementing this in core (which is what a proposal is intended for).
So here's my take on this:
_draw
.Now, I'm fine with having this proposal used for brainstorming about what the API could be for such a plugin-implemented Node. I think if we all agree that doing this as a plugin is the best course, we can drop the irrelevant meta-discussion about other "simple" nodes in core and whether they should be in core or not. And most of pycbouh's critical feedback on the proposal is no longer a direct concern if this is done as a plugin - it's still useful to drive design decisions, but plugin implementers are welcome to implement what they want and it's users or lack thereof who will help ascertain whether the feature and its design are useful.
Implementing features that could be core as a plugin first to experiment with the API and use cases is always a good idea, as long as it can be done without too much trouble. I've done this with godot-logger, and I think there's a use case for making such logging feature part of the core, yet I'm still not happy with the API we came up with in this plugin and a core implementation would likely be another iteration, learning from the mistakes of the first one.
Just for fun, here's the most basic implementation of grid drawing I could whip up in a few minutes:
tool
extends Node2D
const GRID_STEP = 40
const GRID_SIZE = 20
func _draw():
for i in range(GRID_SIZE):
var col = Color("#aaaaaa")
var width = 1.0
if i == GRID_SIZE / 2:
col = Color("#66cc66")
width = 2.0
draw_line(Vector2(i * GRID_STEP, 0), Vector2(i * GRID_STEP, GRID_SIZE * GRID_STEP), col, width)
for j in range(GRID_SIZE):
var col = Color("#aaaaaa")
var width = 1.0
if j == GRID_SIZE / 2:
col = Color("#cc6666")
width = 2.0
draw_line(Vector2(0, j * GRID_STEP), Vector2(GRID_SIZE * GRID_STEP, j * GRID_STEP), col, width)
Of course it's not infinite, doesn't have primary/secondary lines, metrics and origin are hardcoded, it doesn't hold any kind of metadata or other information that could actually be used to draw stuff on the grid (like a vector from one grid position to another), etc. All these are design concerns that are use-case specific and would be best assessed along the way to fix users' expressed needs.
Just as some food for thought, drawing grids may be better done with shaders, especially if we need them to be infinite and smooth looking. For one, AA on draw_line
is a performance killer. May not matter in apps much, but is a problem for games.
Just some food for thought, many proposals that look valid initially turn out to have suprisingly easy GDScript solutions. Can we have a website or something to share snippets such as the grid one above?
Just as some food for thought, drawing grids may be better done with shaders, especially if we need them to be infinite and smooth looking. For one, AA on
draw_line
is a performance killer. May not matter in apps much, but is a problem for games.
May be overkill, unless the grid is going to be rotated (like the canvas in the painting apps) so aliasing artifacts are going to be prominent in those cases without AA...
Just some food for thought, many proposals that look valid initially turn out to have suprisingly easy GDScript solutions. Can we have a website or something to share snippets such as the grid one above?
There are websites such as https://gdscript-online.github.io/ and https://gd.tumeo.space/, but all of them are headless (nothing can be rendered). The official Web editor could further help this limitation, but it's still considered experimental...
By the way, this "proposal" can be converted into a discussion if/when we move to use this workflow as proposed in #2069. I guess neither me nor anyone else here would go into direction of whether this should be a plugin vs core debate in the first place.
Just some food for thought, many proposals that look valid initially turn out to have suprisingly easy GDScript solutions. Can we have a website or something to share snippets such as the grid one above?
The asset library is a perfect place for this kind of stuff :slightly_smiling_face:
If its usability isn't good enough, we should improve that instead of creating yet another platform, which would further fragment the community.
Just some food for thought, many proposals that look valid initially turn out to have suprisingly easy GDScript solutions. Can we have a website or something to share snippets such as the grid one above?
The asset library is a perfect place for this kind of stuff slightly_smiling_face
If its usability isn't good enough, we should improve that instead of creating yet another platform, which would further fragment the community.
Getting off-topic, but I'd love a snippet sharing site for Godot, I have thousands of lines of small utility functions which I think could be helpful for many. Just browsing the site would be great for learning, too.
Just as some food for thought, drawing grids may be better done with shaders, especially if we need them to be infinite and smooth looking. For one, AA on
draw_line
is a performance killer. May not matter in apps much, but is a problem for games.
I thought about this a little bit, and while I do think it would have better performance with shaders (since shaders would run on the GPU), I don't actually think shaders would be a good solution here.
Namely, if this were implemented in a shader, then I don't believe we have a way to call into user-defined code. And since we can't call into user-defined code, we can't let the user implement game-specific things such as what you mentioned before (making some lines thicker, but not others; making some lines disappear; etc.).
Of course, this is assuming we want to go a similar direction as what I suggested before (a virtual function called for each line), but within a shader.
I'm more interested in a container that would create an infinite area, scrolling and zooming, and which is drawn with a grid. Like GraphEdit. And children can be freely rearranged with or without grid snapping
I need this to create various applications and plugins such as mind map and drawing app, charts etc.
To create a mindmap app, I hope GraphEdit will be a good base, but in other cases, when I do not need to use connections between children, GraphEdit will not be useful.
Due to questioned usefulness of the plain Grid
node by pycbouh, yeah, I guess implementing something like GraphEdit
could be much useful. Of course, all these scrolling and zooming features are better implemented as opt-in features, depending on what you actually need to enable for your plugin.
But if we take the Godot's approach of "composing simple nodes to do complex stuff", those features may be already available using existing built-in nodes such as ScrollContainer
to be used as parent of Grid
node. Yet implementing the zooming behavior wouldn't be as trivial to do via script for less experienced users, though. Would we also need a ZoomableContainer
? That actually makes some sense to me since what ScrollContainer
does is actually translating child nodes, and ZoomableContainer
would scale child nodes. Technically, zooming features could also be implemented as part of ScrollContainer
if there's a desire to prevent bloat.
These are all ideas, mind you!
I have come up with an implementation which I'm personally satisfied with in goostengine/goost#80. Only constructive criticism is accepted. 🙂
You can download the editor from the GitHub Actions build artifacts in the PR above and run the example project (along with any other feature the Goost project currently provides).
By the way, I've found another project which uses a grid: https://github.com/Zylann/godot_grapher. The functions provided by proposed GridRect
class could certainly help converting between grid/plot and Control
rect coordinates: https://github.com/Zylann/godot_grapher/blob/12e46a5f9660fbbae765fc0a306f465be986903c/graph_view.gd#L47-L48.
Describe the project you are working on
VectorResource
.Describe the problem or limitation you are having in your project
This mostly applies to editor plugins development, where you need to draw a grid for snapping/aligning purposes. Drawing a grid boils down to rendering a bunch of intercrossing lines, and this is more or less straightforward process, but may be more complex to implement depending on the feature set.
But the complexity is not really a problem, the problem is that Godot may lack a very needed feature. The problem is that I don't see anyone mentioning this, so I'd like to understand whether we do have a problem which needs to be solved (more like #2532).
Describe the feature / enhancement and how it helps to overcome the problem or limitation
I propose to implement a new type of
Control
node with the sole purpose of rendering a infinite grid in 2D. It would be up to the user to code the scrolling behavior if needed.A grid will have:
cell_size
and number ofdivisions
(accepting different width and height);This feature wouldn't be limited to editor development. See also plugins like https://github.com/fenix-hub/godot-engine.easy-charts which do allow to make charts for games such as City Game Studio currently developed in Godot. In-game minimaps could also benefit from basic grid subdivisions representing chunks of the game world etc.
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
In theory, the grid's background and outline colors could be styled via
Theme
resource.Usage examples
If this enhancement will not be used often, can it be worked around with a few lines of script?
Sure, it's totally possible.
Is there a reason why this should be core and not an add-on in the asset library?
This probably shouldn't be part of core, but I'd like to understand whether community would find this kind of feature useful in their real-life projects.
Yet Godot does display grids in various editors already, like
AnimationTree
,VisualScript
,VisualShader
etc, so this alone signifies that a feature like this should be very useful for plugin creators (sayFiniteStateMachine
/BehaviorTree
plugins which are unlikely to be implemented in core, according to previous discussions).The node name is up to discussion, of course. I picked
Grid
because that's basically what it would represent (orGrid2D
may be just fine, but it's unlikely that the 3D part is going to have such a node, it's mostly about GUI). I did implement other class with the sameGrid2D
name in the past (now renamed toVariantMap
) which works as a general-purpose 2D data container (which is different fromArray2D
), so this is also a minor reason why I'd like to discuss this.