PlayerController
unknown
csharp
a month ago
26 kB
5
Indexable
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using Grappling; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Rendering.PostProcessing; using UnityEngine.SceneManagement; using UnityEngine.UI; public class PlayerController : MonoBehaviour { public static PlayerController Singleton; [Header("References")] [SerializeField] Rigidbody2D rb; [HideInInspector] public GrapplingGun grapplingGun; [SerializeField] new ParticleSystem particleSystem; [SerializeField] PostProcessVolume volume; TrailRenderer tr; [Header("Stats")] [SerializeField] bool invincible = false; public bool canAttack { get; private set; } public int coins = 0; [Tooltip("How much damage the player does")] public float damageMult = 1; [Tooltip("How much damage the player takes")] public float takeDamageMult = 1; public float critChance; [Tooltip("Period after taking damage when you are invincible")] [SerializeField] float invincibilityTime = 0.1f; [Header("Bounds")] [SerializeField] Color heavenColor; [SerializeField] float heavenVignetteIntensity; [SerializeField] int heavenSize = 9; [SerializeField] float outOfBoundsDamage; [SerializeField] float outOfBoundsDamageCooldown; [Tooltip("The velocity at which the player will be bounced up if he lands on a barrier")] [SerializeField] float outOfBoundsFallingGraceVelocity; [Header("Health Regeneration")] [Tooltip("How long it takes until player starts regenerating health after taking daamge")] [SerializeField] float damageRegenCooldown = 3; [HideInInspector] public float additionalDamageRegenCooldown; [Tooltip("How long it takes for another tick of regeneration to occur")] [SerializeField] float regenTickCooldown = 0.25f; [Tooltip("How much each tick of regeneration heals for")] [SerializeField] public float regenValue = 0.75f; [HideInInspector] public float additionalRegenValue; [SerializeField] float healVignetteIntensity = 0.5f; [SerializeField] float healVignetteFlashTime = 0.15f; [SerializeField] ParticleSystem regenParticles; [Header("Movement")] [SerializeField] float movementSpeed; [SerializeField] float friction; [SerializeField] float airFriction; float _friction; [HideInInspector] public float speedMult; [SerializeField] float jumpForce; [HideInInspector] public float jumpMult; [SerializeField] float jumpCooldown = 0.3f; [SerializeField] float raycastDist; [SerializeField] LayerMask groundLayer; [SerializeField] float baseMaxFallSpeed; public int maxDoubleJump = 1; public bool grounded; [SerializeField] float coyoteTime = 0.2f; ParticleSystem groundParticles; Vector2 groundColliderSize; [SerializeField] float footstepsPerSecondPerSpeed; [Header("Dashing")] [SerializeField] float dashForce; public float dashDuration; public float dashCooldown; [SerializeField] float gravityResetSpeed; [Header("Parachute")] [HideInInspector] public float maxFallSpeed = -10; [HideInInspector] public float gravityReductionMult; [Header("Health")] [SerializeField] public float maxHealth; [SerializeField] static float health; float defence; [SerializeField] Slider healthbar; [Header("Chests")] [HideInInspector] public ChestSpawnData chestWithinRangeData; [Header("Damage camera shake")] [SerializeField] float intensity; [SerializeField] float duration; [SerializeField] float frequency; [Header("Item upgrades")] [SerializeField] float sniperScopeIncrement = 0.1f; [SerializeField] float bloodyDaggerIncrement = 0.05f; float randomBleedChance = 0; [SerializeField] float stunPerkIncrement = 0.075f; float randomStunChance; [SerializeField] float airDefenceIncrement = 0.05f; float airDamageReduction; [SerializeField] float cactusIncrement = 0.1f; [SerializeField] float cactusKnockback = 5; float cactus; [SerializeField] float stonksIncrease; float stonks; float _gravity; float spawnOffset; private void Start() { canJump = true; tr = GetComponent<TrailRenderer>(); tr.emitting = false; groundParticles = transform.GetChild(3).GetChild(3).GetComponent<ParticleSystem>(); groundColliderSize = GetComponent<BoxCollider2D>().size; Singleton = this; spawnOffset = FindObjectOfType<TerrainGenerator>().chunkSize / -2; transform.position = new Vector2(spawnOffset, spawnOffset); healthbar.maxValue = maxHealth; health = maxHealth; healthbar.value = health; speedMult = 1; jumpMult = 1; canDash = false; gravityReductionMult = 1; stonks = 1; _gravity = rb.gravityScale; canAttack = true; ResetAllStaticFields(typeof(DataPersistency)); // Starter items: ItemSelectionMenuSystem.Singleton.OpenItemSelectionMenu(UnityEngine.Random.Range(0, 9999), 2, null, ItemSelectionMenuSystem.ItemSelectionType.StarterItemsOnly); // Give player pickaxe: StartCoroutine(GivePlayerPickaxe()); } private IEnumerator GivePlayerPickaxe() { yield return null; InventoryManager.Singleton.AddItem(0); } void ResetAllStaticFields(Type targetType) { // Get all static fields in the class FieldInfo[] fields = targetType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); int resets = 0; foreach (var field in fields) { if (field.FieldType == typeof(float)) { // Set static float fields to -1 field.SetValue(null, -1f); // Use 'null' because these are static fields resets++; } else if (field.FieldType == typeof(bool)) { // Set static bool fields to false field.SetValue(null, false); resets++; } else if (field.FieldType == typeof(int)) { // Static int field.SetValue(null, -1); resets++; } } Debug.Log($"Reset {resets} of {fields.Count()} fields."); } bool canBeHelpedOutOfBounds; bool grappling; bool invincibleBeforeInHeaven; private void Update() { Movement(); if (grapplingGun != null) grappling = grapplingGun.grappling; // Health regeneration PlayerNaturalHealthRegeneration(); if (naturallyRegening && !regenParticles.isPlaying) regenParticles.Play(); else if (!naturallyRegening && regenParticles.isPlaying) regenParticles.Stop(); // Heaven float y = transform.position.y; bool inHeaven = false; if (!enteredHeaven && invincible) invincibleBeforeInHeaven = true; for (int i = 0; i < 2; i++) { if (y < (i + 1) * -200 - heavenSize && y > (i + 1) * -200) { inHeaven = true; InHeaven(); } } // Exit heaven if (!inHeaven && enteredHeaven) { canAttack = true; enteredHeaven = false; PlayerVignetteManager.Singleton.RemoveVignette("heaven vignette"); // Only undo invincibility if we were not invincible before if (!invincibleBeforeInHeaven) invincible = false; } if (health <= 0) { Die(); } if (playerOutOfBounds) { if (rb.velocity.y < outOfBoundsFallingGraceVelocity && canBeHelpedOutOfBounds) { rb.velocity = new Vector2(rb.velocity.x, 15); canBeHelpedOutOfBounds = false; return; } canBeHelpedOutOfBounds = false; PlayerOutOfBounds(); } else if (!playerOutOfBounds) canBeHelpedOutOfBounds = true; // Chest if (Input.GetKeyDown(KeyCode.E) && withinChestRange) { if (!itemSelectionMenuOpen) { int seed = chestWithinRangeData.LootSeed; int count = chestWithinRangeData.ItemOptionCount; ItemSelectionMenuSystem.Singleton.OpenItemSelectionMenu(seed, count, chestWithinRangeData); itemSelectionMenuOpen = true; } else { ItemSelectionMenuSystem.Singleton.CloseItemSelectionMenu(); itemSelectionMenuOpen = false; } } DebugLogs(); } private void Die() { SceneManager.LoadScene(0); for (int i = 0; i < times.Count; i++) { Debug.Log($"Stage {i} duration: {TimeSpan.FromSeconds(times[i])}"); } } Coroutine footstepCoroutine; bool canJump = true; [HideInInspector] public int doubleJumps = 0; // Amount of double jumps used in air private void Movement() { // Return if we are dashing if (dashing) return; // Movement float x = Input.GetAxis("Horizontal") * movementSpeed * speedMult; bool velocityWithinAffectionRange = rb.velocity.x <= movementSpeed * speedMult + 0.001f && rb.velocity.x >= -movementSpeed * speedMult - 0.001f; if (!grappling && !dashing && velocityWithinAffectionRange) rb.velocity = new Vector2(x, rb.velocity.y); if (!velocityWithinAffectionRange) { if (grounded) _friction = friction; else _friction = airFriction; ApplyFriction(); } // Ground check if (Physics2D.BoxCast(transform.position, new Vector2(groundColliderSize.x / 2, transform.localScale.y), 0, Vector2.down, raycastDist, groundLayer)) { defence = 1; grounded = true; doubleJumps = 0; coyoteTimeCoroutine = null; } else { defence = 1 - airDamageReduction; grounded = false; if (coyoteTimeCoroutine == null) coyoteTimeCoroutine = StartCoroutine(CoyoteTime()); } // Footsteps if (Mathf.Abs(x) > 0.1f && grounded) { if (footstepCoroutine == null) footstepCoroutine = StartCoroutine(Footstep()); } // Ground particles if (grounded && !groundParticles.isPlaying) groundParticles.Play(); else if (!grounded && groundParticles.isPlaying) groundParticles.Stop(); // Double jumping if (Input.GetKeyDown(KeyCode.Space) && !grounded && !canJumpCoyoteTime && doubleJumps < maxDoubleJump && canJump) { doubleJumps++; Jump(); } // Jumping if (Input.GetKeyDown(KeyCode.Space) && canJump && (grounded || canJumpCoyoteTime)) { Jump(); } if (Input.GetKeyDown(KeyCode.Space) && grappling && grapplingGun != null) grapplingGun.StopGrappling(); Debug.DrawRay(transform.position, Vector2.down * raycastDist, Color.red); // Dashing if (Input.GetKeyDown(KeyCode.LeftShift) && canDash && !dashing && !grappling) StartCoroutine(Dash()); // Lerp gravity if (lerpGravity) { time += Time.deltaTime / gravityResetSpeed; gravity = Mathf.Lerp(0, _gravity, time); rb.gravityScale = gravity; if (gravity >= _gravity) { rb.gravityScale = _gravity; lerpGravity = false; time = 0; gravity = 0; } } // Gliding / Parachuting if (Input.GetKey(KeyCode.LeftShift) && !grounded && rb.velocity.y < 0 && !dashing && gravityReductionMult != 1 && !grappling) { rb.gravityScale = _gravity * gravityReductionMult; if (rb.velocity.y < maxFallSpeed) rb.velocity = new Vector2(rb.velocity.x, maxFallSpeed); if (!tr.emitting) tr.emitting = true; } else if (!dashing) { rb.gravityScale = _gravity; if (tr.emitting) tr.emitting = false; } if (rb.velocity.y < baseMaxFallSpeed) rb.velocity = new Vector2(rb.velocity.x, baseMaxFallSpeed); //if (grounded && !dashing && grappling && !velocityWithinAffectionRange) ApplyFriction(); // Grappling if (Input.GetMouseButtonDown(1)) { // If we right click and we can swap items Vector2 dir = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 10)); if (Physics2D.Raycast(transform.position, -dir.normalized, GrapplingGun.minPullDistance, 1 << 3)) return; if (InventoryManager.Singleton.canDeselect && TimingManager.Singleton._CooldownEnded("grappleCooldown")) { if (!EventSystem.current.IsPointerOverGameObject()) { previousItemGrapple = InventoryManager.Singleton.currentItemSelected; InventoryManager.Singleton.RightClickFavoritedItem(2); // Select grappling gun StartCoroutine(GrappleSetDelay()); } } } } float time = 0; private IEnumerator Footstep() { // Play sound int length = SoundManager.Singleton.soundLists[3].sounds.Length; int i = UnityEngine.Random.Range(0, length - 1); SoundManager.Singleton.PlaySound("Player walking", "", i, 0.1f); yield return new WaitForSeconds(footstepsPerSecondPerSpeed / movementSpeed); footstepCoroutine = null; } bool enteredHeaven; private void InHeaven() { if (!enteredHeaven) { // Enter heaven enteredHeaven = true; PlayerVignetteManager.Singleton.RequestVignette(new VignetteRequest(heavenColor, heavenVignetteIntensity, 5), "heaven vignette"); invincible = true; canAttack = false; } } int previousItemGrapple; private IEnumerator GrappleSetDelay() { yield return null; if (grapplingGun != null) { grapplingGun.previusItemEquiped = previousItemGrapple; } } private void Jump() { StartCoroutine(_Jump()); } private IEnumerator _Jump() { rb.velocity = new Vector2(rb.velocity.x, 0); rb.AddForce(Vector3.up * jumpForce * 100 * jumpMult); if (doubleJumps == 0) particleSystem.transform.GetChild(0).gameObject.SetActive(true); else particleSystem.transform.GetChild(0).gameObject.SetActive(false); if (!particleSystem.isPlaying) particleSystem.Play(); canJump = false; StartCoroutine(DustParticles()); yield return new WaitForSeconds(jumpCooldown); canJump = true; } bool canJumpCoyoteTime; Coroutine coyoteTimeCoroutine; private IEnumerator CoyoteTime() { canJumpCoyoteTime = true; yield return new WaitForSeconds(coyoteTime); canJumpCoyoteTime = false; } private IEnumerator DustParticles() { particleSystem.Play(); yield return new WaitForSeconds(0.15f); particleSystem.Stop(); } public void DamagePlayerTest() { DamagePlayer(new DamageData(1, 0, Vector2.zero, null)); } Coroutine damageCooldownCoroutine; public void DamagePlayer(DamageData damageData) { if (invincible || damageCooldownCoroutine != null) return; damageCooldownCoroutine = StartCoroutine(DamageCooldown()); float damage = damageData.Damage * takeDamageMult * defence; float knockback = damageData.Knockback; Vector2 knockbackDir = damageData.Vector; health -= damage; UpdateHealthBar(); timeSinceDamage = 0; Knockback(knockback, knockbackDir); // Camera shake CameraShakeManager.Singleton._CameraShake(intensity, duration, frequency, CameraShakeManager.CurveType.InverseParabola); // Damage particles transform.GetChild(3).GetChild(2).GetComponent<ParticleSystem>().Play(); // Damage sound SoundManager.Singleton.PlaySound("Player sounds", "PlayerDamage", -1, 0.1f); if (!BarrierMain.Singleton.outOfBounds) PlayerVignetteManager.Singleton.DamagePlayerVignette(); if (cactus != 0 && damageData.Attacker != null) { PlayerDealDamage(damageData.Attacker, new DamageData(damage * cactus, cactusKnockback, transform.position - damageData.Attacker.transform.position)); } } Color originColor; private IEnumerator DamageCooldown() { originColor = GetComponent<SpriteRenderer>().color; GetComponent<SpriteRenderer>().color = Color.white; yield return new WaitForSeconds(invincibilityTime); damageCooldownCoroutine = null; GetComponent<SpriteRenderer>().color = originColor; } public void GiveCoins(int amount) { coins += Mathf.FloorToInt(amount * stonks); } public void UpdateHealthBar() { healthbar.value = health; healthbar.maxValue = maxHealth; healthbar.transform.GetChild(2).GetComponent<TextMeshProUGUI>().text = $"{Mathf.Round(health)} / {maxHealth}"; } float timeSinceDamage; bool naturallyRegening; private void PlayerNaturalHealthRegeneration() { if (health != maxHealth && timeSinceDamage >= damageRegenCooldown + additionalDamageRegenCooldown) { if (healCoroutine == null) { naturallyRegening = true; // Start healing healCoroutine = StartCoroutine(Heal()); } } else naturallyRegening = false; timeSinceDamage += Time.deltaTime; } Coroutine healCoroutine; private IEnumerator Heal() { yield return new WaitForSeconds(regenTickCooldown); //Debug.Log("Healing player"); HealPlayer(regenValue + additionalRegenValue, false); healCoroutine = null; } public void HealPlayer(float healAmount, bool vignette) { health += healAmount; health = Mathf.Round(health * 10) / 10; health = Mathf.Clamp(health, 0, maxHealth); UpdateHealthBar(); } public void SetPlayerHealth(float value) { health = value; UpdateHealthBar(); } [HideInInspector] public bool canDash = false; bool dashing = false; bool lerpGravity = false; float gravity = 0; IEnumerator Dash() { rb.gravityScale = 0; canDash = false; dashing = true; Vector2 movementVector = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")).normalized; rb.velocity = movementVector * dashForce; tr.emitting = true; yield return new WaitForSeconds(dashDuration); rb.gravityScale = _gravity; dashing = false; rb.velocity = new Vector2(0, 0); lerpGravity = true; tr.emitting = false; yield return new WaitForSeconds(dashCooldown); canDash = true; } private void ApplyFriction() { Vector2 velocity = rb.velocity; if (Mathf.Abs(velocity.x) > 0.1f) velocity.x = Mathf.Lerp(velocity.x, 0, Time.deltaTime * _friction); else velocity.x = 0; rb.velocity = velocity; } private void Knockback(float Knockback, Vector2 dir) { if (dir == Vector2.zero) return; rb.velocity = dir.normalized * Knockback; } [HideInInspector] public bool playerOutOfBounds; Coroutine oobDamageCoroutine; private void PlayerOutOfBounds() { if (oobDamageCoroutine == null && playerOutOfBounds) oobDamageCoroutine = StartCoroutine(OutOfBoundsDamage()); } private IEnumerator OutOfBoundsDamage() { yield return new WaitForSeconds(outOfBoundsDamageCooldown); if (playerOutOfBounds) DamagePlayer(new DamageData(outOfBoundsDamage, 0, Vector2.zero)); oobDamageCoroutine = null; } public void PlayerDealDamage(GameObject target, DamageData damageData) { float lifeSteal = DataPersistency.player_lifeStealPercentage; if (lifeSteal != -1) HealPlayer(damageData.Damage * lifeSteal, true); float critMult = UnityEngine.Random.Range(0, 100) < critChance * 100 ? 2 : 1; DamageData finalDamage = new DamageData(damageData.Damage * damageMult * critMult, damageData.Knockback, damageData.Vector); if (UnityEngine.Random.Range(0f, 1f) < randomBleedChance) PlayerBleedEnemy(target, 5); if (UnityEngine.Random.Range(0f, 1f) < randomStunChance) PlayerStunEnemy(target, 1); target.SendMessage("DamageEnemy", finalDamage, SendMessageOptions.DontRequireReceiver); } public void PlayerBleedEnemy(GameObject target, float bleedDamage) { target.SendMessage("BleedEnemy", bleedDamage, SendMessageOptions.DontRequireReceiver); } public void PlayerStunEnemy(GameObject target, float stunTime) { target.SendMessage("StunEnemy", stunTime, SendMessageOptions.DontRequireReceiver); } [HideInInspector] public bool withinChestRange; bool itemSelectionMenuOpen; void OnTriggerEnter2D(Collider2D collider) { // Player trigger if (collider.gameObject.layer == 15) { // Chest if (collider.gameObject.tag == "Chest") { PlayerInfoBoard.Singleton.ShowInfoBoard("[E] Open chest"); withinChestRange = true; foreach (ChestSpawnData chestData in TerrainGenerator.Singleton.chunkChestLookup.Values) { if (chestData.GlobalPosition == Vector3.zero) continue; if (chestData.GlobalPosition == collider.transform.position) { chestWithinRangeData = chestData; break; } } } } } void OnTriggerExit2D(Collider2D collider) { // Player trigger if (collider.gameObject.layer == 15) { // Chest if (collider.gameObject.tag == "Chest") { PlayerInfoBoard.Singleton.HideInfoBoard(); withinChestRange = false; itemSelectionMenuOpen = false; ItemSelectionMenuSystem.Singleton.CloseItemSelectionMenu(); } } } List<float> times; EnemySpawnManager enemySpawnManager; private void DebugLogs() { if (enemySpawnManager == null) { enemySpawnManager = EnemySpawnManager.Singletone; times = new List<float> { 0, 0, 0, 0, 0 }; } times[enemySpawnManager.stage - 1] += Time.deltaTime; } public void PurchaseSniperScope() { Debug.Log("Pruchase sniper scope"); critChance += sniperScopeIncrement; } public void PurchaseBloodyDagger() { Debug.Log("Purchase bloody dagger"); randomBleedChance += bloodyDaggerIncrement; } public void PurchaseStunPerk() { Debug.Log("Purchase stun perk"); randomStunChance += stunPerkIncrement; } public void PurchaseAirDefence() { Debug.Log("Purchase air defences"); airDamageReduction += airDefenceIncrement; } public void PurchaseCactus() { Debug.Log("Purchase cactus"); cactus += cactusIncrement; } public void PurchaseStonks() { Debug.Log("Purchase cactus"); stonks += stonksIncrease; } [SerializeField] float healthUpgraqeIncr; public void PurchaseHealthUpgrade() { Debug.Log("Purchase health"); maxHealth += healthUpgraqeIncr; UpdateHealthBar(); } [SerializeField] float regenUpgrade = 0.2f; public void PurchaseBandaid() { Debug.Log("Purchase regen"); regenValue += regenUpgrade; } [SerializeField] float lifeStealUpgrade = 0.2f; public void PurchaseLifeSteal() { Debug.Log("Purchase lifesteal"); DataPersistency.player_lifeStealPercentage = lifeStealUpgrade; } [SerializeField] float movementSpeedUpgrade = 0.25f; public void PurchaseSneaker() { Debug.Log("Purchase sneaker"); movementSpeed *= movementSpeedUpgrade + 1; } [SerializeField] float jumpBoostUpgade = 0.2f; public void PurchaseJumpBoost() { Debug.Log("Purchase jump boost"); jumpForce += jumpBoostUpgade; } [SerializeField] int doubleJumpUpgrade = 2; public void PurchaseDoubleJump() { Debug.Log("Purchase double jump"); maxDoubleJump += doubleJumpUpgrade; } } public class DamageData { public float Damage; public float Knockback; public Vector2 Vector; public GameObject Attacker; public DamageData(float damage, float knockback, Vector2 vector, GameObject attacker = null) { Damage = damage; Knockback = knockback; Vector = vector; Attacker = attacker; } }
Editor is loading...
Leave a Comment