You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is somewhat related to my previous post #9296 - whereas that post was suggesting a new feature, this post is asking for help on how to achieve the same thing in the current system. Because I'm relatively new to Bevy, I'm looking for advice and help on how to structure my code.
Here's the setup: I'm porting my existing three.js game to Bevy. The game has multiple worlds called "realms". A Realm is a Component that has a name, a layer mask, and some lighting params. This layer mask be important later when I start to port my portal code over from JavaScript, since portals can connect realms, which means that more than one realm is resident in memory.
Realms have different kinds of renderable content. One type of content is "terrain". Terrain is not randomly generated (it's not that kind of game), instead terrain is made up of modular units called "parcels" - each parcel is 16 x 16 meters. Because not every Realm has terrain (for example, dungeon levels do not), the TerrainMap is a separate Component which is attached to the realm.
Both realms and terrain maps are represented as assets, in different directories. How do we know which terrain map is associated with a given realm? The answer is that both have the same filename, but with different file extensions.
Aside: getting the base filename from an asset handle is surprisingly complicated:
fn asset_name_from_handle(server: &Res<AssetServer>, handle: &Handle<TerrainMapAsset>) -> String {
let asset_path = server.get_handle_path(handle).unwrap();
let path = asset_path.path();
let filename = path.file_name().expect("Asset has no file name!");
let filename_str = filename.to_str().unwrap();
let dot = filename_str.find(".").unwrap_or(filename_str.len());
return filename_str[0..dot].to_string();
}
I use the load_folder() method on asset server to discover which realms exist. Then I attempt to load the corresponding terrain asset. If the terrain map asset does not exist, then that's ok - it means that this is a realm with no terrain.
Aside 2: is there a way to test if an asset exists without loading it? I can try loading it and check the error code, but I don't like getting console warnings.
Once the terrain map is loaded, the engine starts to generate parcels. Parcels contain the vertex buffers for the terrain mesh, as well as instances of flora (trees, shrubs, etc.)
Parcels are managed by the ParcelCache resource / system, which creates the parcel mesh for parcels that are near the camera (including portal cameras). Parcels which are far away from the camera are evicted from the cache. This approach means that game maps can be virtually unlimited in size.
Each TerrainMap component includes a handle to a TerrainMaterial, which is the custom shader for terrain. The reason for having a separate material instance per Realm is that the shader uniforms are different for different realms, mostly having to do with biomes. There's also a custom monochrome texture which stores the biome data passed to the shader.
Because terrain maps are frequently edited during development, we want to update the TerrainMap component whenever the terrain asset changes. This is done by an asset event reader which looks at the terrain map folder.
This is where things start to get complicated: I've observed that the order of loading is not always deterministic - for example, when I get an event that tells me a terrain map has been created, that may happen after the realm asset has loaded, or it may happen before. TerrainMaps have to be associate with a Realm before they can be used - that is, they are components on the same entity.
This means that the code for creating the terrain shader and other objects used in terrain maps (meshes, physics, etc.) has to happen in two places in the code: whichever asset is loaded last (realm or terrain map), we need to generate the shader, biome texture and so on at that point.
And this is just with two assets! If I had a third asset type, now I have to put the code in three places, since I don't know which of the three assets will get loaded last.
So my general question here is - am I thinking about this wrong? Is there a better approach for dealing with objects that are synthesized from multiple assets, where any of the source assets can be hot-loaded?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
This is somewhat related to my previous post #9296 - whereas that post was suggesting a new feature, this post is asking for help on how to achieve the same thing in the current system. Because I'm relatively new to Bevy, I'm looking for advice and help on how to structure my code.
Here's the setup: I'm porting my existing three.js game to Bevy. The game has multiple worlds called "realms". A
Realm
is aComponent
that has a name, a layer mask, and some lighting params. This layer mask be important later when I start to port my portal code over from JavaScript, since portals can connect realms, which means that more than one realm is resident in memory.Realms
have different kinds of renderable content. One type of content is "terrain". Terrain is not randomly generated (it's not that kind of game), instead terrain is made up of modular units called "parcels" - each parcel is 16 x 16 meters. Because not every Realm has terrain (for example, dungeon levels do not), theTerrainMap
is a separateComponent
which is attached to the realm.Both realms and terrain maps are represented as assets, in different directories. How do we know which terrain map is associated with a given realm? The answer is that both have the same filename, but with different file extensions.
Aside: getting the base filename from an asset handle is surprisingly complicated:
I use the
load_folder()
method on asset server to discover which realms exist. Then I attempt to load the corresponding terrain asset. If the terrain map asset does not exist, then that's ok - it means that this is a realm with no terrain.Aside 2: is there a way to test if an asset exists without loading it? I can try loading it and check the error code, but I don't like getting console warnings.
Once the terrain map is loaded, the engine starts to generate parcels. Parcels contain the vertex buffers for the terrain mesh, as well as instances of flora (trees, shrubs, etc.)
Parcels are managed by the
ParcelCache
resource / system, which creates the parcel mesh for parcels that are near the camera (including portal cameras). Parcels which are far away from the camera are evicted from the cache. This approach means that game maps can be virtually unlimited in size.Each
TerrainMap
component includes a handle to aTerrainMaterial
, which is the custom shader for terrain. The reason for having a separate material instance perRealm
is that the shader uniforms are different for different realms, mostly having to do with biomes. There's also a custom monochrome texture which stores the biome data passed to the shader.Because terrain maps are frequently edited during development, we want to update the TerrainMap component whenever the terrain asset changes. This is done by an asset event reader which looks at the terrain map folder.
This is where things start to get complicated: I've observed that the order of loading is not always deterministic - for example, when I get an event that tells me a terrain map has been created, that may happen after the realm asset has loaded, or it may happen before. TerrainMaps have to be associate with a Realm before they can be used - that is, they are components on the same entity.
This means that the code for creating the terrain shader and other objects used in terrain maps (meshes, physics, etc.) has to happen in two places in the code: whichever asset is loaded last (realm or terrain map), we need to generate the shader, biome texture and so on at that point.
And this is just with two assets! If I had a third asset type, now I have to put the code in three places, since I don't know which of the three assets will get loaded last.
So my general question here is - am I thinking about this wrong? Is there a better approach for dealing with objects that are synthesized from multiple assets, where any of the source assets can be hot-loaded?
Beta Was this translation helpful? Give feedback.
All reactions