rtstragedy2 [fae/faer, she/her]

i’m back

  • 0 Posts
  • 20 Comments
Joined 18 days ago
cake
Cake day: August 6th, 2025

help-circle



  • update: its WORKING, and i cant even remember what i did to fix it late last night! oh right, git history, yeah my SummedAabb function is a mess now, as it responds to the addition of an Aabb somewhere in the code with a re-summing of the parents. weird for sure. at some point i should probably make it recursive, and look into whether I really need a newtype for Aabb (SummedAabb(Aabb)) or if I can just use Aabb without screwing up frustrum culling (since that’s what its used for apparently)

    i guess its time to read the bevy source code again, i love open source (not sarcastic)





  • beep boop i am the update robot

    THE TRIP

    its ok we’ll figure it out. last time was copious amounts of checklists and we only almost got trapped in a city we don’t know anyone in overnight and only 3 of the four flights were rescheduled. but apparently there are puppies at my parents’ house … i just like being at home and hate travelling.

    bottom surgery

    apparently i got an email yesterday from the clinic that wants to book me so now i need to figure that out - is it really gonna be worth all the pain for me? who knows … lots to think about, like also having to get electrolysis done for like a year beforehand, ugh

    gamedev

    i just kinda clicked some buttons in blender to make a simple idle animation for the shitty sword in my game, and then loaded it into Bevy. the animation stuff in Bevy took me a while to grasp (why does AnimationGraph::from_clip(...) return a tuple of (graph, node_index) instead of a single value, for instance? it finally made sense once I got it working of course, the node appears to always be 1 since there’s only one clip inside the graph I’m making, and it points to the point in the graph that the clip was put to. confusing at first, not really well documented IMO, i am very excited for the official Bevy Book to be not a secret link and also have a section on animation.

    anyway i can’t figure out how to post the video but now when you pick up the dumb test sword it has an idle animation that just bobs a bit, and the animation set is defined in the spec i showed before. of course, all the animations will be living on the viewmodel (for first person animations) so referencing them by index is right out, but it turns out that the Gltf type has a named_animations field so I can iterate through those and build a little HashMap to store them:

    #[derive(Resource, Default)]
    struct ViewModelAnimations(HashMap<String, (Handle<AnimationGraph>, AnimationNodeIndex)>);
    
    fn build_animation_lut(
        mut er_loaded_viewmodel: EventReader<AssetEvent<Gltf>>,
        handle: Res<ViewModelHandle>,
        gltf_assets: Res<Assets<Gltf>>,
        mut graphs: ResMut<Assets<AnimationGraph>>,
        mut view_model_animations: ResMut<ViewModelAnimations>,
    ) {
        for event in er_loaded_viewmodel.read() {
            let AssetEvent::LoadedWithDependencies { id } = *event else {
                continue;
            };
    
            if id != handle.0.id() {
                continue;
            }
    
            let gltf_asset = gltf_assets.get(id).unwrap();
    
            for (name, clip_handle) in &gltf_asset.named_animations {
                info!("discovered named animation {name}");
    
                let (graph, index) = AnimationGraph::from_clip(clip_handle.clone());
                let graph_handle = graphs.add(graph);
    
                view_model_animations
                    .0
                    .insert(name.to_string(), (graph_handle.clone(), index));
            }
        }
    }
    

    then it’s a trivial matter to actually play them later using the AnimationPlayer added to the scene automatically by Bevy (since it has an Armature)









  • gamedev rambling

    The fun thing about working with Rust (or maybe Bevy?) is that every silly little thing feels like such a huge accomplishment. It’s like studying the arcane arts, I’m deep into Bevy source code or sparse documentation and when 0.17 comes out some of my code will probably need to change (for the better, of course), and occasionally if you cancel compilation at the wrong time it corrupts your build directory.

    Anyway, I present to you, loading .ron files from a folder to populate item stats! This is probably a one-liner in Unity, lol, but that just ain’t me.

    The file structure:

    InventoryItem(
      id: "sword_test",
      friendly_name: "Test Sword",
      scene_path: "sword_test.glb",
      item_type: Weapon(
        slot: PrimaryHand,
        two_handed: false,
        damage: ({
          Slash: 2
        })
      )
    )
    

    And partial code to actually deal with async loading:

    #[derive(Resource, Default)]
    pub struct ItemRegistry(Handle<LoadedFolder>, HashMap<String, InventoryItem>);
    
    fn load_items(asset_server: Res<AssetServer>, mut item_registry: ResMut<ItemRegistry>) {
        // Preload everything in the folder.
        item_registry.0 = asset_server.load_folder("items");
    }
    
    fn folder_loaded(
        mut er_loaded_folder: EventReader<AssetEvent<LoadedFolder>>,
        folders: Res<Assets<LoadedFolder>>,
        items: Res<Assets<InventoryItem>>,
        mut item_registry: ResMut<ItemRegistry>,
    ) {
        for event in er_loaded_folder.read() {
            let AssetEvent::LoadedWithDependencies { id } = *event else {
                continue;
            };
    
            if id != item_registry.0.id() {
                continue;
            }
    
            let folder = folders.get(&item_registry.0).unwrap();
    
            for file in &folder.handles {
                let item = items.get(&file.clone().typed()).unwrap().clone();
                info!("discovered item {}", &item.id);
    
                item_registry.1.insert(item.id.clone(), item);
            }
        }
    }
    

    I am not sure at this point whether I’ll keep the “stripping the InventoryItem out of the Handle,” it doesn’t seem necessary but it might be handy to not have the items cloned into player inventories - to ensure all instances of an item are the same, but if I want to do item XP or anything like that that kind of precludes it.

    Of course, all this is to say nothing of the actual design of the game which uh looks like this.

    And once again, I am very proud of the view model, which is apparently a somewhat standard term for the view of the player’s hands and weapons in first-person (although I just resized the window and its no longer visible, so that’s a problem lol oh no). Several confused rounds in Blender as the co-ordinate systems are weird and I basically had to set up the camera view to roughly match the game by eyesight in Blender. Oh, and I guess the 5-hour donut tutorial paid off because look at that HIGH-DEF ART.




  • why'd i come back

    i don’t really have anyone that i can really be myself around other than my partner. my irl friends are cis mostly and I don’t talk at all about real stuff to them when I see them like once every few months. i tend to isolate myself when i’m stressed and i struggle to really open up to people in general and even if i do i tend to turtle after because i fear later rejection. in some ways its way easier to just post here and hope people respond or at least upbear because i don’t ever have to worry if i’m being too imposing or clingy or otherwise burdensome on individual people. i spent a lot of my life being an outsider and being rejected without really understanding why and i think it fundamentally broke my brain chemistry and its possible that normal friendships are just beyond me now. so i’m reclaiming this space i guess


  • i’m back btw

    what have i been up to

    work has been ridiculously stressful. i started adhd meds which made me more productive and are generally helping me a lot. i can stick with things now that i want to be doing, so that’s neat. i got through a major release and such that was stupid and stressful and afterwards the residual stress was so bad I had to take a couple sick days. lol.

    i’ve been back on making games. i experimented with making a Minecrap clone in rust+bevy and got super deep into the terrain generation, so now I am a font of knowledge about how Minecraft 1.18+ terrain gen works, ask me anything about density functions and octaves and shit, I guess. One of the most satisfying things was improving the performance of the algorithms and rendering since it was Very Slow at several stages.

    1. Render a cube for each block that’s not air - this is obviously not performant, but I wouldn’t recommend anyone skip the easiest step for performance for like a bunch of reasons (a. the performance characteristics may not be as you expect! b. simple code is easier to modify than optimized code and easier to find bugs in). It was slow, lol. ESPECIALLY when I added colliders to each block, yikes, neither Rapier or Avian was prepared for like 32k colliders. I hoped there would be some optimizations for non-moving blocks but it seems that that was too much to ask (since technically, I guess any of the blocks could move every frame because I controlled the Transform)
    2. I then optimized to only render the blocks that were actually visible (ie. they have at least one air block adjacent to them),
    3. I tried to make a Mesh per face and only show the visible faces. This was slower than the above, somehow?! (like, unusably, 4fps on my laptop with huge stutters as you traversed the world) I guess this was a good lesson for me that just because an optimization sounds good on paper, there’s a ton of nuance and other things you maybe didn’t consider that only arises from testing. In this case, I believe the issue was the huge number of Entity-s I was spawning (one for each face). ECS has limits I suppose and they are … (if the average chunk has 16 * 16 top faces + say another 16 * 16 side faces to be generous, and I’m trying to show a 10x10 grid, then that’s 51k entities that are completely static that need a bunch of transform propagation etc. every frame)

    I ended up settling on a system that would:

    1. On startup, stitch all the textures for the blocks into one single atlas. Minecraft does this too: https://minecraft.wiki/w/Blocks.png-atlas . This allows me to have one Material for the entirety of the static game world.
    2. Each chunk is built into a single custom Mesh filled with vertices and carefully calculated UV co-ordinates (and I even stuck in some extra vertex attributes to bake light levels in) to select the block type, a custom Mesh topology that would calculate visible faces based on adjacent blocks.

    I found that actually building the mesh for a given chunk would take ~2ms, but that doesn’t include generation time (which I moved to an async task pool).

    For actually generating chunks, there’s so much information out there about how Minecraft actually does this stuff that it was really easy to solve these problems. Things I liked were the talk by one of the devs on the wiki about terrain generation and the basics of how it works, the wiki which explained density functions, the fact that the worldgen code is literally just json files inside the jar, and of course the mostly-working Deepslate JavaScript library https://github.com/misode/deepslate which had a close-enough noise implementation (although yikes I think the naming of the deeply nested noise classes is not great, not that I could do much better) which helped take a lot of the difficulties of the documentation on the wiki and turn it into code implementation, and led me down the path of using the Visitor pattern for actually handling the deeply nested web of complex operations that involve determining the final density of a given block.

    It was slow, so I tried to get SIMD working and struggled with the FastNoise2 library (which has rust bindings, which is nice, but I had to symlink some files to get it to work right as it would build the library in the wrong folder for some reason) and once I did suddenly it was fast, but as is typical with optimization, a complete refactor was necessary. Lots of hours.

    Eventually, I decided to move on to other things as I felt like I was neglecting other skills I needed to actually be a competent game dev like modelling, mechanics design, etc. stuff like that that’s a lot more nebulous and way outside of my skill set. So my partner and I did a 5 hour Blender tutorial about making donuts and animating them, and while I think I learned a lot from it I still feel totally lost on how to take the mess of ideas in my head and turn them into a compelling game without getting lost or burnt out along the way. So I’m taking some time off from creation to read Tynan Sylvester’s Designing Games to see if having a bit of a more solid framework will help make it all make sense.

    I still feel totally lost in a lot of ways, but I’m trying to take it easy and just idk be kind to myself.