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>())
|
||||
{
|
||||
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>())
|
||||
|
||||
@@ -24,6 +24,14 @@ public struct float2
|
||||
{
|
||||
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]
|
||||
|
||||
@@ -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 GlitchyEngine.Core;
|
||||
using System.Collections;
|
||||
using GlitchyEngine.Scripting.Classes;
|
||||
|
||||
namespace GlitchyEngine.Scripting;
|
||||
|
||||
@@ -288,6 +289,14 @@ class ScriptClass : SharpClass
|
||||
private OnUpdateMethod _onUpdate;
|
||||
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 ClassName => _className;
|
||||
public StringView FullName => _fullName;
|
||||
@@ -303,6 +312,11 @@ class ScriptClass : SharpClass
|
||||
_onCreate = (OnCreateMethod)GetMethodThunk("OnCreate");
|
||||
_onUpdate = (OnUpdateMethod)GetMethodThunk("OnUpdate", 1);
|
||||
_onDestroy = (OnDestroyMethod)GetMethodThunk("OnDestroy");
|
||||
|
||||
_onCollisionEnter2D = (.)GetMethodThunk("OnCollisionEnter2D", 1);
|
||||
_onCollisionLeave2D = (OnDestroyMethod)GetMethodThunk("OnCollisionLeave2D");
|
||||
|
||||
_onCollisionEnter2DMethod = GetMethod("OnCollisionEnter2D", 1);
|
||||
}
|
||||
|
||||
public void OnCreate(MonoObject* instance, out MonoException* exception)
|
||||
@@ -329,6 +343,22 @@ class ScriptClass : SharpClass
|
||||
_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)
|
||||
{
|
||||
MonoObject* instance = Mono.mono_object_new(ScriptEngine.[Friend]s_AppDomain, _monoClass);
|
||||
|
||||
@@ -64,7 +64,7 @@ static class ScriptGlue
|
||||
s_RemoveComponentMethods.Clear();
|
||||
|
||||
RegisterComponent<TransformComponent>("GlitchyEngine.Transform");
|
||||
RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.RigidBody2D");
|
||||
RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.Rigidbody2D");
|
||||
}
|
||||
|
||||
[RegisterMethod]
|
||||
@@ -99,7 +99,7 @@ static class ScriptGlue
|
||||
}
|
||||
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 GlitchyEngine.Core;
|
||||
using System;
|
||||
using GlitchyEngine.Scripting.Classes;
|
||||
|
||||
namespace GlitchyEngine.Scripting;
|
||||
|
||||
@@ -81,6 +82,17 @@ class ScriptInstance : RefCounter
|
||||
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)
|
||||
{
|
||||
return _scriptClass.GetFieldValue<T>(_instance, field.[Friend]_monoField);
|
||||
|
||||
@@ -92,6 +92,23 @@ namespace GlitchyEngine.World
|
||||
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
|
||||
{
|
||||
return _scene._ecsWorld.HasComponent<T>(_entity);
|
||||
|
||||
@@ -6,6 +6,8 @@ using Box2D;
|
||||
using GlitchyEngine.Core;
|
||||
using GlitchyEngine.Content;
|
||||
using GlitchyEngine.Scripting;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine.Scripting.Classes;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
@@ -17,6 +19,8 @@ namespace GlitchyEngine.World
|
||||
internal EcsWorld _ecsWorld = new .() ~ delete _;
|
||||
|
||||
internal b2World* _physicsWorld2D;
|
||||
b2ContactListener _contactListener;
|
||||
b2Draw draw = .();
|
||||
|
||||
private Dictionary<Type, function void(Entity entity, Type componentType, void* component)> _onComponentAddedHandlers = new .() ~ delete _;
|
||||
|
||||
@@ -173,14 +177,143 @@ namespace GlitchyEngine.World
|
||||
|
||||
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>())
|
||||
{
|
||||
Entity entity = .(ecsHandle, this);
|
||||
|
||||
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)
|
||||
@@ -189,49 +322,117 @@ namespace GlitchyEngine.World
|
||||
|
||||
b2BodyDef def = .();
|
||||
def.type = GetBox2DBodyType(rigidBody.BodyType);
|
||||
def.userData = (void*)(uint)entity.Handle;
|
||||
|
||||
// TODO: breaks with hierarchy
|
||||
def.position = b2Vec2(transform.Position.X, transform.Position.Y);
|
||||
def.angle = transform.RotationEuler.Z;
|
||||
// TODO: check how stable this is
|
||||
Matrix.Decompose(transform.WorldTransform, let worldPosition, let worldRotation, let worldScale);
|
||||
float3 worldRotationEuler = Quaternion.ToEulerAngles(worldRotation);
|
||||
|
||||
def.position = b2Vec2(worldPosition.X, worldPosition.Y);
|
||||
def.angle = worldRotationEuler.Z;
|
||||
|
||||
b2Body* body = Box2D.World.CreateBody(_physicsWorld2D, &def);
|
||||
Box2D.Body.SetFixedRotation(body, rigidBody.FixedRotation);
|
||||
|
||||
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();
|
||||
Box2D.Shape.PolygonSetAsBox(boxShape, boxCollider.Size.X * transform.Scale.X, boxCollider.Size.Y * transform.Scale.Y);
|
||||
Box2D.Shape.PolygonSetAsBoxWithCenterAngle(boxShape, boxCollider.Size.X * transform.Scale.X, boxCollider.Size.Y * transform.Scale.Y, ref boxCollider.b2Offset, 0.0f);
|
||||
// Found the parent with our beloved component
|
||||
if (walker.TryGetComponent<Rigidbody2DComponent>(out rigidbody) == true)
|
||||
break;
|
||||
|
||||
b2FixtureDef fixtureDef = .();
|
||||
fixtureDef.shape = boxShape;
|
||||
fixtureDef.density = boxCollider.Density;
|
||||
fixtureDef.friction = boxCollider.Friction;
|
||||
fixtureDef.restitution = boxCollider.Restitution;
|
||||
fixtureDef.restitutionThreshold = boxCollider.RestitutionThreshold;
|
||||
let parent = walker.Parent;
|
||||
|
||||
b2Fixture* fixture = Box2D.Body.CreateFixture(body, &fixtureDef);
|
||||
boxCollider.RuntimeFixture = fixture;
|
||||
// We need a rigid body
|
||||
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();
|
||||
Box2D.Shape.CircleSetPosition(circleShape, ref circleCollider.b2Offset);
|
||||
Box2D.Shape.SetRadius(circleShape, circleCollider.Radius);
|
||||
points[i] = ((float2)points[i] * boxCollider.Size + boxCollider.Offset);
|
||||
|
||||
b2FixtureDef fixtureDef = .();
|
||||
fixtureDef.shape = circleShape;
|
||||
fixtureDef.density = circleCollider.Density;
|
||||
fixtureDef.friction = circleCollider.Friction;
|
||||
fixtureDef.restitution = circleCollider.Restitution;
|
||||
fixtureDef.restitutionThreshold = circleCollider.RestitutionThreshold;
|
||||
if (entity == entityWithRigidbody)
|
||||
points[i] = entity.Transform.Scale.XY * (float2)points[i];
|
||||
|
||||
b2Fixture* fixture = Box2D.Body.CreateFixture(body, &fixtureDef);
|
||||
circleCollider.RuntimeFixture = fixture;
|
||||
points[i] = (worldToRigidbody * localToWorld * float4(points[i], 0, 1)).XY;
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -335,8 +536,24 @@ namespace GlitchyEngine.World
|
||||
b2Vec2 position = Box2D.Body.GetPosition(body);
|
||||
float angle = Box2D.Body.GetAngle(body);
|
||||
|
||||
transform.Position = .(position.x, position.y, transform.Position.Z);
|
||||
transform.RotationEuler = .(transform.RotationEuler.XY, angle);
|
||||
if (entity.Parent != null)
|
||||
{
|
||||
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();
|
||||
|
||||
if (Scene._physicsWorld2D != null)
|
||||
Box2D.World.DebugDraw(Scene._physicsWorld2D);
|
||||
|
||||
Renderer2D.EndScene();
|
||||
|
||||
// Gamma correct composit target and draw it into viewport
|
||||
|
||||
@@ -2,7 +2,7 @@ using GlitchyEngine.Math;
|
||||
|
||||
namespace GlitchyEngine;
|
||||
|
||||
public class RigidBody2D : Component
|
||||
public class Rigidbody2D : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Apply a force at a world point.
|
||||
|
||||
@@ -15,17 +15,13 @@ internal struct EntityHandle
|
||||
|
||||
public class Entity : EngineObject
|
||||
{
|
||||
//private UUID _uuid;
|
||||
|
||||
//public UUID UUID => _uuid;
|
||||
|
||||
/// <summary>
|
||||
/// Empty constructor not used. Do NOT USE!
|
||||
/// </summary>
|
||||
protected Entity()
|
||||
{ }
|
||||
|
||||
private Entity(UUID uuid)
|
||||
internal Entity(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>
|
||||
<BaseOutputPath></BaseOutputPath>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<RootNamespace>GlitchyEngine</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
|
||||
Reference in New Issue
Block a user