Physics components and physics sim working

Cleaned up tree view panels (no arrows on items with no children)
dev
Joey Pollack 3 years ago
parent c901fe6f9b
commit f0dd9e4e4d

@ -120,7 +120,8 @@ ECS:
✔ Velocity @done(22-09-07 14:49)
✔ Camera @done(22-09-07 14:49)
✔ BlockOut @done(22-09-08 15:41)
☐ SpriteRenderer
✔ SpriteRenderer @done(22-11-28 20:09)
☐ TextRenderer
☐ Animation Controller
✔ Script @done(22-11-14 18:19)
☐ Audio Listener
@ -181,6 +182,7 @@ Assets:
✔ Decouple Image class from OGLRenderer @high @done (10/27/2021, 7:41:50 PM)
☐ Font class
☐ Sound class
☐ Animation
✔ Script class @done (1/25/2022, 3:58:28 PM)
Loaders:

@ -3,7 +3,7 @@ Editor:
☐ Generate boiler-plate code when a new script is created
☐ Include setting the entity ID
Add pure virtual ShowProperties method to EditorAsset
Add pure virtual ShowProperties method to EditorAsset @done(22-11-28 20:11)
✔ Script Editor Asset @done(22-11-14 18:19)
✔ Editor Assets need to switch to using UUIDs @critical @done(22-11-02 18:51)
✔ Remove Entity @done(22-10-14 18:28)

@ -0,0 +1,35 @@
Tasks/Features needed to build and release a complete game:
☐ Audio System
☐ Implement Audio API into the core
☐ Integrate OpenAL
☐ Expose API methods
☐ Integrate Audio API into the editor
☐ Audio listener component
☐ Audio source component
☐ Entity Template System
☐ Entity template asset
☐ Entity spawning in scripts
☐ Entity destruction in scripts
☐ Build and Release System
☐ Asset Compiling
☐ Binary data formats
☐ Implement binary asset use in the World
☐ Game playback Module
☐ Binary asset manager
☐ Binary asset loader
☐ Basic Physics
✔ Physics sim implemented in World @done(23-01-04 18:22)
✔ Expose physics settings of the world @done(23-01-04 14:43)
✔ Gravity setting @done(23-01-04 14:43)
✔ Scale factor @done(23-01-04 14:43)
✔ Rigid Body Component @done(23-01-04 15:08)
✔ Collider Components @done(23-01-04 15:08)
☐ Collision Listeners
Nice-To-Haves:
☐ ImGizmo Implemented
☐ Basic Sprite Animation

@ -81,6 +81,15 @@ namespace lunarium
return values_updated;
}
bool ImGuiExt::Vec2Control(const std::string& label, glm::vec2& values, float resetValue, float columnWidth)
{
glm::vec3 temp = { values.x, values.y, 0.0 };
bool result = Vec2Control(label, temp, resetValue, columnWidth);
values.x = temp.x;
values.y = temp.y;
return result;
}
bool ImGuiExt::Vec2Control(const std::string& label, glm::vec3& values, float resetValue, float columnWidth)
{

@ -23,6 +23,7 @@ namespace lunarium
/// https://github.com/TheCherno/Hazel/blob/master/Hazelnut/src/Panels/SceneHierarchyPanel.cpp
static bool Vec3Control(const std::string& label, glm::vec3& values, float resetValue = 0.0f, float columnWidth = 100.0f);
static bool Vec2Control(const std::string& label, glm::vec3& values, float resetValue = 0.0f, float columnWidth = 100.0f);
static bool Vec2Control(const std::string& label, glm::vec2& values, float resetValue = 0.0f, float columnWidth = 100.0f);
static bool FloatControl(const std::string& label, float& values, float resetValue = 0.0f, float columnWidth = 100.0f);
static void TextCentered(const std::string text);
static bool ButtonCentered(const char* label, float alignment = 0.5f);

@ -282,6 +282,122 @@ namespace lunarium { namespace editor
ImGui::EndCombo();
}
return remove;
}
bool CompGui::RenderRigidBodyComp(RigidBodyComponent& comp)
{
bool remove = false;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, ImGui::GetStyle().ItemSpacing.y + 10.0f));
remove = DrawTitle("Rigid Body Component");
ImGui::PopStyleVar();
bool is_static = comp.IsStatic;
if (ImGuiExt::CheckBoxLeft("Is Static:", &is_static))
{
comp.IsStatic = is_static;
}
float mass = comp.Mass;
if (ImGuiExt::FloatControl("Mass:", mass, 1.0f, 85.0f))
{
comp.Mass = mass;
}
bool freeze_rotation = comp.Defintion.fixedRotation;
if (ImGuiExt::CheckBoxLeft("Freeze Rotation: ", &freeze_rotation))
{
comp.Defintion.fixedRotation = freeze_rotation;
}
bool is_high_speed = comp.Defintion.bullet;
if (ImGuiExt::CheckBoxLeft("Is High Speed: ", &is_high_speed))
{
comp.Defintion.bullet = is_high_speed;
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Is this a fast moving body that should be prevented from tunneling through other moving bodies? Note that all bodies are prevented from tunneling through kinematic and static bodies. This setting is only considered on dynamic bodies. warning: You should use this flag sparingly since it increases processing time.");
}
// TODO: Expose other body parameters (damping, gravity scale, sleeping, etc)
// Maybe as "advanced" parameters hidden in a collapsable area
return remove;
}
bool CompGui::RenderCollisionComp(CollisionComponent& comp)
{
bool remove = false;
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, ImGui::GetStyle().ItemSpacing.y + 10.0f));
remove = DrawTitle("Collision Component");
ImGui::PopStyleVar();
// Shape Type
std::string preview = "NOT SET";
switch (comp.Type)
{
case CollisionComponent::ShapeType::Box: preview = "Box"; break;
case CollisionComponent::ShapeType::Circle: preview = "Circle"; break;
}
ImGui::SetNextItemWidth(85);
if (ImGui::BeginCombo("Shape Type", preview.c_str()))
{
if (ImGui::Selectable("Box"))
{
comp.Type = CollisionComponent::ShapeType::Box;
}
if (ImGui::Selectable("Circle"))
{
comp.Type = CollisionComponent::ShapeType::Circle;
}
ImGui::EndCombo();
}
// Is Sensor
bool Is_sensor = comp.IsSensor;
if (ImGuiExt::CheckBoxLeft("Is Sensor: ", &Is_sensor))
{
comp.IsSensor = Is_sensor;
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("A sensor does not generate collision responses (aka a trigger)");
}
if (comp.Type == CollisionComponent::ShapeType::Circle)
{
ImGuiExt::FloatControl("Radius:", comp.Radius, 1.0f, 85.0f);
}
if (comp.Type == CollisionComponent::ShapeType::Box)
{
ImGuiExt::FloatControl("Width:", comp.Width, 1.0f, 85.0f);
ImGuiExt::FloatControl("Height:", comp.Height, 1.0f, 85.0f);
}
// Collision Group
ImGui::Text("Collision Group: ");
ImGui::SameLine();
ImGui::SetNextItemWidth(80);
ImGui::InputInt("##Collision Group", &comp.CollisionGroup, 1, 10);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Only objects in the same Collision Group can collide");
}
// Physics properties
ImGuiExt::FloatControl("Density:", comp.Density, 1.0f, 85.0f);
ImGuiExt::FloatControl("Friction:", comp.Friction, 0.25f, 85.0f);
ImGuiExt::FloatControl("Restitution:", comp.Restitution, 0.25f, 85.0f);
return remove;
}
}}

@ -23,6 +23,8 @@ namespace lunarium { namespace editor
static bool RenderBlockOutComp(BlockOutComponent& comp);
static bool RenderSpriteRendererComp(SpriteRendererComponent& comp);
static bool RenderScriptComp(ScriptComponent& comp);
static bool RenderRigidBodyComp(RigidBodyComponent& comp);
static bool RenderCollisionComp(CollisionComponent& comp);
};
}}

