mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Invoke on collision enter + start of attach child colliders to rigidbody
+ Changed default Namespace of ScriptCore to GlitchyEngine + Implicit Casts float2 <-> b2Vec2 + Entity constructor internal + Renamed RigidBody2D to Rigidbody2D (notice the B) + Basic Debug Draw actual 2D Colliders + Added Entity::GetParentWithComponent
This commit is contained in:
@@ -405,7 +405,7 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
for (var (entity, transform, collider) in _activeScene.GetEntities<TransformComponent, BoxCollider2DComponent>())
|
for (var (entity, transform, collider) in _activeScene.GetEntities<TransformComponent, BoxCollider2DComponent>())
|
||||||
{
|
{
|
||||||
Renderer2D.DrawRect(transform.WorldTransform * Matrix.Translation(collider.Offset.X, collider.Offset.Y, 0) * Matrix.Scaling(collider.Size.X * 2, collider.Size.Y * 2, 0));
|
Renderer2D.DrawRect(transform.WorldTransform * Matrix.Translation(collider.Offset.X, collider.Offset.Y, 0) * Matrix.Scaling(collider.Size.X * 2, collider.Size.Y * 2, 0), .Green);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var (entity, transform, collider) in _activeScene.GetEntities<TransformComponent, CircleCollider2DComponent>())
|
for (var (entity, transform, collider) in _activeScene.GetEntities<TransformComponent, CircleCollider2DComponent>())
|
||||||
|
|||||||
@@ -24,6 +24,14 @@ public struct float2
|
|||||||
{
|
{
|
||||||
return half2((half)value.X, (half)value.Y);
|
return half2((half)value.X, (half)value.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
#unwarn
|
||||||
|
public static implicit operator Box2D.b2Vec2(in Self value) => *(Box2D.b2Vec2*)&value;
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
#unwarn
|
||||||
|
public static implicit operator Self(in Box2D.b2Vec2 value) => *(Self*)&value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BonTarget]
|
[BonTarget]
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Scripting.Classes;
|
||||||
|
|
||||||
|
[Ordered, Packed]
|
||||||
|
struct Collision2D
|
||||||
|
{
|
||||||
|
public UUID Entity;
|
||||||
|
public UUID OtherEntity;
|
||||||
|
|
||||||
|
public UUID Rigidbody;
|
||||||
|
public UUID OtherRigidbody;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ using Mono;
|
|||||||
using System;
|
using System;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using GlitchyEngine.Scripting.Classes;
|
||||||
|
|
||||||
namespace GlitchyEngine.Scripting;
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
@@ -287,6 +288,14 @@ class ScriptClass : SharpClass
|
|||||||
private OnCreateMethod _onCreate;
|
private OnCreateMethod _onCreate;
|
||||||
private OnUpdateMethod _onUpdate;
|
private OnUpdateMethod _onUpdate;
|
||||||
private OnDestroyMethod _onDestroy;
|
private OnDestroyMethod _onDestroy;
|
||||||
|
|
||||||
|
private function [CallingConvention(.Cdecl)] MonoObject*(MonoObject* instance, Collision2D collision, MonoException** exception) _onCollisionEnter2D;
|
||||||
|
|
||||||
|
//private OnCollisionEnter2DMethod _onCollisionEnter2D;
|
||||||
|
private OnDestroyMethod _onCollisionLeave2D;
|
||||||
|
private MonoMethod* _onCollisionEnter2DMethod;
|
||||||
|
|
||||||
|
public bool HasCollisionEnter2D => _onCollisionEnter2D != null;
|
||||||
|
|
||||||
/*public StringView Namespace => _namespace;
|
/*public StringView Namespace => _namespace;
|
||||||
public StringView ClassName => _className;
|
public StringView ClassName => _className;
|
||||||
@@ -303,6 +312,11 @@ class ScriptClass : SharpClass
|
|||||||
_onCreate = (OnCreateMethod)GetMethodThunk("OnCreate");
|
_onCreate = (OnCreateMethod)GetMethodThunk("OnCreate");
|
||||||
_onUpdate = (OnUpdateMethod)GetMethodThunk("OnUpdate", 1);
|
_onUpdate = (OnUpdateMethod)GetMethodThunk("OnUpdate", 1);
|
||||||
_onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy");
|
_onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy");
|
||||||
|
|
||||||
|
_onCollisionEnter2D = (.)GetMethodThunk("OnCollisionEnter2D", 1);
|
||||||
|
_onCollisionLeave2D = (OnDestroyMethod)GetMethodThunk("OnCollisionLeave2D");
|
||||||
|
|
||||||
|
_onCollisionEnter2DMethod = GetMethod("OnCollisionEnter2D", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnCreate(MonoObject* instance, out MonoException* exception)
|
public void OnCreate(MonoObject* instance, out MonoException* exception)
|
||||||
@@ -328,6 +342,22 @@ class ScriptClass : SharpClass
|
|||||||
if (_onDestroy != null)
|
if (_onDestroy != null)
|
||||||
_onDestroy(instance, &exception);
|
_onDestroy(instance, &exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnCollisionEnter2D(MonoObject* instance, Collision2D collision, out MonoException* exception)
|
||||||
|
{
|
||||||
|
exception = null;
|
||||||
|
|
||||||
|
// TODO: use method thunk
|
||||||
|
if (_onCollisionEnter2DMethod != null)
|
||||||
|
{
|
||||||
|
#unwarn
|
||||||
|
void*[1] args = .(&collision);
|
||||||
|
|
||||||
|
Invoke(_onCollisionEnter2DMethod, instance, (.)&args);
|
||||||
|
}
|
||||||
|
// if (_onCollisionEnter2D != null)
|
||||||
|
// _onCollisionEnter2D(instance, collision, &exception);
|
||||||
|
}
|
||||||
|
|
||||||
public MonoObject* CreateInstance(UUID uuid, out MonoException* exception)
|
public MonoObject* CreateInstance(UUID uuid, out MonoException* exception)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ static class ScriptGlue
|
|||||||
s_RemoveComponentMethods.Clear();
|
s_RemoveComponentMethods.Clear();
|
||||||
|
|
||||||
RegisterComponent<TransformComponent>("GlitchyEngine.Transform");
|
RegisterComponent<TransformComponent>("GlitchyEngine.Transform");
|
||||||
RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.RigidBody2D");
|
RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.Rigidbody2D");
|
||||||
}
|
}
|
||||||
|
|
||||||
[RegisterMethod]
|
[RegisterMethod]
|
||||||
@@ -99,7 +99,7 @@ static class ScriptGlue
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.EngineLogger.AssertDebug(managedType != null, scope $"No C# component with name \"{{className}}\" found for Beef type \"{typeof(T)}\"");
|
Log.EngineLogger.AssertDebug(managedType != null, scope $"No C# component with name \"{className}\" found for Beef type \"{typeof(T)}\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Mono;
|
using Mono;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using System;
|
using System;
|
||||||
|
using GlitchyEngine.Scripting.Classes;
|
||||||
|
|
||||||
namespace GlitchyEngine.Scripting;
|
namespace GlitchyEngine.Scripting;
|
||||||
|
|
||||||
@@ -80,6 +81,17 @@ class ScriptInstance : RefCounter
|
|||||||
if (exception != null)
|
if (exception != null)
|
||||||
ScriptEngine.HandleMonoException(exception, this);
|
ScriptEngine.HandleMonoException(exception, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InvokeOnCollisionEnter2D(Collision2D collision)
|
||||||
|
{
|
||||||
|
if (!_scriptClass.HasCollisionEnter2D)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_scriptClass.OnCollisionEnter2D(_instance, collision, let exception);
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
ScriptEngine.HandleMonoException(exception, this);
|
||||||
|
}
|
||||||
|
|
||||||
public T GetFieldValue<T>(ScriptField field)
|
public T GetFieldValue<T>(ScriptField field)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,7 +91,24 @@ namespace GlitchyEngine.World
|
|||||||
|
|
||||||
return _scene._ecsWorld.GetComponent<T>(_entity);
|
return _scene._ecsWorld.GetComponent<T>(_entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns this entity or the closest parent that has the given component.
|
||||||
|
public (Entity parent, T* component) GetParentWithComponent<T>() where T: struct, new
|
||||||
|
{
|
||||||
|
Entity? walker = this;
|
||||||
|
|
||||||
|
while (walker?.IsValid == true)
|
||||||
|
{
|
||||||
|
T* component = null;
|
||||||
|
if (walker?.TryGetComponent<T>(out component) == true)
|
||||||
|
return (walker.Value, component);
|
||||||
|
|
||||||
|
walker = walker?.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (.(), null);
|
||||||
|
}
|
||||||
|
|
||||||
public bool HasComponent<T>() where T: struct, new
|
public bool HasComponent<T>() where T: struct, new
|
||||||
{
|
{
|
||||||
return _scene._ecsWorld.HasComponent<T>(_entity);
|
return _scene._ecsWorld.HasComponent<T>(_entity);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ using Box2D;
|
|||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
using GlitchyEngine.Scripting;
|
using GlitchyEngine.Scripting;
|
||||||
|
using GlitchyEngine.Math;
|
||||||
|
using GlitchyEngine.Scripting.Classes;
|
||||||
|
|
||||||
namespace GlitchyEngine.World
|
namespace GlitchyEngine.World
|
||||||
{
|
{
|
||||||
@@ -17,6 +19,8 @@ namespace GlitchyEngine.World
|
|||||||
internal EcsWorld _ecsWorld = new .() ~ delete _;
|
internal EcsWorld _ecsWorld = new .() ~ delete _;
|
||||||
|
|
||||||
internal b2World* _physicsWorld2D;
|
internal b2World* _physicsWorld2D;
|
||||||
|
b2ContactListener _contactListener;
|
||||||
|
b2Draw draw = .();
|
||||||
|
|
||||||
private Dictionary<Type, function void(Entity entity, Type componentType, void* component)> _onComponentAddedHandlers = new .() ~ delete _;
|
private Dictionary<Type, function void(Entity entity, Type componentType, void* component)> _onComponentAddedHandlers = new .() ~ delete _;
|
||||||
|
|
||||||
@@ -173,14 +177,143 @@ namespace GlitchyEngine.World
|
|||||||
|
|
||||||
public void OnSimulationStart()
|
public void OnSimulationStart()
|
||||||
{
|
{
|
||||||
_physicsWorld2D = Box2D.World.Create(ref _gravity2D);
|
_physicsWorld2D = World.Create(ref _gravity2D);
|
||||||
|
|
||||||
|
_contactListener = b2ContactListener();
|
||||||
|
_contactListener.beginContactCallback = (contact, userData) =>
|
||||||
|
{
|
||||||
|
// TODO: This is bare minimum! Later we need to take hierarchies into account.
|
||||||
|
// e.g. A is parent of B and B gets event -> A needs to get event too!
|
||||||
|
|
||||||
|
var fixtureA = Contact.GetFixtureA(contact);
|
||||||
|
var fixtureB = Contact.GetFixtureB(contact);
|
||||||
|
|
||||||
|
var bodyA = Fixture.GetBody(fixtureA);
|
||||||
|
var bodyB = Fixture.GetBody(fixtureB);
|
||||||
|
|
||||||
|
// Cast is obviously 64bit only
|
||||||
|
var colliderEntityHandleA = (EcsEntity)(uint)Fixture.GetUserData(fixtureA);
|
||||||
|
var colliderEntityHandleB = (EcsEntity)(uint)Fixture.GetUserData(fixtureB);
|
||||||
|
|
||||||
|
Entity colliderEntityA = .(colliderEntityHandleA, ScriptEngine.Context);
|
||||||
|
Entity colliderEntityB = .(colliderEntityHandleB, ScriptEngine.Context);
|
||||||
|
|
||||||
|
// Cast is obviously 64bit only
|
||||||
|
var rigidbodyEntityHandleA = (EcsEntity)(uint)Body.GetUserData(bodyA);
|
||||||
|
var rigidbodyEntityHandleB = (EcsEntity)(uint)Body.GetUserData(bodyB);
|
||||||
|
|
||||||
|
Entity rigidbodyEntityA = .(rigidbodyEntityHandleA, ScriptEngine.Context);
|
||||||
|
Entity rigidbodyEntityB = .(rigidbodyEntityHandleB, ScriptEngine.Context);
|
||||||
|
|
||||||
|
bool fireEventA = colliderEntityA.TryGetComponent<ScriptComponent>(let scriptOfColliderA);
|
||||||
|
fireEventA |= rigidbodyEntityA.TryGetComponent<ScriptComponent>(let scriptOfRigidbodyA);
|
||||||
|
|
||||||
|
if (fireEventA)
|
||||||
|
{
|
||||||
|
Collision2D collision = .();
|
||||||
|
collision.Entity = colliderEntityA.UUID;
|
||||||
|
collision.OtherEntity = colliderEntityB.UUID;
|
||||||
|
collision.Rigidbody = rigidbodyEntityA.UUID;
|
||||||
|
collision.OtherRigidbody = rigidbodyEntityB.UUID;
|
||||||
|
|
||||||
|
scriptOfColliderA?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
|
scriptOfRigidbodyA?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fireEventB = colliderEntityB.TryGetComponent<ScriptComponent>(let scriptOfColliderB);
|
||||||
|
fireEventB |= rigidbodyEntityB.TryGetComponent<ScriptComponent>(let scriptOfRigidbodyB);
|
||||||
|
|
||||||
|
if (fireEventB)
|
||||||
|
{
|
||||||
|
Collision2D collision = .();
|
||||||
|
collision.Entity = colliderEntityB.UUID;
|
||||||
|
collision.OtherEntity = colliderEntityA.UUID;
|
||||||
|
collision.Rigidbody = rigidbodyEntityB.UUID;
|
||||||
|
collision.OtherRigidbody = rigidbodyEntityA.UUID;
|
||||||
|
|
||||||
|
scriptOfColliderB?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
|
scriptOfRigidbodyB?.Instance?.InvokeOnCollisionEnter2D(collision);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
World.SetContactListener(_physicsWorld2D, &_contactListener);
|
||||||
|
|
||||||
|
draw.drawPolygonCallback = (vertices, vertexCount, color, userData) =>
|
||||||
|
{
|
||||||
|
for (int i = 1; i < vertexCount; i++)
|
||||||
|
{
|
||||||
|
let start = vertices[i - 1];
|
||||||
|
let end = vertices[i];
|
||||||
|
|
||||||
|
Renderer2D.DrawLine(float3(start.x, start.y, 0.0f), float3(end.x, end.y, 0.0f), *(ColorRGBA*)&color);
|
||||||
|
}
|
||||||
|
let start = vertices[vertexCount - 1];
|
||||||
|
let end = vertices[0];
|
||||||
|
|
||||||
|
Renderer2D.DrawLine(float3(start.x, start.y, 0.0f), float3(end.x, end.y, 0.0f), *(ColorRGBA*)&color);
|
||||||
|
};
|
||||||
|
draw.drawSolidPolygonCallback = (vertices, vertexCount, color, userData) =>
|
||||||
|
{
|
||||||
|
for (int i = 1; i < vertexCount; i++)
|
||||||
|
{
|
||||||
|
let start = vertices[i - 1];
|
||||||
|
let end = vertices[i];
|
||||||
|
|
||||||
|
Renderer2D.DrawLine(float3(start.x, start.y, 0.0f), float3(end.x, end.y, 0.0f), *(ColorRGBA*)&color);
|
||||||
|
}
|
||||||
|
let start = vertices[vertexCount - 1];
|
||||||
|
let end = vertices[0];
|
||||||
|
|
||||||
|
Renderer2D.DrawLine(float3(start.x, start.y, 0.0f), float3(end.x, end.y, 0.0f), *(ColorRGBA*)&color);
|
||||||
|
};
|
||||||
|
draw.drawCircleCallback = (center, radius, color, userData) =>
|
||||||
|
{
|
||||||
|
Renderer2D.DrawCircle(center, radius.XX, *(ColorRGBA*)&color, 0.1f);
|
||||||
|
};
|
||||||
|
draw.drawSolidCircleCallback = (center, radius, axis, color, userData) =>
|
||||||
|
{
|
||||||
|
Renderer2D.DrawCircle(center, radius.XX, *(ColorRGBA*)&color);
|
||||||
|
};
|
||||||
|
draw.drawSegmentCallback = (p1, p2, color, userData) =>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
draw.drawPointCallback = (p, size, color, userData) =>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
draw.drawTransformCallback = (xf, userData) =>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
draw.userData = Internal.UnsafeCastToPtr(_physicsWorld2D);
|
||||||
|
|
||||||
|
World.SetDebugDraw(_physicsWorld2D, &draw);
|
||||||
|
World.SetDebugDrawFlags(_physicsWorld2D, .e_shapeBit);
|
||||||
|
|
||||||
|
InitPhysics2D();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitPhysics2D()
|
||||||
|
{
|
||||||
|
// Initialize all Rigidbodies
|
||||||
for (let (ecsHandle, rigidBody) in _ecsWorld.Enumerate<Rigidbody2DComponent>())
|
for (let (ecsHandle, rigidBody) in _ecsWorld.Enumerate<Rigidbody2DComponent>())
|
||||||
{
|
{
|
||||||
Entity entity = .(ecsHandle, this);
|
Entity entity = .(ecsHandle, this);
|
||||||
|
|
||||||
InitializeRigidbody2D(entity, rigidBody);
|
InitializeRigidbody2D(entity, rigidBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let (ecsHandle, boxCollider) in _ecsWorld.Enumerate<BoxCollider2DComponent>())
|
||||||
|
{
|
||||||
|
Entity entity = .(ecsHandle, this);
|
||||||
|
|
||||||
|
InitBoxCollider2D(entity, boxCollider);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let (ecsHandle, circleCollider) in _ecsWorld.Enumerate<CircleCollider2DComponent>())
|
||||||
|
{
|
||||||
|
Entity entity = .(ecsHandle, this);
|
||||||
|
|
||||||
|
InitCircleCollider2D(entity, circleCollider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeRigidbody2D(Entity entity, Rigidbody2DComponent* rigidBody)
|
private void InitializeRigidbody2D(Entity entity, Rigidbody2DComponent* rigidBody)
|
||||||
@@ -189,49 +322,117 @@ namespace GlitchyEngine.World
|
|||||||
|
|
||||||
b2BodyDef def = .();
|
b2BodyDef def = .();
|
||||||
def.type = GetBox2DBodyType(rigidBody.BodyType);
|
def.type = GetBox2DBodyType(rigidBody.BodyType);
|
||||||
|
def.userData = (void*)(uint)entity.Handle;
|
||||||
|
|
||||||
// TODO: breaks with hierarchy
|
// TODO: check how stable this is
|
||||||
def.position = b2Vec2(transform.Position.X, transform.Position.Y);
|
Matrix.Decompose(transform.WorldTransform, let worldPosition, let worldRotation, let worldScale);
|
||||||
def.angle = transform.RotationEuler.Z;
|
float3 worldRotationEuler = Quaternion.ToEulerAngles(worldRotation);
|
||||||
|
|
||||||
|
def.position = b2Vec2(worldPosition.X, worldPosition.Y);
|
||||||
|
def.angle = worldRotationEuler.Z;
|
||||||
|
|
||||||
b2Body* body = Box2D.World.CreateBody(_physicsWorld2D, &def);
|
b2Body* body = Box2D.World.CreateBody(_physicsWorld2D, &def);
|
||||||
Box2D.Body.SetFixedRotation(body, rigidBody.FixedRotation);
|
Box2D.Body.SetFixedRotation(body, rigidBody.FixedRotation);
|
||||||
|
|
||||||
rigidBody.RuntimeBody = body;
|
rigidBody.RuntimeBody = body;
|
||||||
|
}
|
||||||
|
|
||||||
if (entity.TryGetComponent<BoxCollider2DComponent>(let boxCollider))
|
private Result<void> FindParentWithRigidbody(Entity entity, out Entity walker, out Rigidbody2DComponent* rigidbody, out Matrix rigidbodyTransform)
|
||||||
|
{
|
||||||
|
walker = entity;
|
||||||
|
rigidbody = null;
|
||||||
|
rigidbodyTransform = .Identity;
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
b2Shape* boxShape = Box2D.Shape.CreatePolygon();
|
// Found the parent with our beloved component
|
||||||
Box2D.Shape.PolygonSetAsBox(boxShape, boxCollider.Size.X * transform.Scale.X, boxCollider.Size.Y * transform.Scale.Y);
|
if (walker.TryGetComponent<Rigidbody2DComponent>(out rigidbody) == true)
|
||||||
Box2D.Shape.PolygonSetAsBoxWithCenterAngle(boxShape, boxCollider.Size.X * transform.Scale.X, boxCollider.Size.Y * transform.Scale.Y, ref boxCollider.b2Offset, 0.0f);
|
break;
|
||||||
|
|
||||||
b2FixtureDef fixtureDef = .();
|
let parent = walker.Parent;
|
||||||
fixtureDef.shape = boxShape;
|
|
||||||
fixtureDef.density = boxCollider.Density;
|
|
||||||
fixtureDef.friction = boxCollider.Friction;
|
|
||||||
fixtureDef.restitution = boxCollider.Restitution;
|
|
||||||
fixtureDef.restitutionThreshold = boxCollider.RestitutionThreshold;
|
|
||||||
|
|
||||||
b2Fixture* fixture = Box2D.Body.CreateFixture(body, &fixtureDef);
|
// We need a rigid body
|
||||||
boxCollider.RuntimeFixture = fixture;
|
if (parent == null)
|
||||||
|
{
|
||||||
|
Log.ClientLogger.Warning($"Entity {entity.Name} ({entity.Handle}) has a collider but no parent with a rigid body!");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct transform matrix from our local space to the rigidbody space
|
||||||
|
rigidbodyTransform = rigidbodyTransform * walker.Transform.LocalTransform;
|
||||||
|
|
||||||
|
walker = parent.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.TryGetComponent<CircleCollider2DComponent>(let circleCollider))
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitBoxCollider2D(Entity entity, BoxCollider2DComponent* boxCollider)
|
||||||
|
{
|
||||||
|
if (FindParentWithRigidbody(entity, let entityWithRigidbody, let rigidbody, let parentToRigidbody) case .Err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let localToWorld = entity.Transform.WorldTransform;
|
||||||
|
let worldToRigidbody = entityWithRigidbody.Transform.WorldTransform.Invert();
|
||||||
|
|
||||||
|
let boxShape = Box2D.Shape.CreatePolygon();
|
||||||
|
|
||||||
|
Box2D.b2Vec2[4] points = .(
|
||||||
|
.(-1, -1),
|
||||||
|
.( 1, -1),
|
||||||
|
.( 1, 1),
|
||||||
|
.(-1, 1));
|
||||||
|
|
||||||
|
for (int i < 4)
|
||||||
{
|
{
|
||||||
b2Shape* circleShape = Box2D.Shape.CreateCircle();
|
points[i] = ((float2)points[i] * boxCollider.Size + boxCollider.Offset);
|
||||||
Box2D.Shape.CircleSetPosition(circleShape, ref circleCollider.b2Offset);
|
|
||||||
Box2D.Shape.SetRadius(circleShape, circleCollider.Radius);
|
|
||||||
|
|
||||||
b2FixtureDef fixtureDef = .();
|
if (entity == entityWithRigidbody)
|
||||||
fixtureDef.shape = circleShape;
|
points[i] = entity.Transform.Scale.XY * (float2)points[i];
|
||||||
fixtureDef.density = circleCollider.Density;
|
|
||||||
fixtureDef.friction = circleCollider.Friction;
|
|
||||||
fixtureDef.restitution = circleCollider.Restitution;
|
|
||||||
fixtureDef.restitutionThreshold = circleCollider.RestitutionThreshold;
|
|
||||||
|
|
||||||
b2Fixture* fixture = Box2D.Body.CreateFixture(body, &fixtureDef);
|
points[i] = (worldToRigidbody * localToWorld * float4(points[i], 0, 1)).XY;
|
||||||
circleCollider.RuntimeFixture = fixture;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shape.PolygonSet(boxShape, &points, 4);
|
||||||
|
|
||||||
|
b2FixtureDef fixtureDef = .();
|
||||||
|
fixtureDef.shape = boxShape;
|
||||||
|
fixtureDef.density = boxCollider.Density;
|
||||||
|
fixtureDef.friction = boxCollider.Friction;
|
||||||
|
fixtureDef.restitution = boxCollider.Restitution;
|
||||||
|
fixtureDef.restitutionThreshold = boxCollider.RestitutionThreshold;
|
||||||
|
fixtureDef.userData = (void*)(uint)entity.Handle;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(rigidbody.RuntimeBody != null);
|
||||||
|
b2Fixture* fixture = Box2D.Body.CreateFixture(rigidbody.RuntimeBody, &fixtureDef);
|
||||||
|
boxCollider.RuntimeFixture = fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitCircleCollider2D(Entity entity, CircleCollider2DComponent* circleCollider)
|
||||||
|
{
|
||||||
|
if (FindParentWithRigidbody(entity, let entityWithRigidbody, let rigidbody, let parentToRigidbody) case .Err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let localToWorld = entity.Transform.WorldTransform;
|
||||||
|
let worldToRigidbody = entityWithRigidbody.Transform.WorldTransform.Invert();
|
||||||
|
|
||||||
|
b2Vec2 center = (worldToRigidbody * localToWorld * float4(circleCollider.b2Offset, 0, 1)).XY;
|
||||||
|
|
||||||
|
b2Shape* circleShape = Box2D.Shape.CreateCircle();
|
||||||
|
Box2D.Shape.CircleSetPosition(circleShape, center);
|
||||||
|
Box2D.Shape.SetRadius(circleShape, circleCollider.Radius);
|
||||||
|
|
||||||
|
b2FixtureDef fixtureDef = .();
|
||||||
|
fixtureDef.shape = circleShape;
|
||||||
|
fixtureDef.density = circleCollider.Density;
|
||||||
|
fixtureDef.friction = circleCollider.Friction;
|
||||||
|
fixtureDef.restitution = circleCollider.Restitution;
|
||||||
|
fixtureDef.restitutionThreshold = circleCollider.RestitutionThreshold;
|
||||||
|
fixtureDef.userData = (void*)(uint)entity.Handle;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(rigidbody.RuntimeBody != null);
|
||||||
|
b2Fixture* fixture = Box2D.Body.CreateFixture(rigidbody.RuntimeBody, &fixtureDef);
|
||||||
|
circleCollider.RuntimeFixture = fixture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSimulationStop()
|
public void OnSimulationStop()
|
||||||
@@ -335,8 +536,24 @@ namespace GlitchyEngine.World
|
|||||||
b2Vec2 position = Box2D.Body.GetPosition(body);
|
b2Vec2 position = Box2D.Body.GetPosition(body);
|
||||||
float angle = Box2D.Body.GetAngle(body);
|
float angle = Box2D.Body.GetAngle(body);
|
||||||
|
|
||||||
transform.Position = .(position.x, position.y, transform.Position.Z);
|
if (entity.Parent != null)
|
||||||
transform.RotationEuler = .(transform.RotationEuler.XY, angle);
|
{
|
||||||
|
Matrix worldToParent = entity.Parent.Value.Transform.WorldTransform.Invert();
|
||||||
|
|
||||||
|
float4 newLocalPosition = worldToParent * float4(position, 0, 1);
|
||||||
|
transform.Position = float3(newLocalPosition.XY, transform.Position.Z);
|
||||||
|
|
||||||
|
// TODO: when the parent of the rigidbody-entity is rotated, the rotation is applied wrong...
|
||||||
|
Matrix.Decompose(worldToParent, let p, var worldToParentRotation, let s);
|
||||||
|
Quaternion newLocalRotation = (worldToParentRotation * Quaternion.FromEulerAngles(0, 0, angle))..Normalize();
|
||||||
|
// TODO: when the parent has rotation on X or Y everything breaks even more...
|
||||||
|
transform.Rotation = (newLocalRotation * Quaternion.FromEulerAngles(transform.RotationEuler.Y, transform.RotationEuler.X, 0))..Normalize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transform.Position = .(position.x, position.y, transform.Position.Z);
|
||||||
|
transform.RotationEuler = .(transform.RotationEuler.XY, angle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,9 @@ class SceneRenderer
|
|||||||
|
|
||||||
DrawDebug2D();
|
DrawDebug2D();
|
||||||
|
|
||||||
|
if (Scene._physicsWorld2D != null)
|
||||||
|
Box2D.World.DebugDraw(Scene._physicsWorld2D);
|
||||||
|
|
||||||
Renderer2D.EndScene();
|
Renderer2D.EndScene();
|
||||||
|
|
||||||
// Gamma correct composit target and draw it into viewport
|
// Gamma correct composit target and draw it into viewport
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using GlitchyEngine.Math;
|
|||||||
|
|
||||||
namespace GlitchyEngine;
|
namespace GlitchyEngine;
|
||||||
|
|
||||||
public class RigidBody2D : Component
|
public class Rigidbody2D : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply a force at a world point.
|
/// Apply a force at a world point.
|
||||||
|
|||||||
@@ -15,17 +15,13 @@ internal struct EntityHandle
|
|||||||
|
|
||||||
public class Entity : EngineObject
|
public class Entity : EngineObject
|
||||||
{
|
{
|
||||||
//private UUID _uuid;
|
|
||||||
|
|
||||||
//public UUID UUID => _uuid;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Empty constructor not used. Do NOT USE!
|
/// Empty constructor not used. Do NOT USE!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Entity()
|
protected Entity()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
private Entity(UUID uuid)
|
internal Entity(UUID uuid)
|
||||||
{
|
{
|
||||||
_uuid = uuid;
|
_uuid = uuid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Physics;
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack=1)]
|
||||||
|
public struct Collision2D
|
||||||
|
{
|
||||||
|
private UUID _entity;
|
||||||
|
private UUID _otherEntity;
|
||||||
|
|
||||||
|
private UUID _rigidbody;
|
||||||
|
private UUID _otherRigidbody;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Entity whose Collider takes part in the collision.
|
||||||
|
/// This entity is either the entity of the script instance receiving the event or a child of it.
|
||||||
|
/// </summary>
|
||||||
|
public Entity Entity => new(_entity);
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the other Entity whose collider takes part in the collision.
|
||||||
|
/// </summary>
|
||||||
|
public Entity OtherEntity => new(_otherEntity);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the rigidbody whose Collider takes part in the collision.
|
||||||
|
/// This Rigidbody is either a component of the entity whose script instance received the event or a parent of it.
|
||||||
|
/// </summary>
|
||||||
|
public Rigidbody2D Rigidbody => new() { Entity = Entity };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the other rigidbody whose Collider takes part in the collision.
|
||||||
|
/// </summary>
|
||||||
|
public Rigidbody2D OtherRigidbody => new() { Entity = OtherEntity };
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<BaseOutputPath></BaseOutputPath>
|
<BaseOutputPath></BaseOutputPath>
|
||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
|
<RootNamespace>GlitchyEngine</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||||
|
|||||||
Reference in New Issue
Block a user