Files
sbox-public/engine/Sandbox.Engine/Scene/Components/Map/MapInstance.Collision.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

183 lines
4.0 KiB
C#

namespace Sandbox;
partial class MapInstance
{
private PhysicsGroupDescription Physics;
private List<PhysicsBody> Bodies { get; set; } = new();
private List<CollisionEventSystem> CollisionEvents { get; set; } = new();
private MapCollider Collider { get; set; }
protected override void OnDirty()
{
AddCollision();
foreach ( var body in Bodies )
{
if ( !body.IsValid() )
continue;
body.Enabled = EnableCollision;
}
}
protected override void OnTagsChanged()
{
UpdateTags();
}
private void UpdateTags()
{
if ( !_mapPhysics.IsValid() )
return;
foreach ( var body in Bodies )
{
if ( !body.IsValid() )
continue;
var shapes = body.Shapes;
foreach ( var shape in shapes )
{
shape.Tags.SetFrom( _mapPhysics.Tags );
}
}
}
private void RemoveCollision()
{
foreach ( var e in CollisionEvents )
e.Dispose();
CollisionEvents.Clear();
foreach ( var body in Bodies )
{
if ( !body.IsValid() )
continue;
body.Remove();
}
Bodies.Clear();
}
private void AddCollision()
{
if ( Bodies.Any() )
return;
if ( !EnableCollision )
return;
if ( Physics is null )
return;
if ( Physics.Parts.Count == 0 )
return;
var world = NoOrigin ? new Transform( 0 ) : WorldTransform.WithScale( 1.0f );
foreach ( var part in Physics.Parts )
{
Assert.NotNull( part, "Physics part was null" );
var body = new PhysicsBody( Scene.PhysicsWorld );
body.Component = Collider;
body.Transform = world;
Bodies.Add( body );
CollisionEvents.Add( new CollisionEventSystem( body ) );
var local = part.Transform;
foreach ( var sphere in part.Spheres )
{
var shape = body.AddSphereShape( local.PointToWorld( sphere.Sphere.Center ), sphere.Sphere.Radius * local.UniformScale );
Assert.NotNull( shape, "Sphere shape was null" );
shape.Surface = sphere.Surface;
}
foreach ( var capsule in part.Capsules )
{
var shape = body.AddCapsuleShape( local.PointToWorld( capsule.Capsule.CenterA ), local.PointToWorld( capsule.Capsule.CenterB ), capsule.Capsule.Radius * local.UniformScale );
Assert.NotNull( shape, "Capsule shape was null" );
shape.Surface = capsule.Surface;
}
foreach ( var hull in part.Hulls )
{
var shape = body.AddShape( hull, local );
Assert.NotNull( shape, "Hull shape was null" );
shape.Surface = hull.Surface;
}
foreach ( var mesh in part.Meshes )
{
var shape = body.AddShape( mesh, local, false );
Assert.NotNull( shape, "Mesh shape was null" );
shape.Surface = mesh.Surface;
shape.Surfaces = mesh.Surfaces;
}
SetCollisionAttributes( body, part );
}
UpdateTags();
}
private void SetCollisionAttributes( PhysicsBody body, PhysicsGroupDescription.BodyPart part )
{
if ( !body.IsValid() )
return;
var shapeCount = body.ShapeCount;
var indicesCount = part.native.GetCollisionAttributeCount();
var attributeCount = Physics.native.GetCollisionAttributeCount();
if ( indicesCount > 0 )
{
if ( indicesCount != shapeCount )
{
Log.Warning( $"Inconsistent collision attribute index array of size {indicesCount}, expected {shapeCount} (number of shapes)" );
}
for ( int i = 0; i < shapeCount && i < indicesCount; ++i )
{
var index = part.native.GetCollisionAttributeIndex( i );
if ( index < attributeCount )
{
var shape = body.native.GetShape( i );
if ( !shape.IsValid() )
continue;
var tags = Physics.GetTags( index );
if ( tags is null )
continue;
foreach ( var tag in tags )
{
shape.native.AddTag( tag.Value );
}
}
else
{
Log.Warning( $"Invalid collision attribute palette entry {index}, expected below {attributeCount}" );
}
}
}
else if ( part.native.m_nCollisionAttributeIndex < attributeCount )
{
var tags = Physics.GetTags( part.native.m_nCollisionAttributeIndex );
foreach ( var shape in body.Shapes )
{
foreach ( var tag in tags )
{
shape.native.AddTag( tag.Value );
}
}
}
}
}