Skip to content

Instantly share code, notes, and snippets.

@thelebaron
Created January 11, 2020 08:19
Show Gist options
  • Save thelebaron/67ac2e81ffe947ee26ae5365dbbe3a84 to your computer and use it in GitHub Desktop.
Save thelebaron/67ac2e81ffe947ee26ae5365dbbe3a84 to your computer and use it in GitHub Desktop.
using Game.Components;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Authoring;
using Unity.Physics.Systems;
using Unity.Transforms;
using UnityEngine;
using Material = Unity.Physics.Material;
public struct Door : IComponentData
{
public Entity Trigger;
public Entity Collider;
public float3 OpenPosition;
public float3 ClosedPosition;
public float Speed;
public bool Use;
public float MovementDuraction;
public DoorState State;
public float CurrentMoveTime;
}
public struct DoorTrigger : IComponentData
{
public Entity Door;
public bool Use;
}
public enum DoorState
{
Closed, Opened, Opening, Closing
}
[RequiresEntityConversion]
[DisallowMultipleComponent]
[SelectionBase]
public class DoorAuthoring : MonoBehaviour, IConvertGameObjectToEntity
{
[Header("Trigger")]
[SerializeField] private PhysicsCategoryTags triggerBelongsTo;
[SerializeField] private PhysicsCategoryTags triggerCollidesWith;
[SerializeField] private Vector3 triggerCenter;
[SerializeField] private Vector3 triggerDimensions = Vector3.one;
[Header("Door")]
[SerializeField] private bool3 rotationAxis;
[SerializeField] private float3 rotationAngle;
[SerializeField] private float3 rotationPivot;
[Header("Collider")]
[SerializeField] private Vector3 colliderShape = Vector3.one;
[SerializeField] private Vector3 colliderOffset = Vector3.zero;
[SerializeField] private PhysicsCategoryTags colliderBelongsTo;
[SerializeField] private PhysicsCategoryTags colliderCollidesWith;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
/////////////////////////////////////
// Create the collider for the door
/////////////////////////////////////
var collider = conversionSystem.CreateAdditionalEntity(gameObject);
dstManager.AddComponentData(collider, new Translation {Value = float3.zero});
dstManager.AddComponentData(collider, new Rotation{Value = quaternion.identity});
dstManager.AddComponentData(collider, new LocalToWorld());
#if UNITY_EDITOR
dstManager.SetName(collider, name + " Collider");
#endif
var colliderFilter = CollisionFilter.Default;
colliderFilter.BelongsTo = colliderBelongsTo.Value;
colliderFilter.CollidesWith = colliderCollidesWith.Value;
var colliderMaterial = Unity.Physics.Material.Default;
var colliderBlob = Unity.Physics.BoxCollider.Create(new BoxGeometry
{
BevelRadius = 0.001f,
Center = colliderOffset,
Orientation = quaternion.identity,
Size = colliderShape
}, colliderFilter, colliderMaterial);
var colliderMass = new Unity.Physics.MassProperties();
dstManager.AddComponentData(collider, new PhysicsCollider { Value = colliderBlob });
dstManager.AddComponentData(collider, PhysicsMass.CreateKinematic(colliderMass));
/////////////////////////////////////
// Trigger for trigger queries
/////////////////////////////////////
var trigger = conversionSystem.CreateAdditionalEntity(gameObject);
#if UNITY_EDITOR
dstManager.SetName(trigger, name + " Trigger");
#endif
var filter = CollisionFilter.Default;
filter.BelongsTo = triggerBelongsTo.Value;
filter.CollidesWith = triggerCollidesWith.Value;
var material = Unity.Physics.Material.Default;
material.Flags = Material.MaterialFlags.IsTrigger;
var blob = Unity.Physics.BoxCollider.Create(new BoxGeometry
{
BevelRadius = 0.001f,
Center = triggerCenter,
Orientation = quaternion.identity,
Size = triggerDimensions
}, filter, material);
dstManager.AddComponentData(trigger, new PhysicsCollider { Value = blob });
dstManager.AddComponentData(trigger, new PhysicsMass());
dstManager.AddComponentData(trigger, new Translation {Value = transform.position});
dstManager.AddComponentData(trigger, new Rotation{Value = transform.rotation});
dstManager.AddComponentData(trigger, new LocalToWorld());
// Link both entities together
dstManager.AddComponentData(trigger, new DoorTrigger {Door = entity});
/////////////////////////////////////
// Door
/////////////////////////////////////
dstManager.AddComponentData(entity, new Door
{
Trigger = trigger,
Collider = collider,
OpenPosition = transform.position + Vector3.up,
ClosedPosition = transform.position,
Speed = 10,
MovementDuraction = 0.2f
});
dstManager.AddComponentData(entity, new RotationEulerXYZ());
dstManager.AddComponentData(entity, new CompositeRotation());
dstManager.AddComponentData(entity, new RotationPivot {Value = rotationPivot});
// ALso make a linkedentitygroup?
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.white;
Gizmos.DrawWireCube(triggerCenter + transform.position, triggerDimensions);
Gizmos.color = Color.blue;
Gizmos.DrawWireCube(transform.position + colliderOffset, colliderShape);
Gizmos.color = new Color(0f, 0f, 1f, 0.15f);
Gizmos.DrawCube(transform.position + colliderOffset, colliderShape);
}
public void FitColliderShape()
{
var meshFilter = GetComponent<MeshFilter>();
var mesh = meshFilter.sharedMesh;
var center = mesh.bounds.center;
var extents = new Vector3(mesh.bounds.size.x * transform.localScale.x,mesh.bounds.size.y * transform.localScale.y,mesh.bounds.size.z * transform.localScale.z);
colliderShape = extents;
colliderOffset = center;
}
}
[UpdateAfter(typeof(EndFramePhysicsSystem))]
public class DoorSystem : JobComponentSystem
{
private BuildPhysicsWorld m_BuildPhysicsWorldSystem;
private StepPhysicsWorld m_StepPhysicsWorldSystem;
protected override void OnCreate()
{
m_BuildPhysicsWorldSystem = World.GetOrCreateSystem<BuildPhysicsWorld>();
m_StepPhysicsWorldSystem = World.GetOrCreateSystem<StepPhysicsWorld>();
}
[BurstCompile]
private struct TriggerJob: ITriggerEventsJob
{
[ReadOnly] public ComponentDataFromEntity<PlayerTag> PlayerTag;
[ReadOnly] public ComponentDataFromEntity<GameplayInputs> PlayerInput;
[NativeDisableParallelForRestriction] public ComponentDataFromEntity<DoorTrigger> DoorTrigger;
public void Execute(TriggerEvent triggerEvent)
{
var otherEntity = triggerEvent.Entities.EntityA;
var triggerEntity = triggerEvent.Entities.EntityB;
if(!DoorTrigger.Exists(triggerEntity))
return;
var trigger = DoorTrigger[triggerEntity];
var isBodyATrigger = PlayerTag.Exists(otherEntity);
if (isBodyATrigger && PlayerInput.Exists(otherEntity))
{
if (PlayerInput[otherEntity].Use)
{
trigger.Use = true;
DoorTrigger[triggerEntity] = trigger;
}
}
}
}
[BurstCompile]
private struct DoorJob : IJobForEachWithEntity<Door, RotationEulerXYZ>
{
public float FixedTime;
[NativeDisableParallelForRestriction] public ComponentDataFromEntity<DoorTrigger> DoorTrigger;
[NativeDisableParallelForRestriction] public ComponentDataFromEntity<Translation> Translation;
[NativeDisableParallelForRestriction] public ComponentDataFromEntity<Rotation> Rotation;
[NativeDisableParallelForRestriction] public ComponentDataFromEntity<LocalToWorld> LocalToWorld;
public void Execute(Entity entity, int index, ref Door door, ref RotationEulerXYZ rotationEulerXYZ)
{
if(!DoorTrigger.Exists(door.Trigger))
return;
var trigger = DoorTrigger[door.Trigger];
// State behaviour setup
// If door is not moving and received use command
if (trigger.Use)
{
//door.State = default; //?what
switch (door.State)
{
case DoorState.Closed:
door.State = DoorState.Opening;
break;
case DoorState.Opened:
door.State = DoorState.Closing;
break;
case DoorState.Opening:
break;
case DoorState.Closing:
break;
default:
break;
}
// Clear use command
trigger.Use = false;
DoorTrigger[door.Trigger] = trigger;
}
// Movement behaviour
if (door.State == DoorState.Opening)
{
// Tick the movement
if (door.CurrentMoveTime < door.MovementDuraction)
{
door.CurrentMoveTime += FixedTime;
//translation.Value += maths.up * FixedTime * door.Speed;
rotationEulerXYZ.Value.y += FixedTime * door.Speed / 1;
}
// If finished, set state and reset timers
if (door.CurrentMoveTime > door.MovementDuraction)
{
door.CurrentMoveTime = 0;
door.State = DoorState.Opened;
}
}
if (door.State == DoorState.Closing)
{
// Tick the movement
if (door.CurrentMoveTime < door.MovementDuraction)
{
door.CurrentMoveTime += FixedTime;
//translation.Value -= maths.up * FixedTime * door.Speed/3;
rotationEulerXYZ.Value.y -= FixedTime * door.Speed / 1;
}
// If finished, set state and reset timers
if (door.CurrentMoveTime > door.MovementDuraction)
{
door.CurrentMoveTime = 0;
door.State = DoorState.Closed;
}
}
var translationCollider = Translation[door.Collider];
translationCollider.Value = LocalToWorld[entity].Position;
Translation[door.Collider] = translationCollider;
var rotationCollider = Rotation[door.Collider];
rotationCollider.Value = new quaternion(LocalToWorld[entity].Value);
Rotation[door.Collider] = rotationCollider;
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
var triggerjob = new TriggerJob
{
PlayerTag = GetComponentDataFromEntity<PlayerTag>(true),
PlayerInput = GetComponentDataFromEntity<GameplayInputs>(true),
DoorTrigger = GetComponentDataFromEntity<DoorTrigger>(),
};
var triggerHandle = triggerjob.Schedule( m_StepPhysicsWorldSystem.Simulation, ref m_BuildPhysicsWorldSystem.PhysicsWorld, inputDeps);
var doorJobHandle = new DoorJob
{
FixedTime = Time.fixedDeltaTime,
DoorTrigger = GetComponentDataFromEntity<DoorTrigger>(),
Translation = GetComponentDataFromEntity<Translation>(),
LocalToWorld = GetComponentDataFromEntity<LocalToWorld>(),
Rotation = GetComponentDataFromEntity<Rotation>()
}.Schedule(this, triggerHandle);
return doorJobHandle;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment