Created
September 22, 2025 11:28
-
-
Save Hegemege/6eab1445fba03bd2481238b542ed39b2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using UnityEngine; | |
| using System.Collections; | |
| using System.Net; | |
| #if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) | |
| using XInputDotNetPure; | |
| #endif | |
| public class PlayerPhysicsScript : MonoBehaviour { | |
| // Physics | |
| // Movement speed in units per second | |
| public float movementSpeed; | |
| public float maxVerticalSpeed; | |
| public float maxHorizontalSpeed; | |
| public float horizontalInputThreshold; | |
| public float minBounceVelocity; | |
| // Gravity in acceleration speed | |
| public float gravity; | |
| // Jump variables | |
| public float jumpSpeed; | |
| public float jumpCooldownTimerMax; | |
| private float jumpCooldownTimer; | |
| private bool canJump; | |
| private bool jumped; | |
| // Dampening and friction | |
| public float dampening; | |
| public float bounceDampening; | |
| public float friction; | |
| // Last horizontal movement direction | |
| [HideInInspector] | |
| public int lastHorizontalDirection; | |
| // A vector variable other gameobjects can use to add impulse-like force to the physics objects | |
| [HideInInspector] | |
| public Vector3 impulseForce; | |
| // Physics properties | |
| private Vector3 velocity; | |
| private Vector3 lastUnstuckPosition; | |
| // Private helpers | |
| private BackgroundCollisionScript bgCollisionScript; | |
| private PlayerBehaviourScript behaviourScript; | |
| private Animator animator; | |
| // Audio effect event flags | |
| private bool startedMoving; | |
| private bool stoppedMoving; | |
| private X360ControllerManagerScript x360Script; | |
| #if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) | |
| public PlayerIndex playerIndex; | |
| #endif | |
| // Property for accessing the collision point of the player | |
| private Vector3 CollisionPoint | |
| { | |
| get { return transform.position + collisionOffset; } | |
| set { transform.position = value - collisionOffset; } | |
| } | |
| private Vector3 collisionOffset; | |
| // Which input axes to use (Horizontal_P1 etc) | |
| // Get it from the general behaviour script | |
| private string ControlSchemePostfix | |
| { | |
| get | |
| { | |
| return behaviourScript.ControlSchemePostfix; | |
| } | |
| } | |
| private string ControlDevicePostfix | |
| { | |
| get | |
| { | |
| return behaviourScript.ControlDevicePostfix; | |
| } | |
| } | |
| // Controls properties | |
| private float HorizontalInput | |
| { | |
| get | |
| { | |
| if (ControlDevicePostfix == "kb") | |
| { | |
| return Input.GetAxis("Horizontal_" + ControlSchemePostfix + "_" + ControlDevicePostfix); | |
| } | |
| else | |
| { | |
| #if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) | |
| return x360Script.HorizontalLeftInput(playerIndex); | |
| #endif | |
| } | |
| return 0f; | |
| } | |
| } | |
| private float JumpInput | |
| { | |
| get | |
| { | |
| if (ControlDevicePostfix == "kb") | |
| { | |
| return Input.GetAxis("Jump_" + ControlSchemePostfix + "_" + ControlDevicePostfix); | |
| } | |
| else | |
| { | |
| #if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN) | |
| return x360Script.LeftShoulder(playerIndex); | |
| #endif | |
| } | |
| return 0f; | |
| } | |
| } | |
| void Awake() | |
| { | |
| x360Script = GameObject.Find("X360ControllerManager").GetComponent<X360ControllerManagerScript>(); | |
| } | |
| public void Spawn() | |
| { | |
| bgCollisionScript = GameObject.Find("Background").GetComponent<BackgroundCollisionScript>(); | |
| behaviourScript = GetComponent<PlayerBehaviourScript>(); | |
| animator = transform.Find("Sprite").GetComponent<Animator>(); | |
| collisionOffset = transform.Find("CollisionPoint").transform.position - transform.position; | |
| Respawn(); | |
| } | |
| public void Respawn() | |
| { | |
| // Reset physics values | |
| velocity = new Vector3(0, 0); | |
| lastHorizontalDirection = 1; | |
| impulseForce = new Vector3(0, 0); | |
| jumpCooldownTimer = 0f; | |
| jumped = false; | |
| canJump = false; | |
| lastUnstuckPosition = transform.position; | |
| } | |
| void FixedUpdate() | |
| { | |
| var dt = Time.fixedDeltaTime; | |
| if (behaviourScript.isDead) | |
| { | |
| return; | |
| } | |
| // Movement physics will be calculated in two passes: horizontal and vertical | |
| // This is so that sliding along edges will be smoother | |
| // If player is already stuck, dont calculate physics, instead move them back to a known unstuck location | |
| var wasStuck = bgCollisionScript.IsSolidWorld(CollisionPoint); | |
| wasStuck = wasStuck || !bgCollisionScript.IsInBounds(CollisionPoint); | |
| if (wasStuck) | |
| { | |
| CollisionPoint = lastUnstuckPosition; | |
| } | |
| else | |
| { | |
| lastUnstuckPosition = CollisionPoint; | |
| } | |
| // Horizontal input and gravity | |
| float dx = HorizontalInput * movementSpeed * dt; | |
| float dy = -gravity * dt; | |
| // Jump action | |
| if (jumped) | |
| { | |
| dy += jumpSpeed * dt; | |
| } | |
| if (velocity.x > horizontalInputThreshold) | |
| { | |
| if (dx > 0) | |
| { | |
| dx = 0f; | |
| } | |
| } | |
| else if (velocity.x < -horizontalInputThreshold) | |
| { | |
| if (dx < 0) | |
| { | |
| dx = 0f; | |
| } | |
| } | |
| // Impulse forces | |
| dx += impulseForce.x * dt; | |
| dy += impulseForce.y * dt; | |
| impulseForce = new Vector3(0, 0); | |
| // Apply velocity in steps (x and y separately), and test for collision | |
| var stuckXResult = bgCollisionScript.IsSolidWorld(CollisionPoint, velocity + new Vector3(dx, 0f)); | |
| var stuckYResult = bgCollisionScript.IsSolidWorld(CollisionPoint, velocity + new Vector3(0f, dy)); | |
| var isStuckBoundsX = !bgCollisionScript.IsInBounds(CollisionPoint + velocity + new Vector3(dx, 0f)); | |
| var isStuckBoundsY = !bgCollisionScript.IsInBounds(CollisionPoint + velocity + new Vector3(0f, dy)); | |
| var isStuckX = stuckXResult.x != -100f || isStuckBoundsX; | |
| var isStuckY = stuckYResult.x != -100f || isStuckBoundsY; | |
| if (!isStuckX) | |
| { | |
| velocity.x += dx; | |
| } | |
| if (!isStuckY) | |
| { | |
| velocity.y += dy; | |
| } | |
| // Friction | |
| if (isStuckX) //apply friction to velocity.y | |
| { | |
| velocity.y *= friction; | |
| } | |
| if (isStuckY) //apply friction to velocity.x | |
| { | |
| velocity.x *= friction; | |
| } | |
| // Sliding up a slope, while holding input key and dx is 0 | |
| if (isStuckX && HorizontalInput != 0f) | |
| { | |
| var nudge = 0.01f; | |
| var boostedDx = dx > 0f ? dx + nudge : dx - nudge; // Give dx a little nudge to better climb slopes from stand-still | |
| var absDx = Mathf.Abs(boostedDx); | |
| // Check if there is free space at dx, absDx (diagonal up) | |
| // If there is, move there! | |
| var stuckDiagResult = bgCollisionScript.IsSolidWorld(CollisionPoint, velocity + new Vector3(boostedDx, absDx)); | |
| var isStuckDiagonal = stuckDiagResult.x != -100f || | |
| !bgCollisionScript.IsInBounds(CollisionPoint + velocity + new Vector3(boostedDx, absDx)); | |
| if (!isStuckDiagonal) | |
| { | |
| velocity.x = boostedDx; | |
| velocity.y = absDx; | |
| } | |
| } | |
| // Enable jumping if y-wise we are stuck | |
| if (isStuckY) | |
| { | |
| // If was hit by terrain, use the raycast points for normal. Otherwise, get at position + velocity | |
| Vector3 normal; | |
| if (!isStuckBoundsY) | |
| { | |
| normal = bgCollisionScript.GetNormalWorld(new Vector2(stuckYResult.z, stuckYResult.w)); | |
| } | |
| else | |
| { | |
| normal = bgCollisionScript.GetNormalWorld(CollisionPoint + velocity); | |
| } | |
| // If the surface is facing up even somewhat, enable jumping | |
| if (Vector3.Dot(normal, new Vector3(0, 1, 0)) > 0f) | |
| { | |
| canJump = true; | |
| if (!jumped) | |
| { | |
| animator.SetTrigger("playerLand"); | |
| } | |
| } | |
| } | |
| else // otherwise disable it (air jumps are possible otherwise) | |
| { | |
| canJump = false; | |
| } | |
| // Clamp velocity to min/max range | |
| var clampedDx = Mathf.Clamp(velocity.x, -maxHorizontalSpeed, maxHorizontalSpeed); | |
| var clampedDy = Mathf.Clamp(velocity.y, -maxVerticalSpeed, maxVerticalSpeed); | |
| velocity = new Vector3(clampedDx, clampedDy); | |
| // Dampening | |
| velocity *= dampening; | |
| var stuckResult = bgCollisionScript.IsSolidWorld(CollisionPoint, velocity); | |
| // Test if the velocity would put us into terrain | |
| var isStuck = stuckResult.x != -100f; | |
| if (isStuck) | |
| { | |
| var normal = bgCollisionScript.GetNormalWorld(new Vector2(stuckResult.z, stuckResult.w)); | |
| var projectedVelocity = Vector3.Dot(normal, velocity); | |
| // If the velocity along the normal is not high enough, mitigate velocity | |
| if (Mathf.Abs(projectedVelocity) < minBounceVelocity) | |
| { | |
| velocity = new Vector3(0f, 0f); | |
| } | |
| else | |
| { | |
| // Bounce from the surface, use surface normal | |
| velocity -= normal * projectedVelocity * 2; | |
| // Bounce loses some energy | |
| velocity *= bounceDampening; | |
| } | |
| } | |
| // Test for being stuck again, in case the bounce puts us into terrain | |
| var finalStuckResult = bgCollisionScript.IsSolidWorld(CollisionPoint, velocity); | |
| isStuck = finalStuckResult.x != -100f || | |
| !bgCollisionScript.IsInBounds(CollisionPoint + velocity); | |
| if (isStuck) | |
| { | |
| velocity *= 0f; | |
| canJump = true; | |
| } | |
| // Apply velocity | |
| transform.Translate(velocity); | |
| // Reset jumping | |
| jumped = false; | |
| } | |
| void Update() | |
| { | |
| var dt = Time.deltaTime; | |
| if (behaviourScript.isDead) | |
| { | |
| return; | |
| } | |
| jumpCooldownTimer += dt; | |
| // If holding jump and cooldown is gone | |
| if (JumpInput > 0 && jumpCooldownTimer > jumpCooldownTimerMax) | |
| { | |
| if (canJump) | |
| { | |
| animator.SetTrigger("playerJump"); | |
| Fabric.EventManager.Instance.PostEvent("Player_Jump"); | |
| jumpCooldownTimer = 0f; | |
| jumped = true; | |
| canJump = false; | |
| } | |
| } | |
| if (HorizontalInput != 0.0f) | |
| { | |
| stoppedMoving = false; | |
| if (!startedMoving) | |
| { | |
| startedMoving = true; | |
| Fabric.EventManager.Instance.PostEvent("Player_Move"); | |
| } | |
| animator.SetTrigger("playerMove"); | |
| if (HorizontalInput > 0) | |
| { | |
| lastHorizontalDirection = 1; | |
| } | |
| else | |
| { | |
| lastHorizontalDirection = -1; | |
| } | |
| } | |
| else | |
| { | |
| startedMoving = false; | |
| if (!stoppedMoving) | |
| { | |
| stoppedMoving = true; | |
| Fabric.EventManager.Instance.PostEvent("Player_Stop"); | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment