A little tribute to the Dango Daikazoku from Clannad (by Key, KyoAni, et al)

Overview

dango

A little tribute to the Dango Daikazoku from Clannad (by Key, KyoAni, et al)
Try it with your friends at http://ernestwong.nz/dango-tribute/server/
It might not work :)

demo.mp4

What is this?

Just a little experiment made using the Bevy game engine to get myself a bit more familiar with Rust.

I don't take pride in the quality of this codebase. It is full of hacks, non-idiomatic Bevy code, and more inefficient hacks. Be warned when looking through the code.

Will I continue to work on this?

No. I don't want to ruin the image of Clannad any further. Let's keep this as a small experiment.

Blob physics

The dangos are octagon meshes, simulated as FEM surfaces within nphysics.

To get variable jump heights, it applies a jump force that:

  1. spikes when the jump button is pressed, and
  2. decays until the jump button is released.
  3. drops to zero after the jump button is released.

By default, these FEM surfaces like to roll around. To fix their angle so they're always upright, it measures the aggregate angle and angular momentum of the whole dango using its 8 individual FEM surface elements, and then use something that resembles a PD control loop to lock it in place naturally. To re-enable rolling, we just turn off this PD control loop.

To get the wobbly walking animation, it modulates the horizontal walking force with some squishing and stretching.

Currently, the dango physics don't obey Newton's third law (i.e. the jump force is asymmetrically applied), so if two dangos ever get tangled, they can fly into the air ignoring gravity.

Blob drawing

To draw the dangos, I used a Catmull-Rom spline from the Splines crate to smooth the octagon out into 32 vertices, and then used the lyon crate to tessellate them into triangular meshes that can be rendered.

The shadows are just hard-coded octagons on the ground. The eyes are also tessellated using lyon, and are made to blink once in a while using a simple finite state machine.

Background and post-processing

The background and the hand-drawn look are done in a post-processing shader with the help of a bevy plugin that's propably not good enough to be made into its own public crate. The fragment shader script is pretty slow and unnecessarily intensive, so I had to limit the size of the screen to keep the framerate consistently smooth. The shader script itself was inspired from a shadertoy script by flockaroo.

Music

Yeah, sorry, the short background music was whipped up in a day or two, so it sounds kinda bad. I used Dorico to write it up, and then performed it with Spitfire Audio's BBC Symphony Orchestra Discover's celesta instrument, recorded inside Cakewalk.

The audio playback might not start in Chrome due to Chrome's autoplay policies, and at the moment, there might be some audio degradation at the start of the playback.

Multiplayer

The prediction/rollback logic was eventually refactored out into its own crate: CrystalOrb. This networking code probably isn't efficient, and there are still some bugs that show up when the browser tab sleeps for too long.

The player hosts the servers themselves, but it's still written in a server-client way, so it's like an inefficient version of peer-to-peer? The connections are established using WebRTC, with a WebSocket signalling server written in Rust using Actix. However, I haven't configured a TURN server, so many connections could fail. Trying to connect within a LAN might also have some issues, because web browser anonymize their IP addresses by using an mDNS address, but not all OSes support them.

Patches

To get this experiment somewhat working, I hacked together some patches for some dependencies. Some of the patches are genuine fixes and enhancements, but most of them are short-term solutions that are specific to this experiment. When I get time, I'll see if I can make proper pull-requests for some of the fixes back into the upstream repositories.

You might also like...
Convert your ascii diagram scribbles into happy little SVG

Svgbob Svgbob can create a nice graphical representation of your text diagrams. Svgbob provides a cli which takes text as an input and creates an svg

A little bit fast and modern Ruby version manager written in Rust
A little bit fast and modern Ruby version manager written in Rust