@ -10,6 +10,8 @@
#include <LunariumConfig.h>
#include <editor/editor.h>
#include <world/world.h>
#include <dearimgui/imgui.h>
#include <gui/imgui_ext.h>
#include <filesystem>
#include <fstream>
@ -121,7 +123,26 @@ namespace lunarium { namespace editor
bool World::DrawProperties()
{
return false;
std::string name = mpWorld->GetName();
char buffer[256];
strcpy(buffer, name.c_str());
ImGui::Text("World Name: ");
ImGui::SameLine();
bool result0 = ImGui::InputText("##World Name", buffer, 256);
if (result0) mpWorld->SetName(buffer);
// Show gravity and Physics scale value
glm::vec2 gravity = mpWorld->GetGravity();
bool result1 = ImGuiExt::Vec2Control("World Gravity", gravity);
if (result1) mpWorld->SetGravity(gravity);
float scale = mpWorld->GetPhysicsScaleFactor();
ImGui::Text("World Physics Scale Factor:");
ImGui::SameLine();
bool result2 = ImGui::DragFloat("##Scale Factor", &scale);
if (result2) mpWorld->SetPhysicsScaleFactor(scale);
return (result0 || result1 || result2);
}
}}

@ -480,6 +480,33 @@ namespace editor
// }
void Editor::OnComponentAdd(lunarium::Entity* pEnt, void* pComp, lunarium::ComponentType type)
{
if (lunarium::ComponentType::RigidBodyComponent == type || lunarium::ComponentType::CollisionComponent == type)
{
if (pEnt->HasComponent<VelocityComponent>())
{
Logger::Warn(LogCat, "Entity with ID %llu has both a physics component and a VelocityComponent. These will not work together, the VelocityComponent will be ignored.", pEnt->GetUUID());
}
}
if (lunarium::ComponentType::CollisionComponent == type)
{
if (!pEnt->HasComponent<RigidBodyComponent>())
{
Logger::Warn(LogCat, "Entity with ID %llu has a CollisionComponent but does not have a RigidBodyComponent. The CollisionComponent will not do anything.");
}
}
if (lunarium::ComponentType::VelocityComponent == type)
{
if (pEnt->HasComponent<RigidBodyComponent>() || pEnt->HasComponent<CollisionComponent>())
{
Logger::Warn(LogCat, "Entity with ID %llu has both a physics component and a VelocityComponent. These will not work together, the VelocityComponent will be ignored.", pEnt->GetUUID());
}
}
}
void Editor::OnAssetOpen(EditorAsset* pAsset)
{
switch (pAsset->GetType())

@ -58,6 +58,7 @@ namespace lunarium { namespace editor
Project* GetProject();
// Panel events
void OnComponentAdd(lunarium::Entity* pEnt, void* pComp, lunarium::ComponentType type);
void OnEntitySelect(lunarium::Entity* pEnt);
//void ChangeWorld(lunarium::World* pWorld);
void OnAssetOpen(EditorAsset* pAsset);

@ -105,30 +105,53 @@ namespace editor
}
}
if (ImGui::TreeNode(next_node_name.c_str()))
{
if (!mSyncTree)
// Doing this to prevent arrows from showing up on items that have no child directories
// Seems a bit clumsy to iterate the directory twice though so this can probably
// be cleaned up a bit
int num_child_dirs = 0;
for(auto const& dir_entry: std::filesystem::directory_iterator{dir})
{
if (std::filesystem::is_directory(dir_entry))
{
if (ImGui::IsItemClicked())
{
mSelectedDir = dir;
ImGui::SetNextItemOpen(false);
}
HandleAssetDrop(dir);
num_child_dirs++;
}
for(auto const& dir_entry: std::filesystem::directory_iterator{dir})
}
if (num_child_dirs < 1)
{
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
if (ImGui::Selectable(next_node_name.c_str()))
{
DoDirTree(dir_entry);
mSelectedDir = dir;
}
ImGui::TreePop();
}
else
else
{
if (ImGui::IsItemClicked())
if (ImGui::TreeNode(next_node_name.c_str()))
{
mSelectedDir = dir;
ImGui::SetNextItemOpen(false);
if (!mSyncTree)
{
if (ImGui::IsItemClicked())
{
mSelectedDir = dir;
ImGui::SetNextItemOpen(false);
}
HandleAssetDrop(dir);
}
for(auto const& dir_entry: std::filesystem::directory_iterator{dir})
{
DoDirTree(dir_entry);
}
ImGui::TreePop();
}
else
{
if (ImGui::IsItemClicked())
{
mSelectedDir = dir;
ImGui::SetNextItemOpen(false);
}
}
}
}

