private void HandleUserInput(CharacterMoveSetting ccComponentData, UserCommand command, float3 up, float3 surfaceVelocity, ref CharacterMovePredictedState ccPredictedState, out float3 linearVelocity, ref MoveInternalState moveInternalState) { // Reset jumping state and unsupported velocity if (moveInternalState.SupportedState == CharacterSupportState.Supported) { moveInternalState.IsJumping = false; ccPredictedState.UnsupportedVelocity = float3.zero; } var shouldJump = command.Buttons.IsSet(UserCommand.Button.Jump) && moveInternalState.SupportedState == CharacterSupportState.Supported; if (shouldJump) { // Add jump speed to surface velocity and make character unsupported moveInternalState.IsJumping = true; moveInternalState.SupportedState = CharacterSupportState.Unsupported; ccPredictedState.UnsupportedVelocity = surfaceVelocity + ccComponentData.JumpUpwardsVelocity * up; } else if (moveInternalState.SupportedState != CharacterSupportState.Supported) { // Apply gravity ccPredictedState.UnsupportedVelocity += ccComponentData.Gravity * DeltaTime; } // If unsupported then keep jump and surface momentum linearVelocity = (float3)command.TargetDir * ccComponentData.Velocity + (moveInternalState.SupportedState != CharacterSupportState.Supported ? ccPredictedState.UnsupportedVelocity : float3.zero); }
public unsafe void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { var up = math.up(); var chunkEntityData = chunk.GetNativeArray(EntityType); var chunkMoveSettingData = chunk.GetNativeArray(CharacterMoveType); var chunkTransformData = chunk.GetNativeArray(TransformType); var chunkVelocityData = chunk.GetNativeArray(VelocityType); var chunkUserCommand = chunk.GetNativeArray(UserCommandComponentType); var chunkMovePredictedData = chunk.GetNativeArray(CharacterMovePredictedType); var chunkPhysicsColliderData = chunk.GetNativeArray(PhysicsColliderType); DeferredImpulseWriter.BeginForEachIndex(chunkIndex); for (var i = 0; i < chunk.Count; i++) { var entity = chunkEntityData[i]; var moveSetting = chunkMoveSettingData[i]; var userCommand = chunkUserCommand[i]; var movePredictedData = chunkMovePredictedData[i]; var collider = chunkPhysicsColliderData[i]; var transformData = chunkTransformData[i]; var velocityData = chunkVelocityData[i]; // Collision filter must be valid if (!collider.IsValid || collider.Value.Value.Filter.IsEmpty) { continue; } // Character step input var stepInput = new CharacterControllerStepInput { World = PhysicsWorld, DeltaTime = DeltaTime, Up = math.up(), Gravity = moveSetting.Gravity, MaxIterations = moveSetting.MaxIterations, Tau = KDefaultTau, Damping = KDefaultDamping, SkinWidth = moveSetting.SkinWidth, ContactTolerance = moveSetting.ContactTolerance, MaxSlope = moveSetting.MaxSlope, RigidBodyIndex = PhysicsWorld.GetRigidBodyIndex(entity), CurrentVelocity = velocityData.Linear, MaxMovementSpeed = moveSetting.MaxVelocity }; // Character transform var transform = new RigidTransform { pos = transformData.Position, rot = transformData.Rotation }; var moveInternalState = new MoveInternalState { SupportedState = CharacterSupportState.Unsupported, IsJumping = false }; // Check support CheckSupport(ref PhysicsWorld, ref collider, stepInput, transform, moveSetting.MaxSlope, out moveInternalState.SupportedState, out var surfaceNormal, out var surfaceVelocity); // User input HandleUserInput(moveSetting, userCommand, stepInput.Up, surfaceVelocity, ref movePredictedData, out var desiredVelocity, ref moveInternalState); //add InitVelocity , clear InitVelocity desiredVelocity += movePredictedData.ImpulseVelocity; if (movePredictedData.ImpulseDuration > 0) { movePredictedData.ImpulseDuration--; } else { movePredictedData.ImpulseVelocity = float3.zero; } // FSLog.Info($"stepInput.CurrentVelocity:{stepInput.CurrentVelocity},desiredVelocity:{desiredVelocity}"); // Calculate actual velocity with respect to surface if (moveInternalState.SupportedState == CharacterSupportState.Supported) { CalculateMovement(transformData.Rotation, stepInput.Up, moveInternalState.IsJumping, stepInput.CurrentVelocity, desiredVelocity, surfaceNormal, surfaceVelocity, out velocityData.Linear); } // if(math.distancesq(velocityData.Linear, float3.zero) > 0.0001f) // FSLog.Info($"Entity:{entity},velocityData.Linear:{velocityData.Linear}," + // $"stepInput.CurrentVelocity:{stepInput.CurrentVelocity}"); else { velocityData.Linear = desiredVelocity; } // World collision + integrate CollideAndIntegrate(stepInput, moveSetting.CharacterMass, moveSetting.AffectsPhysicsBodies > 0, collider.ColliderPtr, ref transform, ref velocityData.Linear, ref DeferredImpulseWriter); // if(math.distancesq(velocityData.Linear, float3.zero) > 0.0001f) // FSLog.Info($"end velocityData.Linear:{ velocityData.Linear}"); // Write back and orientation integration transformData.Position = transform.pos; // character rotate if (math.distancesq(userCommand.TargetDir, float3.zero) > 0.0001f) { // var dir = Vector3.SqrMagnitude(velocityData.Linear) < 0.001f // ? Vector3.zero :(Vector3) math.normalize(velocityData.Linear); var fromRotation = transformData.Rotation; var toRotation = quaternion.LookRotationSafe(userCommand.TargetDir, up); var angle = Quaternion.Angle(fromRotation, toRotation); transformData.Rotation = Quaternion.RotateTowards(fromRotation, toRotation, math.abs(angle - 180.0f) < float.Epsilon ? -moveSetting.RotationVelocity : moveSetting.RotationVelocity); } // Write back to chunk data { chunkMovePredictedData[i] = movePredictedData; chunkTransformData[i] = transformData; chunkVelocityData[i] = velocityData; } } DeferredImpulseWriter.EndForEachIndex(); }