godot-constraint-solving
godot-constraint-solving copied to clipboard
[Docs] Custom Preconditions2D
Hello, I want to preface with how much I appreciate this addon as it offers a very complete and relatively easy to use integration of WFC. I am trying to make a custom Precondition2D that uses perlin noise (Or simplex noise) to create denser forested areas and plains that are to be populated by WFC. However, I am having trouble understanding how to use the bitset object and the mapper object. I'm also uncertain on how to add the custom precondition to the generator. Would it be possible to have a small crash course? The dungeon example isn't super explanatory...
Hi.
how to use the bitset object
WFCBitSet is a bit array implementation. It uses N bits of memory to store sets of integers between 0 and N-1.
You may think of it as of a fancy but limited and inconvenient array.
In context of preconditions, it is used to return (from read_domain method) sets of tiles allowed in certain cell. Each tile is represented as an integer.
The minimal set of operations you will have to use is creating a bit set and adding a value to it.
The bit set is created as by calling a constructor:
var mybitset = WFCBitSet.new(size);
where size is number of tiles in WFC rules, which can be acquired from a mapper.
By default a set will contain no values. If true is passed as second constructor argument, the set will contain all valuest between 0 (inclusive) and size (exclusive).
A value is added to a set by calling set_bit method:
mybitset.set_bit(2)
These two operations may be enough for basic precondition implementation (just create a bit set and add some tile ids to it). But other methods may be useful as well.
There is some minimal documentation for all of WFCBitSet methods and I hope it should be enough to use them with some basic understanding of bit array data structure and set operations in general.
and the mapper object.
The mapper is responsible for interaction between WFC generator and a map node. There are different mapper subclasses that work with different map nodes (WFCGridMapMapper2D for GridMaps, WFCLayeredTileMapMapper2D and legacy WFCTileMapMapper2D for TileMaps).
They map data between formats specific for map types and unified representation used by WFC generator and related stuff, including preconditions.
In precondition mapper is used to get data about available tile types:
- number of tiles available to generator
- parameters of different tiles that determine what category each tile belongs to
The number of tiles is returned by size() method of mapper. It should be used later to create WFCBitSets.
There are two approaches to provide tile categories data to the precondition:
- Use tile metadata. Metadata is values associated with each tile. In case of
TileMaps, data layers are used as metadata. In case ofGridMaps - it's possible to attach metadata to each mesh using a mapper property. - Use an auxiliary map.
Tile metadata is accessed using read_tile_meta method of a mapper. There is also a read_tile_meta_boolean method, useful for booleam attributes.
For example, if you want to mark some tiles as tiles belonging to "forest" area, you may create a "is_forest" boolean data layer in the tileset and then use the following code to create a set of all tiles that have this data layer set to true:
var forest_domain = WFCBitSet.new(mapper.size());
for i in range(mapper.size()):
if mapper.read_tile_meta_boolean(i, "is_forest"):
forest_domain.set_bit(i)
In dungeon precondition this approach is implemented in learn_classes method.
This approach is extremally convenient with TileMaps. But GridMaps don't have a built-in metadata functionality and metadata settings in mapper aren't very convenient.
In case of GridMap, an auxiliary map approach is more usable.
In this case to configure a precondition a separate map is created. And reference to that map stored in your precondition settings object (see below).
Then you place, for example, "forest" tiles in the first row of the map and "plain" tiles in the second row.
Then ids of tiles belonging to each category can be extracted using mapper's get_used_rect and read_cell methods that reads tile from given coordinates in given map.
In dungeon precondition this is implemented in learn_classes_from_map method.
Dungeon precondition demos show most of configuration variants - tilemap with metadata, gridmap with metadata and gridmap with auxiliary map.
I'm also uncertain on how to add the custom precondition to the generator
To use a custom precondition with WFC2DGenerator you'll have to:
-
Create a settings class (a subclass of WFC2DPrecondition2DNullSettings) for your precondition. The settings class should export the properties you'd like to be customizable. It also should implement a method create_precondition based on those settings. Settings class must be placed in it's own
.gdfile and must have aclass_nameset in order to be discoverable by inspector. -
Set (using the inspector) an instance of you settings class as
preconditionproperty of generator.
Thank you! This clears up a lot of questions I had reading the code! I will let you know if I have more problems worth documenting.