The Socket
system allows users to snap/attach an entity to a specific Socket
entity. We called the socketed entity Socketable
.
The main case we can use Socket-Socketable
is when we want an object/entity to be placed in a specific position and rotation every time.
Whenever user move the Socketable
entity close/touching the Socket's
collider, the Socketable
entity will be snapped to the Socket's
position. For this to happen, both socket and socketable must have same SocketFilterData
.
Important: Both Socket
and Socketable
needs to be Ghost entity because they need to be synched between server and client.
Core Components
Socket
Marks an entity as socket and keep the reference to the SocketableEntity
socketed to it:
public struct Socket : IComponentData, IEnableableComponent
{
public Entity SocketableEntity;
}
Socketable
Marks an entity as socketable that is allowed to be socketed to a socket:
public struct Socketable : IComponentData, IEnableableComponent
{
public bool HintOverriden;
}
SocketFilterData
Buffer added to socket and socketable during authoring so that both can hold a list of socket filters:
[InternalBufferCapacity(2)]
public struct SocketFilterData : IBufferElementData
{
public FixedString64Bytes SocketFilter;
}
SocketableHintTemplate
Specify source entities that will be used when initializing hint entities at runtime when the socket hint is shown whether it is available or overlapped.
public struct SocketableHintTemplate : IComponentData
{
public Entity HintAvailableTemplateEntity;
public Entity HintOverlapTemplateEntity;
}
SocketableHintTemplatesInitialized
Tags the socketables, whose hints templates have not been created yet.
public struct SocketableHintTemplatesInitialized : IComponentData, IEnableableComponent { }
SocketableHintTemplateInstance
Tags the hint template entities created at runtime from either Socketable
itself or SocketableHintTemplate.HintAvailableTemplateEntity/HintOverlapTemplateEntity
.
public struct SocketableHintTemplateInstance : IComponentData, IEnableableComponent
{
public Entity Socketable;
public bool IsAvailable;
}
SocketableHintVisual
Tag the instantiated hint entities from socketable's template entities when socketable is grabbed. It keeps reference to the instantiated hint entity. SocketVisualSystem caches the entities with this component to avoid creating and destroying every frame. It also allows querying all the instantiated hint objects easily.
public struct SocketableHintVisual : IComponentData
{
public Entity Instance;
}
SocketOverlap
Marks that a socketable overlaps with a socket entity. The overlapped socket entity is also saved in the component:
public struct SocketOverlap : IComponentData, IEnableableComponent
{
public Entity SocketEntity;
}
SocketFilter
SocketFilter
is a scriptable object to be used to define socketable-socket pairs. It can be created by Create->SocketSystem/SocketFilter
.
Intended Use
Basic Setup
Socket
To make an entity socket, add Socket
and PhysicsCollider
components:
var entity = EntityManager.CreateEntity(
typeof(LocalTransform),
typeof(LocalToWorld),
typeof(Socket));
EntityManager.AddComponentData(entity, new PhysicsCollider
{
Value = BoxCollider.Create(
new BoxGeometry
{
Center = float3.zero,
Orientation = quaternion.identity,
Size = new float3(0.2f),
},
CollisionFilter.Default
),
});
Socketable
To make an entity socketable, add Socketable
, SocketOverlap
, SocketableHintTemplate
components.
var entity = EntityManager.CreateEntity(
typeof(LocalTransform),
typeof(LocalToWorld),
typeof(Interactable),
typeof(ActiveInteractable),
typeof(Attachable),
typeof(Movable),
typeof(Socketable),
typeof(SocketOverlap));
EntityManager.AddComponentData(entity, new SocketableHintTemplate()
{
HintAvailableTemplateEntity = GetEntity(authoring.HintOverride, TransformUsageFlags.Dynamic),
HintOverlapTemplateEntity = GetEntity(authoring.HintOverride, TransformUsageFlags.Dynamic)
});
var socketFilterDatas = AddBuffer<SocketFilterData>(entity);
foreach (
var socketFilterData in from socketFilter in authoring.SocketFilters
where socketFilter != null
select new SocketFilterData { SocketFilter = socketFilter.GUID ?? string.Empty }
)
{
socketFilterDatas.Add(socketFilterData);
}
EntityManager.SetComponentEnabled<Socketable>(entity, true);
EntityManager.SetComponentEnabled<SocketOverlap>(entity, false);
EntityManager.AddComponentData(entity, new PhysicsCollider
{
Value = BoxCollider.Create(
new BoxGeometry
{
Center = float3.zero,
Orientation = quaternion.identity,
Size = new float3(0.2f),
},
CollisionFilter.Default
),
});
Base Flow
- Socketable hints entities are generated as children of socketables in
SocketHintInitializationSystem
.
- When any socketable entity is grabbed, a new hint entity is instantiated from
SocketableHintTemplate
.HintAvailableTemplateEntity
in the location of all of the sockets with same SocketFilter
.
- When the grabbed socketable entity is overlapping with socket entity,
SocketOverlap
in socketable entity is enabled. Then a new hint entity is instantiated from SocketableHintTemplate
.HintOverlapTemplateEntity
under the overlapped socket.
- When the grabbed socketable entity is released while it is overlapping, the socketable entity will be socketed to the socket entity.
- When the socketable entity is grabbed by the interactor (hand) while it is socketed, the socketable entity will desocket from its socket making the socket to be available again.