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 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.
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 - holdLeftCtrl
. 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 forVectorImage
widget.- Group animation tracks under respective nodes in the animation editor.
- Property editor for
Machine
type - showsOpen ABSM Editor
button. - Property inheritance improvements for
AnimationPlayer
andAnimationBlendingStateMachine
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
- showsOpen 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 theCurveEditor
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 forfyrox-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)