Skip to content

Commit

Permalink
Merge pull request #1 from yuzhengwen/Testing
Browse files Browse the repository at this point in the history
Initial commit
  • Loading branch information
yuzhengwen committed Mar 11, 2024
2 parents 9392102 + da1bafe commit f493623
Show file tree
Hide file tree
Showing 122 changed files with 18,031 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .vsconfig
@@ -0,0 +1,6 @@
{
"version": "1.0",
"components": [
"Microsoft.VisualStudio.Workload.ManagedGame"
]
}
53 changes: 53 additions & 0 deletions Assets/Movement.cs
@@ -0,0 +1,53 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static PlayerPhysics;

public class Movement : MonoBehaviour
{
[Header("Jump Parameters")]
public float jumpHeight = 4f;
public float timeToApex = .5f;

// will be set based on jump height & time to apex
float jumpVel;
float jumpGravity;
float jumpGravityModifier;

float moveSpeed = 6;
float gravity = -10;

Vector2 targetVel;

float xVelSmooth;
[Header("Smoothing")]
public float smoothTimeGrounded = .05f;
public float smoothTimeAirborne = .15f;

PlayerPhysics phyObj;

void Start()
{
phyObj = GetComponent<PlayerPhysics>();

jumpGravity = -2 * (jumpHeight / Mathf.Pow(timeToApex, 2));
jumpGravityModifier = jumpGravity / gravity;
jumpVel = -(jumpGravity * timeToApex);
}

void Update()
{
if (phyObj.collisionInfo.below || phyObj.collisionInfo.above) targetVel.y = 0;

Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), 0);

if (Input.GetKeyDown(KeyCode.Space) && phyObj.collisionInfo.below)
{
targetVel.y = jumpVel;
}
float rawTargetXVel = input.x * moveSpeed;
targetVel.x = Mathf.SmoothDamp(targetVel.x, rawTargetXVel, ref xVelSmooth, phyObj.collisionInfo.below ? smoothTimeGrounded : smoothTimeAirborne);
targetVel.y += jumpGravity * Time.deltaTime;
phyObj.Move(targetVel * Time.deltaTime);
}
}
11 changes: 11 additions & 0 deletions Assets/Movement.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 107 additions & 0 deletions Assets/PhysicsObject.cs
@@ -0,0 +1,107 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysicsObject : MonoBehaviour
{
public float gravityModifier = 1f;
protected Vector2 velocity;
protected const float minMoveDistance = 0.001f;

protected ContactFilter2D contactFilter;
protected List<RaycastHit2D> hits = new();
protected const float shellRadius = 0.01f; // slight padding between objects (when colliding)
public const float minGroundNormalY = 0.707f; // value of y for a unit vector at 45 deg from (0,1)
protected Vector2 groundNormal = new(0, 1);
protected Vector2 groundParallel;
protected bool grounded = false;

protected Vector2 targetVelocity;

protected Rigidbody2D rb;

private void Awake()
{
rb = GetComponent<Rigidbody2D>();
}
// Start is called before the first frame update
void Start()
{
contactFilter.useTriggers = false; // dont collide with triggers
contactFilter.SetLayerMask(Physics2D.GetLayerCollisionMask(gameObject.layer)); // only collide with layers that can collide with layer of gameobject (in physics2d settings)
contactFilter.useLayerMask = true;
}
// we will separately check collisions
// y will check for ground, if slope detected, treat as flat ground
// x will check for wall/ slope
private void FixedUpdate()
{
velocity += gravityModifier * Time.deltaTime * Physics2D.gravity; // dv = g * dt
velocity.x = targetVelocity.x;
grounded = false;
// initial distance we want to move (without accounting for collisions)
Vector2 deltaPos = velocity * Time.deltaTime; // dx = v * dt

groundParallel = new(groundNormal.y, -groundNormal.x); // gets a vector perpendicular to ground normal
Debug.DrawRay(transform.position, groundParallel * 2, Color.red);

Vector2 move = deltaPos.y * Vector2.up;
Vector2 y = Movement(move, true);

move = groundParallel * deltaPos.x; //move along slope/flat ground at same speed
Vector2 x = Movement(move, false);

rb.MovePosition(rb.position + (x + y));
Debug.DrawRay(transform.position, groundNormal, Color.green);
Debug.DrawRay(transform.position, (x + y) * 10, Color.black);
}
private Vector2 Movement(Vector2 move, bool yMovement)
{
float distance = move.magnitude; // distance we want to move
if (distance > minMoveDistance)
{
// one problem right now is that it returns 1 raycasthit per collider, very buggy when transitioning from flat to slope
int count = rb.Cast(move, contactFilter, hits, distance + shellRadius);
Debug.Log($"Colliding with {count} objects");
foreach (RaycastHit2D hit in hits)
{
Vector2 normal = hit.normal;
Debug.DrawRay(hit.point, normal, Color.blue);
if (IsGround(normal))
{
grounded = true;
groundNormal = normal;
if (yMovement)
{
normal.x = 0; // if we are considered grounded, set normal to (0, 1)
}
}
if (IsWall(normal))
{
if (velocity.x * normal.x > 0) velocity.x = 0;
}
else
{
float projection = Vector2.Dot(velocity, normal);
if (projection < 0)
{
velocity -= projection * normal; // cancel out component of velocity parallel to normal
}
}
float modifiedDistance = hit.distance - shellRadius; // distance between object and incoming colliding obj
distance = modifiedDistance < distance ? modifiedDistance : distance;
}
}
return (move.normalized * distance);
}
// if slope <= 45 deg considered ground
private bool IsGround(Vector2 normal)
{
return normal.y >= minGroundNormalY;
}
// if 45 deg < slope < 90 deg considered wall
private bool IsWall(Vector2 normal)
{
return normal.y >= 0 && normal.y < minGroundNormalY;
}
}
11 changes: 11 additions & 0 deletions Assets/PhysicsObject.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

