Reconstruct the physical Entity architecture to support more shapes

The previous section showed how to compile the BEPUphysicsint source code into your own project and how to integrate the physics engine and Unity graphics rendering. This section will re-adjust the design to separate the basic operations of physical entities from physical shapes, support more physical shapes, and support the synchronization of displacement and rotation between physical entities and Unity objects. Mainly divided into the following 3 parts:

Yes, there is a game development exchange group. I hope everyone can click in to exchange development experiences together!

PhyBaseEntity Design

The PhyBoxEntity we designed in the previous lesson mainly contains two parts. One is the creation of the physical shape of the Entity (this is related to the specific shape), and the other is the basic functions of the physical Entity, such as position, rotation synchronization, and linear speed for the Entity. wait. Moreover, the physical entities of other shapes are basically the same except for the shape creation, so we adjust the design and change

Next, we extract the shape-independent data and functions of PhyBoxEntity from the previous lesson into PhyBaseEntity. PhyBoxEntity only retains shape-related code. Shape-independent data portion:

public class PhyBaseEntity : MonoBehaviour {
    protected BEPUphysics.Entities.Entity phyEntity = null;
    protected Vector3 center = Vector3.zero;
    [SerializeField]
    protected float mass = 1;

    protected bool isTrigger = false;
    protected PhysicMaterial phyMat = null;
    
    [SerializeField]
    protected bool isStatic = false;
}

Synchronize the displacement and rotation of physical Entity and Unity nodes

At the same time, PhyBaseEntity implements the function of synchronizing physical Entity and Unity nodes and adds position + rotation. As shown in the code:

public void AddSelfToPhyWorld() {
        if(this.phyEntity == null) {
            return;
        }

        BEPUPhyMgr.Instance.space.Add(this.phyEntity);
    }

    public void SyncPhyTransformWithUnityTransform() {
        if (this.phyEntity == null) {
            return;
        }


        // Location
        Vector3 unityPos = this.transform.position;
        unityPos + = this.center;
        this.phyEntity.position = ConversionHelper.MathConverter.Convert(unityPos);
        // end

        // rotate
        Quaternion rot = this.transform.rotation;
        this.phyEntity.orientation = ConversionHelper.MathConverter.Convert(rot);
        // end
    }

    public void SyncUnityTransformWithPhyTransform() {
        if (this.phyEntity == null) {
            return;
        }

        // Location
        BEPUutilities.Vector3 pos = this.phyEntity.position;
        Vector3 unityPosition = ConversionHelper.MathConverter.Convert(pos);
        unityPosition -= this.center;
        this.transform.position = unityPosition;
        // end

        // rotate
        BEPUutilities.Quaternion rot = this.phyEntity.orientation;
        Quaternion r = ConversionHelper.MathConverter.Convert(rot);
        this.transform.rotation = r;
        // end
    }

    //Synchronize the position of the physical entity to transform;
    void LateUpdate() {
        if (this.phyEntity == null || this.isStatic) {
            return;
        }

        this.SyncUnityTransformWithPhyTransform();
    }

Interface SyncUnityTransformWithPhyTransform: synchronize from physical Entity to Unity node

Interface SyncPhyTransformWithUnityTransform: synchronize from Unity node to physical Entity

Looking at the adjusted PhyBoxEntity, it’s very simple:

[RequireComponent(typeof(BoxCollider))]
public class PhyBoxEntity : PhyBaseEntity {
    
    void Start() {
        BoxCollider box = this.gameObject.GetComponent<BoxCollider>();
        float width = box.size.x;
        float height = box.size.y;
        float length = box.size.z;
        
        this.center = box.center;
        this.phyMat = box.material;
        this.isTrigger = box.isTrigger;


        if (this.isStatic) {
            this.phyEntity = new BEPUphysics.Entities.Prefabs.Box(BEPUutilities.Vector3.Zero, (FixMath.NET.Fix64)width, (FixMath.NET.Fix64)height, (FixMath.NET.Fix64)length);
        }
        else {
            this.phyEntity = new BEPUphysics.Entities.Prefabs.Box(BEPUutilities.Vector3.Zero, (FixMath.NET.Fix64)width, (FixMath.NET.Fix64)height, (FixMath.NET.Fix64)length, (FixMath.NET .Fix64)this.mass);
        }

        this.AddSelfToPhyWorld();
        this.SyncPhyTransformWithUnityTransform();
    }

   
}

Create the physical entity of the Box based on the data of the BoxCollider, synchronize it to the position and rotation of the Unity node, and add it to the physical world.

Write physical entities of other shapes

After the above adjustments, we quickly wrote other shapes, such as implementing PhySphereEntity,

[RequireComponent(typeof(SphereCollider))]
public class PhySphereEntity : PhyBaseEntity
{
    // Start is called before the first frame update
    void Start() {
        SphereCollider sphere = this.gameObject.GetComponent<SphereCollider>();

        float radius = sphere.radius;

        this.center = sphere.center;
        this.phyMat = sphere.material;
        this.isTrigger = sphere.isTrigger;

        if (this.isStatic) {
            this.phyEntity = new BEPUphysics.Entities.Prefabs.Sphere(BEPUutilities.Vector3.Zero, (FixMath.NET.Fix64)radius);
        }
        else {
            this.phyEntity = new BEPUphysics.Entities.Prefabs.Sphere(BEPUutilities.Vector3.Zero, (FixMath.NET.Fix64)radius, (FixMath.NET.Fix64)this.mass);
        }

        this.AddSelfToPhyWorld();
        this.SyncPhyTransformWithUnityTransform();
    }
}

That’s it for today’s design adjustments of the physical entity. Follow us to get the actual source code of Unity BEPUphysint3D.