protected override void OnUpdate() { //Prepare all components without the correct data. for (int i = 0; i < data.Length; i++) { //Add the collision info. (NOTE: this does mean no //archetyping CollisionInfo in!) CollisionInfo cols = new CollisionInfo(); cols.faceDirection = 1; PostUpdateCommands.AddComponent(data.entities[i], cols); //Configure inverseMaxSlope to be truly inverse of maxSlopeAngle. //CharacterControllerComponent controller = data.characterController[i]; //If inverseMaxSlope is set, don't do the calculation again. //if (controller.maxSlopeInverse == default(float)) { // controller.maxSlopeInverse = 90 / controller.maxSlopeAngle; // PostUpdateCommands.SetSharedComponent(data.entities[i], controller); //} } }
//@TODO: Replace raycast calls with CombCast2D jobs. All will have same length, but can filter by distance to same effect. //@TODO: Variable down direction. Not just good for gravity games, but also for SONIC! protected override void OnUpdate() { //Slightly more efficient to use GetExistingManager. //As long as you make sure it actually is existing before update! EntityManager em = World.Active.GetExistingManager <EntityManager>(); NativeArray <RaycastHit2D> hCast; NativeArray <RaycastHit2D> vCast; for (int i = 0; i < data.Length; i++) { //Working copy of the movement value. float2 moveAmount = data.movement[i].Value; //For when we need an unaltered copy later. float2 moveAmountPreChange = moveAmount; //Layer mask. LayerMask mask = data.collisionMask[i].SolidMask; //@NEW: This is my implementation of semi-solid platforms. { bool checkSemiSolid = data.collisions[i].below | moveAmount.y < 0; checkSemiSolid &= em.HasComponent(data.entities[i], typeof(FallThroughSemiSolid)); mask |= math.select( 0, data.collisionMask[i].SemiSolidMask, checkSemiSolid ); } //EXPLANATION: This merges in a second layer mask conditionally. //Specifically, if grounded or going down. //The intuitive thing would be to occlude going-up ONLY when //checking vertical, but doing that makes for some problems when //trying to jump through semi-solid slopes. //And we have the grounded check because you technically are //going up while climbing slopes--so otherwise, we would fall //straight through upward slopes, or even weirder behavior! //float maxSlopeAngleInverse; //Create a new collision info to be populated. CollisionInfo collisions = new CollisionInfo(); //Covered in a prior system. //UpdateRaycastOrigins(); //Descending slope check. //@TODO: Apparently, a better solution is to do an initial groundward cast //and run this method if (groundward_cast.hit). //The result of this could also replace collisions.below in the above select statement. if (moveAmount.y < 0) { //I'm not sure if I copied the sliding-down code correctly when I first //followed the Sebastian Lague tutorials, so I've no guarantee that this //implementation shown here matches his implementation. //Works fine without, in any case. CheckIfSlidingDownSlope( ref moveAmount, ref collisions, data.raycastController[i].bottomCorners, data.characterController[i].maxSlopeAngle, data.raycastController[i].skinWidth, mask ); CheckIfDescendingSlope( ref moveAmount, data.characterController[i].maxSlopeAngle, ref collisions, data.raycastController[i].skinWidth, data.raycastController[i].bottomCorners, mask, collisions.slidingDownSlope ); } //Needs to be before setting the move direction, lest the X collision check //toward the slope rather than in the direction of any possible collisions (i.e. our move direction). //Store last move direction if (moveAmount.x != 0) { collisions.faceDirection = (int)math.sign(moveAmount.x); } //Collisions here //Do horizontal collisions unconditionally. HorizontalCollisions( ref moveAmount, ref collisions, data.raycastController[i], data.characterController[i].maxSlopeAngle, moveAmountPreChange, mask ); //Do vertical collisions only if moving vertically. if (moveAmount.y != 0) { VerticalCollisions( ref moveAmount, ref collisions, data.raycastController[i], mask ); CounteractJointCatching( ref moveAmount, ref collisions, data.raycastController[i].skinWidth, data.raycastController[i].bottomCorners, mask ); } collisions.below |= em.HasComponent(data.entities[i], typeof(ForceGrounded)); //Apply components' new data. float3 positionOutput = data.position[i].Value; positionOutput.x += moveAmount.x; positionOutput.y += moveAmount.y; data.position[i] = new Position { Value = positionOutput }; //Movement component's job is done, and it will be blanked by MoveResetSystem. //Output this for next frame. data.collisions[i] = collisions; } }
void CheckIfSlidingDownSlope( ref float2 moveAmount, ref CollisionInfo collisions, in float2x2 bottomCorners, //@TODO: Do variables passed as in interfere with cache friendliness?