I_wanna_be_a_Fox/Assets/Script/Controller2D.cs
Koha9 a80f3d6560 I wanna be a fox first commit.
Initial commit. Complete project for 'I Wanna Be A Fox' - a 2D scrolling game inspired by 'I Wanna Be The Guy'.
2024-02-22 07:27:59 +09:00

258 lines
8.3 KiB
C#

using UnityEngine;
using System.Collections;
public class Controller2D : RaycastController
{
float maxClimbAngle = 80;
float maxDescendAngle = 80;
public CollisionInfo collisions;
[HideInInspector]
public Vector2 playerInput;
public override void Start()
{
base.Start();
collisions.faceDir = 1;
}
public void Move(Vector3 velocity, bool standingOnPlatform)
{
Move(velocity, Vector2.zero, standingOnPlatform);
}
public void Move(Vector3 velocity, Vector2 input, bool standingOnPlatform = false)
{
UpdateRaycastOrigins();
collisions.Reset();
collisions.velocityOld = velocity;
playerInput = input;
if (velocity.x != 0)
{
collisions.faceDir = (int)Mathf.Sign(velocity.x);
}
if (velocity.y < 0)
{
DescendSlope(ref velocity);
}
HorizontalCollisions(ref velocity);
if (velocity.y != 0)
{
VerticalCollisions(ref velocity);
}
transform.Translate(velocity);
if (standingOnPlatform)
{
collisions.below = true;
}
}
void HorizontalCollisions(ref Vector3 velocity)
{
float directionX = collisions.faceDir;
float rayLength = Mathf.Abs(velocity.x) + skinWidth;
if (Mathf.Abs(velocity.x) < skinWidth)
{
rayLength = 2 * skinWidth;
}
for (int i = 0; i < horizontalRayCount; i++)
{
Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
rayOrigin += Vector2.up * (horizontalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, rayLength, collisionMask);
Debug.DrawRay(rayOrigin, Vector2.right * directionX * rayLength, Color.red);
if (hit)
{
if (hit.distance == 0)
{
continue;
}
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (i == 0 && slopeAngle <= maxClimbAngle)
{
if (collisions.descendingSlope)
{
collisions.descendingSlope = false;
velocity = collisions.velocityOld;
}
float distanceToSlopeStart = 0;
if (slopeAngle != collisions.slopeAngleOld)
{
distanceToSlopeStart = hit.distance - skinWidth;
velocity.x -= distanceToSlopeStart * directionX;
}
ClimbSlope(ref velocity, slopeAngle);
velocity.x += distanceToSlopeStart * directionX;
}
if (!collisions.climbingSlope || slopeAngle > maxClimbAngle)
{
velocity.x = (hit.distance - skinWidth) * directionX;
rayLength = hit.distance;
if (collisions.climbingSlope)
{
velocity.y = Mathf.Tan(collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Abs(velocity.x);
}
collisions.left = directionX == -1;
collisions.right = directionX == 1;
}
}
}
}
void VerticalCollisions(ref Vector3 velocity)
{
float directionY = Mathf.Sign(velocity.y);
float rayLength = Mathf.Abs(velocity.y) + skinWidth;
for (int i = 0; i < verticalRayCount; i++)
{
Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);
Debug.DrawRay(rayOrigin, Vector2.up * directionY * rayLength, Color.red);
if (hit)
{
if (hit.collider.tag == "Through")
{
if (directionY == 1 || hit.distance == 0)
{
continue;
}
if (collisions.fallingThroughPlatform)
{
continue;
}
if (playerInput.y == -1)
{
collisions.fallingThroughPlatform = true;
Invoke("ResetFallingThroughPlatform", .5f);
continue;
}
}
velocity.y = (hit.distance - skinWidth) * directionY;
rayLength = hit.distance;
if (collisions.climbingSlope)
{
velocity.x = velocity.y / Mathf.Tan(collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign(velocity.x);
}
collisions.below = directionY == -1;
collisions.above = directionY == 1;
}
}
if (collisions.climbingSlope)
{
float directionX = Mathf.Sign(velocity.x);
rayLength = Mathf.Abs(velocity.x) + skinWidth;
Vector2 rayOrigin = ((directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight) + Vector2.up * velocity.y;
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, rayLength, collisionMask);
if (hit)
{
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (slopeAngle != collisions.slopeAngle)
{
velocity.x = (hit.distance - skinWidth) * directionX;
collisions.slopeAngle = slopeAngle;
}
}
}
}
void ClimbSlope(ref Vector3 velocity, float slopeAngle)
{
float moveDistance = Mathf.Abs(velocity.x);
float climbVelocityY = Mathf.Sin(slopeAngle * Mathf.Deg2Rad) * moveDistance;
if (velocity.y <= climbVelocityY)
{
velocity.y = climbVelocityY;
velocity.x = Mathf.Cos(slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(velocity.x);
collisions.below = true;
collisions.climbingSlope = true;
collisions.slopeAngle = slopeAngle;
}
}
void DescendSlope(ref Vector3 velocity)
{
float directionX = Mathf.Sign(velocity.x);
Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomRight : raycastOrigins.bottomLeft;
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, -Vector2.up, Mathf.Infinity, collisionMask);
if (hit)
{
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (slopeAngle != 0 && slopeAngle <= maxDescendAngle)
{
if (Mathf.Sign(hit.normal.x) == directionX)
{
if (hit.distance - skinWidth <= Mathf.Tan(slopeAngle * Mathf.Deg2Rad) * Mathf.Abs(velocity.x))
{
float moveDistance = Mathf.Abs(velocity.x);
float descendVelocityY = Mathf.Sin(slopeAngle * Mathf.Deg2Rad) * moveDistance;
velocity.x = Mathf.Cos(slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(velocity.x);
velocity.y -= descendVelocityY;
collisions.slopeAngle = slopeAngle;
collisions.descendingSlope = true;
collisions.below = true;
}
}
}
}
}
void ResetFallingThroughPlatform()
{
collisions.fallingThroughPlatform = false;
}
public struct CollisionInfo
{
public bool above, below;
public bool left, right;
public bool climbingSlope;
public bool descendingSlope;
public float slopeAngle, slopeAngleOld;
public Vector3 velocityOld;
public int faceDir;
public bool fallingThroughPlatform;
public void Reset()
{
above = below = false;
left = right = false;
climbingSlope = false;
descendingSlope = false;
slopeAngleOld = slopeAngle;
slopeAngle = 0;
}
}
}