130 changes: 130 additions & 0 deletions Assets/PlayerPhysics.cs
@@ -0,0 +1,130 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerPhysics : MonoBehaviour
{
public LayerMask collisionMask;

const float skinWidth = .015f;
public int horizontalRayCount = 4;
public int verticalRayCount = 4;

float horizontalRaySpacing;
float verticalRaySpacing;

BoxCollider2D col;
Corners raycastOrigins;
public CollisionInfo collisionInfo;

void Start()
{
col = GetComponent<BoxCollider2D>();
CalculateRaySpacing();
}

public void Move(Vector3 deltaPos)
{
collisionInfo.Reset();
UpdateRaycastOrigins();
if (deltaPos.x != 0) // if not moving in x axis, no need to check hor collisions
{
HorizontalCollisions(ref deltaPos);
}
if (deltaPos.y != 0) // same, but since gravity is always applied, this will always !=0
{
VerticalCollisions(ref deltaPos);
}
Debug.DrawRay(transform.position, deltaPos * (1/Time.deltaTime)/2, Color.red);
transform.Translate(deltaPos);
}

void HorizontalCollisions(ref Vector3 deltaPos)
{
float xDir = Mathf.Sign(deltaPos.x);
float rayLength = Mathf.Abs(deltaPos.x) + skinWidth;

for (int i = 0; i < horizontalRayCount; i++)
{
Vector2 rayOrigin = (xDir == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
rayOrigin += Vector2.up * (horizontalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * xDir, rayLength, collisionMask);
Debug.DrawRay(rayOrigin, Vector2.right * xDir * rayLength, Color.red);

if (hit)
{
deltaPos.x = (hit.distance - skinWidth) * xDir;
rayLength = hit.distance;

collisionInfo.left = xDir == -1;
collisionInfo.right = xDir == 1;
}
}
}

void VerticalCollisions(ref Vector3 deltaPos)
{
float yDir = Mathf.Sign(deltaPos.y);
float rayLength = Mathf.Abs(deltaPos.y) + skinWidth;

for (int i = 0; i < verticalRayCount; i++)
{
Vector2 rayOrigin = (yDir == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i + deltaPos.x);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * yDir, rayLength, collisionMask);

Debug.DrawRay(rayOrigin, Vector2.up * yDir * rayLength, Color.red);

if (hit)
{
deltaPos.y = (hit.distance - skinWidth) * yDir;
rayLength = hit.distance;

collisionInfo.below = yDir == -1;
collisionInfo.above = yDir == 1;
}
}
}

void UpdateRaycastOrigins()
{
Bounds bounds = col.bounds;
bounds.Expand(skinWidth * -2);

raycastOrigins.bottomLeft = new Vector2(bounds.min.x, bounds.min.y);
raycastOrigins.bottomRight = new Vector2(bounds.max.x, bounds.min.y);
raycastOrigins.topLeft = new Vector2(bounds.min.x, bounds.max.y);
raycastOrigins.topRight = new Vector2(bounds.max.x, bounds.max.y);
}

void CalculateRaySpacing()
{
Bounds bounds = col.bounds;
bounds.Expand(skinWidth * -2);

horizontalRayCount = Mathf.Clamp(horizontalRayCount, 2, int.MaxValue);
verticalRayCount = Mathf.Clamp(verticalRayCount, 2, int.MaxValue);

horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);
verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);
}

struct Corners
{
public Vector2 topLeft, topRight;
public Vector2 bottomLeft, bottomRight;
}
[Serializable]
public struct CollisionInfo
{
public bool below, above, left, right;
public void Reset()
{
below = false;
above = false;
left = false;
right = false;
}
}
}
11 changes: 11 additions & 0 deletions Assets/PlayerPhysics.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Assets/Scenes.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f493623

Please sign in to comment.