Hello!
Been working on some Archery VR game using ECS to learn and practice. Added a ICollisionEventsJob to the ArrowCollisionSystem to detect collision of an Arrow with another collider.
public void Execute(CollisionEvent collisionEvent)
{
bool isEntityARotationFollowsLinearVelocity =
RotationFollowsLinearVelocityGroup.Exists(collisionEvent.EntityA);
bool isEntityBRotationFollowsLinearVelocity =
RotationFollowsLinearVelocityGroup.Exists(collisionEvent.EntityB);
if (isEntityARotationFollowsLinearVelocity && isEntityBRotationFollowsLinearVelocity
|| !isEntityARotationFollowsLinearVelocity && !isEntityBRotationFollowsLinearVelocity)
{
return;
}
Entity arrowEntity;
if (isEntityARotationFollowsLinearVelocity)
{
arrowEntity = collisionEvent.EntityA;
RotationFollowsLinearVelocityGroup[arrowEntity] =
new RotationFollowsLinearVelocityComponent() { IsActive = false };
}
else if (isEntityBRotationFollowsLinearVelocity)
{
arrowEntity = collisionEvent.EntityB;
RotationFollowsLinearVelocityGroup[arrowEntity] =
new RotationFollowsLinearVelocityComponent() { IsActive = false };
}
else
{
return;
}
Entity otherEntity = !isEntityARotationFollowsLinearVelocity
? collisionEvent.EntityA
: collisionEvent.EntityB;
float3 collisionHeading =
LocalToWorldGroup[arrowEntity].Position -
LocalToWorldGroup[otherEntity].Position;
float angle = Float3Utility.Angle(
collisionHeading,
PhysicsVelocityGroup[arrowEntity].Linear);
if (angle > 45f)
{
// TODO: Turn off all physics and reparent arrow
}
}
Collision is working, but I want to reparent my Arrow to whatever it hit such that it will follow that entity, whether it be a wall or eventually an enemy.
That’s where the problems arise. This is what I’ve tried so far:
- The Arrow entity doesn’t have a Parent component because while flying through the air it shouldn’t have a parent. So I decided to add a Parent component to the entity. Problem is that later on when setting the Parent component through using ComponentDataFromEntity in it says that the Arrow entity doesn’t have a Parent component. This is confirmed by the Entity Debugger.
- So I decided that maybe the Parent component will be removed if no data is given to the Parent so I decided to start doing some dumb tests; setting the Parent to struct default, setting the Parent to itself, and setting the Parent to Entity.Null. All of these hits the problem of Parent not being added for some reason.
- Try adding the Parent component when we instantiate the Arrow entity. At this point I could have the Parent be the ArrowManagerEntity, an entity that would have components such as arrow count and arrow pooling (maybe). ArrowManagerEntity is currently doing nothing but holding the ArrowEntityReferenceComponent.
public void Convert(
Entity entity,
EntityManager entityManager,
GameObjectConversionSystem conversionSystem)
{
entityManager.SetName(entity, "ArrowManagerEntity");
ArrowEntity =
GameObjectConversionUtility.ConvertGameObjectHierarchy(
_arrowEntityPrefab.gameObject,
_conversionSettings);
entityManager.SetName(ArrowEntity, "ConvertedArrowEntity");
entityManager.AddComponentData(
entity,
new ArrowEntityReferenceComponent(ArrowEntity));
entityManager.AddComponentData(
entity,
new ArrowManagerEntityReferenceComponent(entity));
}
Which is then is used in the ArrowShootSystem:
Entities
.WithName("CreateArrowEntityJob")
.ForEach(
(in ArrowEntityReferenceComponent arrowReference,
in ArrowManagerEntityReferenceComponent managerReference) =>
{
Translation arrowTranslation =
new Translation { Value = arrowPosition };
Rotation arrowRotation =
new Rotation { Value = arrowQuaternion };
Entity arrowEntityInstance =
EntityUtility.InstantiateEntity(
arrowReference.Value,
_entityManager,
arrowTranslation,
arrowRotation);
_entityManager.SetName(
arrowEntityInstance,
"Arrow");
_entityManager.AddComponentData(
arrowEntityInstance,
new Parent { Value = managerReference.Value });
PhysicsVelocity physicsVelocity =
_entityManager.GetComponentData<PhysicsVelocity>(
arrowEntityInstance);
PhysicsMass physicsMass =
_entityManager.GetComponentData<PhysicsMass>(
arrowEntityInstance);
PhysicsVelocity updatedVelocity = new PhysicsVelocity
{
Linear =
physicsVelocity.Linear +
BowUtility.CalculateArrowShootVelocity(
arrowTranslation,
arrowRotation,
physicsMass.InverseMass,
bowShotPercentage)
};
_entityManager.SetComponentData(
arrowEntityInstance,
updatedVelocity);
})
.WithStructuralChanges()
.Run();
This is where I decided to add the Parent component and have it be ArrowEntityManager. Problem is that for some reason setting that as the Parent immediately stops all physics and just makes the arrow appear in a specific position.
- So finally I decided to add the Parent all the way in the job of the ArrowCollisionSystem. I didn’t know how to add components inside a ICollisionEventsJob, and it felt like it would violate the separation of needed for Burst compilation, but decided to look into it. Found this forum using EntityCommandBuffer, albeit in a IJobForEachWithEntity job: AddComponent from inside JobComponentSystem Job? . Now I’m having trouble finding what the job index is as ICollisionEventsJob.Execute does not provide that information.
So that’s where I am now. Now I’m playing with the idea to add a new component to my arrow called ArrowCollisionDataComponent that would have the following:
- public bool HasCollided;
- public Entity CollidedEntity;
- public float3 PositionOnCollision;
- public quaternion RotationOnCollision;
Then I would have another system check which arrows have collided and set up and add the Parent component appropriately. Would like some help either debugging why Parent component isn’t getting added or if there is a work around. Any further discussion is also appreciated.