该项目的目的是同时测试和演示来自 Unity DOTS 技术堆栈的多个新包。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

246 行
9.2 KiB

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Extensions;
using Unity.Physics.Systems;
using Unity.Transforms;
using Unity.NetCode;
[UpdateInGroup(typeof(AbilityUpdateSystemGroup))]
[UpdateAfter(typeof(MovementUpdatePhase))]
[UpdateBefore(typeof(CharacterControllerStepSystem))]
[DisableAutoCreation]
[AlwaysSynchronizeSystem]
public class CharacterControllerFollowGroundSystem : JobComponentSystem
{
BuildPhysicsWorld m_BuildPhysicsWorldSystem;
protected override void OnCreate()
{
m_BuildPhysicsWorldSystem = World.GetOrCreateSystem<BuildPhysicsWorld>();
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
inputDeps.Complete();
var physicsWorld = m_BuildPhysicsWorldSystem.PhysicsWorld;
var PredictingTick = World.GetExistingSystem<GhostPredictionSystemGroup>().PredictingTick;
Entities
.ForEach((
ref CharacterControllerComponentData ccData,
ref CharacterControllerInitializationData ccInitData,
ref CharacterControllerMoveQuery ccMoveQuery,
ref CharacterControllerVelocity ccVelocity,
in PredictedGhostComponent predictedGhostComponent) =>
{
if (!GhostPredictionSystemGroup.ShouldPredict(PredictingTick, predictedGhostComponent))
return;
if (!ccMoveQuery.FollowGround)
return;
var vel = ccVelocity.Velocity;
if (math.lengthsq(vel) == 0.0f)
return;
var skinWidth = ccData.SkinWidth;
var startPos = ccMoveQuery.StartPosition - math.up() * skinWidth;
var dir = math.normalizesafe(vel);
var horizDir = new float3(dir.x, 0.0f, dir.z);
var len = ccInitData.CapsuleRadius;
var endPos = startPos + len * dir;
var slopeAdjustment = math.up() * len * math.tan(ccData.MaxSlope);
var rayInput = new RaycastInput
{
Start = endPos + slopeAdjustment,
End = endPos - slopeAdjustment,
Filter = new CollisionFilter { BelongsTo = 1, CollidesWith = 1, GroupIndex = 0 }
};
var rayHit = new RaycastHit();
if (!physicsWorld.CastRay(rayInput, out rayHit))
return;
var newDir = math.normalize(rayHit.Position - startPos);
var newHorizDir = new float3(newDir.x, 0.0f, newDir.z);
var newVel = newDir * math.length(vel) * math.length(horizDir) / math.length(newHorizDir);
if (math.abs(newVel.y) > 0.01f)
ccVelocity.Velocity = newVel;
}).Run();
return default;
}
}
[UpdateInGroup(typeof(AbilityUpdateSystemGroup))]
[UpdateAfter(typeof(MovementUpdatePhase))]
[UpdateBefore(typeof(MovementResolvePhase))]
[DisableAutoCreation]
[AlwaysSynchronizeSystem]
public class CharacterControllerStepSystem : JobComponentSystem
{
[BurstCompile]
struct ApplyDeferredImpulses : IJob
{
public NativeStream.Reader DeferredImpulseReader;
public ComponentDataFromEntity<PhysicsVelocity> PhysicsVelocityData;
public ComponentDataFromEntity<PhysicsMass> PhysicsMassData;
public ComponentDataFromEntity<Translation> TranslationData;
public ComponentDataFromEntity<Rotation> RotationData;
public void Execute()
{
int index = 0;
int maxIndex = DeferredImpulseReader.ForEachCount;
DeferredImpulseReader.BeginForEachIndex(index++);
while (DeferredImpulseReader.RemainingItemCount == 0 && index < maxIndex)
{
DeferredImpulseReader.BeginForEachIndex(index++);
}
while (DeferredImpulseReader.RemainingItemCount > 0)
{
// Read the data
var impulse = DeferredImpulseReader.Read<DeferredCharacterControllerImpulse>();
while (DeferredImpulseReader.RemainingItemCount == 0 && index < maxIndex)
{
DeferredImpulseReader.BeginForEachIndex(index++);
}
PhysicsVelocity pv = PhysicsVelocityData[impulse.Entity];
PhysicsMass pm = PhysicsMassData[impulse.Entity];
Translation t = TranslationData[impulse.Entity];
Rotation r = RotationData[impulse.Entity];
// Don't apply on kinematic bodies
if (pm.InverseMass > 0.0f)
{
// Apply impulse
pv.ApplyImpulse(pm, t, r, impulse.Impulse, impulse.Point);
// Write back
PhysicsVelocityData[impulse.Entity] = pv;
}
}
}
}
BuildPhysicsWorld m_BuildPhysicsWorldSystem;
EntityQuery m_CharacterControllersGroup;
EntityQuery m_TimeSingletonQuery;
protected override void OnCreate()
{
m_BuildPhysicsWorldSystem = World.GetOrCreateSystem<BuildPhysicsWorld>();
m_CharacterControllersGroup = GetEntityQuery( new EntityQueryDesc
{
All = new []
{
ComponentType.ReadWrite<CharacterControllerComponentData>(),
}
});
m_TimeSingletonQuery = GetEntityQuery(ComponentType.ReadOnly<GlobalGameTime>());
}
protected unsafe override JobHandle OnUpdate(JobHandle inputDeps)
{
var entityCount = m_CharacterControllersGroup.CalculateEntityCount();
if (entityCount == 0)
return inputDeps;
var deferredImpulses = new NativeStream(entityCount, Allocator.TempJob);
var time = m_TimeSingletonQuery.GetSingleton<GlobalGameTime>().gameTime;
var physicsWorld = m_BuildPhysicsWorldSystem.PhysicsWorld;
var writer = deferredImpulses.AsWriter();
var constraints = new NativeList<SurfaceConstraintInfo>(Allocator.Temp);
var castHits = new NativeList<ColliderCastHit>(Allocator.Temp);
var distanceHits = new NativeList<DistanceHit>(Allocator.Temp);
var PredictingTick = World.GetExistingSystem<GhostPredictionSystemGroup>().PredictingTick;
Entities
.WithName("CharacterControllerStepSystem")
.ForEach((
ref CharacterControllerComponentData ccData,
ref CharacterControllerCollider ccCollider,
ref CharacterControllerMoveQuery moveQuery,
ref CharacterControllerMoveResult moveResult,
ref CharacterControllerVelocity velocity,
in PredictedGhostComponent predictedGhostComponent) =>
{
if (!GhostPredictionSystemGroup.ShouldPredict(PredictingTick, predictedGhostComponent))
return;
constraints.Clear();
castHits.Clear();
distanceHits.Clear();
var collider = (Collider*)ccCollider.Collider.GetUnsafePtr();
var stepInput = new CharacterControllerUtilities.CharacterControllerStepInput
{
World = physicsWorld,
DeltaTime = time.tickDuration,
Up = math.up(),
Gravity = new float3(0.0f, -9.8f, 0.0f),
MaxIterations = ccData.MaxIterations,
Tau = CharacterControllerUtilities.k_DefaultTau,
Damping = CharacterControllerUtilities.k_DefaultDamping,
SkinWidth = ccData.SkinWidth,
ContactTolerance = ccData.ContactTolerance,
MaxSlope = ccData.MaxSlope,
RigidBodyIndex = -1,
CurrentVelocity = velocity.Velocity,
MaxMovementSpeed = ccData.MaxMovementSpeed,
FollowGround = moveQuery.FollowGround
};
var transform = new RigidTransform
{
pos = moveQuery.StartPosition,
rot = quaternion.identity
};
// World collision + integrate
CharacterControllerUtilities.CollideAndIntegrate(
stepInput,
ccData.CharacterMass,
ccData.AffectsPhysicsBodies > 0,
collider,
ref transform,
ref velocity.Velocity,
ref writer,
ref constraints,
ref castHits,
ref distanceHits);
moveResult.MoveResult = transform.pos;
}).Run();
var applyJob = new ApplyDeferredImpulses()
{
DeferredImpulseReader = deferredImpulses.AsReader(),
PhysicsVelocityData = GetComponentDataFromEntity<PhysicsVelocity>(),
PhysicsMassData = GetComponentDataFromEntity<PhysicsMass>(),
TranslationData = GetComponentDataFromEntity<Translation>(),
RotationData = GetComponentDataFromEntity<Rotation>()
};
applyJob.Run();
deferredImpulses.Dispose();
constraints.Dispose();
castHits.Dispose();
distanceHits.Dispose();
return inputDeps;
}
}