protected BufferZoneInfo GetBufferZoneInfo(float gravityScale, Direction.Vertical verticalDirection) { BufferZoneInfo bufferZoneInfo = new BufferZoneInfo(); bool willSnapToLedgeHeight = wallClimb.enableClimbing || ledgeGrab.enableLedgeGrab; if(willSnapToLedgeHeight) { RaycastHelper.LedgeInfo ledgeInfo = RaycastHelper.DetectLedgeOnWall(controller.direction.horizontal, (Direction.Vertical)((int)verticalDirection * gravityScale), controller.slots.actor.GetComponent<BoxCollider2D>(), controller.slots.physicsObject.properties.velocity.y * PhysicsManager.Instance.fixedDeltaTime * -(int)verticalDirection); if(!ledgeInfo.didHit) { ledgeInfo = RaycastHelper.DetectLedgeOnWall(controller.direction.horizontal, (Direction.Vertical)((int)verticalDirection * gravityScale), controller.slots.actor.GetComponent<BoxCollider2D>(), controller.slots.physicsObject.properties.velocity.y * PhysicsManager.Instance.fixedDeltaTime * -(int)verticalDirection, 0.0f); } if(ledgeInfo.didHit) { bufferZoneInfo.isLedgeDetected = true; bufferZoneInfo.bufferCutoff = ledgeInfo.hitY - (controller.slots.actor.GetComponent<BoxCollider2D>().size.y * 0.5f * gravityScale * -(int)verticalDirection); float adjustedPositionY = transform.position.y + controller.slots.physicsObject.properties.velocity.y * PhysicsManager.Instance.fixedDeltaTime * -(int)verticalDirection; if(verticalDirection == Direction.Vertical.Down && ((gravityScale < 0.0f && adjustedPositionY < bufferZoneInfo.bufferCutoff) || (gravityScale > 0.0f && adjustedPositionY > bufferZoneInfo.bufferCutoff))) //At top of wall { bufferZoneInfo.isInBufferZone = true; } else if(verticalDirection == Direction.Vertical.Up && ((gravityScale < 0.0f && adjustedPositionY > bufferZoneInfo.bufferCutoff) || (gravityScale > 0.0f && adjustedPositionY < bufferZoneInfo.bufferCutoff))) { bufferZoneInfo.isInBufferZone = true; } } } return bufferZoneInfo; }
//If a projectile is slotted, this spawns it public void CreateProjectile() { Direction.Horizontal direction = (slots.actor.slots.controller) ? slots.actor.slots.controller.direction.horizontal : Direction.Horizontal.Right; if (attackDirection == AttackDirection.Behind) { direction = (Direction.Horizontal)((int)direction * -1.0f); } Projectile newProjectile = projectile.rexPool.Spawn().GetComponent <Projectile>(); Direction.Horizontal startingHorizontalDirection = direction; Direction.Vertical startingVerticalDirection = Direction.Vertical.Up; if (projectile.isAimable) { if (Mathf.Abs(slots.actor.slots.input.verticalAxis) == 1.0f && slots.actor.slots.input.horizontalAxis == 0.0f) { startingHorizontalDirection = Direction.Horizontal.Neutral; } startingVerticalDirection = (Direction.Vertical)(slots.actor.slots.input.verticalAxis * PhysicsManager.Instance.gravityScale); } newProjectile.isAimable = projectile.isAimable; newProjectile.Fire(new Vector2(slots.actor.transform.position.x + transform.localPosition.x * (int)direction, transform.position.y), startingHorizontalDirection, startingVerticalDirection, slots.actor, projectile.rexPool); }
protected void MoveVertical() { bool willTurn = false; if ((physicsObject.IsOnSurface() && willTurnOnWallContact)) { willTurn = true; } else if (willTurnOnDistance && ((transform.position.y >= maxMovePositionVector.y && directionY == Direction.Vertical.Up) || (transform.position.y <= minMovePositionVector.y && directionY == Direction.Vertical.Down))) { willTurn = true; float snappingPosition; if (transform.position.y >= maxMovePositionVector.y && directionY == Direction.Vertical.Up) { snappingPosition = maxMovePositionVector.y; } else { snappingPosition = minMovePositionVector.y; } physicsObject.previousFrameProperties.position = new Vector3(transform.position.x, snappingPosition, transform.position.z); physicsObject.properties.position = new Vector3(transform.position.x, snappingPosition, transform.position.z); } if (willTurn) { directionY = (directionY == Direction.Vertical.Up) ? Direction.Vertical.Down : Direction.Vertical.Up; } physicsObject.SetVelocityY(moveSpeed.y * (int)directionY); }
public static LedgeInfo DetectLedgeOnWall(Direction.Horizontal _direction, Direction.Vertical _verticalDirection, BoxCollider2D _collider, float velocityToCheck, float offset = 0.25f) { RaycastHit2D raycastHits = new RaycastHit2D(); int collisionLayerMask = 1 << LayerMask.NameToLayer("Terrain"); float rayLength = _collider.size.y + Mathf.Abs(velocityToCheck) + offset; Vector2 rayDirection = (_verticalDirection == Direction.Vertical.Up) ? Vector2.up : Vector2.down; bool isConnected = false; Vector2 rayOrigin = new Vector2(_collider.transform.position.x + (_collider.size.x * 0.5f) * (int)_direction, _collider.transform.position.y - (_collider.size.y * 0.5f * (int)_verticalDirection)); rayOrigin.y = (rayDirection == Vector2.up) ? _collider.bounds.min.y - offset : _collider.bounds.max.y + offset; float raycastSpacing = _collider.size.x * 0.5f; rayOrigin.x = (_direction == Direction.Horizontal.Left) ? rayOrigin.x - raycastSpacing : rayOrigin.x + raycastSpacing; raycastHits = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, collisionLayerMask); if (raycastHits.fraction > 0) { isConnected = true; } #if UNITY_EDITOR //Debug.DrawRay(rayOrigin, new Vector2(0.25f * (int)_direction, (int)rayDirection.y * rayLength), Color.red); #endif float hitY = (isConnected) ? raycastHits.point.y : 0.0f; LedgeInfo ledgeInfo = new LedgeInfo(); ledgeInfo.didHit = isConnected; ledgeInfo.hitY = hitY; return(ledgeInfo); }
public static bool IsOnSurface(string surfaceTag, Direction.Vertical _verticalDirection, BoxCollider2D _collider, float gravityScaleMultiplier = 1.0f) { RaycastHit2D raycastHits = new RaycastHit2D(); int collisionLayerMask = 1 << LayerMask.NameToLayer("Terrain") | 1 << LayerMask.NameToLayer("PassThroughBottom"); float rayLength = _collider.size.y * 0.5f + 0.25f; Vector2 rayDirection = (_verticalDirection == Direction.Vertical.Up) ? Vector2.up : Vector2.down; bool isConnected = false; Vector2 rayOrigin = new Vector2(_collider.transform.position.x, _collider.transform.position.y + (_collider.offset.y * gravityScaleMultiplier)); float raycastSpacing = _collider.size.x * 0.5f; rayOrigin.x = rayOrigin.x - raycastSpacing; for (int i = 0; i < 3; i++) { raycastHits = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, collisionLayerMask); if (raycastHits.fraction > 0) { if (raycastHits.collider.tag == surfaceTag) { isConnected = true; } } #if UNITY_EDITOR //Debug.DrawRay(rayOrigin, new Vector2(0.0f, (int)_verticalDirection) * rayLength, Color.red); #endif rayOrigin.x += raycastSpacing; } return(isConnected); }
public static bool IsNextToLedge(Direction.Horizontal _direction, Direction.Vertical _verticalDirection, BoxCollider2D _collider, float gravityScaleMultiplier = 1.0f) { RaycastHit2D raycastHits = new RaycastHit2D(); int collisionLayerMask = 1 << LayerMask.NameToLayer("Terrain") | 1 << LayerMask.NameToLayer("PassThroughBottom"); float rayLength = _collider.size.y * 0.5f + 0.1f; Vector2 rayDirection = (_verticalDirection == Direction.Vertical.Up) ? Vector2.up : Vector2.down; bool isConnected = false; Vector2 rayOrigin = new Vector2(_collider.transform.position.x, _collider.transform.position.y + (_collider.offset.y * gravityScaleMultiplier)); float raycastSpacing = _collider.size.x * 0.5f; rayOrigin.x = (_direction == Direction.Horizontal.Left) ? rayOrigin.x - raycastSpacing : rayOrigin.x + raycastSpacing; raycastHits = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, collisionLayerMask); if (raycastHits.fraction > 0) { isConnected = true; } #if UNITY_EDITOR //Debug.DrawRay(rayOrigin, new Vector2(0.0f, (int)_verticalDirection) * rayLength, Color.red); #endif return(!isConnected); }
public static bool DropThroughFloorRaycast(Direction.Vertical _verticalDirection, BoxCollider2D _collider, float gravityScaleMultiplier = 1.0f) { RaycastHit2D raycastHits = new RaycastHit2D(); int collisionLayerMask = 1 << LayerMask.NameToLayer("PassThroughBottom"); Vector3 rayDirection = (_verticalDirection == Direction.Vertical.Down) ? Vector3.down : Vector3.up; bool isConnected = false; Vector2 rayOrigin = new Vector2(_collider.transform.position.x, _collider.transform.position.y + (_collider.offset.y * gravityScaleMultiplier)); float raycastSpacing = _collider.size.x * 0.5f; float rayLength = _collider.size.y * 0.5f + 0.05f; rayOrigin.x -= rayLength; for (int i = 0; i < 3; i++) { raycastHits = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, collisionLayerMask); if (raycastHits.fraction > 0) { isConnected = true; } //Debug.DrawRay(rayOrigin, rayDirection * rayLength, Color.red); rayOrigin.x += rayLength; } return(isConnected); }
public static bool IsUnderOverhang(Direction.Vertical _verticalDirection, Vector2 _colliderSize, Vector3 _colliderPosition) { RaycastHit2D raycastHits = new RaycastHit2D(); int collisionLayerMask = 1 << LayerMask.NameToLayer("Terrain"); float sideBuffer = 0.025f; //This pulls the raycasts slightly in from the sides of the collider; it prevents the player from crouching NEXT TO an overhang and being unable to get back up float rayLength = _colliderSize.y * 0.5f + 0.25f; Vector2 rayDirection = (_verticalDirection == Direction.Vertical.Up) ? Vector2.up : Vector2.down; bool isConnected = false; Vector2 rayOrigin = new Vector2(_colliderPosition.x, _colliderPosition.y); float raycastSpacing = _colliderSize.x * 0.5f - sideBuffer; rayOrigin.x = rayOrigin.x - raycastSpacing; for (int i = 0; i < 3; i++) { raycastHits = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, collisionLayerMask); if (raycastHits.fraction > 0) { isConnected = true; } #if UNITY_EDITOR //Debug.DrawRay(rayOrigin, new Vector2(0.0f, (int)_verticalDirection) * rayLength, Color.red); #endif rayOrigin.x += raycastSpacing; } return(isConnected); }
//Used internally for added safety when checking slope collisions private void CheckForSlopesInOtherDirection() { box = GetRectAtPosition(properties.position); Direction.Vertical direction = (properties.velocity.y + properties.externalVelocity.y <= 0.0f) ? Direction.Vertical.Up : Direction.Vertical.Down; if (Mathf.Abs(properties.velocity.y + properties.externalVelocity.y) == 0.0f) { return; } float edgeBuffer = 0.025f; Vector2 startPoint = new Vector2(box.xMin + edgeBuffer, box.center.y); Vector2 endPoint = new Vector2(box.xMax - edgeBuffer, box.center.y); RaycastHit2D[] raycastHits = new RaycastHit2D[raycastAmounts.vertical]; float rayLength = box.height / 2.0f + slopeDetectionMargin; float lowestFraction = Mathf.Infinity; int savedIndex = 0; bool didCollide = false; for (int i = 0; i < raycastAmounts.vertical; i++) { float raycastSpacing = (float)i / (float)(raycastAmounts.vertical - 1); Vector2 rayOrigin = Vector2.Lerp(startPoint, endPoint, raycastSpacing); Vector2 rayDirection = (direction == Direction.Vertical.Down) ? -Vector2.up : Vector2.up; raycastHits[i] = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, collisionLayerMask); if (raycastHits[i].fraction > 0) { didCollide = true; if (raycastHits[i].fraction < lowestFraction) { savedIndex = i; lowestFraction = raycastHits[i].fraction; } } } if (didCollide) { if (direction == Direction.Vertical.Down) { Vector2 tempNewPosition = properties.position + Vector2.down * (raycastHits[savedIndex].fraction * rayLength - box.height / 2); if (properties.position.y < tempNewPosition.y) { properties.position += Vector2.down * (raycastHits[savedIndex].fraction * rayLength - box.height / 2); } } else { Vector2 tempNewPosition = properties.position + Vector2.up * (raycastHits[savedIndex].fraction * rayLength - box.height / 2); if (properties.position.y > tempNewPosition.y) { properties.position += Vector2.up * (raycastHits[savedIndex].fraction * rayLength - box.height / 2); } } } }
void Start() { directionX = startingDirectionX; directionY = startingDirectionY; if (!willStartWhenPlayerIsOnTop && isMovementEnabled) { StartMoving(); } }
protected void SetVerticalDirection(Direction.Vertical _direction) { direction.vertical = _direction; if (direction.vertical == Direction.Vertical.Down) { transform.localScale = new Vector3(-1.0f, 1.0f, 1.0f); } else if (direction.vertical == Direction.Vertical.Up) { transform.localScale = new Vector3(1.0f, 1.0f, 1.0f); } }
public bool CanExitCrouch() { bool canExit = true; Direction.Vertical direction = (Direction.Vertical)controller.GravityScaleMultiplier(); if (RaycastHelper.IsUnderOverhang(direction, nonCrouchingColliderSize, boxCollider.transform.position)) { canExit = false; } return(canExit); }
//Checks to see if we hit either the floor or the ceiling private bool CheckForCeilingFloorContact(Direction.Vertical _direction, bool willDetectWithMargin = false) { float edgeBuffer = 0.025f; Vector2 startPoint = new Vector2(box.xMin + edgeBuffer, box.center.y); Vector2 endPoint = new Vector2(box.xMax - edgeBuffer, box.center.y); RaycastHit2D[] raycastHits = new RaycastHit2D[raycastAmounts.vertical]; int numberOfCollisions = 0; float fraction = 0; float margin = (willDetectWithMargin) ? 0.25f : 0.001f; float rayLength = box.height / 2 + margin; Vector3 direction = new Vector3(0.0f, (int)_direction, 0.0f); bool didCollide = false; float lowestFraction = Mathf.Infinity; int savedIndex = 0; for (int i = 0; i < raycastAmounts.vertical; i++) { float raycastSpacing = (float)i / (float)(raycastAmounts.vertical - 1); Vector2 rayOrigin = Vector2.Lerp(startPoint, endPoint, raycastSpacing); Vector2 rayDirection = (_direction == Direction.Vertical.Down) ? -Vector2.up : Vector2.up; int mask = (_direction == Direction.Vertical.Down) ? collisionLayerMaskDown : collisionLayerMask; raycastHits[i] = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, mask); if (raycastHits[i].fraction > 0) { didCollide = true; if (_direction == Direction.Vertical.Up) { properties.isAgainstCeiling = true; return(true); } else if (_direction == Direction.Vertical.Down) { properties.isGrounded = true; willSnapToFloorOnStart = false; return(true); } break; } } return(false); }
public void Fire(Vector2 _startingPosition, Direction.Horizontal _horizontal, Direction.Vertical _vertical, RexActor _spawningActor, RexPool _parentSpawnPool = null) { if (!willDestroyWhenSceneChanges) { DontDestroyOnLoad(gameObject); } isFiring = true; isBeingReflected = false; movementSpeed = originalMovementSpeed; spawningActor = _spawningActor; if (sounds.fireSound) { GetComponent <AudioSource>().PlayOneShot(sounds.fireSound); } if (_parentSpawnPool != null) { parentSpawnPool = _parentSpawnPool; } SetPosition(_startingPosition); SetHorizontalDirection(_horizontal); SetVerticalDirection((Direction.Vertical)((int)startingVerticalDirection * (int)_vertical * PhysicsManager.Instance.gravityScale)); firingDirection = _horizontal; slots.physicsObject.properties.acceleration = Vector2.zero; float startingXSpeed = (acceleration == 0.0f) ? movementSpeed.x * (int)direction.horizontal : 0.0f; slots.physicsObject.SetVelocityX(startingXSpeed); slots.physicsObject.SetAccelerationCapX(movementSpeed.x * (int)direction.horizontal); float startingYSpeed = (acceleration == 0.0f) ? movementSpeed.y * (int)direction.vertical : 0.0f; slots.physicsObject.SetVelocityY(startingYSpeed); slots.physicsObject.SetAccelerationCapY(movementSpeed.y * (int)direction.vertical); }
//Checks our vertical collisions, and either stops us from moving or enables us to continue moving private void CheckVerticalCollisions(float velocityToCheck, bool isTranslatingDirectly = false) { if (!willStickToMovingPlatforms) { movingPlatform = null; } box = GetRectAtPosition(properties.position); Direction.Vertical direction = (velocityToCheck <= 0.0f) ? Direction.Vertical.Down : Direction.Vertical.Up; if (velocityToCheck == 0.0f) { return; } //The edge buffer prevents you from standing on a ledge with the very corner of your hitbox //This fixes problems where you jump straight up *next to* a ledge and the end up resting on the ledge itself on the way down float edgeBuffer = 0.025f; Vector2 startPoint = new Vector2(box.xMin + edgeBuffer, box.center.y); Vector2 endPoint = new Vector2(box.xMax - edgeBuffer, box.center.y); RaycastHit2D[] raycastHits = new RaycastHit2D[raycastAmounts.vertical]; float rayLength = box.height / 2.0f + (((properties.isGrounded && direction == Direction.Vertical.Down) || (properties.isAgainstCeiling && direction == Direction.Vertical.Up)) ? slopeDetectionMargin : Mathf.Abs(velocityToCheck)); float lowestFraction = Mathf.Infinity; int savedIndex = 0; bool didCollide = false; for (int i = 0; i < raycastAmounts.vertical; i++) { float raycastSpacing = (float)i / (float)(raycastAmounts.vertical - 1); Vector2 rayOrigin = Vector2.Lerp(startPoint, endPoint, raycastSpacing); Vector2 rayDirection = (direction == Direction.Vertical.Down) ? -Vector2.up : Vector2.up; //Debug.DrawRay(rayOrigin, rayDirection * rayLength, Color.red); int mask = ((direction == Direction.Vertical.Down && gravitySettings.gravityScale > 0.0f) || (direction == Direction.Vertical.Up && gravitySettings.gravityScale <= 0.0f)) ? collisionLayerMaskDown : collisionLayerMask; raycastHits[i] = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, mask); if (raycastHits[i].fraction > 0) { didCollide = true; if (raycastHits[i].fraction < lowestFraction) { savedIndex = i; lowestFraction = raycastHits[i].fraction; } } } //This prevents you from walking off a one-way platform, holding left or right to be back inside it as you fall, and clipping back up on top of it if (didCollide && raycastHits[savedIndex].collider.gameObject.layer == LayerMask.NameToLayer("PassThroughBottom")) { float buffer = 0.1f; if ((gravitySettings.gravityScale > 0.0f && box.yMin < raycastHits[savedIndex].collider.bounds.max.y - buffer) || (gravitySettings.gravityScale <= 0.0f && box.yMax > raycastHits[savedIndex].collider.bounds.min.y + buffer)) { didCollide = false; } } //In rare instances, if the actor is already on top of a PassThroughBottom collider when they land on the ground, the above raycast can fail to detect the terrain; this is a failsafe if (!didCollide && raycastAmounts.enableRedundantVerticalCollisions) { int adjustedVerticalRaycasts = Mathf.CeilToInt(raycastAmounts.vertical * 0.5f); for (int i = 0; i < adjustedVerticalRaycasts; i++) { float raycastSpacing = (float)i / (float)(adjustedVerticalRaycasts - 1); Vector2 rayOrigin = Vector2.Lerp(startPoint, endPoint, raycastSpacing); Vector2 rayDirection = (direction == Direction.Vertical.Down) ? -Vector2.up : Vector2.up; int mask = collisionLayerMask; raycastHits[i] = Physics2D.Raycast(rayOrigin, rayDirection, rayLength, mask); if (raycastHits[i].fraction > 0) { didCollide = true; if (raycastHits[i].fraction < lowestFraction) { savedIndex = i; lowestFraction = raycastHits[i].fraction; } } } } if (didCollide) { properties.velocity = new Vector2(properties.velocity.x, 0); properties.externalVelocity = new Vector2(properties.externalVelocity.x, 0); if (direction == Direction.Vertical.Down) { properties.isGrounded = true; willSnapToFloorOnStart = false; properties.isFalling = false; properties.isAgainstCeiling = false; properties.position += Vector2.down * (raycastHits[savedIndex].fraction * rayLength - box.height / 2); MovingPlatform platform = raycastHits[savedIndex].collider.GetComponent <MovingPlatform>(); if (platform != null) { movingPlatform = platform; movingPlatform.NotifyOfObjectOnTop(); } else { movingPlatform = null; } } else { if (willStickToMovingPlatforms) { MovingPlatform platform = raycastHits[savedIndex].collider.GetComponent <MovingPlatform>(); if (platform != null) { movingPlatform = platform; } else { movingPlatform = null; } } properties.isAgainstCeiling = true; if (gravitySettings.gravityScale > 0.0f) //Hit your head on the ceiling; stop your jump { properties.isFalling = true; } else { properties.isFalling = false; } properties.position += Vector2.up * (raycastHits[savedIndex].fraction * rayLength - box.height / 2); } if (DidLandThisFrame()) { if (gravitySettings.gravityScale >= 0.0f) { NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Bottom, RexObject.CollisionType.Enter); } else { NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Top, RexObject.CollisionType.Enter); } } if (DidHitCeilingThisFrame()) { if (gravitySettings.gravityScale >= 0.0f) { NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Top, RexObject.CollisionType.Enter); } else { NotifyOfCollision(raycastHits[savedIndex].collider, RexObject.Side.Bottom, RexObject.CollisionType.Enter); } } } else { properties.isAgainstCeiling = false; properties.isGrounded = false; if (isTranslatingDirectly) { properties.position = new Vector2(transform.position.x, properties.position.y + velocityToCheck); } } }