mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 21:01:52 +00:00
2D Physics
This commit is contained in:
@@ -337,4 +337,29 @@ namespace GlitchyEngine.World
|
||||
{
|
||||
public SceneLight SceneLight;
|
||||
}
|
||||
|
||||
struct Rigidbody2DComponent
|
||||
{
|
||||
public enum BodyType { Static = 0, Dynamic = 1, Kinematic = 2 }
|
||||
|
||||
public BodyType BodyType = .Static;
|
||||
|
||||
public bool FixedRotation = false;
|
||||
|
||||
internal int _runtimeBody = 0;
|
||||
}
|
||||
|
||||
struct BoxCollider2DComponent
|
||||
{
|
||||
public Vector2 Offset = .(0.0f, 0.0f);
|
||||
public Vector2 Size = .(0.5f, 0.5f);
|
||||
|
||||
// TODO: move into 2D physics material
|
||||
public float Density = 1.0f;
|
||||
public float Friction = 0.5f;
|
||||
public float Restitution = 0.0f;
|
||||
public float RestitutionThreshold = 0.5f;
|
||||
|
||||
internal int _runtimeFixture = 0;
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,8 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
}
|
||||
|
||||
public TransformComponent* Transform => GetComponent<TransformComponent>();
|
||||
|
||||
public T* AddComponent<T>(T value = T()) where T: struct, new
|
||||
{
|
||||
Log.EngineLogger.AssertDebug(!HasComponent<T>(), scope $"Entity already has component.");
|
||||
@@ -85,6 +87,18 @@ namespace GlitchyEngine.World
|
||||
{
|
||||
return _scene._ecsWorld.HasComponent<T>(_entity);
|
||||
}
|
||||
|
||||
public bool TryGetComponent<T>(out T* component) where T: struct, new
|
||||
{
|
||||
if (HasComponent<T>())
|
||||
{
|
||||
component = GetComponent<T>();
|
||||
return true;
|
||||
}
|
||||
|
||||
component = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RemoveComponent<T>() where T: struct, new
|
||||
{
|
||||
|
||||
@@ -2,19 +2,26 @@ using GlitchyEngine.Math;
|
||||
using GlitchyEngine.Renderer;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Box2D;
|
||||
|
||||
namespace GlitchyEngine.World
|
||||
{
|
||||
using internal ScriptableEntity;
|
||||
using internal GlitchyEngine.World;
|
||||
|
||||
class Scene
|
||||
{
|
||||
internal EcsWorld _ecsWorld = new .() ~ delete _;
|
||||
|
||||
|
||||
internal b2World* _physicsWorld2D;
|
||||
|
||||
private Dictionary<Type, function void(Entity entity, Type componentType, void* component)> _onComponentAddedHandlers = new .() ~ delete _;
|
||||
|
||||
private RenderTargetGroup _compositeTarget ~ _.ReleaseRef();
|
||||
|
||||
// Temporary target for camera. Needs to change as soon as we support multiple cameras
|
||||
private RenderTargetGroup _cameraTarget ~ _.ReleaseRef();
|
||||
|
||||
private Effect _gammaCorrectEffect ~ _.ReleaseRef();
|
||||
|
||||
public Entity ActiveCamera => {
|
||||
@@ -54,21 +61,134 @@ namespace GlitchyEngine.World
|
||||
RenderTargetFormat.D24_UNorm_S8_UInt);
|
||||
_compositeTarget = new RenderTargetGroup(desc);
|
||||
|
||||
_cameraTarget = new RenderTargetGroup(.(){
|
||||
Width = 100,
|
||||
Height = 100,
|
||||
ColorTargetDescriptions = TargetDescription[](
|
||||
.(.R16G16B16A16_Float),
|
||||
.(.R32_UInt)
|
||||
),
|
||||
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
|
||||
});
|
||||
|
||||
_gammaCorrectEffect = Application.Get().EffectLibrary.Load("content/Shaders/GammaCorrect.hlsl");
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
}
|
||||
|
||||
b2Vec2 _gravity2D = .(0.0f, -9.8f);
|
||||
|
||||
static b2BodyType GetBox2DBodyType(Rigidbody2DComponent.BodyType bodyType)
|
||||
{
|
||||
switch (bodyType)
|
||||
{
|
||||
case .Static:
|
||||
return .b2_staticBody;
|
||||
case .Dynamic:
|
||||
return .b2_dynamicBody;
|
||||
case .Kinematic:
|
||||
return .b2_kinematicBody;
|
||||
default:
|
||||
Log.EngineLogger.AssertDebug(false, "Unknown body type");
|
||||
return .b2_staticBody;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRuntimeStart()
|
||||
{
|
||||
_physicsWorld2D = Box2D.World.Create(ref _gravity2D);
|
||||
|
||||
for (var entry in _ecsWorld.Enumerate<Rigidbody2DComponent>())
|
||||
{
|
||||
Entity entity = .(entry.Entity, this);
|
||||
|
||||
var transform = entity.Transform;
|
||||
var rigidBody = entry.Component;
|
||||
|
||||
b2BodyDef def = .();
|
||||
def.type = GetBox2DBodyType(rigidBody.BodyType);
|
||||
|
||||
// TODO: breaks with hierarchy
|
||||
def.position = b2Vec2(transform.Position.X, transform.Position.Y);
|
||||
def.angle = transform.RotationEuler.Z;
|
||||
|
||||
b2Body* body = Box2D.World.CreateBody(_physicsWorld2D, &def);
|
||||
Box2D.Body.SetFixedRotation(body, rigidBody.FixedRotation);
|
||||
|
||||
rigidBody._runtimeBody = (int)(void*)body;
|
||||
|
||||
if (entity.TryGetComponent<BoxCollider2DComponent>(let boxCollider))
|
||||
{
|
||||
b2Shape* boxShape = Box2D.Shape.CreatePolygon();
|
||||
Box2D.Shape.PolygonSetAsBox(boxShape, boxCollider.Size.X * transform.Scale.X, boxCollider.Size.Y * transform.Scale.Y);
|
||||
|
||||
b2FixtureDef fixtureDef = .();
|
||||
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);
|
||||
boxCollider._runtimeFixture = (int)(void*)fixture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRuntimeStop()
|
||||
{
|
||||
Box2D.World.Delete(_physicsWorld2D);
|
||||
_physicsWorld2D = null;
|
||||
}
|
||||
|
||||
public void UpdateRuntime(GameTime gameTime, RenderTargetGroup finalTarget)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
finalTarget.AddRef();
|
||||
|
||||
|
||||
TransformSystem.Update(_ecsWorld);
|
||||
|
||||
// Run scripts
|
||||
for (var (entity, script) in _ecsWorld.Enumerate<NativeScriptComponent>())
|
||||
{
|
||||
if (script.Instance == null)
|
||||
{
|
||||
script.Instance = script.InstantiateFunction();
|
||||
script.Instance._entity = Entity(entity, this);
|
||||
script.Instance.[Friend]OnCreate();
|
||||
}
|
||||
|
||||
script.Instance.[Friend]OnUpdate(gameTime);
|
||||
}
|
||||
|
||||
// Update 2D physics
|
||||
{
|
||||
const int32 velocityIterations = 6;
|
||||
const int32 positionIterations = 2;
|
||||
const int32 particleIterations = 2;
|
||||
|
||||
Box2D.World.Step(_physicsWorld2D, gameTime.DeltaTime, velocityIterations, positionIterations, particleIterations);
|
||||
|
||||
// Retrieve transform from Box2D
|
||||
for (var entry in _ecsWorld.Enumerate<Rigidbody2DComponent>())
|
||||
{
|
||||
Entity entity = .(entry.Entity, this);
|
||||
|
||||
var transform = entity.Transform;
|
||||
var rigidbody = entry.Component;
|
||||
|
||||
b2Body* body = (b2Body*)(void*)rigidbody._runtimeBody;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Find camera
|
||||
Camera* primaryCamera = null;
|
||||
Matrix primaryCameraTransform = default;
|
||||
@@ -80,7 +200,8 @@ namespace GlitchyEngine.World
|
||||
{
|
||||
primaryCamera = &camera.Camera;
|
||||
primaryCameraTransform = transform.WorldTransform;
|
||||
renderTarget = camera.RenderTarget..AddRef();
|
||||
// TODO: bind render targets to cameras
|
||||
// renderTarget = camera.RenderTarget..AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,6 +513,7 @@ namespace GlitchyEngine.World
|
||||
}
|
||||
|
||||
_compositeTarget.Resize(ViewportWidth, ViewportHeight);
|
||||
_cameraTarget.Resize(ViewportWidth, ViewportHeight);
|
||||
}
|
||||
|
||||
private void OnComponentAdded(Entity entity, Type componentType, void* component)
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace GlitchyEngine.World
|
||||
// TODO: Texture
|
||||
|
||||
Serialize.Value(writer, "Color", component.Color);
|
||||
Serialize.Value(writer, "UvTransform", component.UvTransform);
|
||||
});
|
||||
|
||||
SerializeComponent<TransformComponent>(writer, entity, "TransformComponent", scope (component) =>
|
||||
@@ -128,6 +129,24 @@ namespace GlitchyEngine.World
|
||||
|
||||
Serialize.Value(writer, "Color", light.Color);
|
||||
});
|
||||
|
||||
SerializeComponent<Rigidbody2DComponent>(writer, entity, "Rigidbody2D", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "BodyType", component.BodyType);
|
||||
|
||||
Serialize.Value(writer, "FixedRotation", component.FixedRotation);
|
||||
});
|
||||
|
||||
SerializeComponent<BoxCollider2DComponent>(writer, entity, "BoxCollider2D", scope (component) =>
|
||||
{
|
||||
Serialize.Value(writer, "Offset", component.Offset);
|
||||
Serialize.Value(writer, "Size", component.Size);
|
||||
|
||||
Serialize.Value(writer, "Density", component.Density);
|
||||
Serialize.Value(writer, "Friction", component.Friction);
|
||||
Serialize.Value(writer, "Restitution", component.Restitution);
|
||||
Serialize.Value(writer, "RestitutionThreshold", component.RestitutionThreshold);
|
||||
});
|
||||
}
|
||||
|
||||
writer.EntryEnd();
|
||||
@@ -252,6 +271,8 @@ namespace GlitchyEngine.World
|
||||
// TODO: Texture
|
||||
|
||||
Try!(Deserialize.Value(reader, "Color", out component.Color));
|
||||
reader.EntryEnd();
|
||||
Try!(Deserialize.Value(reader, "UvTransform", out component.UvTransform));
|
||||
|
||||
return .Ok;
|
||||
}));
|
||||
@@ -337,9 +358,38 @@ namespace GlitchyEngine.World
|
||||
Deserialize.Value(reader, "Color", out light.[Friend]_color);
|
||||
return .Ok;
|
||||
}));
|
||||
case "Rigidbody2D":
|
||||
Try!(DeserializeComponent<Rigidbody2DComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
Deserialize.Value(reader, "BodyType", out component.BodyType);
|
||||
reader.EntryEnd();
|
||||
|
||||
Deserialize.Value(reader, "FixedRotation", out component.FixedRotation);
|
||||
|
||||
return .Ok;
|
||||
}));
|
||||
case "BoxCollider2D":
|
||||
Try!(DeserializeComponent<BoxCollider2DComponent>(reader, entity, scope (component) =>
|
||||
{
|
||||
Deserialize.Value(reader, "Offset", out component.Offset);
|
||||
reader.EntryEnd();
|
||||
Deserialize.Value(reader, "Size", out component.Size);
|
||||
reader.EntryEnd();
|
||||
|
||||
Deserialize.Value(reader, "Density", out component.Density);
|
||||
reader.EntryEnd();
|
||||
Deserialize.Value(reader, "Friction", out component.Friction);
|
||||
reader.EntryEnd();
|
||||
Deserialize.Value(reader, "Restitution", out component.Restitution);
|
||||
reader.EntryEnd();
|
||||
Deserialize.Value(reader, "RestitutionThreshold", out component.RestitutionThreshold);
|
||||
|
||||
return .Ok;
|
||||
}));
|
||||
|
||||
default:
|
||||
return .Err;
|
||||
Log.EngineLogger.AssertDebug(false, "Unknown component type");
|
||||
//return .Err;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user