This Week in Fyrox #3

Fyrox is a Rust game engine with lots of out-of-box game-ready features and a full-featured editor. Third week of November continues the work started two weeks ago - animation system rework and editor improvements. Another interesting topic is improved WebAssembly support and various bugfixes.

# Animation Improvements

animation editor

Animation system of the engine is getting more improvements over the time, making the release of 0.29 closer. The most of changes on this week were done in the editor side. Let's start from the animation editor, since it has the most changes. On the picture above at the bottom half of it you can see the animation editor in its current (far from finished) form. The list of tracks now groups tracks under respective nodes, which makes editing much more user-friendly. The toolbar now allows you to create a new animation, remove selected, pick one for editing, play/pause/stop current animation and set playback speed.

animation editor

Now let's switch to Animation Blending State Machine (ABSM) editor (a tool to mix multiple animation into one and transition between states). This tool is now fully functional, but since it is somewhat tightly coupled with the animation editor, you should wait until it is finished (if you're eager to try the new functionality). The major reason why you should wait is that animation editor is not capable to do animation import and retargetting yet. Animation importing is important if you have multiple animation sources (multiple files) for a single model and you need to put them into a single animation player so you can use the variety of animation in the ABSM editor. Also, there's still no way to duplicate animations so using multiple animations that backed into a single timeline is not possible yet.

Let's now look at the changes in the engine internals. The most significant change is that Animation resource was removed, it is not needed anymore because now animation is stored inside AnimationPlayer scene node. It is also possible to set animation name (as you can see on the first screenshot).

# Curve Editor Improvements

CurveEditor widget is a major part of animation editor that helps you to define complex laws of changing of any numeric value you want. On this week it has some significant quality-of-life improvements:

  • Non-uniform zoom - allows you to zoom differently on different axes. Default binding is mouse wheel - it changes the zoom uniformly as before. To zoom on X axis separately you need to hold Shift key while rotating the wheel, to zoom on Y axis - hold LeftCtrl. This feature is important for cases where you have major differences in values on different axes and you want to fit one axis while keep seeing the rest of the data.
  • View bounds restriction - allows you to set a particular rectangle to restrict view position in the editor. Its main usage is to restrict curve editing in the animation editor to right half-space with positive times (negative time have no meaning).
  • Zoom-to-fit functionality is now works as intended, the bug was causing incorrect view positioning and zoom calculation.

# Improved WebAssembly Support

Previously, WebAssembly builds suffered from tons of issues - starting from simple compile errors and ending with various runtime issues related to lack of blocking execution of async methods. Let's briefly highlight major issues that were fixed:

# Scene Loading

Lack of blocking execution of async methods was fixed in several ways. Scene loading is now done with AsyncSceneLoader which executes loading task differently depending on platform: on PC it just spawns a thread and loads scene there. On WebAssembly it spawns a micro-task using wasm_bindgen_futures and it handles loading for us. To get a scene from the loader you should use fetch_result method, just call it each frame (or with some other period) in your update loop. Here's a small code snippet that illustrates new approach to scene loading.

use std::path::Path;
use fyrox::event_loop::ControlFlow;
use fyrox::plugin::{Plugin, PluginContext};
use fyrox::scene::loader::AsyncSceneLoader;
use fyrox::utils::log::Log;

struct Game {
    loader: Option<AsyncSceneLoader>,
}

impl Game {
    // Step 1. Call this method once when you need to "kick off" scene loading.
    fn load_scene(&mut self, path: &Path, context: &mut PluginContext) {
        // Request asynchronous scene loading.
        self.loader = Some(AsyncSceneLoader::begin_loading(
            path.into(),
            context.serialization_context.clone(),
            context.resource_manager.clone(),
        ));
    }
    // Step 2. Call this method in your game loop to continuously check loading progress.
    fn check_loading_progress(&mut self, context: &mut PluginContext) {
        if let Some(loader) = self.loader.as_ref() {
            if let Some(result) = loader.fetch_result() {
                // Loading could end in either successfully loaded scene or some error.
                match result {
                    Ok(scene) => {
                        // Add the scene to the engine, so it will be included in engine processing pipeline.
                        context.scenes.add(scene);
                    }
                    Err(err) => Log::err(err),
                }
                // Discard the loader once it is finished its job.
                self.loader = None;
            }
        }
    }
}
impl Plugin for Game {
    fn update(&mut self, context: &mut PluginContext, _control_flow: &mut ControlFlow) {
        // Check whether the scene is loaded or not. While it is loading, we can show progress bar
        // or even loading screen with useful information.
        self.check_loading_progress(context)
    }
}