A little bit fast and modern Ruby version manager written in Rust Features Pure Rust implementation not using ruby-build Cross-platform support (macOS

A little wrapper I've written for creating UI screens from files for the BevyEngine.
A little wrapper I've written for creating UI screens from files for the BevyEngine.

UI Screens for BevyEngine This is a little thing I put together for creating simple UI screens using the BevyEngine. The idea is to define the screens

A little cross-platform graphics engine written in rust.

Bismuth This is a version of my C++ graphics engine named Bismuth re-written with Rust. My goal is to learn more about the Rust language and make my g

ChiselStore is an embeddable, distributed SQLite for Rust, powered by Little Raft.

ChiselStore ChiselStore is an embeddable, distributed SQLite for Rust, powered by Little Raft. SQLite is a fast and compact relational database manage

Click-once - A small tiny little binary to fix undesired mouse double clicks in Windows, written in Rust.

click-once A small tiny little binary to fix malfunctioning mouse double clicks in Windows, written in Rust. Minimal executable with little to no over

🐦 Friendly little instrumentation profiler for Rust πŸ¦€
🐦 Friendly little instrumentation profiler for Rust πŸ¦€

🐦 puffin The friendly little instrumentation profiler for Rust How to use fn my_function() { puffin::profile_function!(); ... if ... {

Just a little game I made in a day to try out the WASM-4 fantasy console.

Dodgeball This is just a little game I made in a day to try out the WASM-4 fantasy console. Play it here. The palette is SODA-CAP by Cappuchi. License

The library for those who need a little extra from their windows. β„’

WinEx The library for those who need a little extra from their windows. β„’ WinEx - Short for Window Extended - is a library whose goal is to implement

little brother of gnu-copypasta-maker To compile, use make.

UWU Maker little brother of gnu-copypasta-maker To compile, use make. To install, use sudo make install or if you are root make install To uninstall,

TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker
TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker

TimeKnight is a neat little TUI-based timer app I use in conjunction with a task tracker. It's kind of a secret sauce for productivity (particularly if you have ADHD or have a ridiculously overactive brain).

Swish - The powerful little audio node for Discord
Swish - The powerful little audio node for Discord

Swish - The powerful little audio node for Discord. Swish is a standalone server that allows you to connect multiple bots and play audio across all yo

Little tool so you can swap out user jsons easily

Little tool so you can swap out user jsons easily To run: $ cargo run user-name inside of root directory. Or you can build and use the executable with

Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better
Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better

Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better

a little game, limbo on a mountain pass
a little game, limbo on a mountain pass

limbo pass a little game, limbo on a mountain pass run the game build / run with the release flag so the overworld theme loads on time :) cargo run --

Little 2D physics engine used for my game Crate Before Attack.
Little 2D physics engine used for my game Crate Before Attack.

Circle2D Circle2D is a little physics library used for my game CrateBeforeAttack. Live demo: https://koalefant.github.io/circle2d/ It is not productio

Planetoid is a toy project to demonstrate and learn several technologies. The goal is to create a little multiplayer asteriod game clone.
Planetoid is a toy project to demonstrate and learn several technologies. The goal is to create a little multiplayer asteriod game clone.

Planetoid is a toy project to demonstrate and learn several technologies. The goal is to create a little multiplayer asteriod game clone.

A little command-line script written in Rust to interface with Discord webhooks.

Rust Discord Webhook Agent This is a little "script" I wrote for practice with Rust and asynchronous operations within Rust. Getting started Clone thi

'apk-yara-checker' is a little CLI tool written in Rust to check Yara rules against a folder of APK files.
'apk-yara-checker' is a little CLI tool written in Rust to check Yara rules against a folder of APK files.

apk-yara-checker 'apk-yara-checker' is a little CLI tool written in Rust to check Yara rules against a folder of APK files. You have to pass the folde

Comments
  • Crash: panicked at 'assertion failed: num_segments > 0'

    Crash: panicked at 'assertion failed: num_segments > 0'

    wasm.js:437 panicked at 'assertion failed: num_segments > 0', /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/lyon_tessellation-0.16.2/src/stroke.rs:1027:9
    
    Stack:
    
    Error
        at imports.wbg.__wbg_new_59cb74e423758ede (https://ernestwong.nz/dango-tribute/client/target/wasm.js:443:19)
        at console_error_panic_hook::Error::new::h799f20735cac74b5 (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[104024]:0x1bc1f1f)
        at console_error_panic_hook::hook_impl::hfe98f285576b7df7 (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[13912]:0xf66d55)
        at console_error_panic_hook::hook::h024505b23e1898e2 (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[115166]:0x1c5cc4b)
        at core::ops::function::Fn::call::h5de70dd740a33179 (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[97893]:0x1b61edb)
        at std::panicking::rust_panic_with_hook::h894f2bdeea4d0ce8 (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[31806]:0x14481ad)
        at std::panicking::begin_panic_handler::{{closure}}::he30feeb51ae9f99b (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[44794]:0x1676051)
        at std::sys_common::backtrace::__rust_end_short_backtrace::h83a4032c6b997446 (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[120244]:0x1c9c24d)
        at rust_begin_unwind (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[109028]:0x1c0a738)
        at core::panicking::panic_fmt::h0dfe153eb0ef456a (https://ernestwong.nz/dango-tribute/client/target/wasm_bg.wasm:wasm-function[120246]:0x1c9c2b3)
    
    
    imports.wbg.__wbg_error_4bb6c2a97407129a @ wasm.js:437
    wasm_bg.wasm:0x1d1e900 Uncaught RuntimeError: unreachable
        at __rust_start_panic (wasm_bg.wasm:0x1d1e900)
        at rust_panic (wasm_bg.wasm:0x1ccc83d)
        at std::panicking::rust_panic_with_hook::h894f2bdeea4d0ce8 (wasm_bg.wasm:0x14481d3)
        at std::panicking::begin_panic_handler::{{closure}}::he30feeb51ae9f99b (wasm_bg.wasm:0x1676051)
        at std::sys_common::backtrace::__rust_end_short_backtrace::h83a4032c6b997446 (wasm_bg.wasm:0x1c9c24d)
        at rust_begin_unwind (wasm_bg.wasm:0x1c0a738)
        at core::panicking::panic_fmt::h0dfe153eb0ef456a (wasm_bg.wasm:0x1c9c2b3)
        at core::panicking::panic::ha2f229d777a180c9 (wasm_bg.wasm:0x1b4a750)
        at lyon_tessellation::stroke::StrokeBuilder::tessellate_round_join::h374f8ac4bab2ff0d (wasm_bg.wasm:0x56e6dd)
        at lyon_tessellation::stroke::StrokeBuilder::tessellate_join::h6ed00a53e24f1c48 (wasm_bg.wasm:0x376f34)
    
    opened by ErnWong 0
  • Migrate signalling server away from Heroku free tier

    Migrate signalling server away from Heroku free tier

    Consider either upgrade or move to another PaaS. Going to move to railway.

    Plan:

    • [x] Deploy signalling server instance Railway
    • [x] Update code to point to new signalling server instance
    • [ ] Shutdown Heroku signalling server instance.

    Places to update in the code:

    • [x] The RustConfig file (used by Heroku to know which crate we want to build) https://github.com/ErnWong/dango-tribute/blob/c0fd1ee1ff332fc35705ad3fa426f8b97b14518a/RustConfig#L1
    • [x] Heroku endpoint URL hardcoded to the client now needs to be updated to the Railway endpoint https://github.com/ErnWong/dango-tribute/blob/c0fd1ee1ff332fc35705ad3fa426f8b97b14518a/client/src/main.rs#L149
    • [x] Heroku endpoint URL hardcoded to the server also needs to be updated to the Railway endpoint https://github.com/ErnWong/dango-tribute/blob/456307efca075886a78797d412505b2ff36d0d2c/server/src/main.rs#L88

    To check:

    • [ ] Cross origin policies
    • [ ] SSL
    opened by ErnWong 30
  • Website doesn't load due to insecure WebSocket endpoint

    Website doesn't load due to insecure WebSocket endpoint

    macOS Monterey (12.5) Chrome Version 104.0.5112.101 (Official Build) (arm64)

    wasm.js:514 Mixed Content: The page at 'https://ernestwong.nz/dango-tribute/server/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://dango-daikazoku.herokuapp.com/host'. This request has been blocked; this endpoint must be available over WSS.
    
    wasm.js:357 panicked at 'called `Result::unwrap()` on an `Err` value: JsValue(SecurityError: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.
    Error: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.
    

    Seems to load fine on Chrome on Windows?

    opened by ErnWong 0
Owner
Ernest Wong
πŸ’» + 🎹 + πŸ”¨ + 🎼 = πŸ•΄
Ernest Wong
Click-once - A small tiny little binary to fix undesired mouse double clicks in Windows, written in Rust.

click-once A small tiny little binary to fix malfunctioning mouse double clicks in Windows, written in Rust. Minimal executable with little to no over

null 23 Dec 29, 2022
little brother of gnu-copypasta-maker To compile, use make.

UWU Maker little brother of gnu-copypasta-maker To compile, use make. To install, use sudo make install or if you are root make install To uninstall,

Ahmet Efe AKYAZI 1 Jan 12, 2022
A little command-line script written in Rust to interface with Discord webhooks.

Rust Discord Webhook Agent This is a little "script" I wrote for practice with Rust and asynchronous operations within Rust. Getting started Clone thi

David Chen 2 Sep 7, 2022
A scripting language that allows complex key remapping on Linux.

Map2 A scripting language that allows complex key remapping on Linux, written in Rust. All of the functionality related to interacting with graphical

Matt 99 Dec 6, 2022
Dynamic key remapper for X11 and Wayland

???????????? ⌨️ xremap is a key remapper for Linux. Unlike xmodmap, it supports app-specific remapping and Wayland. Concept Fast - Xremap is written i

Takashi Kokubun 643 Jan 8, 2023
69-key split mechanical keyboard (PCB, case, firmware)

ErgoNICE An open source 69-key column-staggered split mechanical keyboard with a rotary knob, extra connectors, a 3D printed case with "floating key"

null 12 Oct 1, 2022
General basic key-value structs for Key-Value based storages

General basic key-value structs for Key-Value based storages

Al Liu 0 Dec 3, 2022
Key-value cache RESP server with support for key expirations βŒ›

BADER-DB (بادِر) Key-value cache RESP server with support for key expirations βŒ› Supported Features β€’ Getting Started β€’ Basic Usage β€’ Cache Eviction β€’

Mahmoud Salem 7 Apr 21, 2023
Rust library for reading/writing numbers in big-endian and little-endian.

byteorder This crate provides convenience methods for encoding and decoding numbers in either big-endian or little-endian order. Dual-licensed under M

Andrew Gallant 811 Jan 1, 2023
hado-rshado β€” A little macro for writing haskell-like do expressions without too much ceremony

hado Monadic haskell-like expressions brought to rust via the hado! macro What? A little macro for writing haskell-like do expressions without too muc

Lucas David Traverso 44 Jul 31, 2022