@ -30,6 +30,7 @@ if (ImGui::Selectable(str_name)){\
if (!pv->mpSelectedEntity->HasComponent<type_name>()) {\
Logger::Error(Editor::LogCat, "Component not added to entity - unknown error");\
}\
pv->mpEditor->OnComponentAdd(pv->mpSelectedEntity, (void*)&pv->mpSelectedEntity->GetComponent<type_name>(), lunarium::ComponentType::type_name);\
Logger::Info(Editor::LogCat, "Component added to entity: %ll", pv->mpSelectedEntity->GetUUID());\
return false;\
}
@ -70,6 +71,8 @@ namespace lunarium { namespace editor
PRESENT_COMP_CHOICE("Block Out Component", BlockOutComponent, pv)
PRESENT_COMP_CHOICE("Sprite Renderer Component", SpriteRendererComponent, pv)
PRESENT_COMP_CHOICE("Script Component", ScriptComponent, pv)
PRESENT_COMP_CHOICE("Rigid Body Component", RigidBodyComponent, pv)
PRESENT_COMP_CHOICE("Collision Component", CollisionComponent, pv)
if ((ImGui::IsMouseClicked(ImGuiMouseButton_Left) && is_hover < 1))
@ -191,6 +194,8 @@ namespace lunarium { namespace editor
DRAW_COMP_GUI(BlockOutComponent, RenderBlockOutComp)
DRAW_COMP_GUI(SpriteRendererComponent, RenderSpriteRendererComp)
DRAW_COMP_GUI(ScriptComponent, RenderScriptComp)
DRAW_COMP_GUI(RigidBodyComponent, RenderRigidBodyComp)
DRAW_COMP_GUI(CollisionComponent, RenderCollisionComp)
// After all components rendered
if (ImGuiExt::ButtonCentered("Add Component"))

@ -141,10 +141,21 @@ namespace lunarium { namespace editor
bool was_clicked = false;
bool was_right_clicked = false;
bool node_open = ImGui::TreeNode(pEnt->GetName().c_str());
bool node_open = false;
if (pEnt->HasChildren())
{
node_open = ImGui::TreeNode(pEnt->GetName().c_str());
}
else
{
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
ImGui::Selectable(pEnt->GetName().c_str());
was_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
was_right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
}
// Handle drag and drop even if the node is closed
if (ImGui::BeginDragDropSource())
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
{
// Need to pass a pointer to the payload data. This means we need to pass a
// pointer to the Entity pointer (Entity**) which &pEnt becomes
@ -210,8 +221,8 @@ namespace lunarium { namespace editor
}
else
{
was_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
was_right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
// was_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Left);
// was_right_clicked = ImGui::IsItemClicked(ImGuiMouseButton_Right);
}
if (was_clicked)

@ -6,6 +6,20 @@
* Description - ECS component declarations
******************************************************************************/
/*
STEPS FOR CREATING A NEW COMPONENT:
1) add the struct to components.h
2) add the gui code to component_guis.h
3) add the code to call the gui function to properties_view.cpp
4) add the code to add a new instance of the component to selected entity in properties_view's ADD_COMPONENT popup (using PRESENT_COMP_CHOICE)
5) add serialize/deserialize code to entity.cpp
Situational:
6) add code (system) to use the component in World
7) add a foreign class to the scripting system to access/manipulate the component
*/
#ifndef LUNARIUM_COMPONENTS_H_
#define LUNARIUM_COMPONENTS_H_
@ -21,8 +35,27 @@
#include <string>
#include <vector>
namespace lunarium
{
enum class ComponentType
{
TagComponent,
TransformComponent,
VelocityComponent,
CameraComponent,
BlockOutComponent,
SpriteRendererComponent,
ScriptComponent,
RigidBodyComponent,
CollisionComponent,
UUIDComponent,
ParentEntityComponent,
ChildrenComponent,
};
struct TagComponent
{
std::string Info;
@ -58,6 +91,8 @@ namespace lunarium
}
};
// TODO: Deprecate in favor of using the physics system for all motion
// Or perhaps manually control the Transform component
struct VelocityComponent
{
glm::vec3 Velocity = { 0.0f, 0.0f, 0.0f};
@ -104,6 +139,37 @@ namespace lunarium
ScriptComponent(const ScriptComponent&) = default;
};
struct RigidBodyComponent
{
b2Body* pBody = nullptr;
bool IsStatic = false;
float Mass = 1.0f;
b2BodyDef Defintion;
RigidBodyComponent() = default;
RigidBodyComponent(const RigidBodyComponent&) = default;
};
struct CollisionComponent
{
b2Shape* pShape = nullptr;
enum class ShapeType { Circle, Box };
ShapeType Type;
float Radius = 1.0f; // only applies to circles
float Width = 1.0f; // only applies to boxes
float Height = 1.0f; // only applies to boxes
bool IsSensor = false; // Does not generate collision responses (a trigger)
int CollisionGroup = 0; // Only objects in the same Collision Group can collide
float Density = 1.0f;
float Friction = 0.25f;
float Restitution = 0.25f;
CollisionComponent() = default;
CollisionComponent(const CollisionComponent&) = default;
};
/////////////////////////////////////////////////////////////////////
// UTILITY COMPONENTS
/////////////////////////////////////////////////////////////////////

@ -256,7 +256,7 @@ namespace lunarium
auto& color = blockout["color"];
color["r"] = comp.Color.x;
color["g"] = comp.Color.y;
color["b"] = comp.Color.a;
color["b"] = comp.Color.z;
color["a"] = comp.Color.w;
auto& size = blockout["size"];
@ -306,6 +306,40 @@ namespace lunarium
components.emplace_back(script);
}
if (HasComponent<RigidBodyComponent>())
{
nlohmann::ordered_json rigid_body;
RigidBodyComponent& comp = GetComponent<RigidBodyComponent>();
rigid_body["type_name"] = "RigidBodyComponent";
rigid_body["is_static"] = comp.IsStatic;
rigid_body["mass"] = comp.Mass;
rigid_body["freeze_rotation"] = comp.Defintion.fixedRotation;
rigid_body["is_high_speed"] = comp.Defintion.bullet;
components.emplace_back(rigid_body);
}
if (HasComponent<CollisionComponent>())
{
nlohmann::ordered_json collision;
CollisionComponent& comp = GetComponent<CollisionComponent>();
collision["type_name"] = "CollisionComponent";
collision["radius"] = comp.Radius;
collision["width"] = comp.Width;
collision["height"] = comp.Height;
collision["shape_type"] = (int)comp.Type;
collision["is_sensor"] = comp.IsSensor;
collision["collision_group"] = comp.CollisionGroup;
collision["density"] = comp.Density;
collision["friction"] = comp.Friction;
collision["restitution"] = comp.Restitution;
components.emplace_back(collision);
}
if (HasComponent<ParentEntityComponent>())
{
nlohmann::ordered_json parent;
@ -474,6 +508,35 @@ namespace lunarium
AddComponent<ScriptComponent>(id);
}
if ("RigidBodyComponent" == comp_type_name)
{
bool is_static = comp["is_static"].get<bool>();
float mass = comp["mass"].get<float>();
bool freeze_rot = comp["freeze_rotation"].get<bool>();
bool is_high_speed = comp["is_high_speed"].get<bool>();
b2BodyDef definition;
definition.fixedRotation = freeze_rot;
definition.bullet = is_high_speed;
AddComponent<RigidBodyComponent>(nullptr, is_static, mass, definition);
}
if ("CollisionComponent" == comp_type_name)
{
CollisionComponent::ShapeType type = (CollisionComponent::ShapeType)comp["shape_type"].get<int>();
float radius = comp["radius"].get<float>();
float width = comp["width"].get<float>();
float height = comp["height"].get<float>();
bool is_sensor = comp["is_sensor"].get<bool>();
int collision_group = comp["collision_group"].get<int>();
float density = comp["density"].get<float>();
float friction = comp["friction"].get<float>();
float restitution = comp["restitution"].get<float>();
AddComponent<CollisionComponent>(nullptr, type, radius, width, height, is_sensor, collision_group, density, friction, restitution);
}
if ("ParentEntityComponent" == comp_type_name)
{
LUUID parent = comp["UUID"].get<u64>();

@ -20,6 +20,7 @@
#include <renderer/frame_buffer.h>
#include <renderer/orthographic_camera.h>
#include <renderer/texture.h>
#include <box2d/box2d.h>
#include "entity.h"
//#define LOAD_ASSETS_FROM_EDITOR true
@ -38,19 +39,113 @@ namespace lunarium
// }
World::World(std::string name)
: mUUID(UUID::GetNewID()), mName(name), mpActiveCamera(nullptr), mFrameBuffer(nullptr)
: mUUID(UUID::GetNewID()), mName(name), mpActiveCamera(nullptr), mFrameBuffer(nullptr), mpPhysicsWorld(nullptr), mDrawDebugObjects(false)
//mGetAssetsFromEditor(EDITOR_MODE)
{
WorldSettings.Physics.PhysicsScaleFactor = 16.0f;
}
std::string World::GetName() const
{
return mName;
}
void World::OnLoad()
void World::SetName(std::string name)
{
mName = name;
}
glm::vec2 World::GetGravity() const
{
return { WorldSettings.Physics.Gravity.x, WorldSettings.Physics.Gravity.y };
}
void World::SetGravity(glm::vec2 gravity)
{
WorldSettings.Physics.Gravity.x = gravity.x;
WorldSettings.Physics.Gravity.y = gravity.y;
}
float World::GetPhysicsScaleFactor() const
{
return WorldSettings.Physics.PhysicsScaleFactor;
}
void World::SetPhysicsScaleFactor(float factor)
{
WorldSettings.Physics.PhysicsScaleFactor = factor;
}
void World::OnLoad()
{
// INITIALIZE SCRIPTS
WorldAPI::Initialize(this).LogIfFailed(LogCategory::GAME_SYSTEM, "Failed to initialized the world scripting api");
// Initialize Physics
mpPhysicsWorld = new b2World({WorldSettings.Physics.Gravity.x, WorldSettings.Physics.Gravity.y});
// Iterate all entities with physics components and initialize them
// Only checking for RigidBody because any physics object needs at least that
auto group_phys = mECSRegistry.view<RigidBodyComponent, TransformComponent>();
for (auto entity: group_phys)
{
auto& transform = group_phys.get<TransformComponent>(entity);
auto& rigid_body = group_phys.get<RigidBodyComponent>(entity);
float scale_factor = WorldSettings.Physics.PhysicsScaleFactor;
rigid_body.Defintion.position.Set(transform.Position.x / scale_factor, transform.Position.y / scale_factor);
rigid_body.Defintion.angle = transform.Rotation.z;
if (!rigid_body.IsStatic)
{
rigid_body.Defintion.type = b2_dynamicBody;
}
rigid_body.pBody = mpPhysicsWorld->CreateBody(&rigid_body.Defintion);
// Handle collision components
if (mECSRegistry.all_of<CollisionComponent>(entity))
{
auto& comp = mECSRegistry.get<CollisionComponent>(entity);
switch (comp.Type)
{
case CollisionComponent::ShapeType::Box:
{
b2PolygonShape Shape;
Shape.SetAsBox(comp.Width / scale_factor, comp.Height / scale_factor);
b2FixtureDef fixtureDef;
fixtureDef.shape = &Shape;
fixtureDef.isSensor = comp.IsSensor;
fixtureDef.density = comp.Density;
fixtureDef.friction = comp.Friction;
fixtureDef.restitution = comp.Restitution;
rigid_body.pBody->CreateFixture(&fixtureDef);
} break;
case CollisionComponent::ShapeType::Circle:
{
b2CircleShape Shape;
Shape.m_radius = comp.Radius / scale_factor;
b2FixtureDef fixtureDef;
fixtureDef.shape = &Shape;
fixtureDef.isSensor = comp.IsSensor;
fixtureDef.density = comp.Density;
fixtureDef.friction = comp.Friction;
fixtureDef.restitution = comp.Restitution;
rigid_body.pBody->CreateFixture(&fixtureDef);
} break;
}
}
}
// Load scripts from all ScriptComponents in the world
auto group_scripts = mECSRegistry.view<ScriptComponent>();
auto group_scripts = mECSRegistry.view<ScriptComponent>();
for(auto entity: group_scripts)
{
auto& script_comp = group_scripts.get<ScriptComponent>(entity);
@ -62,6 +157,8 @@ namespace lunarium
WrenScript script(pScript->GetScriptFile().filename().string().c_str(), pScript->GetScript());
// mScriptState.RunScript(&script);
WorldAPI::RunScript(script);
#else
// Get Binary assets
#endif
}
@ -74,6 +171,9 @@ namespace lunarium
// Call OnUnLoad for each registered EntityBehavior class object
WorldAPI::InvokeEvent(WorldAPI::Event::ON_UNLOAD);
WorldAPI::Shutdown();
delete mpPhysicsWorld;
mpPhysicsWorld = nullptr;
}
void World::SetRunMode(RunMode mode)
@ -94,21 +194,50 @@ namespace lunarium
// Update Transforms for any enity with a velocity
// NOTE: Might remove the VelocityComponent in favor of using the physics system
auto group = mECSRegistry.group<>(entt::get<VelocityComponent, TransformComponent>);
for(auto entity: group)
{
{
// Skip any entity that has a physics component
if (mECSRegistry.any_of<RigidBodyComponent, CollisionComponent>(entity))
{
continue;
}
auto &transform = group.get<TransformComponent>(entity);
auto &velocity = group.get<VelocityComponent>(entity);
transform.Position += velocity.Velocity * dt;
}
// Update the physics sim and then use the results to update objects Transforms
float timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
mpPhysicsWorld->Step(timeStep, velocityIterations, positionIterations);
auto group_phys = mECSRegistry.view<TransformComponent, RigidBodyComponent>();
for (auto entity: group_phys)
{
auto& transform = group_phys.get<TransformComponent>(entity);
auto& rigid_body = group_phys.get<RigidBodyComponent>(entity);
float scale_factor = WorldSettings.Physics.PhysicsScaleFactor;
transform.Position = glm::vec3(rigid_body.pBody->GetPosition().x * scale_factor, rigid_body.pBody->GetPosition().y * scale_factor, 0.0f);
transform.Rotation.z = rigid_body.pBody->GetAngle();
}
}
void World::Render(lunarium::Renderer2D* pGraphics)
{
RenderBlockouts(pGraphics);
RenderSprites(pGraphics);
RenderBlockouts(pGraphics);
RenderSprites(pGraphics);
if (mDrawDebugObjects)
{
RenderDebugObjects(pGraphics);
}
}
@ -271,40 +400,36 @@ namespace lunarium
// pGraphics->DrawQuad(rect, color, nullptr, transform.Rotation.z, Rectangle(-1, -1, -1, -1), parent_transform);
}
}
// void World::DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform)
// {
// // Draw current entity
// Rectangle rect(my_trans.Position.x, my_trans.Position.y, bo_comp.Size.x, bo_comp.Size.y);
// Color color(bo_comp.Color.x, bo_comp.Color.y, bo_comp.Color.z, bo_comp.Color.w);
// g->DrawQuad(rect, color, nullptr, -my_trans.Rotation.z, Rectangle(-1, -1, -1, -1), current_transform);
// // Apply transform to children's transforms
// current_transform *= my_trans.GetTransform();
// // Iterate and draw children
// if (mECSRegistry.all_of<ChildrenComponent>(entity))
// {
// ChildrenComponent& children_comp = mECSRegistry.get<ChildrenComponent>(entity);
// for (int i = 0; i < children_comp.Children.size(); i++)
// {
// Entity* pEnt = GetEntity(children_comp.Children[i]);
// entt::entity handle = pEnt->GetEnttHandle();
// if (pEnt->HasComponent<TransformComponent>() && pEnt->HasComponent<BlockOutComponent>())
// {
// TransformComponent& trans_comp = pEnt->GetComponent<TransformComponent>();
// BlockOutComponent& bo_comp = pEnt->GetComponent<BlockOutComponent>();
// DrawHeirarchy(g, handle, trans_comp, bo_comp, current_transform);
// }
// }
// }
// }
void World::RenderDebugObjects(lunarium::Renderer2D* pGraphics)
{
auto group_phys = mECSRegistry.view<TransformComponent, RigidBodyComponent, CollisionComponent>();
for (auto entity : group_phys)
{
auto& rigid_body = group_phys.get<RigidBodyComponent>(entity);
auto& collision = group_phys.get<CollisionComponent>(entity);
if (!rigid_body.pBody)
continue;
if (collision.Type == CollisionComponent::ShapeType::Box)
{
b2AABB box;
b2Transform transform = { rigid_body.pBody->GetTransform().p, b2Rot(0.0f) };
rigid_body.pBody->GetFixtureList()->GetShape()->ComputeAABB(&box, transform, 0);
float scale_factor = WorldSettings.Physics.PhysicsScaleFactor;
float angle = rigid_body.pBody->GetAngle();
Rectangle rect(box);
rect.Scale(scale_factor, scale_factor);
rect.X *= scale_factor;
rect.Y *= scale_factor;
pGraphics->DrawBox(rect, Color(0.1f, 0.2f, 1.0f, 1.0f), 1.5f, angle);
}
}
}
glm::mat4 World::GetParentTransform(LUUID parent)
{
glm::mat4 transform(1.0f);
@ -360,8 +485,11 @@ namespace lunarium
{
#if !BUILD_NO_EDITOR // Only does this when this is an editor build
// General data
node["UUID"] = mUUID;
node["Name"] = mName;
// Game entities
node["NumberOfEntities"] = mEntities.size();
auto& ents = node["Entities"];
for (int i = 0; i < mEntities.size(); i++)
@ -371,6 +499,17 @@ namespace lunarium
ents.emplace_back(e);
}
// World settings
auto& settings = node["Settings"];
auto& physics = settings["Physics"];
physics["scale_factor"] = WorldSettings.Physics.PhysicsScaleFactor;
auto& gravity = physics["gravity"];
gravity["x"] = WorldSettings.Physics.Gravity.x;
gravity["y"] = WorldSettings.Physics.Gravity.y;
gravity["z"] = WorldSettings.Physics.Gravity.z;
#endif
return OpRes::OK();
}
@ -379,7 +518,11 @@ namespace lunarium
{
#if !BUILD_NO_EDITOR // Only does this when this is an editor build
// General Data
mUUID = node["UUID"].get<u64>();
mName = node["Name"].get<std::string>();
// Game entities
int num_entities = node["NumberOfEntities"].get<int>();
auto& ents = node["Entities"];
for (auto it = ents.begin(); it != ents.end(); ++it)
@ -398,6 +541,18 @@ namespace lunarium
mEntitiesByUUID[new_ent->GetUUID()] = new_ent;
}
// World Settings
if (!node["Settings"].is_null())
{
auto& settings = node["Settings"];
auto& physics = settings["Physics"];
WorldSettings.Physics.PhysicsScaleFactor = physics["scale_factor"].get<float>();
auto& gravity = physics["gravity"];
WorldSettings.Physics.Gravity = { gravity["x"].get<float>(), gravity["y"].get<float>(), gravity["z"].get<float>() };
}
#endif
return OpRes::OK();
}

@ -25,6 +25,7 @@
#include <map>
struct WrenHandle;
class b2World;
namespace lunarium
{
@ -96,6 +97,12 @@ namespace lunarium
WorldState GetState();
void ResetState(WorldState& state);
std::string GetName() const;
void SetName(std::string name);
glm::vec2 GetGravity() const;
void SetGravity(glm::vec2 gravity);
float GetPhysicsScaleFactor() const;
void SetPhysicsScaleFactor(float factor);
// Serializing
[[nodiscard]] virtual OpRes Serialize(nlohmann::ordered_json& node);
@ -107,15 +114,25 @@ namespace lunarium
private:
LUUID mUUID;
std::string mName;
RunMode mMode;
bool mDrawDebugObjects;
// State critical Data
entt::registry mECSRegistry;
std::vector<Entity*> mEntities;
std::map<LUUID, Entity*> mEntitiesByUUID;
RunMode mMode;
FrameBuffer* mFrameBuffer;
OrthographicCamera* mpActiveCamera;
b2World* mpPhysicsWorld;
struct
{
struct
{
float PhysicsScaleFactor;
glm::vec3 Gravity;
} Physics;
} WorldSettings;
//
// TODO: Move these into a TileMap class?
@ -136,7 +153,7 @@ namespace lunarium
glm::mat4 GetParentTransform(LUUID parent);
void RenderBlockouts(lunarium::Renderer2D* pGraphics);
void RenderSprites(lunarium::Renderer2D* pGraphics);
//void DrawHeirarchy(lunarium::Renderer2D* g, entt::entity& entity, TransformComponent& my_trans, BlockOutComponent& bo_comp, glm::mat4 current_transform);
void RenderDebugObjects(lunarium::Renderer2D* pGraphics);
};
}

Loading…
Cancel
Save