Tsar Engine Logo

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

  1. 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
    
  2. 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
  1. Open the Solution
    Open Tsar.sln in Visual Studio 2022.

  2. Build the Engine
    Set the build configuration to Debug or Release and build the solution.

  3. 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 Joint constraints

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()
  • glm::vec3 LocalTranslation Position or Offset of Entity relative to Parent. When parent is absent, position is relative to World.

    • Get: GetLocalTranslation()
    • Set: SetLocalTranslation()
  • glm::vec3 Rotation Rotation of Entity in World. Angles in radians.

    • Get: GetRotation()
    • Set: SetRotation()
  • 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()
  • 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()
  • 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()

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: Something that looks like C#

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 name
2. 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 Source Component

Audio Listener Component

Audio Settings

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 Volume
State
Pitch Effect
Doppler Effect
Spatialization

Initialize

Add component AudioSourceComponent to your entity
1. Select the entity 2. In the Properties window click 'Add' and select Audio Source Component 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
Doppler
Spatialization

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 spatialization
  • AttenuationType::Reverse - Volume increases with distance
  • AttenuationType::Linear - Linear decrease in volume, reaches zero at maxDistance
  • AttenuationType::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:

Colliders Joint constraints

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 be false.
  • Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it. IsSensor should be true.

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 be false.
  • Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it. IsSensor should be true.

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 be false.
  • Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it. IsSensor should be true.

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 be false.
  • Sensor -> collider which doesn't provide collision and other colliders pass through (overlap) it. IsSensor should be true.

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

Animation Source: https://miro.medium.com/v2/resize:fit:720/format:webp/1*ScmlN-PtI0DTvpRWg3GmFw.gif

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.

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.

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.