class Shape
{
public float mass;
public Box boundingBox;
public virtual Vector SupportMapping(ref Vector direction)
{
//do some thing default
}
}
class BoxShape : Shape
{
//some boxshape data
public virtual Vector SupportMapping(ref Vector direction)
{
//do some thing for box shape
}
}
class CapsuleShape : Shape
{
//some boxshape data
public virtual Vector SupportMapping(ref Vector direction)
{
//do some thing for box shape
}
}
class CollisionSystem
{
Shape theShape;
void Update()
{
//calculate some thing use SupportMapping
Vector sm = theShape.SupportMapping(direction);
}
}
There is a base class called Shape, a BoxShape class inherits from Shape, a CapsuleShape class inherits from Shape.
The Classic code I only need to write a CollisionSystem, use the virtual function provided by them to calculate.
With ECS, is it need to write a ShapeComponent, a BoxShapeComponent, a CapsuleShapeComponent, and then write a ShapeCollisionSystem, aBoxShapeCollisionSystem, a CapsuleShapeCollisionSystem.
This is too hard to write code, is there any skill to be more general?
You do this to learn yourself? There’s already collision system on Unity Physics package which works on ECS. Also a more limited setup on FPS Sample from Unity.
Just checking that you don’t do the same work that’s already done for nothing Again still not the point but Unity does plan to make the Unity Physics deterministic as well (it’s mainly waiting for Burst compiler update for it), just throwing that out there if that’s the reason why you are going for fixed-point physics.
Unity physics does it with interfaces and a base struct.
You really need to have a good understanding of Entities, DOD and pointers to implement something like this though.
Code snippet to explain what I mean
// Base struct common to all colliders.
// Dispatches the interface methods to appropriate implementations for the collider type.
public struct Collider : ICompositeCollider
{
private ColliderHeader m_Header;
#region ICollider
public ColliderType Type => m_Header.Type;
public CollisionType CollisionType => m_Header.CollisionType;
public unsafe int MemorySize
{
get
{
fixed (Collider* collider = &this)
{
switch (collider->Type)
{
case ColliderType.Convex:
return ((ConvexCollider*)collider)->MemorySize;
case ColliderType.Sphere:
return ((SphereCollider*)collider)->MemorySize;
case ColliderType.Capsule:
return ((CapsuleCollider*)collider)->MemorySize;
case ColliderType.Triangle:
case ColliderType.Quad:
return ((PolygonCollider*)collider)->MemorySize;
case ColliderType.Box:
return ((BoxCollider*)collider)->MemorySize;
case ColliderType.Cylinder:
return ((CylinderCollider*)collider)->MemorySize;
case ColliderType.Mesh:
return ((MeshCollider*)collider)->MemorySize;
case ColliderType.Compound:
return ((CompoundCollider*)collider)->MemorySize;
default:
//Assert.IsTrue(Enum.IsDefined(typeof(ColliderType), collider->Type));
return 0;
}
}
}
}
public CollisionFilter Filter
{
get => m_Header.Filter;
set
{
// Disallow changing the filter of composite types directly, since that is a combination of its children
if(m_Header.CollisionType == CollisionType.Convex)
{
m_Header.Filter = value;
}
}
}
public unsafe MassProperties MassProperties
{
get
{
fixed (Collider* collider = &this)
{
switch (collider->Type)
{
case ColliderType.Convex:
return ((ConvexCollider*)collider)->MassProperties;
case ColliderType.Sphere:
return ((SphereCollider*)collider)->MassProperties;
case ColliderType.Capsule:
return ((CapsuleCollider*)collider)->MassProperties;
case ColliderType.Triangle:
case ColliderType.Quad:
return ((PolygonCollider*)collider)->MassProperties;
case ColliderType.Box:
return ((BoxCollider*)collider)->MassProperties;
case ColliderType.Cylinder:
return ((CylinderCollider*)collider)->MassProperties;
case ColliderType.Mesh:
return ((MeshCollider*)collider)->MassProperties;
case ColliderType.Compound:
return ((CompoundCollider*)collider)->MassProperties;
default:
//Assert.IsTrue(Enum.IsDefined(typeof(ColliderType), collider->Type));
return MassProperties.UnitSphere;
}
}
}
}
#endregion
#region ICompositeCollider
public unsafe uint NumColliderKeyBits
{
get
{
fixed (Collider* collider = &this)
{
switch (collider->Type)
{
case ColliderType.Mesh:
return ((MeshCollider*)collider)->NumColliderKeyBits;
case ColliderType.Compound:
return ((CompoundCollider*)collider)->NumColliderKeyBits;
default:
//Assert.IsTrue(Enum.IsDefined(typeof(ColliderType), collider->Type));
return 0;
}
}
}
}
// ... ETC ETC
I would recommended against doing something like this though unless a) you’re doing it purely for educational purposes or b) you need extreme performance.
You shouldn’t really be thinking about inheritance at all. You need to stop thinking in OOP and start thinking DOD.
I just wanted to show how you can implement it, since you asked, not to tel you that you should implement it that way. You shouldn’t unless you really know what you’re doing and have a very good reason for doing it.
Thank you for your suggestion. I hope to have a concrete example. It is a little difficult to think lightly. I want to see how my example above turns into DOD and then get inspiration from it.
Well for an example if you know your shape has a mass and a bounding box, you can create two structures
BoundingBox → stores a float2 or whatever data consists of a box (if box is a class you would think about the data specifically of the class not the functionalities)
Mass → stores a float/double
It also looks like each derived shape has the same function, SupportMapping(…). You can make a system which queries all the data (BoundingBox, Mass, etc) you need regarding Shapes and run the SupportMapping(…) functionality on all matched elements in the query.