What's good about it is that scene loading is non-blocking, which means that you can show loading screen with some progress bar and tips while the scene is loading.

# Resource Awaiting

The next major problem was the fact that you should wait until all resources are loaded before you run scripts logic. Previously it was done by simple blocking execution and this was causing panic on WebAssembly. Now it is fixed, the engine now checks if all pending resources were loaded and only if they're loaded, starts (or continues) scripts update. This is not ideal solution, because some resources can be used later when they're loaded, but current solution forces the engine to wait until all resource are loaded.

# WebAssembly Executor

There's more good stuff in this release - fyrox-template (a simple tool that generates game project and script templates) is now able to generate separate version of executor for your game to create WebAssembly builds of your game almost effortlessly. Separate executor is needed because WebAssembly builds requires the crate to be lib type, while standard executor is bin. Also, WebAssembly executor adds custom panic hooks to print panic info when your game panics.

WebAssembly deployment is also now much easier - you need to run wasm-pack build --target web --release, bundle produced binaries with some JS, HTML and add your game data folder to it and you're pretty much ready for deployment.

# Other

VectorImage UI widget now supports two more primitives: Rectangle and RectangleFilled which can be used for some specific cases.

Previously it was impossible to set sound status via editor's Inspector due to missing property editor for the Status type, now it is fixed. Also, there was a chance, that at the moment of changing sound buffer of a sound source and setting a playback position the engine would panic, because of incorrect playback position. The reason why it might happen is that sound buffer was set after the playback position.

# What's next?

The editor lacks preview mode - it is a special state of the editor where you can see animations, effects, listen sound, etc. but do not take results of such preview into list of changes of your scene. Right now if you create an animation player, it will play the animation and the changes made with it will be written to the scene. Preview mode will allow you to return to state of the scene in which it was before activating the preview. Such isolation is very important to prevent preview changes to sneak in the final scene.

Animation editor itself still requires a lot of work - there's no dopesheet mode, no timeline, no record mode, etc. Finishing an MVP will take at least 3 weeks.

# Full List of Changes in Random Order

  • Ability to add and remove new animations in the animation editor.
  • Improvements for toolbar in the animation editor (tooltips, pictograms for buttons, new ui elements)
  • Rectangle + RectangleFilled primitives for VectorImage widget.
  • Group animation tracks under respective nodes in the animation editor.
  • Property editor for Machine type - shows Open ABSM Editor button.
  • Property inheritance improvements for AnimationPlayer and AnimationBlendingStateMachine scene nodes.
  • impl PartialEq for Machine and its parts.
  • Ensure to sync sound source's buffer before setting its playback position.
  • Added missing property for Status of sound sources.
  • Property editor for AnimationContainer - shows Open Animation Editor button.
  • Ability to set view bounds in the CurveEditor widget.
  • Use zoom-to-fit option in the animation editor when selecting a curve.
  • Fixed zoom-to-fit functionality in the CurveEditor widget.
  • Non-uniform zoom for CurveEditor widget.
  • Animation selector for animation editor's toolbar.
  • Non-blocking resource awaiting before executing scripts logic.
  • editor-wasm project for fyrox-template to build your games for WebAssembly effortlessly.
  • AsyncSceneLoader - universal asynchronous scene loader that works well on all supported platforms (including WebAssembly).
  • Animation resource was removed.
  • Property editor for Handle<Animation> type.
  • Animations imported from FBX files now have default name.
  • Ability to set name for animations.

# Support

If you want to support the development of the project, click one of the links below. Preferable way is to use Boosty (opens new window) - this way the money will be available for the development immediately. Alternatively you can can use Patreon (opens new window), but in this case the money will be on-hold for unknown period of time (details are here (opens new window)).

Also, you can help by fixing one of the "good first issues" (opens new window), adding a desired feature to the engine, or making a contribution to the book (opens new window)

Fyrox Engine 2019 - 2024