Tsar Game Engine
A Modern, Powerful, and Versatile C++ Game Engine
Welcome to Tsar, a modern, powerful, and versatile C++ game engine designed to bring your creative visions to life. While we recognize that we can't yet compete with giants like Unreal Engine or Unity, our goal is to combine the best aspects of these engines with unique innovations of our own—elements we believe are missing from the current landscape.
Tsar is built with the latest C++20 standards and leverages Vulkan 1.4 for high-performance rendering, among other cutting-edge technologies. Our aim is to create a tool that feels familiar to developers experienced with Unreal or Unity, allowing them to transition seamlessly while benefiting from a modern architecture that pushes the boundaries of what’s possible. Tsar aspires to be the Unreal Engine 2.0, reimagined with the latest advancements and built for the future.
Whether you're a beginner or an experienced developer, Tsar provides the tools and flexibility you need to create stunning games.
🚀 Features
- Modern C++20: Built with the latest C++20 standards, ensuring clean, efficient, and maintainable code.
- Vulkan 1.4 Rendering: High-performance graphics rendering using Vulkan, providing low-level access and control over the GPU.
- C++ Scripting: Custom scripting with a powerful reflection system using the RTTR library.
- Editor UI with ImGui: Intuitive and responsive user interface for the editor, powered by ImGui.
- Audio with miniaudio: High-quality, cross-platform audio playback and control with miniaudio.
- 2D Physics with Box2D: Fast, reliable, and highly accurate 2D physics simulations with Box2D.
- Cross-Platform (Windows for now, Linux support coming soon): Development on Windows with plans to extend support to Linux.
- YAML-based Serialization: Efficient and human-readable serialization using yaml-cpp.
- Logging with spdlog: High-performance, thread-safe logging using spdlog.
- Windowing with GLFW: Flexible and multi-platform windowing and input system.
🎮 Getting Started
Prerequisites
Before you begin, ensure you have the following installed:
- Vulkan: Required for rendering. Version 1.4 is recommended
- Visual Studio: Our main IDE for development. Visual Studio 22 is recommended
- Python: Required for build scripts and certain tools. Python 3.12+ is recommended
- PyYAML: Required for build scripts and certain tools.
- Git: For version control and cloning the repository.
Installation
-
Clone the Repository
git clone --recursive https://github.com/EmberEyeStudio/Tsar-Game-Engine
If you're an active developer, you may want to clone the dev branch directly:
git clone --recursive -b dev https://github.com/EmberEyeStudio/Tsar-Game-Engine
-
Generate Project Files
Execute the following script to install Tsar global variables:
scripts/Install.py
Execute the following script to generate the Visual Studio project files:
scripts/Gen-Projects.py
-
Open the Solution
OpenTsar.sln
in Visual Studio 2022. -
Build the Engine
Set the build configuration to Debug or Release and build the solution. -
Run the Editor
Once built, you can run the editor directly from Visual Studio.
🛠️ Usage
Tsar is designed to be intuitive and easy to use. You can start by creating a new project from the editor or open an existing one. The editor provides a visual interface for designing scenes, scripting behaviors, and configuring game settings.
For more detailed usage instructions, check out our Documentation.
We welcome contributions from the community! To get started, check out our Contributing Guidelines. Whether you're fixing bugs, improving documentation, or adding new features, your help is appreciated.
👥 Meet the Team
Our team is composed of talented and passionate individuals who bring their unique skills and perspectives to the development of Tsar.
-
Dzhan (Wizendraw)
Dzhan is an avid technologist with a deep love for audio engineering and physics. His creative problem-solving skills and attention to detail have made him an invaluable member of the Tsar team. -
Mustafa (CreatorInDeep)
Mustafa is a versatile developer with a passion for creating cutting-edge technology. His curiosity and drive for innovation push the boundaries of what's possible in game development. When he's not coding, Mustafa loves diving into complex systems and experimenting with new tools and languages.
We are a small but dedicated team, constantly working to improve Tsar and make it the best engine it can be. We believe in continuous learning and innovation, and we're excited to share our journey with the community.
Follow us on
Twitter |
Discord |
YouTube
Documentation based on Tsar 2025.08a
Overview
ECS (Entity Component System) is a data-oriented design which binds together everything in Tsar. It gives precise control over every game object and allows creating scalable systems thanks to its high-performance nature.
Each object in the game world is called Entity. An Entity can have multiple Components.
A Component is a structure holding some specific information like Image, Sound, Player Health etc. This information is processed by Systems to realise its intended functionality.
A System is essentialy a process which acts on the data for specific components. For example, the Physics system acts on all Entities with RigidbodyComponent by calculating their mass, velocity and then applying a change in TransformComponent based on results.
Quick Reference
Components Reference List
Built-in
Physics 2D
Colliders- Box Collider2D Component
- Circle Collider2D Component
- Capsule Collider2D Component
- Chain Collider2D Component
- Distance Joint2D Component
- Revolute Joint2D Component
- Prismatic Joint2D Component
- Weld Joint2D Component
- Motor Joint2D Component
- Wheel Joint2D Component
Audio
Entity
Entity is a object withint the Scene which can have components added to it.
It also has some built-in properties which cannot be removed, but you can modify their values.
ID
Unique ID is used to identify each Entity in the Scene.
You can get it using u64 GetID()
.
Name
Each Entity has a name for easier organization and management.
You can get the name of Entity using const char* GetName()
Layer
Every Entity is assigned to a Layer. Layers are organized in a Collision matrix which is used to specify if objects should interract with each other.
Currently this is used by Physics to determine which objects should collide and which not.
Tsar currently supports 31 layers (soon 64). First layer is "Default" and you cannot change that, which leaves you with 30 free layers.
You can find more information about layers here
-
u32 GetLayerID()
Returns ID of the layer the Entity is assigned to. -
void SetLayerID(u32 layerID)
Assign Entity to a layer using its ID -
string GetLayerName()
Get name of the layer the Entity is assigned to -
u32 LayerNameToID(const string& layerName)
Get layer ID using name -
string LayerIDToName(u32 layerID)
Get layer name using ID
Components
The purpose of ECS is to have freedom working with flexible behaviour matching your needs.
You can add, remove and update components using Entity.
-
bool HasComponent<T>()
Check if Entity has component of type T -
T GetComponent<T>()
Returns component of type T if it exists, if Entity doesn't have such component an empty/new is returned. -
T AddComponent<T>()
Adds component of type T and returns it. If component already exists it is returned instead. -
bool RemoveComponent<T>()
Tries to remove component of type T, returns true if removed and false if no remove was performed(Entity already didn't have such component). -
bool ChildHasComponent<T>()
Check if any child of Entity has component of type T. -
Entity FindEntityByName(const char* name)
Get Entity using its name, if Entity not found returned Entity will have ID=0. -
T* GetScript<T>()
Get class/script of type T
Transform Component
The Transform
class is a component in Tsar engine used to manage an object's position, rotation, and scale in 3D space.
Class Declaration
class Transform : public Component
This class inherits from the Component
class and adds functionality related to transformation in 3D space. It uses Reflexion library for reflection.
Public Methods
Translation
-
glm::vec3 GetTranslation()
Returns the current translation (position) of Entity as a
glm::vec3
in World space. -
void SetTranslation(const glm::vec3& translation)
Sets the Entity translation using the provided
glm::vec3
in World space. -
glm::vec3 GetLocalTranslation();
Returns the current translation (position) of Entity as a
glm::vec3
in Local space. That is relative to parent Entity, when there is no parent you get position in World space. -
void SetLocalTranslation(const glm::vec3& localTranslation);
Sets the Entity translation using the provided
glm::vec3
in Local space. That is relative to parent Entity, when there is no parent you set position in World space.
Rotation
-
glm::vec3 GetRotation()
Returns current rotation of the Entity as a
glm::vec3
angles in radians, World space. -
void SetRotation(const glm::vec3& rotation)
Sets the Entity rotation using the provided
glm::vec3
angles in radians, World space. -
glm::vec3 GetLocalRotation();
Returns current rotation of the Entity as a
glm::vec3
angles in radians, Local space. That is relative to parent Entity, when there is no parent you get rotation in World space. -
void SetLocalRotation(const glm::vec3& localRotation);
Sets the Entity rotation using the provided
glm::vec3
angles in radians, Local space. That is relative to parent Entity, when there is no parent you set rotation in World space.
Scale
-
glm::vec3 GetScale()
Returns the current scale of Entity as a
glm::vec3
in World space. -
void SetScale(const glm::vec3& scale)
Sets the Entity scale using the provided
glm::vec3
in World space. -
glm::vec3 GetLocalScale();
Returns the current scale of Entity as a
glm::vec3
. That is relative to parent Entity, when there is no parent you get scale in World space. -
void SetLocalScale(const glm::vec3& localScale);
Sets the Entity scale using the provided
glm::vec3
in Local space. That is relative to parent Entity, when there is no parent you set scale in World space.
Properties
The Transform
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the position, rotation, and scale of the object in a more intuitive manner:
-
glm::vec3 Translation
Position of Entity in World.- Get:
GetTranslation()
- Set:
SetTranslation()
- Get:
-
glm::vec3 LocalTranslation
Position or Offset of Entity relative to Parent. When parent is absent, position is relative to World.- Get:
GetLocalTranslation()
- Set:
SetLocalTranslation()
- Get:
-
glm::vec3 Rotation
Rotation of Entity in World. Angles in radians.- Get:
GetRotation()
- Set:
SetRotation()
- Get:
-
glm::vec3 LocalRotation
Rotation of Entity relative to Parent. When parent is absent, rotation is relative to World. Angles in radians- Get:
GetLocalRotation()
- Set:
SetLocalRotation()
- Get:
-
glm::vec3 Scale
Scale of Entity relative to World. Final scale is calculated by multiplying world and local scale. 1 is default.- Get:
GetScale()
- Set:
SetScale()
- Get:
-
glm::vec3 LocalScale
Scale of Entity relative to Parent. When there is no Parent, scale is relative to World. Final scale is calculated by multiplying world and local scale. 1 is default.- Get:
GetLocalScale()
- Set:
SetLocalScale()
- Get:
Scripting
Tsar uses C++ as scripting language to benefit from its unmatched speed and versatility as its the best OOP language.
Writing scripts is essential for creating immersive and complex games. All of your game logic will be modeled by your scripts.
For this reason our scripting interface is focused on simplicity.
Here's an example NPC logic script:
How to create a script
!!! Make sure you have a scripting project, if not generate it by executing this script:TsarEd\assets\scripts\GenProject.py
You should now have a default Sandbox solution
Using Editor
Soon to be supported!
Using Visual Studio
1. Navigate your source folder and create .hxx and .cxx files with desired name2. In the header file(.hxx) add your class following this pattern:
MyExampleClass.hxx
#include "ScriptEngine.hxx"
namespace TsarScript
{
TClass() // <-- this macro is used to register your class in Tsar
class MyExampleClass : public Entity//if you want your class to interract with Tsar
{
TFunc()// <-- this macro is used to allow access of your func to Tsar
void SomePrintFunc();
};
TClass()
class MyPlayer : public Entity
{
GENERATE_BODY()
private:
TFunc()
void Start();
TFunc()
void Update(float dt);
private:
Transform m_MyTransform; //every Entity has Transform
};
}
Change MyExampleClass with your script/class name, you can have as many classes you want in single header.
TClass() is used for Reflection so Tsar and your classes can work together.
3. In source file(.cxx) include your header and define your functions:
MyExampleClass.cxx
#include "MyExampleClass.hxx"
#include "scripting/Input.hxx" //for MyPlayer input
#include "scripting/Debug.hxx" //for MyClassExample
namespace TsarScript
{
void MyClassExample::SomePrintFunc()
{
Debug::LogInfo("something happened");
}
void MyPlayer::Start()
{
//Good practise is to get you components once at Start, if possible
m_MyTransform = GetComponent<Transform>();
}
void MyPlayer::Update(float dt)
{
if (Input::GetKeyPressed(KeyCode::T))
{
Debug::LogInfo(m_Entity.GetName());// Log Entity name
}
}
}
Adding Functions/Methods
There are two types of functions/methods: Reflective and Normal.Normal functions are your typical C++ methods, which Tsar knows nothing about.
void MyFunction(); // No engine context here
If you need your function to be seen by Tsar you should use Reflective functions/methods, which are declared with TFunc() before them like this:
TFunc()
void MyFunction(); // Can use engine functionality
If your function should access anything from Tsar, like components, scripts, assets you must define your function with TFunc().
If the function is purely C++ logic, you don’t need TFunc().
Adding Properties
Similar to functions, Properties can use reflection, but mainly for modification in Editor.For example, take this AudioSource component
TClass();
class DumbAI : public Entity
{
public:
AudioSource m_BigSwing; //Not seen in Editor
};
Written like that AudioSource cannot be assigned/referenced/modified from Editor, you can only get this component from code with GetComponent()
, if its assigned on the same Entity the script is assigned to.
If you want to expose the Property to Editor use TProperty() before declaration. This way you don't need to call GetComponent()
in code.
TClass();
class DumbAI : public Entity
{
public:
TProperty();
AudioSource m_BigSwing; //Modifiable in Editor
};
Physics Event Callbacks
There are two types of events: Enter and Exit.For 2D physics there are three conditions triggering each event: Collision, Hit and Sensor
- Collision Event is when two shapes on differnet rigidbodies start/stop touching each other. These shapes must not be sensors.
- Hit Event is when two shapes on different bodies collide with velocity/speed above specified threshold. Hit Event requires collision events to be enabled/working.
- Sensor Event is when two shapes on different bodies, one of which is sensor (hollow. not solid) overlap. Sensor shapes don't provide collision so they overlap with other shapes.
Implementing callbacks is easy, first you have to declare it in .hxx file
TFunc()
void OnSensorEnter2D(CollisionData& data);
TFunc()
void OnSensorExit2D(CollisionData& data);
Then you can write your implementation logic in .cxx file. Below is partial example of jump logic which when Player sensor overlaps(Enter Event) with Ground(which is not sensor), the Player becomes 'grounded' and when Player is no longer overlapping(Exit Event) with Ground, Player is 'ungrounded'.
void Player::OnSensorEnter2D(CollisionData& data)
{
if(data.CollidedEntity.GetLayerName() == "Ground")
m_Grounded = true;
}
void Player::OnSensorExit2D(CollisionData& data)
{
if(data.CollidedEntity.GetLayerName() == "Ground")
m_Grounded = false;
}
Audio System
Tsar’s audio is built using miniaudio and currently features include full 3D spatial sound, real-time mixing and effects.
Read these sections to learn about audio in Tsar, including:
Audio Listener
The audio listener is an interface which allows control over handful of features such as:
Master Volume Control
Volume in Tsar is percent based, which means you can set it between 0(mute) and 1(Full volume).
You can set master volume in script using:
AudioListener listener = GetComponent<AudioListener>();
listener.SetVolume(0.8f); //Set master volume to 80%
There is only one listener per Scene!
3D Spatial Sound
Spatialization is based on both Listener and Audio Sources position and direction, for Listener it can be enabled/disabled using:
AudioListener listener = GetComponent<AudioListener>();
listener.EnableSpatialization(true);
You can switch between manual and automatic update of listener position & orientation.
By default they're updated automatically.
AudioListener listener = GetComponent<AudioListener>();
listener.EnableAutomaticUpdate(true);
If you disabled automatic update, you can update them manually:
AudioListener listener = GetComponent<AudioListener>();
listener.SetPosition({10.f, 10.f, 5.f}); //x=10, y=10, z=5
listener.SetDirection({1.f, 0.f, 0.f}); //facing Right along X, use normalized vector
Audio Playback
Tsar currently supports wav and mp3 audio files, also refered as audio clips.
In Editor, for now, you can only Preview the clip in Audio Source without Pause, Resume, or any applied effects.
Applying effects works during Runtime.
Audio Source Component
Each audio source is a node on a graph inside an Audio Engine. You can connect them however you like and apply different effects
Usage
Initialize
Add component AudioSourceComponent to your entity
Click 'Find' button and navigate to desired audio clip
Audio Clip
To have actual sound it needs an Audio Clip. You can assign one by Drag-n-Drop from Content Browser.
An audio clip is audio file stored on disk/drive. This is your typical sound effect or music.
Tsar currently supports WAV and MP3 file formats.
Audio clip is the source of sound which is "fed" to Audio Source, which then does some processing with it.
You can imagine Audio Clip to be a book and Audio Source to be a reader.
To improve performance Audio Clip has loading flags specified in Audio Source Component.
IsLoadedAsync
- TRUE : Load audio in background without blocking, loading returns immediatly and you can call Play() right away, but sound will be heard after something is loaded.
- FALSE : Load audio before doing anything else, loading blocks until whole clip is loaded.
IsAudioStreamed
- TRUE : Load small chunk of audio(2 seconds by default), when new data is required, load again. This is useful for music(long audio) or if you don't know the length of what you process(like audio over internet).
- FALSE : Load whole clip into memory, this is preferred for smaller files, like SFX.
Audio Clip is loaded only once unless you change the clip during Runtime or Audio Source has IsAudioStreamed=true
.
MaxSounds
How much simultanous sounds can be played from same source. To reduce memory usage, this is a mechanism for managing SFX on low level, by limiting independant buffers, otherwise you have to wait the sound to reach end or rewind it back to start.
Volume
void SetVolume(float volume, bool IsVolumeInDecibels = true)
AudioSource src = GetComponent<AudioSource>();
src.SetVolume(10.0f); //Set volume of sound to 10 decibels
src.SetVolume(100.0f, false); //Set linear volume of sound to 20 decibels.
//See linear to db conversion
void IncreaseVolume(float volumePercentIncrease, bool IsVolumeInDecibels = true)
AudioSource src = GetComponent<AudioSource>();
src.IncreaseVolume(10.0f); //Increase current volume by 10% in decibels 10db->11db
src.IncreaseVolume(10.0f, false); //Increase current volume by 10 decibels.
//Doesn't scale linearly, see linear to db conversion
void DecreaseVolume(float volumePercentDecrease, bool IsVolumeInDecibels = true)
AudioSource src = GetComponent<AudioSource>();
src.DecreaseVolume(30.0f); //Reduce current volume by 30% 10db->7db
src.DecreaseVolume(100.0f, false); //Reduce current volume by 20db
Audio Source State
Audio Source has two states: Playing and Paused
Sounds also have cursor which shows the position at which we play the sound. Sound output always moves the cursor forwards.
Cursor position is always relative to start of the Audio Clip.
During Play the sound is producing output at its attached endpoint on the graph, if sound hasn't been attached manualy, it is directly producing output to Playback device through Audio Listener.
When sound enters Pause state its cursor is saved, so it can be seamlessly resumed later.
Below are methods which allow changing between the two states as well as modifying the cursor.
1000 miliseconds = 1 second
void Play()
Description
Play the sound from the beginning. Shift cursor at 0 and start output/playing.
Example:
AudioSource src = GetComponent<AudioSource>();
src.Play();
void PlayAt(u64 milisecondsFromStart)
Description
Set how many miliseconds from beginning to shift the cursor and start playing from there.
Example:
AudioSource src = GetComponent<AudioSource>();
src.PlayAt(1000); //Go to 1 second and start playing
src.PlayAt(3500); //Go to 3.5 second of clip and play sound
void RewindTo(u64 milisecondsFromStart, bool autoResume /*= true */)
Description
Similar to PlayAt(), but allows control over whether to start playing audio or simply move cursor.
Example:
AudioSource src = GetComponent<AudioSource>();
src.RewindTo(2500); //Resume playing back(or forward) to second 2.5 of the audio clip.
//Move cursor to second 2.5
Example:
AudioSource src = GetComponent<AudioSource>();
src.RewindTo(3000, false); //Stop audio output. Cursor is at second 3.
//After starting the sound again, it will play from second 3.
void RewindToSeconds(float secondsFromStart, bool autoResume /*= true */)
Description
Set how many seconds from beginning to shift the cursor and depending on autoResume
- true => start playing from there (default).
- false => stop playing sound.
Example:
AudioSource src = GetComponent<AudioSource>();
src.RewindToSeconds(5.0f, false); //Stop output and move cursor to second 5
src.RewindToSeconds(4.0f); //Move cursor to second 4 and start output/play sound
void Stop()
Description
Stop audio output immediatly. Switches to Pause state.
Example:
AudioSource src = GetComponent<AudioSource>();
src.Stop();
void PauseAfter(u64 pauseTimeInMiliseconds /* = 0u */)
Description
Set time in miliseconds after which the sound should Pause
Example:
AudioSource src = GetComponent<AudioSource>();
src.PauseAfter(1500); //Continue playing for 1.5 seconds and then stop
void PauseAfterSeconds(float pauseTimeInSeconds /* = 0.0f */)
Description
Set time in seconds after which the sound should Pause
Example:
AudioSource src = GetComponent<AudioSource>();
src.PauseAfterSeconds(6.3f); //Continue playing for 6.3 seconds and then stop
void PauseFor(u64 pauseTimeInMiliseconds /* = 0u */)
Description
Set time in miliseconds for which the sound should be Paused, after this time passes, sound starts playing again.
Example:
AudioSource src = GetComponent<AudioSource>();
src.PauseFor(2000); //Immediately pause the sound for 2 seconds,
//after 2 seconds playing resumes
void PauseForSeconds(float pauseTimeInSeconds /* = 0.0f */)
Description
Set time in miliseconds for which the sound should be Paused, after this time passes, sound starts playing again.
Example:
AudioSource src = GetComponent<AudioSource>();
src.PauseForSeconds(4.0f); //Immediately pause the sound for 4 seconds,
//after 4 seconds playing resumes
Audio Source Effects
Audio Source supports these effects:
Pitch
Pitch makes a melody go higher or lower. Below are methods which can be used to change the pitch.
void SetPitch(float pitch)
Description
Set the pitch by multiplying the current with given value.
resultPitch = currentPitch * pitch.
- ! pitch must be higher than 0
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetPitch(1.5f); //Increase current pitch by 50%
src.SetPitch(0.4f); //Set pitch 40% of current(60% reduction)
void IncreasePitch(float increasePercentage)
Description
Increase pitch by given percentage.
Example:
AudioSource src = GetComponent<AudioSource>();
src.IncreasePitch(15.0f); //Increase current pitch by 15%
void DecreasePitch(float decreasePercentage)
Description
Decrease pitch by given percentage.
Example:
AudioSource src = GetComponent<AudioSource>();
src.DecreasePitch(25.0f); //Reduce current pitch by 25%
Doppler
The Doppler effect (also Doppler shift) is the change in the frequency of a wave in relation to an observer who is moving relative to the source of the wave. For example when a sportbike passes you by, you hear its 'pitch' change depending on its speed and distance. Wikipedia
In the animation below you can observe how moving source closer to listener increases sound frequency and moving away decreases it. The rings represent sound waves.

Animation Source: https://web2.ph.utexas.edu/~coker2/index.files/doppler_effect.gif
void SetDopplerFactor(float dopplerFactor)
Description
Factor greater than 1 increases the effect and is suited for fast moving objects, factor less than 1 reduces the strength of the effect and better suited for slower objects.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetDopplerFactor(1.0f); //Realistic Doppler effect based on physical laws
src.SetDopplerFactor(1.5f); //Exaggerated effect, making pitch shift more pronounced
src.SetDopplerFactor(0.5f); //Reduces the Doppler shift, making it more subtle
Spatialization
As in real world, the sound gets attenuated when you go away from the source, this is achieved by setting the attenuation model, distance, gain and the cone of both AudioSource and AudioListener.
Attenuation Models
AttenuationType::None
- No distance attenuation and no spatializationAttenuationType::Reverse
- Volume increases with distanceAttenuationType::Linear
- Linear decrease in volume, reaches zero at maxDistanceAttenuationType::Exponential
- Exponential decrease in volume, steeper falloff
void SetAttenuationModel(AttenuationType model)
Description
Change the attentuation type of AudioSource. What each model does is described above.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetAttenuationModel(AttenuationType::None);
src.SetAttenuationModel(AttenuationType::Reverse);
src.SetAttenuationModel(AttenuationType::Linear);
src.SetAttenuationModel(AttenuationType::Exponential);
Attenuation Distance
In the calculation of attenuation, you can control the minimum and maximum distances for the attenuation calculation.
This is useful if you want to ensure sounds don't drop below a certain volume after the listener moves further away and
to have sounds play a maximum volume when the listener is within a certain distance.
minDistance defines distance from listener at which the sound is heard at full volume(or maxGain).
maxDistance defines distance from listener at which sound gets attenuated until fading out completely(or minGain).
minDistance maxDistance ↓ ↓ Distance ----------------------------------------------------------------------------------> Volume: |Full volume or maxGain | volume fades with distance | no volume or minGain
|gain transition based on model|
void SetAttenuationDistance(float minDistance, float maxDistance)
Description
Set min and max distance for attenuation.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetAttenuationDistance(10.0f, 50.0f); //Full volume(maxGain) within 10 meters,
//after 50 meters fades to minGain. Transition gain based on model for 10 to 50
void SetAttenuationDistanceMin(float minDistance)
Description
Set distance(between listener and source) after which attenuation is applied.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetAttenuationDistanceMin(15.0f); //When listener is within 15 meters the sound
// volume=maxGain(full volume by default), after that the sound start to fade out
void SetAttenuationDistanceMax(float maxDistance)
Description
Set max distance(between listener and source) in meters, after which, the sound fades out to minGain(no volume by default)
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetAttenuationDistanceMax(30.0f); //If distance to listener is >30 meters,
//sound is faded to minGain
Rolloff
To control how quickly a sound rolls off as it moves away from the listener, you need to configure the rolloff.
The distance is specified in Attenuation Distance.
By default realistic rolloff in air is used. Sound is attenuated in air at -6dB per doubling of distance.
void SetRolloff(float rolloff)
Description
Multiply the current rolloff factor for fading of the sound in attenuation calculation.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetRolloff(2.0f); //The sound attenuates more quickly(twice as fast),
//meaning it will become quieter over a shorter distance
src.SetRolloff(0.5f); //The sound attenuates slowly(two times slower),
//meaning it will become quieter over a longer distance
Gain
The gain is the volume level that the sound can reach when applying distance attenuation or other gain-related effects.
gain = 0
→ Mute
gain = 1
→ Full volume
gain > 1
→ Amplification. Using very high gain values (significantly above 1.0) can lead to clipping, if the resulting amplitude exceeds the maximum range of the audio format
void SetGain(float minGain, float maxGain)
Description
Set minimal gain for when source is outside of hearing range and max gain for when source is heard without attenuation.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetGain(0.1f, 0.8f); //Limit sound volume between 10% & 80%
void SetGainMin(float minGain)
Description
Set min gain level for when sound is out of hearing range.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetGainMin(0.2f); //Constraints to minimal volume reduction of 20%.
//For example if audio is 10db, it cannot be reduced less than 2db
void SetGainMax(float maxGain)
Description
Set max gain level for when sound should be heard clearly without attenuation.
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetGainMax(0.8f); //Constraints to maximal volume amplification of 80%.
//For example if audio is 10db, it cannot be amplified more than 8db.
Cone
The sound propagation is defined with a cone.
When the listener is inside the sound cone's inner angle (facing directly in front of the sound source), they hear the sound at full volume
If the listener is between the inner and outer angles, the sound transitions from full volume(1.0) to attenuated volume(outer gain) smoothly.
When the listener is outside the outer angle (to the sides or behind the sound source), the sound is attenuated (reduced) based on the outer gain.
See Direction ! todo
Inner Cone Transition Zone Outer Cone Full Volume Gradual Attenuation Attenuated Volume /|\ /|\ /|\ | | | -------|-------------------|-----------------|----------- 0° | Inner Angle | Outer Angle | SILENCED AUDIO IS HERE
The stick figures show what the listener would hear depending on its position relative to sound direction. Note that Listener also has such cone to define its hearing angles as well.
void SetConeF(float innerAngleInRadians, float outerAngleInRadians, float outerGain)
Description
Example:
AudioSource src = GetComponent<AudioSource>();
src.SetConeF(glm::radians(30.0f), glm::radians(120.0f), 0.4f);
//Set sound to be attenuated to 40% of full volume if angle between listener and
// sound is greater than 120 degrees
void SetCone(const glm::vec3& innerOuterGain)
Description
Convenience function, works same as SetConeF();
X : innerAngle(radians)
Y : outerAngle(radians)
Z : outerGain([0;1])
Example:
src.SetCone(glm::vec3{glm::radians(50.0f), glm::radians(140.0f), 0.2f});
// |100% volume| |transition| |20% volume
// 0°| |50°| |140°|
Audio Settings
The audio settings are global settings and are subject to change in near future with plans of adding new features.
Playback Device
You can choose which device will output sound.
(Currently Windows only) when your selected device state changes and is unable to play sound(disconnected, disabled, changed), the output device automatically switches to your Default Playback Device on your OS.
Editor Settings
To be added:
- Volume
Runtime Settings
To be added
- Master Volume
- Mixer settings
- Streamed audio chunk size(in seconds)
Physics2D System
Tsar uses Box2D v3.1 for simulating physics in 2D.
Read this section to learn about how to simulate 2D physics in Tsar, including:
Simulation
Tsar uses Box2D for simulating 2D physics so the usage is based on the way Box2D works.
Box2D has active community and you can read in more detail about it: Box2D website and also join the Discord server
The simulation process involves multiple phases and its optimized for parallel execution...
Broad Phase
Narrow Phase
Solver
World Settings
World settings are configured in Tsar Editor by opening window Settings->Physics2D
HitEventThreshold
Velocity above which a hit event is registered, usually in meters per second.
ThreadCount
Number of threads which compute simulation. Avoid changing during runtime.
Rigidbody2D Component
The Rigidbody2D
class is a component in Tsar engine used for simulating an object's position and rotation in 2D space based on its mass, drag and gravity.
Class Declaration
class Rigidbody2D : public Component
This class inherits from the Component
class and adds functionality related to body properties required for physics simulation.
Public Methods
float GetRotationalInertia()
Get angular inertia of body relative to Z axis.
glm::vec2 GetPointInWorld(const glm::vec2& pointLocal)
Get position of a point in world relative to body origin.
glm::vec2 GetPointLocal(const glm::vec2& pointInWorld)
Get position of a point relative to body origin from world coordinates/position.
glm::vec2 GetVectorLocal(const glm::vec2& worldVector)
Get vector/direction relative to body from world vector.
glm::vec2 GetVectorWorld(const glm::vec2& localVector)
Get world vector/direction from local body vector.
glm::vec2 GetPosition()
Get world position of body.
void SetPosition(const glm::vec2& posInWorld)
Set world position of body. This acts as teleport and is fairly expensive
float GetRotation()
Get rotation of body along Z axis, in degrees
float GetRotationRad()
Get rotation of body along Z axis, in radians
void SetRotation(float rotationDegrees)
Set rotation of body along Z axis, in degrees. This acts as teleport and is fairly expensive
glm::vec2 GetCenterOfMassLocal()
Get center of mass relative to origin/local offset.
glm::vec2 GetCenterOfMassWorld()
Get center of mass in world coordinates.
void ApplyLinearImpulse(const glm::vec2& impulse, const glm::vec2& point, bool wake = true)
Apply impulse, this changes velocity of body immediately.
This should be used for one-shot impulses. If you need a steady force, use a force instead, which will work better with the sub-stepping solver.
The impulse is ignored if the body is not awake.
- impulse - direction in world space where impulse is applied. Horizontal(X) and vertical(Y) forces are in Newton-seconds or kg*m/s. If we apply impulse of {0.0, 2.0f} to body with mass 1kg it will start moving upward with addidtional velocity of 2m/s.
- point - point in world where the force/impulse is to be applied, if not at center of body/mass this will produce angular velocity.
- wake - should the body be awaken, default is true.
void ApplyLinearImpulseToCenter(const glm::vec2& impulse, bool wake = true)
Apply impulse at center of mass, this immediately changes linear velocity of body.
This should be used for one-shot impulses. If you need a steady force, use a force instead, which will work better with the sub-stepping solver.
The impulse is ignored if the body is not awake.
- impulse - direction in world space where impulse is applied. Horizontal(X) and vertical(Y) forces are in Newton-seconds or kg*m/s. If we apply impulse of {2.0, 2.0f} to body with mass 1kg it will start moving upward and right with addidtional velocity of 2m/s horizontaly and verticaly, or diagonally 2√2m/s.
- wake - should the body be awaken, default is true.
void ApplyForce(const glm::vec2& force, const glm::vec2& point, bool wake = true)
Apply force at world point, this changes linear velocity of body over time.
The force is ignored if the body is not awake.
- force - The world force vector, usually in newtons (N).
- point - The world position of the point of application, If the force is not applied at the center of mass, it will generate a torque and affect the angular velocity.
- wake - Option to wake up the body.
void ApplyForceToCenter(const glm::vec2& force, bool wake = true)
Apply force at body center of mass, this changes linear velocity of body over time.
The force is ignored if the body is not awake.
- force - The world force vector, usually in newtons (N).
- wake - Option to wake up the body.
void ApplyTorque(float torque, bool wake = true)
Apply torque at body center of mass, this changes angular velocity of body over time without affecting linear velocity.
The torque is ignored if the body is not awake.
- torque - Torque along Z-axis, usually in N*m.
- wake - Option to wake up the body.
void ApplyAngularImpulse(float impulse, bool wake = true)
Apply torque at body center of mass, this changes angular velocity of body immediately without affecting linear velocity.
This should be used for one-shot impulses. If you need a steady force, use a force instead, which will work better with the sub-stepping solver.
The torque is ignored if the body is not awake.
- impulse - the angular impulse, usually in units of kgmm/s
- wake - Option to wake up the body.
Properties
The Rigidbody2D
class exposes properties (that can also be accessed via getter and setter functions). This allows users to manipulate all properties of rigid body in a more intuitive manner:
RigidBody2DType Type
: static, dynamic, kinematic
- Get:
GetBodyType()
- Set:
SetBodyType(RigidBody2DType type)
Note that this is to be used when creating a body during runtime (once, right after creation), changing the body type during runtime is bad design choice(doesn't work).
bool IsFixedRotation
Is rotation along Z axis changed by simulation?
- Get:
GetFixedRotation()
- Set:
SetFixedRotation(bool fixedRotation)
glm::vec2 Velocity
Linear velocity(speed) of body in m/s.
- Get:
GetLinearVelocity()
- Set:
SetLinearVelocity(const glm::vec2& velocity)
float LinearDamping
How much the body resist moving, normally in range [0; 1]. 0 meaning no resistance(floaty like in space), 1 meaning rapid slow down(like in honey or glue).
- Get:
GetLinearDamping()
- Set:
SetLinearDamping(float linearDamping)
float Mass
Mass of body, in kilograms by default.
- Get:
GetMass()
- Set:
SetMass(float mass)
Should be positive number, avoid close to zero or negative!
float AngularVelocity
Speed at which the body is rotating in radians per second or half rotations per second(1rad=180deg).
- Get:
GetAngularVelocity()
- Set:
SetAngularVelocity()
float AngularDamping
Resistance of body to rotation, normally in range [0; 1]. 0 meaning no resistance, 1 meaning quick rotation slow down over time.
- Get:
GetAngularDamping()
- Set:
SetAngularDamping()
float GravityScale
Multiplier for affection by gravity, default is 1.0. 0.0 means body is not affected by gravity, 2.0 means two times stronger gravity.
- Get:
GetGravityScale()
- Set:
SetGravityScale()
float SleepThreshold
Velocity below which the body is put to sleep to improve performance.
- Get:
GetSleepThreshold()
- Set:
SetSleepThreashold()
bool Bullet
Bullet is used for more precise calculations, mainly to avoid tunneling at high speeds. Use for fast moving objects as its slightly more expensive.
- Get:
IsBullet()
- Set:
SetBullet()
bool Sleep
Enable/Disable sleeping. Sleeping improves performance when body is not moving.
- Get:
IsSleepingEnabled()
- Set:
EnableSleep()
bool Awake
Is body being simulated/awake?.
- Get:
IsAwake()
- Set:
SetIsAwake()
bool SensorEvents
Sensor events are triggered when overlap happens. Sensor shapes are like hollow detectors as they don't have collisions. Enter and Exit are up to you to implement, see events in scripting
- Get:
IsSensorEventsEnabled()
- Set:
EnableSensorEvents()
bool CollisionEvents
Collision events are triggered when two shapes begin touching. Enter and Exit callbacks are up to you to implement, see events in scripting
- Get:
IsCollisionEventsEnabled()
- Set:
EnableCollisionEvents()
bool HitEvents
Hit events are triggered when collision happens with speed/velocity higher than HitEventThreshold. Hit events require collision events to be enabled. Enter and Exit are up to you to implement, see Scripting-Events
- Get:
IsSensorEventsEnabled()
- Set:
EnableSensorEvents()
Colliders 2D
In Box2D there are two types of colliders: solid and sensor.
- Solid -> default collider which provides collision and other bodies with solid colliders cannot pass through it.
IsSensor
should befalse
. - Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it.
IsSensor
should betrue
.
In the image below you can see how the CircleCollider2D on blue NPC(on right) and CapsuleCollider2D on Player(left) have IsSensor=true
so they overlap with other shapes, unlike the BoxCollider2D on the Player and small CapsuleCollider2D on the NPC which are IsSensor=false
and they prevent them from falling from the horizontal rectangle which is BoxCollider2D with IsSensor=false
.

You can also set more precisely collider behaviour using Collision Matrix from Layer System
soon example will be added
Box Collider2D Component
The BoxCollider2D
class is a component in Tsar engine used to define a box outline to a 2D rigidbody.
Below is an image showing different size rectangles using current Debug rendering inside Tsar. You can change collider color in Editor from Settings->Physics2D->Gizmo.

Class Declaration
class BoxCollider2D : public Component
This class inherits from the Component
class and adds functionality related to defining shape outline of a Rigidbody for simulating 2D physics.
Public Methods
Size
Size is the width(X) and height(Y) of glm::vec2. BoxCollider2D stores these values in meters and when a collider is created the scale from Transform is normally applied.
glm::vec2 GetSize(bool applyTransformScale = true)
Returns the size of collider from compoennt. Width(X) and Height(Y).
- applyTransformScale - should the returned size from component have applied scale, default is true.
void SetSize(const glm::vec2& size, bool applyTransformScale = true)
Change size of shape. May have overhead if not called right after initialization/construction.
- size - Units of width(X) and height(Y), sets component data regardless of applyTransform.
- applyTransform - true(applies scale), false(uses collider size only).
Offset
Offset is the local offset (relative to entity itself) that can be used to precisely adjust collider position on the body.
glm::vec3 Offset
uses X and Y for physics and Z is used only for Debug Rendering.
float OffsetRot
is local angle offset along Z-axis in degrees. Final rotation is: Rotation Z from Transform + OffsetRot
glm::vec3 GetOffset()
Returns shape local offset.
void SetOffset(const glm::vec3& offset)
Set local offset position of collider, X and Y matter for physics.
float GetOffsetRot()
Returns angle offset along Z-axis in degrees.
void SetOffsetRot(float offsetRot)
Set local angle offset of collider along Z-axis in degrees.
Properties
The BoxCollider2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the shape properties of the object in a more intuitive manner:
float Density
Density of the shape, in kg/m².
- Get:
GetDensity()
- Set:
SetDensity(float density, bool updateMass = true)
- density - desired density in kg/m².
- updateMass - should the body mass data be updated with this shape?
float Restitution
From Physics Material. Energy conservation coefficient. 1 means perfect bounce with no energy loss, 0 means perfect absorbtion with no bounce.
- Get:
GetRestitution()
- Set:
SetRestitution(float restitution)
- restitution - should be value between [0; 1].
float Friction
From Physics Material. Friction coefficient, 0 means no friction(slippery, like ice), 1 means high friction(grippy, like rubber), values >1 are allowed.
- Get:
GetFriction()
- Set:
SetFriction(float friction)
- friction - should be non-negative value.
bool IsSensor
Is the shape sensor or not(solid)? true means no collision, false means solid collider providing collision.
Default is false.
- Get:
GetIsSensor()
- Set:
SetIsSensor(bool isTrigger)
- isTrigger - true makes shape like ghost/hollow detector, false makes shape solid.
bool EnableCollisionEvents
Should collision events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
. This itself doesn't affect collisions.
- Get:
GetEnableCollisionEvents()
- Set:
SetEnableCollisionEvents(bool enableCollisionEvents)
- enableCollisionEvents - true enables event registration, false disables event registration.
bool EnableHitEvents
Should hit events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
and EnableCollisionEvents=true
to work
- Get:
GetEnableHitEvents()
- Set:
SetEnableHitEvents(bool enableHitEvents)
- enableHitEvents - true enables event registration, false disables event registration.
bool EnableSensorEvents
Should sensor events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=true
. This itself doesn't affect collisions.
- Get:
GetEnableSensorEvents()
- Set:
SetEnableSensorEvents(bool enableSensorEvents)
- enableSensorEvents - true enables event registration, false disables event registration.
Circle Collider2D Component
The CircleCollider2D
class is a component in Tsar engine used to define a circle outline to a 2D rigidbody.
There are two types of colliders: solid and sensor.
- Solid -> default collider which provides collision and other bodies with solid colliders cannot pass through it.
IsSensor
should befalse
. - Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it.
IsSensor
should betrue
.
Below is an image showing CircleCollider2D component from Debug rendering inside Tsar. You can change collider color in Editor from Settings->Physics2D->Gizmo.

Class Declaration
class CircleCollider2D : public Component
This class inherits from the Component
class and adds functionality related to defining shape outline of a Rigidbody for simulating 2D physics.
Public Methods
Radius
CircleCollider2D stores the radius in meters and when a collider is created the X-scale from Transform is normally applied. Radius of 2.0 and X-scale of 3.0 will result in circle with radius of 6.0 and diameter of 12.0.
float GetRadius(bool applyTransformScale = true)
Returns the radius of collider from component.
- applyTransformScale - should the returned radius from component have applied scale, default is true.
void SetRadius(float radius, bool applyTransformScale = true)
Change radius of shape. May have overhead if not called right after initialization/construction.
- radius - Sets component data regardless of applyTransform.
- applyTransformScale - true(applies scale on X), false(uses collider size only).
Offset
Offset is the local offset (relative to entity itself) that can be used to precisely adjust collider position on the body.
glm::vec3 Offset
uses X and Y for physics and Z is used only for Debug Rendering.
float OffsetRot
is local angle offset along Z-axis in degrees. Final rotation is: Rotation Z from Transform + OffsetRot
glm::vec3 GetOffset()
Returns shape local offset.
void SetOffset(const glm::vec3& offset)
Set local offset position of collider, X and Y matter for physics.
float GetOffsetRot()
Returns angle offset along Z-axis in degrees.
void SetOffsetRot(float offsetRot)
Set local angle offset of collider along Z-axis in degrees.
Properties
The CircleCollider2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the shape properties of the object in a more intuitive manner:
float Density
Density of the shape, in kg/m².
- Get:
GetDensity()
- Set:
SetDensity(float density, bool updateMass = true)
- density - desired density in kg/m².
- updateMass - should the body mass data be updated with this shape?
float Restitution
From Physics Material. Energy conservation coefficient. 1 means perfect bounce with no energy loss, 0 means perfect absorbtion with no bounce.
- Get:
GetRestitution()
- Set:
SetRestitution(float restitution)
- restitution - should be value between [0; 1].
float Friction
From Physics Material. Friction coefficient, 0 means no friction(slippery, like ice), 1 means high friction(grippy, like rubber), values >1 are allowed.
- Get:
GetFriction()
- Set:
SetFriction(float friction)
- friction - should be non-negative value.
bool IsSensor
Is the shape sensor or not(solid)? true means no collision, false means solid collider providing collision.
Default is false.
- Get:
GetIsSensor()
- Set:
SetIsSensor(bool isTrigger)
- isTrigger - true makes shape like ghost/hollow detector, false makes shape solid.
bool EnableCollisionEvents
Should collision events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
. This itself doesn't affect collisions.
- Get:
GetEnableCollisionEvents()
- Set:
SetEnableCollisionEvents(bool enableCollisionEvents)
- enableCollisionEvents - true enables event registration, false disables event registration.
bool EnableHitEvents
Should hit events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
and EnableCollisionEvents=true
to work. This itself doesn't affect collisions.
- Get:
GetEnableHitEvents()
- Set:
SetEnableHitEvents(bool enableHitEvents)
- enableHitEvents - true enables event registration, false disables event registration.
bool EnableSensorEvents
Should sensor/overlap events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=true. This itself doesn't affect collisions.
- Get:
GetEnableSensorEvents()
- Set:
SetEnableSensorEvents(bool enableSensorEvents)
- enableSensorEvents - true enables event registration, false disables event registration.
Capsule Collider2D Component
The CapsuleCollider2D
class is a component in Tsar engine used to define a capsule outline to a 2D rigidbody.
There are two types of colliders: solid and sensor.
- Solid -> default collider which provides collision and other bodies with solid colliders cannot pass through it.
IsSensor
should befalse
. - Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it.
IsSensor
should betrue
.
Below is an image showing different size capsules using current Debug rendering inside Tsar. You can change collider color in Editor from Settings->Physics2D->Gizmo.
Note that if width of capsule is greater than its height, it becomes a circle with diameter = width.

Class Declaration
class CapsuleCollider2D : public Component
This class inherits from the Component
class and adds functionality related to defining shape outline of a Rigidbody for simulating 2D physics.
Public Methods
Size
Size is the width(X) and height(Y) of glm::vec2. CapsuleCollider2D stores these values in meters and when a collider is created, the scale from Transform is normally applied. If width becomes greater than height, the shape becomes circle with radius=width/2.
glm::vec2 GetSize(bool applyTransformScale = true)
Returns the size of collider from compoennt. Width(X) and Height(Y).
- applyTransformScale - should the returned size from component have applied scale, default is true.
void SetSize(const glm::vec2& size, bool applyTransformScale = true)
Change size of shape. May have overhead if not called right after initialization/construction.
- size - Units of width(X) and height(Y), sets component data regardless of applyTransform.
- applyTransform - true(applies scale), false(uses collider size only).
Offset
Offset is the local offset (relative to entity itself) that can be used to precisely adjust collider position on the body.
glm::vec3 Offset
uses X and Y for physics and Z is used only for Debug Rendering.
float OffsetRot
is local angle offset along Z-axis in degrees. Final rotation is: Rotation Z from Transform + OffsetRot
glm::vec3 GetOffset()
Returns shape local offset.
void SetOffset(const glm::vec3& offset)
Set local offset position of collider, X and Y matter for physics.
float GetOffsetRot()
Returns angle offset along Z-axis in degrees.
void SetOffsetRot(float offsetRot)
Set local angle offset of collider along Z-axis in degrees.
Properties
The CapsuleCollider2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the shape properties of the object in a more intuitive manner:
float Density
Density of the shape, in kg/m².
- Get:
GetDensity()
- Set:
SetDensity(float density, bool updateMass = true)
- density - desired density in kg/m².
- updateMass - should the body mass data be updated with this shape?
float Restitution
From Physics Material. Energy conservation coefficient. 1 means perfect bounce with no energy loss, 0 means perfect absorbtion with no bounce.
- Get:
GetRestitution()
- Set:
SetRestitution(float restitution)
- restitution - should be value between [0; 1].
float Friction
From Physics Material. Friction coefficient, 0 means no friction(slippery, like ice), 1 means high friction(grippy, like rubber), values >1 are allowed.
- Get:
GetFriction()
- Set:
SetFriction(float friction)
- friction - should be non-negative value.
bool IsSensor
Is the shape sensor or not(solid)? true means no collision, false means solid collider providing collision.
Default is false.
- Get:
GetIsSensor()
- Set:
SetIsSensor(bool isTrigger)
- isTrigger - true makes shape like ghost/hollow detector, false makes shape solid.
bool EnableCollisionEvents
Should collision events be registered from this shape and trigger Enter/Exit events in scripting.
*Requires IsSensor=false
. This itself doesn't affect collisions.
- Get:
GetEnableCollisionEvents()
- Set:
SetEnableCollisionEvents(bool enableCollisionEvents)
- enableCollisionEvents - true enables event registration, false disables event registration.
bool EnableHitEvents
Should hit events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
and EnableCollisionEvents=true
to work. This itself doesn't affect collisions.
- Get:
GetEnableHitEvents()
- Set:
SetEnableHitEvents(bool enableHitEvents)
- enableHitEvents - true enables event registration, false disables event registration.
bool EnableSensorEvents
Should sensor events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=true
. This itself doesn't affect collisions.
- Get:
GetEnableSensorEvents()
- Set:
SetEnableSensorEvents(bool enableSensorEvents)
- enableSensorEvents - true enables event registration, false disables event registration.
Chain Collider2D Component
The ChainCollider2D
class is a component in Tsar engine used to define a chain of lines to add outline to a 2D rigidbody.
There are two types of colliders: solid and sensor.
- Solid -> default collider which provides collision and other bodies with solid colliders cannot pass through it.
IsSensor
should befalse
. - Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it.
IsSensor
should betrue
.
Below is an image showing ChainCollider2D using current Debug rendering inside Tsar. You can change collider color in Editor from Settings->Physics2D->Gizmo.
Currently all lines share the same Physics Material.

Class Declaration
class ChainCollider2D : public Component
This class inherits from the Component
class and adds functionality related to defining shape outline of a Rigidbody for simulating 2D physics.
Properties
The ChainCollider2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the shape properties of the object in a more intuitive manner:
float Restitution
From Physics Material. Energy conservation coefficient. 1 means perfect bounce with no energy loss, 0 means perfect absorbtion with no bounce.
- Get:
GetRestitution()
- Set:
SetRestitution(float restitution)
- restitution - should be value between [0; 1].
float Friction
From Physics Material. Friction coefficient, 0 means no friction(slippery, like ice), 1 means high friction(grippy, like rubber), values >1 are allowed.
- Get:
GetFriction()
- Set:
SetFriction(float friction)
- friction - should be non-negative value.
bool IsSensor
Is the shape sensor or not(solid)? true means no collision, false means solid collider providing collision.
Default is false.
- Get:
GetIsSensor()
- Set:
SetIsSensor(bool isTrigger)
- isTrigger - true makes shape like ghost/hollow detector, false makes shape solid.
bool EnableCollisionEvents
Should collision events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
. This itself doesn't affect collisions.
- Get:
GetEnableCollisionEvents()
- Set:
SetEnableCollisionEvents(bool enableCollisionEvents)
- enableCollisionEvents - true enables event registration, false disables event registration.
bool EnableHitEvents
Should hit events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=false
and EnableCollisionEvents=true
to work. This itself doesn't affect collisions.
- Get:
GetEnableHitEvents()
- Set:
SetEnableHitEvents(bool enableHitEvents)
- enableHitEvents - true enables event registration, false disables event registration.
bool EnableSensorEvents
Should sensor events be registered from this shape and trigger Enter/Exit events in scripting.
Requires IsSensor=true
. This itself doesn't affect collisions.
- Get:
GetEnableSensorEvents()
- Set:
SetEnableSensorEvents(bool enableSensorEvents)
- enableSensorEvents - true enables event registration, false disables event registration.
Joints 2D
Joints are a link between two bodies which simulate realistic connection between them.
Currently supported joints are:
- Distance Joint - keeps distance/length between the constrained bodies a constant or allows for extension/compression.
- Revolute Joint - also known as hinge joint, pin a common rotation pivot for constrained bodies, useful for rotating blades, rope/chain segments etc.
- Prismatic Joint - restrict movement of two bodies to a specific axis, useful for platforms, pistons etc.
- Motor Joint - bodies try to match target position and rotation, can be used for yoyo, magnets, other returning objects etc.
- Weld Joint - simulate rigid/elastic connection between bodies, restricting relative movement between them, can be used for breakable objects, procedural construction, spring rider and others.
- Wheel Joint - simulate suspension which allows rotation of wheel, useful for making vehicles.
Distance Joint2D Component
The DistanceJoint2D
class is a component in Tsar engine used to define a joint connection between two Rigidbody2D.
The joint has to reference another Entity which has Rigidbody2D Component.
The distance joint maintains a constant length between two anchor points on two different rigid bodies.
Below is an animation showing elastic deformation of solid body, which is also how the joint would behave if EnableSpring=true
and EnableLimit=true
.

Animation Source: https://mm.ethz.ch/research-overview/computational-mechanics/microstructure-evolution.html
Otherwise it would be rigid and constant, for example like pendulum.
Animation Source: https://upload.wikimedia.org/wikipedia/commons/6/6f/Pendulum-no-text.gif
Class Declaration
class DistanceJoint2D : public Component
This class inherits from the Component
class and adds functionality related to defining a joint connection to another Rigidbody2D for simulating 2D physics.
Public Methods
Attach
bool AttachToBody(RigidBody2D& referenceBody)
Attach the joint to Entity which has the referenced Rigidbody2D. One joint component can only have one attached Rigidbody2D.
Attaching when existing joint is present will destroy the old one.
Requires valid Rigidbody2D on both entities.
- referenceBody - the Rigidbody2D component to which the joint will be attached.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool AttachToEntity(u64 entityID)
Attach joint directly using Entity. Requires valid Rigidbody2D on Entity.
- entityID - id of entity to which to attach joint connection.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool DetachFromBody()
Destroys the joint connection.
Returns:
- true if joint has been destroyed.
- false if no joint was destroyed.
Properties
The DistanceJoint2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the joint properties in a more intuitive manner:
glm::vec2 AnchorPos
Position of the anchor point on Rigidbody on same Entity which has the DistanceJoint2D.
This position is a local offset.
- Get:
glm::vec2 GetAnchorPos()
- Set:
SetAnchorPos(const glm::vec2& posLocal)
glm::vec2 ConnectedAnchorPos
Position of the anchor point on referenced Entity which has Rigidbody2D.
This position is a local offset for referenced Entity, not Entity with DistanceJoint2D.
- Get:
glm::vec2 GetConnectedAnchorPos()
- Set:
SetConnectedAnchorPos(const glm::vec2& posLocal)
bool EnableMotor
Enable/Disable motor. Motor changes the distance between the two bodies using speed(direction) and max force.
Works when IsSpringEnabled=true
.
- Get:
bool IsMotorEnabled()
- Set:
void EnableMotor(bool enable)
- enable - true enables motor, false disables motor.
bool EnableSpring
Enable/Disable spring. Spring allows for elastic change of distance between bodies using damping ratio and frequency.
If disabled then the distance joint will be rigid, overriding the limit and motor.
When disabled, frequency=0 and dampingRation=1.
- Get:
bool IsSpringEnabled()
- Set:
void EnableSpring(bool enable)
- enable - true enables spring, false disables spring.
bool EnableLimit
Enable/Disable limit. Limit allows for change of distance between bodies within a clamped range [MinDistance; MaxDistance].
The limit only works if IsSpringEnabled = true
.
When limit is disabled, distance between bodies is always constant.
- Get:
bool IsLimitEnabled()
- Set:
void EnableLimit(bool enable)
- enable - true enables limit, false disables limit.
float SpringFrequency
Frequency (or spring linear stiffness), in Hertz(HZ).
This lets you configure how quickly a spring reacts regardless of the body masses.
For better stability should usually be less than a quarter of the simulation rate. For example, if the simulation runs at 60Hz then the joint stiffness should be 15Hz or less.
- Get:
float GetSpringFrequencyHZ()
- Set:
void SetSpringFrequencyHZ(float freq)
- freq - should be non-negative value.
float SpringDampingRatio
Linear damping ratio of spring, lets you specify how quickly the spring will come to rest.
0 means no damping (energy loss) and 1 means full absorbtion (immediate energy loss).
- Get:
float GetSpringDampingRatio()
- Set:
void SetSpringDampingRatio(float ratio)
- ratio - value in range [0; 1].
float MaxDinstance
When IsLimitEnabled=true
, this specifies maximum distance possible between two bodies, in meters. Imagine this as maximum suspension travel.
- Get:
float GetMaxDistance()
- Set:
void SetMaxDistance(float maxDistance)
- maxDistance - maximum distance allowed between the two constrained bodies, in meters.
float MinDistance
When IsLimitEnabled=true
, this specifies how close the two bodies can go, in meters. Default is 0
- Get:
float GetMinDistance()
- Set:
void SetMinDistance(float minDistance)
- minDistance - must be less than MaxDistance and >=0.
float MotorSpeed
When IsMotor=true
and IsSpringEnabled=true
, this specifies the speed at which the joint pushes(positive value) or pulls(negative value) in meters per second.
This is the speed of contracting(negative value) or expanding(positive value) the length of the joint (distance between bodies).
- Get:
float GetMotorSpeed()
- Set:
void SetMotorSpeed(float motorSpeed)
- motorSpeed - meters per second.
float MaxMotorForce
When IsMotor=true
and IsSpringEnabled=true
, this specifies the maximum force the motor will apply to constrained body, in Newtons. Similar to spring stiffness, imagine this as the strength of the motor pulling or pushing. Note the mass of bodies for better tuning.
- Get:
float GetMaxMotorForce()
- Set:
void SetMaxMotorForce(float force)
- force - non-negative value in Newtons.
bool CollideWithOther
Should the colliders attached to both bodies collide with each other?
- Get:
bool GetCollideWithOther()
- Set:
void SetCollideWithOther(bool collide)
- collide - true makes bodies collide with each other, false disables collision between them.
Revolute Joint2D Component
The RevoluteJoint2D
class is a component in Tsar engine used to define a joint connection between two Rigidbody2D.
The joint has to reference another Entity which has Rigidbody2D Component.
The revolute joint connects two bodies at a point and allows rotation, like a hinge.
Can use motor and angle limits.
Joint Scheme
Image Source: https://box2d.org/documentation/md_simulation.html
Demonstration

Class Declaration
class RevoluteJoint2D : public Component
This class inherits from the Component
class and adds functionality related to defining a revolute joint connection to another Rigidbody2D for simulating 2D physics.
Public Methods
Attach
bool AttachToBody(RigidBody2D& referenceBody)
Attach the joint to Entity which has the referenced Rigidbody2D. One joint component can only have one attached Rigidbody2D.
Attaching when existing joint is present will destroy the old one.
Requires valid Rigidbody2D on both entities.
- referenceBody - the Rigidbody2D component to which the joint will be attached.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool AttachToEntity(u64 entityID)
Attach joint directly using Entity. Requires valid Rigidbody2D on Entity.
- entityID - id of entity to which to attach joint connection.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool DetachFromBody()
Destroys the joint connection.
Returns:
- true if joint has been destroyed.
- false if no joint was destroyed.
Properties
The RevoluteJoint2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the joint properties in a more intuitive manner:
glm::vec2 CommonAnchorPos
Position offset of the common anchor point on same Entity which has the RevoluteJoint2D.
- Get:
glm::vec2 GetCommonAnchorPos()
- Set:
SetCommonAnchorPos(const glm::vec2& posLocal)
float ReferenceAngle
The angle difference between BodyB and BodyA, in degrees, this defines the zero angle for the joint rotation limit.
By defailt it uses initial configuration, but if you want you can change it.
For example if you set it to 60 and you have LowerLimitAngle=40 and UpperLimitAngle=80, the joint in world angles will be limited between [60+40; 60+80] or [100; 140].
- Get:
float GetReferenceAngle()
- Set:
void SetReferenceAngle(float refAngle)
- refAngle - default is bodyB.AngleZ - bodyA.AngleZ.
bool CollideWithOther
Should the colliders attached to both bodies collide with each other?
- Get:
bool GetCollideWithOther()
- Set:
void SetCollideWithOther(bool collide)
- collide - true makes bodies collide with each other, false disables collision between them.
bool IsMotorEnabled
Enable/Disable motor. If you enable the motor, Box2D will apply torque to reach and maintain a given angular speed (MotorSpeed), up to a specified maximum torque (MaxMotorTorque).
Works in combination with IsSpringEnabled=true
and IsLimitEnabled=true
.
- Get:
bool IsMotorEnabled()
- Set:
void EnableMotor(bool enable)
- enable - true enables motor, false disables motor.
bool IsSpringEnabled
Enable/Disable spring. Spring acts on constrained Z-axis, as if bodies have a spring between them which you wind up.
Works in combination with IsLimitEnabled=true
and IsMotorEnabled=true
.
When disabled, frequency=0 and dampingRatio=1.
- Get:
bool IsSpringEnabled()
- Set:
void EnableSpring(bool enable)
- enable - true enables spring, false disables spring.
bool IsRotationLimitEnabled
Enable/Disable limit. Limits angle between bodies and common anchor within a clamped range [MinDistance; MaxDistance] which must contain zero (0.0f), otherwise limit is ignored.
Works well with IsSpringEnabled=true
and IsMotorEnabled=true
.
When limit is disabled, angle between bodies and anchor is not clamped (unless IsSpring=true
in which case the spring will try to keep bodies at initial angle when created).
- Get:
bool IsRotationLimitEnabled()
- Set:
void EnableRotationLimit(bool enable)
- enable - true enables rotation limit, false disables limit.
float SpringFrequency
If IsSpingEnabled = true
, this acts as spring trying to bring angle between two bodies relative to anchor at rest(initial angle when creating the joint or ReferenceAngle
).
Frequency (or spring angular stiffness) is in Hertz(HZ), cycles per second.
For better stability should usually be less than a quarter of the simulation rate. For example, if the simulation runs at 60Hz then the joint stiffness should be 15Hz or less.
- Get:
float GetSpringFrequencyHZ()
- Set:
void SetSpringFrequencyHZ(float freq)
- freq - should be non-negative value.
float SpringDampingRatio
Angular damping ratio of spring, non-dimensional.
0 means no damping (energy loss) and 1 means full absorbtion (immediate energy loss).
- Get:
float GetSpringDampingRatio()
- Set:
void SetSpringDampingRatio(float ratio)
- ratio - value in range [0; 1].
float UpperAngleLimit
When IsLimitEnabled=true
, this specifies maximum angle possible between two bodies, in degrees.
This angle is relative to ReferenceAngle
, which by default is BodyB.AngleZ - BodyA.AngleZ.
- Get:
float GetUpperAngleLimit()
- Set:
void SetUpperAngleLimit(float angleLimitDeg)
- angleLimitDeg - maximum angle allowed between the two constrained bodies, in degrees. Must be less than 171 degrees and greater than
LoweAngleLimit
.
- angleLimitDeg - maximum angle allowed between the two constrained bodies, in degrees. Must be less than 171 degrees and greater than
float LowerAngleLimit
When IsLimitEnabled=true
, this specifies minimum angle possible between two bodies, in degrees.
This angle is relative to ReferenceAngle
, which by default is BodyB.AngleZ - BodyA.AngleZ.
- Get:
float GetLowerAngleLimit()
- Set:
void SetLowerAngleLimit(float angleLimitDeg)
- angleLimitDeg - minimum angle allowed between the two constrained bodies, in degrees. Must be greater than -171 degrees and less than
UpperAngleLimit
.
- angleLimitDeg - minimum angle allowed between the two constrained bodies, in degrees. Must be greater than -171 degrees and less than
float MotorSpeed
When IsMotor=true
, this specifies the speed at which the joint rotates the dynamic body relative to the hinge (common anchor) point in radians per second.
This speed won't be reached if MaxTorque
is not strong enough.
Positive value rotates counter-clockwise, negative value rotates clockwise.
- Get:
float GetMotorSpeed()
- Set:
void SetMotorSpeed(float motorSpeed)
- motorSpeed - radians per second.
float MaxMotorTorque
When IsMotor=true
, this specifies the maximum torque (angular force) the motor will apply to constrained bodies, in Newton-meters.
Note the mass of bodies for better tuning.
- Get:
float GetMaxMotorTorque()
- Set:
void SetMaxMotorTorque(float torque)
- torque - non-negative value in Newton-meters.
Prismatic Joint2D Component
The PrismaticJoint2D
class is a component in Tsar engine used to define a joint connection between two Rigidbody2D.
The joint has to reference another Entity which has Rigidbody2D Component.
The prismatic joint limits translation (relative movement) between two bodies on a fixed axis.
Think of it like a sliding piston or platform.
For convenience body with PrismaticJoint2D will be refered as BodyA and other/referenced body as BodyB.
This animation is in 3D, but the idea is same in 2D as well.
Animation Source: https://gepettoweb.laas.fr/hpp/pinocchio/doxygen-html/md_doc_c-maths_c-joints.html
Class Declaration
class PrismaticJoint2D : public Component
This class inherits from the Component
class and adds functionality related to defining a joint connection to another Rigidbody2D for simulating 2D physics.
Public Methods
Attach
bool AttachToBody(RigidBody2D& referenceBody)
Attach the joint to Entity which has the referenced Rigidbody2D. One joint component can only have one attached Rigidbody2D.
Attaching when existing joint is present will destroy the old one.
Requires valid Rigidbody2D on both entities.
- referenceBody - the Rigidbody2D component to which the joint will be attached.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool AttachToEntity(u64 entityID)
Attach joint directly using Entity. Requires valid Rigidbody2D on Entity.
- entityID - id of entity to which to attach joint connection.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool DetachFromBody()
Destroys the joint connection.
Returns:
- true if joint has been destroyed.
- false if no joint was destroyed.
Properties
The PrismaticJoint2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the joint properties in a more intuitive manner:
glm::vec2 AnchorPos
Position of the anchor point on rigid body on same Entity which has the PrismaticJoint2D.
This position is a local offset at which the body is attached.
- Get:
glm::vec2 GetAnchorPos()
- Set:
SetAnchorPos(const glm::vec2& posLocal)
glm::vec2 AnchorPosReferencedBody
Position of the anchor point on referenced Entity which has Rigidbody2D.
This position is a local offset for referenced Entity, not Entity with PrismaticJoint2D.
- Get:
glm::vec2 GetAnchorPosReferencedBody()
- Set:
void SetAnchorPosReferencedBody(const glm::vec2& posLocal)
glm::vec2 LimitedAxis()
World direction vector specifying constrained axis. Movement of both bodies is limited only along this axis.
{1.0, 0.0} - Horizontal movement
{0.0, 1.0} - Vertical movement
{0.5, 0.5}, {-0.5, -0.5} - Diagonal movement
- Get:
glm::vec2 GetLimitedAxis()
- Set:
void SetLimitedAxis(const glm::vec2& axis2D)
- axis2D - direction/axis vector, value is normalized by default.
float ReferenceAngle
The joint preserves the desired relative rotation between the bodies throughout the simulation.
For example, if you want bodyB to be tilted 5 degrees counter-clockwise relative to bodyA, you can set ReferenceAngle
to 5 degrees.
- Get:
float GetReferenceAngle()
- Set:
void SetReferenceAngle(float refAngle)
- refAngle - The constrained angle between the bodies: bodyB_angle - bodyA_angle.
bool CollideWithOther
Should the colliders attached to both bodies collide with each other?
- Get:
bool GetCollideWithOther()
- Set:
void SetCollideWithOther(bool collide)
- collide - true makes bodies collide with each other, false disables collision between them.
bool IsMotorEnabled
Enable/Disable motor. Motor changes the distance between the two bodies using speed(direction) and max force.
Works with IsSpringEnabled=true
and IsLimitEnabled=true
.
- Get:
bool IsMotorEnabled()
- Set:
void EnableMotor(bool enable)
- enable - true enables motor, false disables motor.
bool IsSpringEnabled
Enable/Disable spring. Spring allows for elastic change of distance between bodies using damping ratio and frequency.
Works well in combination with IsLimitEnabled=true
and IsMotorEnabled=true
.
When disabled, frequency=0 and dampingRation=1.
- Get:
bool IsSpringEnabled()
- Set:
void EnableSpring(bool enable)
- enable - true enables spring, false disables spring.
bool IsLimitEnabled
Enable/Disable limit. Limit allows for change of distance between bodies within a clamped range [MinDistance; MaxDistance].
Works in combination with IsSpringEnabled=true
and IsMotorEnabled=true
When limit is disabled, distance between bodies is always constant.
- Get:
bool IsLimitEnabled()
- Set:
void EnableLimit(bool enable)
- enable - true enables limit, false disables limit.
float SpringTargetTranslation
If IsSpringEnabled = true
, The spring-damper will drive to this translation.
The joint translation is zero when the local anchor points coincide in world space.
- Get:
float GetSpringTargetTranslation()
- Set:
void SetSpringTargetTranslation(float distance)
- distance - distance between two bodies, in meters.
Example:
LimitedAxis = {0.0f, 1.0f}; // Vertical axis
SprintTargetTranslation = 1.5f; // 1.5 meters above BodyA
LimitedAxis = {0.0f, 1.0f}; // Vertical axis
SprintTargetTranslation = -1.2f; // 1.2 meters below BodyA
LimitedAxis = {1.0f, 0.0f}; // Horizontal axis
SprintTargetTranslation = 2.f; // 2 meters right of BodyA
float SpringFrequency
If IsSpingEnabled = true
, this allows the distance between two bodies to behave like a spring, instead of being constant and rigid.
Frequency (or spring linear stiffness) is in Hertz(HZ).
This should usually be less than a quarter of the simulation rate. For example, if the simulation runs at 60Hz then the joint stiffness should be 15Hz or less.
- Get:
float GetSpringFrequencyHZ()
- Set:
void SetSpringFrequencyHZ(float freq)
- freq - should be non-negative value.
float SpringDampingRatio
Linear damping ratio of spring, non-dimensional.
0 means no damping (energy loss) and 1 means full absorbtion (immediate energy loss).
- Get:
float GetSpringDampingRatio()
- Set:
void SetSpringDampingRatio(float ratio)
- ratio - value in range [0; 1].
float UpperTranslationLimit
When IsLimitEnabled=true
, this specifies maximum translation distance possible between two bodies, in meters.
The joint translation is zero when the local anchor points coincide in world space.
- Get:
float GetUpperTranslationLimit()
- Set:
void SetUpperTranslationLimit(float maxDist)
- maxDist - must be greater than LowerTranslationLimit, in meters.
float LowerTranslationLimit
When IsLimitEnabled=true
, this specifies minimum translation distance possible between two bodies, in meters.
The joint translation is zero when the local anchor points coincide in world space.
- Get:
float LowerTranslationLimit()
- Set:
void SetLowerTranslationLimit(float minDist)
- maxDist - must be less than UpperTranslationLimit, in meters.
float MotorSpeed
When IsMotor=true
, this specifies the speed at which the joint pushes(positive value) or pulls(negative value) BodyB along the LimitedAxis
direction, in meters per second.
- Get:
float GetMotorSpeed()
- Set:
void SetMotorSpeed(float motorSpeed)
- motorSpeed - meters per second.
Example:
myJoint.LimitedAxis = {0.0f, 1.0f}; // Vectical axis
myJoint.MotorSpeed = 1.0f; // Move Up at 1 m/s
float MaxMotorForce
When IsMotor=true
and IsSpringEnabled=true
, this specifies the maximum force the motor will apply to constrained body, in Newtons. Similar to spring stiffness, imagine this as the strength of the motor pulling or pushing. Note the mass of bodies for better tuning.
- Get:
float GetMaxMotorForce()
- Set:
void SetMaxMotorForce(float force)
- force - non-negative value in Newtons.
Weld Joint2D Component
The WeldJoint2D
class is a component in Tsar engine used to define a joint connection between two Rigidbody2D.
The joint has to reference another Entity which has Rigidbody2D Component.
The weld joint fully constrains the relative transform(position and rotation) between anchors on two bodies while allowing for springiness. Both rotation and translation can have damped springs.
Class Declaration
class WeldJoint2D : public Component
This class inherits from the Component
class and adds functionality related to defining a joint connection to another Rigidbody2D for simulating 2D physics.
Public Methods
Attach
bool AttachToBody(RigidBody2D& referenceBody)
Attach the joint to Entity which has the referenced Rigidbody2D. One joint component can only have one attached Rigidbody2D.
Attaching when existing joint is present will destroy the old one.
Requires valid Rigidbody2D on both entities.
- referenceBody - the Rigidbody2D component to which the joint will be attached.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool AttachToEntity(u64 entityID)
Attach joint directly using Entity. Requires valid Rigidbody2D on Entity.
- entityID - id of entity to which to attach joint connection.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool DetachFromBody()
Destroys the joint connection.
Returns:
- true if joint has been destroyed.
- false if no joint was destroyed.
Properties
The WeldJoint2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the joint properties in a more intuitive manner:
glm::vec2 AnchorPos
Position of the anchor point on Rigidbody on same Entity which has the WeldJoint2D.
This position is a local offset.
- Get:
glm::vec2 GetAnchorPos()
- Set:
SetAnchorPos(const glm::vec2& posLocal)
glm::vec2 ConnectedAnchorPos
Position of the anchor point on referenced Entity which has Rigidbody2D.
This position is a local offset for referenced Entity, not Entity with WeldJoint2D.
- Get:
glm::vec2 GetConnectedAnchorPos()
- Set:
SetConnectedAnchorPos(const glm::vec2& posLocal)
bool IsSpringEnabled
Enable/Disable spring. Spring allows for elastic change of distance/rotation between bodies using damping ratio and frequency.
- Disabled - the joint will be rigid (like a solid weld) making bodies having the same movement.
- Enabled - the joint acts as flexible connection between bodies. Imagine two cherries inside a pudding/jelly, one at top the other below it, the pudding doesn't break but acts as elastic damper between the two bodies which almost don't move/rotate relative to each other.
When disabled, frequency=0 and dampingRation=1.
- Get:
bool IsSpringEnabled()
- Set:
void EnableSpring(bool enable)
- enable - true enables spring, false disables spring.
Below is an animation showing 'springiness' between strawberry on top and the plate below, the pudding oscilates with a frequency and softly dampens the applied force to the plate.

Image Source: https://media1.giphy.com/media/v1.Y2lkPTZjMDliOTUycm81Z25hbHkwd3BxdXpxdDhyMnViNmI0dXNtZzk1NHJuNGxrbjdhYyZlcD12MV9naWZzX3NlYXJjaCZjdD1n/RwnoM2uvfwqcw/source.gif
float LinearFrequency
Spring linear stiffness, in Hertz(HZ).
This lets you configure how quickly a spring reacts for translation.
For better stability should usually be less than a quarter of the simulation rate. For example, if the simulation runs at 60Hz then the joint stiffness should be 15Hz or less.
- Get:
float GetLinearFrequencyHZ()
- Set:
void SetLinearFrequencyHZ(float freq)
- freq - should be non-negative value.
float LinearDampingRatio
Linear damping ratio of spring, lets you specify how quickly the spring will come to rest when force applied(translation change).
0 means no damping (energy loss) and 1 means full absorbtion (immediate energy loss).
- Get:
float GetLineargDampingRatio()
- Set:
void SetLinearDampingRatio(float ratio)
- ratio - value in range [0; 1].
float AngularFrequency
Spring angular stiffness, in Hertz(HZ).
This lets you configure how quickly a spring reacts to rotation.
For better stability should usually be less than a quarter of the simulation rate. For example, if the simulation runs at 60Hz then the joint stiffness should be 15Hz or less.
- Get:
float GetAngularFrequencyHZ()
- Set:
void SetAngularFrequencyHZ(float freq)
- freq - should be non-negative value.
float AngularDampingRatio
Angular damping ratio of spring, lets you specify how quickly the spring will come to rest when torque applied(rotation change).
0 means no damping (energy loss) and 1 means full absorbtion (immediate energy loss).
- Get:
float GetAngularDampingRatio()
- Set:
void SetAngularDampingRatio(float ratio)
- ratio - value in range [0; 1].
bool CollideWithOther
Should the colliders attached to both bodies collide with each other?
- Get:
bool GetCollideWithOther()
- Set:
void SetCollideWithOther(bool collide)
- collide - true makes bodies collide with each other, false disables collision between them.
Motor Joint2D Component
The MotorJoint2D
class is a component in Tsar engine used to define a joint connection between two Rigidbody2D.
The joint has to reference another Entity which has Rigidbody2D Component.
The motor joint is used to drive the relative transform between two bodies. It takes a relative position and rotation and applies the forces and torques needed to achieve that relative transform over time.
Below is animation showing the idea of MotorJoint2D with linear and angular spring.

Animation Source: https://miro.medium.com/v2/resize:fit:1400/1*hGZLebbssht62XMlmmJhZw.gif
Class Declaration
class MotorJoint2D : public Component
This class inherits from the Component
class and adds functionality related to defining a joint connection to another Rigidbody2D for simulating 2D physics.
Public Methods
Attach
bool AttachToBody(RigidBody2D& referenceBody)
Attach the joint to Entity which has the referenced Rigidbody2D. One joint component can only have one attached Rigidbody2D.
Attaching when existing joint is present will destroy the old one.
Requires valid Rigidbody2D on both entities.
- referenceBody - the Rigidbody2D component to which the joint will be attached.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool AttachToEntity(u64 entityID)
Attach joint directly using Entity. Requires valid Rigidbody2D on Entity.
- entityID - id of entity to which to attach joint connection.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool DetachFromBody()
Destroys the joint connection.
Returns:
- true if joint has been destroyed.
- false if no joint was destroyed.
Properties
The MotorJoint2D
class exposes properties (that can also be accessed via getter and setter functions). These properties allow users to manipulate the joint properties in a more intuitive manner:
bool CollideWithOther
Should the colliders attached to both bodies collide with each other?
- Get:
bool GetCollideWithOther()
- Set:
void SetCollideWithOther(bool collide)
- collide - true makes bodies collide with each other, false disables collision between them.
float CorrectionFactor
Position correction factor in the range [0; 1].
The joint tries to match position/rotation based on that factor.
- 0 has no effect.
- 1 mirrors position/rotation.
float MaxMotorForce
Specifies the maximum force the motor will apply to constrained body, in Newtons.
- Get:
float GetMaxMotorForce()
- Set:
void SetMaxMotorForce(float force)
- force - non-negative value in Newtons.
float MaxMotorTorque
Specifies the maximum torque the motor will apply to constrained body, in Newton-meters.
- Get:
float GetMaxMotorForce()
- Set:
void SetMaxMotorForce(float force)
- force - non-negative value in Newton-meters.
Wheel Joint2D Component
The WheelJoint2D
class is a component in Tsar engine used to define a joint connection between two Rigidbody2D.
The joint has to reference another Entity which has Rigidbody2D Component.
The wheel joint combines PrismaticJoint2D, RevoluteJoint2D with spring/damper and motor.
WheelJoint2D
has limited axis on which the 'Wheel' can move along with spring damping, the 'Wheel' can rotate, essentially a full suspension joint.
Can use motor and translation limits.
Joint Scheme
Demonstration

Animation Source: https://miro.medium.com/v2/resize:fit:720/format:webp/1*L7W3ya854UGntCk0Yk5Plw.gif
Class Declaration
class WheelJoint2D : public Component
This class inherits from the Component
class and adds functionality related to defining a revolute joint connection to another Rigidbody2D for simulating 2D physics.
Public Methods
Attach
bool AttachToBody(RigidBody2D& referenceBody)
Attach the joint to Entity which has the referenced Rigidbody2D. One joint component can only have one attached Rigidbody2D.
Attaching when existing joint is present will destroy the old one.
Requires valid Rigidbody2D on both entities.
- referenceBody - the Rigidbody2D component to which the joint will be attached.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool AttachToEntity(u64 entityID)
Attach joint directly using Entity. Requires valid Rigidbody2D on Entity.
- entityID - id of entity to which to attach joint connection.
Returns:
- true if joint was created successfuly.
- false if joint creation failed.
bool DetachFromBody()
Destroys the joint connection.
Returns:
- true if joint has been destroyed.
- false if no joint was destroyed.
Properties
The WheelJoint2D
class exposes properties (that can also be accessed via getter and setter functions).
These properties allow users to manipulate the joint properties in a more intuitive manner:
glm::vec2 MountPoint
Position offset of the mounting point of suspension on same Entity which has the WheelJoint2D.
- Get:
glm::vec2 GetMountPoint()
- Set:
SetMountPoint(const glm::vec2& posLocalOffset)
float WheelOffset
Position offset from referenced body, defining axle of the wheel. {0; 0} for center of referenced Rigidbody2D.
- Get:
float GetWheelOffset()
- Set:
void SetWheelOffset(const glm::vec2& pLocalOffset)
- pLocalOffset - local space offset of wheel center point.
bool CollideWithOther
Should the colliders attached to both bodies collide with each other?
- Get:
bool GetCollideWithOther()
- Set:
void SetCollideWithOther(bool collide)
- collide - true makes bodies collide with each other, false disables collision between them.
bool IsMotorEnabled
Enable/Disable motor. If you enable the motor, Box2D will apply torque to reach and maintain a given angular speed (MotorSpeed), up to a specified maximum torque (MaxMotorTorque).
- Get:
bool IsMotorEnabled()
- Set:
void EnableMotor(bool enable)
- enable - true enables motor, false disables motor.
bool IsSpringEnabled
Enable/Disable spring. Spring acts on constrained LimitedAxis
, as suspension spring on a vehicle.
When disabled, frequency=0 and dampingRatio=1.
- Get:
bool IsSpringEnabled()
- Set:
void EnableSpring(bool enable)
- enable - true enables spring, false disables spring.
bool IsLimitEnabled
Enable/Disable limit. Limits suspension travel.
- Get:
bool IsLimitEnabled()
- Set:
void EnableLimit(bool enable)
- enable - true enables suspension limit, false disables limit.
float SpringFrequency
If IsSpingEnabled = true
, this acts as spring trying to maintain distance between MountPoint
and WheelOffset
in elastic manner.
Frequency (or spring linear stiffness) is in Hertz(HZ), cycles per second.
For better stability should usually be less than a quarter of the simulation rate. For example, if the simulation runs at 60Hz then the joint stiffness should be 15Hz or less.
- Get:
float GetSpringFrequencyHZ()
- Set:
void SetSpringFrequencyHZ(float freq)
- freq - should be non-negative value.
float SpringDampingRatio
Linear damping ratio of spring, non-dimensional, how much the suspension resists oscillation.
0 means no damping (energy loss) and 1 means full absorbtion (immediate energy loss).
- Get:
float GetSpringDampingRatio()
- Set:
void SetSpringDampingRatio(float ratio)
- ratio - value in range [0; 1].
float UpperTranslationLimit
When IsLimitEnabled=true
, this specifies maximum translation distance possible between two bodies (suspension max travel), in meters. Cannot extend beyond set length.
The joint translation is zero when the local anchor points coincide in world space.
- Get:
float GetUpperTranslationLimit()
- Set:
void SetUpperTranslationLimit(float maxDist)
- maxDist - must be greater than LowerTranslationLimit, in meters.
float LowerTranslationLimit
When IsLimitEnabled=true
, this specifies minimum translation distance possible between two bodies (suspension min travel), in meters. Cannot compress below set length.
The joint translation is zero when the local anchor points coincide in world space.
- Get:
float LowerTranslationLimit()
- Set:
void SetLowerTranslationLimit(float minDist)
- maxDist - must be less than UpperTranslationLimit, in meters.
float MotorSpeed
When IsMotor=true
, this specifies the speed at which the joint rotates the dynamic body ('Wheel') along Z-axis in radians per second.
This speed won't be reached if MaxTorque
is not strong enough.
Positive value rotates counter-clockwise, negative value rotates clockwise.
- Get:
float GetMotorSpeed()
- Set:
void SetMotorSpeed(float motorSpeed)
- motorSpeed - radians per second.
float MaxMotorTorque
When IsMotor=true
, this specifies the maximum torque (angular force) the motor will apply to 'Wheel', in Newton-meters.
Note the mass of bodies for better tuning and colliders material settings.
- Get:
float GetMaxMotorTorque()
- Set:
void SetMaxMotorTorque(float torque)
- torque - non-negative value in Newton-meters.