private bool HasWallCollided(out SuperCollision superCollision) { foreach (var col in controller.collisionData) { if (Vector3.Angle(col.normal, controller.up) > 80.0f) { superCollision = col; return(true); } } superCollision = new SuperCollision(); return(false); }
private bool HasFeetCollided(out SuperCollision superCollision) { foreach (var col in controller.collisionData) { Vector3 direction = col.point - controller.OffsetPosition(controller.feet.Offset); if (Vector3.Angle(direction, controller.down) < 88.0f) { superCollision = col; return(true); } } superCollision = new SuperCollision(); return(false); }
/// <summary> /// Check if any of the CollisionSpheres are colliding with any walkable objects in the world. /// If they are, apply a proper pushback and retrieve the collision data /// </summary> void RecursivePushback(int depth, int maxDepth) { PushIgnoredColliders(); bool contact = false; foreach (var sphere in spheres) { foreach (Collider col in Physics.OverlapSphere((SpherePosition(sphere)), radius, Walkable)) { if (col.isTrigger) continue; Vector3 position = SpherePosition(sphere); Vector3 contactPoint = SuperCollider.ClosestPointOnSurface(col, position, radius); if (contactPoint != Vector3.zero) { if (debugPushbackMesssages) DebugDraw.DrawMarker(contactPoint, 2.0f, Color.cyan, 0.0f, false); Vector3 v = contactPoint - position; if (v != Vector3.zero) { // Cache the collider's layer so that we can cast against it int layer = col.gameObject.layer; col.gameObject.layer = TemporaryLayerIndex; // Check which side of the normal we are on bool facingNormal = Physics.SphereCast(new Ray(position, v.normalized), TinyTolerance, v.magnitude + TinyTolerance, 1 << TemporaryLayerIndex); col.gameObject.layer = layer; // Orient and scale our vector based on which side of the normal we are situated if (facingNormal) { if (Vector3.Distance(position, contactPoint) < radius) { v = v.normalized * (radius - v.magnitude) * -1; } else { // A previously resolved collision has had a side effect that moved us outside this collider continue; } } else { v = v.normalized * (radius + v.magnitude); } contact = true; transform.position += v; col.gameObject.layer = TemporaryLayerIndex; // Retrieve the surface normal of the collided point RaycastHit normalHit; Physics.SphereCast(new Ray(position + v, contactPoint - (position + v)), TinyTolerance, out normalHit, 1 << TemporaryLayerIndex); col.gameObject.layer = layer; SuperCollisionType superColType = col.gameObject.GetComponent<SuperCollisionType>(); if (superColType == null) superColType = defaultCollisionType; // Our collision affected the collider; add it to the collision data var collision = new SuperCollision() { collisionSphere = sphere, superCollisionType = superColType, gameObject = col.gameObject, point = contactPoint, normal = normalHit.normal }; collisionData.Add(collision); } } } } PopIgnoredColliders(); if (depth < maxDepth && contact) { RecursivePushback(depth + 1, maxDepth); } }
/// <summary> /// Check if any of the CollisionSpheres are colliding with any walkable objects in the world. /// If they are, apply a proper pushback and retrieve the collision data /// </summary> void RecursivePushback(int depth, int maxDepth) { PushIgnoredColliders(); bool contact = false; foreach (var sphere in spheres) { foreach (Collider col in Physics.OverlapSphere((SpherePosition(sphere)), radius, Walkable, triggerInteraction)) { Vector3 position = SpherePosition(sphere); Vector3 contactPoint; bool contactPointSuccess = SuperCollider.ClosestPointOnSurface(col, position, radius, out contactPoint); if (!contactPointSuccess) { return; } if (debugPushbackMesssages) { DebugDraw.DrawMarker(contactPoint, 2.0f, Color.cyan, 0.0f, false); } Vector3 v = contactPoint - position; if (v != Vector3.zero) { // Cache the collider's layer so that we can cast against it int layer = col.gameObject.layer; col.gameObject.layer = TemporaryLayerIndex; // Check which side of the normal we are on bool facingNormal = Physics.SphereCast(new Ray(position, v.normalized), TinyTolerance, v.magnitude + TinyTolerance, 1 << TemporaryLayerIndex); col.gameObject.layer = layer; // Orient and scale our vector based on which side of the normal we are situated if (facingNormal) { if (Vector3.Distance(position, contactPoint) < radius) { v = v.normalized * (radius - v.magnitude) * -1; } else { // A previously resolved collision has had a side effect that moved us outside this collider continue; } } else { v = v.normalized * (radius + v.magnitude); } contact = true; transform.position += v; col.gameObject.layer = TemporaryLayerIndex; // Retrieve the surface normal of the collided point RaycastHit normalHit; Physics.SphereCast(new Ray(position + v, contactPoint - (position + v)), TinyTolerance, out normalHit, 1 << TemporaryLayerIndex); col.gameObject.layer = layer; SuperCollisionType superColType = col.gameObject.GetComponent <SuperCollisionType>(); if (superColType == null) { superColType = defaultCollisionType; } // Our collision affected the collider; add it to the collision data var collision = new SuperCollision() { collisionSphere = sphere, superCollisionType = superColType, gameObject = col.gameObject, point = contactPoint, normal = normalHit.normal }; collisionData.Add(collision); } } } PopIgnoredColliders(); if (depth < maxDepth && contact) { RecursivePushback(depth + 1, maxDepth); } }
void Fall_SuperUpdate() { //TODO: //Input interpreting //Take camera position into account when determining if wall run shoud start? //Bumbing off the ceiling //Is the extra frame/s for wallrunning needed? //Rope CreateAndDeleteRope(); //For reducing falsely interpreted input lastMoveInputs.Add(input.Current.MoveInput); //Seems to be always the last two frames if (lastMoveInputs.Count > 10) { lastMoveInputs.RemoveAt(0); } Vector3 sum = Vector3.zero; Vector3 average = Vector3.zero; foreach (Vector3 v in lastMoveInputs) { sum += v; } average = sum / lastMoveInputs.Count; if (lastMoveInputs[lastMoveInputs.Count - 1].magnitude == 0)//Edit this to check final inputs to see if they differ from intended { average = Vector3.zero; } lastLocalMoves.Add(LocalMovement()); if (lastLocalMoves.Count > 10) { lastLocalMoves.RemoveAt(0); } Vector3 sum2 = Vector3.zero; Vector3 average2 = Vector3.zero; foreach (Vector3 v in lastLocalMoves) { sum2 += v; } average2 = sum / lastLocalMoves.Count; if (lastLocalMoves[lastLocalMoves.Count - 1].magnitude == 0)//Edit this to check final inputs to see if they differ from intended { average2 = Vector3.zero; } //Horizontal and vertical components Vector3 planarMoveDirection = Math3d.ProjectVectorOnPlane(controller.up, moveDirection); Vector3 verticalMoveDirection = moveDirection - planarMoveDirection; //Are we touching anything? if (controller.collisionData.Count > 0 || previousFirstCollision.gameObject != null) { if (controller.collisionData.Count > 0) { collisionNormal = controller.collisionData[0].normal; collisionPoint = controller.collisionData[0].point; } else { collisionNormal = previousFirstCollision.normal; collisionPoint = previousFirstCollision.point; } if (previousFirstCollision.gameObject) { print(controller.collisionData.Count + "and" + previousFirstCollision.gameObject.name); } if (controller.collisionData.Count > 1) { //print("how many colliders? " + controller.collisionData.Count); //foreach (SuperCollision col in controller.collisionData) //{ // print("type: "+col.superCollisionType+ "object: "+ col.gameObject + "normal: "+ col.normal); //} } //Walljump if (input.Current.JumpInput && jumpCount <= maxJumpCount && canWallJump) { isWallJumping = true; Gravity = originalGravity; WalkSpeed = originalWalkspeed; if (walkSpeedAtJump > originalWalkspeed) { WalkSpeed = walkSpeedAtJump; } if (reducedTime > 0) { print("does this even"); JumpAcceleration = reducedJumpAcceleration; } else { JumpAcceleration = originalJumpAcceleration; } currentState = PlayerStates.Jump; return; } float steepAngle = Vector3.Angle(Vector3.up, collisionNormal); float jumpAngle = Vector3.Angle(planarMoveDirection, collisionNormal); print("steepangle: " + steepAngle); //Wallrun if (110f >= steepAngle && steepAngle >= 55.1f && jumpAngle <= 155f && canWallRun) { if (isWallRunning == false) { print("wallrun started at" + Time.timeSinceLevelLoad); if (verticalMoveDirection.y < 0) { verticalMoveDirection.y = 4; } jumpCount = 1; planarMoveDirection *= 2f; } isWallRunning = true; Gravity = 0; } if (steepAngle < 15f) { print("steepangle < 15f"); WalkSpeed = 0; moveDirection = planarMoveDirection; previousPlanarMovedirection = Vector3.zero; currentState = PlayerStates.Idle; return; } if (steepAngle > 160f) { print("steepangle > 160f"); WalkSpeed = 0; moveDirection = planarMoveDirection; previousPlanarMovedirection = Vector3.zero; currentState = PlayerStates.Fall; return; } } else { if (isWallRunning) { print("stopped wallrun"); planarMoveDirection *= 0.5f; } isWallRunning = false; Gravity = originalGravity; WalkSpeed = originalWalkspeed + momentum; if (walkSpeedAtJump > originalWalkspeed) { WalkSpeed = walkSpeedAtJump + momentum; } if (reducedTime > 0) { JumpAcceleration = reducedJumpAcceleration; } else { JumpAcceleration = originalJumpAcceleration; } //Double jump and beyond if (input.Current.JumpInput && jumpCount < maxJumpCount) { if (moveDirection.y < 0) { moveDirection.y = 0; } currentState = PlayerStates.Jump; return; } } if (Vector3.Angle(verticalMoveDirection, controller.up) > 90 && AcquiringGround()) { moveDirection = planarMoveDirection; previousPlanarMovedirection = Vector3.zero; currentState = PlayerStates.Idle; return; } //Wallrun speed if (isWallRunning) { WalkSpeed = originalWalkspeed + extraWallRunSpeed + momentum; JumpAcceleration = originalJumpAcceleration + extraWallRunJumpAcceleration; } else { WalkSpeed = originalWalkspeed + momentum; if (walkSpeedAtJump > originalWalkspeed || (walkSpeedAtJump > 0 && walkSpeedAtJump < originalWalkspeed)) { WalkSpeed = walkSpeedAtJump + momentum; } JumpAcceleration = originalJumpAcceleration; //IF WE WANT TO STOP FAST IN THE AIR //if (LocalMovement().magnitude == 0) //{ // WalkSpeed = walkSpeedAtJump + momentum; //} } //Do we have LocalMovement caused by input etc if (LocalMovement().magnitude > 0) { //WalkSpeed = originalWalkspeed; if (isWallRunning) { //WalkSpeed = originalWalkspeed + extraWallRunSpeed * 2; //JumpAcceleration = originalJumpAcceleration * 3; } else { WalkSpeed = originalWalkspeed + momentum; if (walkSpeedAtJump > originalWalkspeed || (walkSpeedAtJump > 0 && walkSpeedAtJump < originalWalkspeed)) { WalkSpeed = walkSpeedAtJump; } if (reducedTime > 0) { JumpAcceleration = reducedJumpAcceleration; } else { JumpAcceleration = originalJumpAcceleration; } } if (walkSpeedAtJump > originalWalkspeed) { WalkSpeed = walkSpeedAtJump + momentum; } if (isWallRunning == false) { planarMoveDirection = Vector3.MoveTowards(planarMoveDirection, LocalMovement() * WalkSpeed, JumpAcceleration * controller.deltaTime); } } else { if (isWallRunning == false) { planarMoveDirection = Vector3.MoveTowards(planarMoveDirection, planarMoveDirection.normalized * WalkSpeed, JumpAcceleration * controller.deltaTime); } if (controller.collisionData.Count == 0) { if (WalkSpeed - WalkSpeed * 0.01f > 0) { WalkSpeed -= WalkSpeed * 0.01f; } } } if (isWallRunning) { WalkSpeed = originalWalkspeed + extraWallRunSpeed + momentum; JumpAcceleration = originalJumpAcceleration * 2; float angle = Vector3.Angle(planarMoveDirection, collisionNormal); print("angle: " + angle); //Wallrun direction if (angle >= 90f) { Vector3 tempPlanarMoveDirection = Math3d.ProjectVectorOnPlane(controller.up, collisionPoint) + (planarMoveDirection * WalkSpeed - Math3d.ProjectVectorOnPlane(controller.up, collisionPoint)) - Math3d.ProjectVectorOnPlane(controller.up, collisionNormal) * Vector3.Dot((planarMoveDirection * WalkSpeed - Math3d.ProjectVectorOnPlane(controller.up, collisionPoint)), Math3d.ProjectVectorOnPlane(controller.up, collisionNormal)); angle = Vector3.Angle(tempPlanarMoveDirection, collisionNormal); print("temp planar dir: " + tempPlanarMoveDirection + " normal: " + collisionNormal + " angle after: " + angle); if (angle >= 90f) { tempPlanarMoveDirection = Quaternion.AngleAxis(-(angle - 90f - 1f), Vector3.up) * tempPlanarMoveDirection; float angle2 = angle; angle = Vector3.Angle(tempPlanarMoveDirection, collisionNormal); print("angle if over or equal 90: " + angle); if (angle >= 91.9f) { tempPlanarMoveDirection = Quaternion.AngleAxis(((angle2 - 90f) * 2f - 2f), Vector3.up) * tempPlanarMoveDirection; angle = Vector3.Angle(tempPlanarMoveDirection, collisionNormal); } } else { tempPlanarMoveDirection = Quaternion.AngleAxis((90f - angle + 1f), Vector3.up) * tempPlanarMoveDirection; float angle2 = angle; angle = Vector3.Angle(tempPlanarMoveDirection, collisionNormal); print("angle if under 90: " + angle); if (angle <= 90f) { tempPlanarMoveDirection = Quaternion.AngleAxis(-((90f - angle2) * 2f + 2f), Vector3.up) * tempPlanarMoveDirection; angle = Vector3.Angle(tempPlanarMoveDirection, collisionNormal); } } planarMoveDirection = Vector3.MoveTowards(planarMoveDirection, tempPlanarMoveDirection.normalized * WalkSpeed, JumpAcceleration * controller.deltaTime); } else { planarMoveDirection = Vector3.MoveTowards(planarMoveDirection, planarMoveDirection.normalized * WalkSpeed, JumpAcceleration * controller.deltaTime); } verticalMoveDirection -= controller.up * wallRunGravity * controller.deltaTime; } else { verticalMoveDirection -= controller.up * Gravity * controller.deltaTime; } moveDirection = planarMoveDirection + verticalMoveDirection; if (LocalMovement().magnitude > 0) { previousNonZeroLocalMovement = LocalMovement(); } previousNonZeroAverageLocalMovement = average2; previousPlanarMovedirection = planarMoveDirection; if (controller.collisionData.Count > 0) { previousFirstCollision = controller.collisionData[0]; } else { if (previousFirstCollision.gameObject) { previousFirstCollision.gameObject = null; } } }