using Unity.CharacterController; using Unity.Entities; using Unity.Mathematics; using Unity.Physics; namespace ProjectM.Simulation { /// /// Per-update "global" data the character processor needs (lookups, singletons). Empty for the minimal /// top-down character — kept so the CC update signature is satisfied and future lookups have a home. /// public struct CharacterUpdateContext { public void OnSystemCreate(ref SystemState state) { } public void OnSystemUpdate(ref SystemState state) { } } /// /// Top-down kinematic character processor (CC 1.4.2 pattern: /// + a built in the job, driving the static /// Update_* sequence). Stripped of all FPS features: no jump, /// no air movement, no gravity, no view. runs the canonical CC update /// sequence; lerps RelativeVelocity toward the desired planar /// velocity wrote. Rotation/facing is owned by . /// public struct CharacterProcessor : IKinematicCharacterProcessor { public KinematicCharacterDataAccess CharacterDataAccess; public RefRW CharacterComponent; public RefRW CharacterControl; public void PhysicsUpdate(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext) { ref CharacterComponent characterComponent = ref CharacterComponent.ValueRW; ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW; ref float3 characterPosition = ref CharacterDataAccess.LocalTransform.ValueRW.Position; KinematicCharacterUtilities.Update_Initialize( in this, ref context, ref baseContext, ref characterBody, CharacterDataAccess.CharacterHitsBuffer, CharacterDataAccess.DeferredImpulsesBuffer, CharacterDataAccess.VelocityProjectionHits, baseContext.Time.DeltaTime); KinematicCharacterUtilities.Update_ParentMovement( in this, ref context, ref baseContext, CharacterDataAccess.CharacterEntity, ref characterBody, CharacterDataAccess.CharacterProperties.ValueRO, CharacterDataAccess.PhysicsCollider.ValueRO, CharacterDataAccess.LocalTransform.ValueRO, ref characterPosition, characterBody.WasGroundedBeforeCharacterUpdate); KinematicCharacterUtilities.Update_Grounding( in this, ref context, ref baseContext, ref characterBody, CharacterDataAccess.CharacterEntity, CharacterDataAccess.CharacterProperties.ValueRO, CharacterDataAccess.PhysicsCollider.ValueRO, CharacterDataAccess.LocalTransform.ValueRO, CharacterDataAccess.VelocityProjectionHits, CharacterDataAccess.CharacterHitsBuffer, ref characterPosition); HandleVelocityControl(ref context, ref baseContext); KinematicCharacterUtilities.Update_PreventGroundingFromFutureSlopeChange( in this, ref context, ref baseContext, CharacterDataAccess.CharacterEntity, ref characterBody, CharacterDataAccess.CharacterProperties.ValueRO, CharacterDataAccess.PhysicsCollider.ValueRO, in characterComponent.StepAndSlopeHandling); KinematicCharacterUtilities.Update_GroundPushing( in this, ref context, ref baseContext, ref characterBody, CharacterDataAccess.CharacterProperties.ValueRO, CharacterDataAccess.LocalTransform.ValueRO, CharacterDataAccess.DeferredImpulsesBuffer, float3.zero); KinematicCharacterUtilities.Update_MovementAndDecollisions( in this, ref context, ref baseContext, CharacterDataAccess.CharacterEntity, ref characterBody, CharacterDataAccess.CharacterProperties.ValueRO, CharacterDataAccess.PhysicsCollider.ValueRO, CharacterDataAccess.LocalTransform.ValueRO, CharacterDataAccess.VelocityProjectionHits, CharacterDataAccess.CharacterHitsBuffer, CharacterDataAccess.DeferredImpulsesBuffer, ref characterPosition); KinematicCharacterUtilities.Update_MovingPlatformDetection(ref baseContext, ref characterBody); KinematicCharacterUtilities.Update_ParentMomentum(ref baseContext, ref characterBody, CharacterDataAccess.LocalTransform.ValueRO.Position); KinematicCharacterUtilities.Update_ProcessStatefulCharacterHits( CharacterDataAccess.CharacterHitsBuffer, CharacterDataAccess.StatefulHitsBuffer); } void HandleVelocityControl(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext) { float deltaTime = baseContext.Time.DeltaTime; ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW; ref CharacterComponent characterComponent = ref CharacterComponent.ValueRW; CharacterControl characterControl = CharacterControl.ValueRO; // Planar twin-stick: smoothly approach the desired world velocity (already speed-scaled, Y==0). float3 targetVelocity = characterControl.MoveVelocity; CharacterControlUtilities.StandardGroundMove_Interpolated( ref characterBody.RelativeVelocity, targetVelocity, characterComponent.GroundedMovementSharpness, deltaTime, math.up(), math.up()); } public void VariableUpdate(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext) { } public void UpdateGroundingUp(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext) { ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW; KinematicCharacterUtilities.Default_UpdateGroundingUp( ref characterBody, CharacterDataAccess.LocalTransform.ValueRO.Rotation); } public bool CanCollideWithHit(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext, in BasicHit hit) { return PhysicsUtilities.IsCollidable(hit.Material); } public bool IsGroundedOnHit(ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext, in BasicHit hit, int groundingEvaluationType) { CharacterComponent characterComponent = CharacterComponent.ValueRO; return KinematicCharacterUtilities.Default_IsGroundedOnHit( in this, ref context, ref baseContext, CharacterDataAccess.CharacterEntity, CharacterDataAccess.PhysicsCollider.ValueRO, CharacterDataAccess.CharacterBody.ValueRO, CharacterDataAccess.CharacterProperties.ValueRO, in hit, in characterComponent.StepAndSlopeHandling, groundingEvaluationType); } public void OnMovementHit( ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext, ref KinematicCharacterHit hit, ref float3 remainingMovementDirection, ref float remainingMovementLength, float3 originalVelocityDirection, float hitDistance) { ref KinematicCharacterBody characterBody = ref CharacterDataAccess.CharacterBody.ValueRW; ref float3 characterPosition = ref CharacterDataAccess.LocalTransform.ValueRW.Position; CharacterComponent characterComponent = CharacterComponent.ValueRO; KinematicCharacterUtilities.Default_OnMovementHit( in this, ref context, ref baseContext, ref characterBody, CharacterDataAccess.CharacterEntity, CharacterDataAccess.CharacterProperties.ValueRO, CharacterDataAccess.PhysicsCollider.ValueRO, CharacterDataAccess.LocalTransform.ValueRO, ref characterPosition, CharacterDataAccess.VelocityProjectionHits, ref hit, ref remainingMovementDirection, ref remainingMovementLength, originalVelocityDirection, hitDistance, characterComponent.StepAndSlopeHandling.StepHandling, characterComponent.StepAndSlopeHandling.MaxStepHeight, characterComponent.StepAndSlopeHandling.CharacterWidthForStepGroundingCheck); } public void OverrideDynamicHitMasses( ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext, ref PhysicsMass characterMass, ref PhysicsMass otherMass, BasicHit hit) { } public void ProjectVelocityOnHits( ref CharacterUpdateContext context, ref KinematicCharacterUpdateContext baseContext, ref float3 velocity, ref bool characterIsGrounded, ref BasicHit characterGroundHit, in DynamicBuffer velocityProjectionHits, float3 originalVelocityDirection) { CharacterComponent characterComponent = CharacterComponent.ValueRO; KinematicCharacterUtilities.Default_ProjectVelocityOnHits( ref velocity, ref characterIsGrounded, ref characterGroundHit, in velocityProjectionHits, originalVelocityDirection, characterComponent.StepAndSlopeHandling.ConstrainVelocityToGroundPlane, in CharacterDataAccess.CharacterBody.ValueRO); } } }