Portponky / better-terrain

Terrain plugin for Godot 4
The Unlicense
509 stars 24 forks source link

Terrain category support #4

Closed Portponky closed 1 year ago

Portponky commented 1 year ago

I've been looking at implementing terrain grouping, and I have figured out a way to implement it whilst at the same time improving performance across the board. This will be my next feature, and I would like to get it done before Godot 4.0 releases, as it will likely be a breaking change.

In general, I want terrain types to belong to a category (or multiple categories), and then be able to connect to other terrains of those categories. For example, if you have different types of ground - sand, dirt and paved - you can give them all the same category and set up their peering bits to connect to their category. That's easier than setting up every combination of connections between them.

At the same time, I want to be able to support the terrain's uniqueness, so if there a specific special connection, that can be supported. In the same example, if you have water tiles that can connect with sand but not dirt/paved, then that should still be supported.

There are a number of ways that groups or categories could be implemented. For example:

An extra property on the terrain

Perhaps it could be an extra property on the terrain which allows it to appear as any other type of terrain, or a selection of other types. This is the most flexible (maybe overly so) but a poor UI.

Terrain types in a hierarchical arrangement

Another option which is more clear and intuitive is to arrange terrain types in a hierarchy. This is a slightly less flexible, but very easy to understand. This is probably what I will go with unless there is a strong reason to do something different.

If you have any feedback about this, feel free to comment.

Portponky commented 1 year ago

I implemented something similar to the first mockup in the original post. The underlying code uses arbitrary length bitfields to match terrain categories together. Although this is much faster in theory, relying on sequential bitwise operations rather than linear searches of arrays, the actual result is considerably slower due to the overhead of GDScript.

Functionally, it works very well. The only real issue is that the speed is bad, probably too bad for real time usage.

Overall, I'm not exactly sure what I can do to improve the quality of this plugin, but the obvious strategy is to use GDExtension to strip out some of the GDScript overhead. I'll experiment with that and see if I can make significant gains. Perhaps there is some way to have it run some components natively, but fallback on a pure GDScript solution in situations where native is unavailable.

Portponky commented 1 year ago

I've pushed the changes into a category branch, but I'm unhappy with the performance. I'm looking into GDExtension because that should be able to speed it up a lot.

Portponky commented 1 year ago

I'm going to make some adjustments to the category branch to remove certain implementation details from the internal API. That will simplify making a C++ version of the matching engine via GDExtension. I will do this over the next few weeks.

Portponky commented 1 year ago

Reworking the precalculation / caching allowed the performance to be comparable (almost equivalent) to previous. I will skip a GDExtension for now, as I think the plugin works sufficiently well with just GDScript, and that is most versatile.

fritzy commented 1 year ago

I appreciate you taking a look at my PR as inspiration to solve the problem in a way that better suited your goals for this project (also a much better develop experience than what I came up with). I'll be kicking the tires on it this weekend! https://opengameart.org/content/dawnlike-16x16-universal-rogue-like-tileset-v181 Dawnlike has been a challenging tileset to set rules for, but your terrain tool has been up to the task so far!

Portponky commented 1 year ago

Merged back to master now.