Forum begins after the advertisement:
Search Results for 'fader'
-
AuthorSearch Results
-
May 7, 2024 at 8:38 am #14533
In reply to: [Part 7] My Respawn button isnt working
AlexFormer PatronI was, in fact, missing the EventSystem in my other scenes; adding it allowed me to be able to click the respawn button, but it still did not spawn me back in. This only occurs in cave 2 and Cave 3. Cave 1 is working perfectly fine.
Demo
View post on imgur.com
playerController.cs
<code>using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; public class playerController : MonoBehaviour { [Header("Horizontal Movement Settings")] [SerializeField] private float walkSpeed = 1; [Space(5)] [Header("Vertical Movement Settings")] [SerializeField] private float jumpForce = 45; private int jumpBufferCounter = 0; [SerializeField] private int jumpBufferFrames; private float coyoteTimeCounter = 0; [SerializeField] private float coyoteTime; private int airJumpCounter = 0; [SerializeField] private int maxAirJumps; private float gravity; [Space(5)] [Header("Ground Check Settings")] [SerializeField] private Transform groundCheckPoint; [SerializeField] private float groundCheckY = 0.2f; [SerializeField] private float groundCheckX = 0.5f; [SerializeField] private LayerMask whatIsGround; [Space(5)] [Header("Dash Settings")] [SerializeField] private float dashSpeed; [SerializeField] private float dashTime; [SerializeField] private float dashCooldown; [SerializeField] GameObject dashEffect; private bool canDash = true; private bool dashed; [Space(5)] [Header("Attack Settings")] bool attack = false; float timeBetweenAttack, timeSinceAttack; [SerializeField] Transform SideAttackTransform, UpAttackTransform, DownAttackTransform; [SerializeField] Vector2 SideAttackArea, UpAttackArea, DownAttackArea; [SerializeField] LayerMask attackableLayer; [SerializeField] float damage; [SerializeField] GameObject slashEffect; bool restoreTime; float restoreTimeSpeed; [Space(5)] [Header("Recoil Settings")] [SerializeField] int recoilXSteps = 5; [SerializeField] int recoilYSteps = 5; [SerializeField] float recoilXSpeed = 100; [SerializeField] float recoilYSpeed = 100; private int stepsXRecoiled, stepsYRecoiled; [Space(5)] [Header("Health Settings")] public int health; public int maxHealth; [SerializeField] GameObject bloodSpurt; [SerializeField] float hitFlashSpeed; public delegate void OnHealthChangedDelegate(); [HideInInspector] public OnHealthChangedDelegate onHealthChangedCallback; float healTimer; [SerializeField] float timeToHeal; [Space(5)] [Header("Mana Settings")] [SerializeField] Image manaStorage; [SerializeField] float mana; [SerializeField] float manaDrainSpeed; [SerializeField] float manaGain; [Space(5)] [Header("Spell Settings")] // Spell Stats [SerializeField] float manaSpellCost = 0.3f; [SerializeField] float timeBetweenCast = 0.5f; [SerializeField] float spellDamage; // Up Spell Explosion and Down Spell Fireball [SerializeField] float downSpellForce; // Dive Spell // Spell Cast Objects [SerializeField] GameObject sideSpellFireball; [SerializeField] GameObject upSpellExplosion; [SerializeField] GameObject downSpellFireball; float timeSinceCast; float castOrHealtimer; [Space(5)] [HideInInspector] public PlayerStateList pState; [HideInInspector] public Rigidbody2D rb; Animator anim; private SpriteRenderer sr; private float xAxis, yAxis; public static playerController Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); } // Start is called before the first frame update void Start() { pState = GetComponent<PlayerStateList>(); rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>(); gravity = rb.gravityScale; Mana = mana; manaStorage.fillAmount = Mana; if (Health == 0) { pState.alive = false; GameManager.Instance.RespawnPlayer(); } Health = maxHealth; } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea); Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea); Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea); } // Update is called once per frame void Update() { if (pState.cutscene) return; if (pState.alive) { GetInputs(); } UpdateJumpVariables(); RestoreTimeScale(); if (pState.dashing) return; FlashWhileInvincible(); if (pState.alive) { Move(); Heal(); CastSpell(); Flip(); Jump(); StartDash(); Attack(); } if (pState.healing) return; } private void OnTriggerEnter2D(Collider2D _other) // For up and down cast spell { if (_other.GetComponent<Enemy>() != null && pState.casting) { _other.GetComponent<Enemy>().EnemyHit(spellDamage, (_other.transform.position - transform.position).normalized, -recoilYSpeed); } } private void FixedUpdate() { if (pState.cutscene) return; if (pState.dashing) return; Recoil(); } void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetButtonDown("Attack"); if (Input.GetButton("Cast/Heal")) { castOrHealtimer += Time.deltaTime; } } void Flip() { if (xAxis < 0) { // transform.localScale = new Vector2(-1, transform.localScale.y); transform.eulerAngles = new Vector2(0, 180); pState.lookingRight = false; } else if (xAxis > 0) { // transform.localScale = new Vector2(1, transform.localScale.y); transform.eulerAngles = new Vector2(0, 0); pState.lookingRight = true; } } private void Move() { rb.velocity = new Vector2(walkSpeed * xAxis, rb.velocity.y); anim.SetBool("Walking", rb.velocity.x != 0 && Grounded()); } void StartDash() { if (Input.GetButtonDown("Dash") && canDash && !dashed) { StartCoroutine(Dash()); dashed = true; } if (Grounded()) { dashed = false; } } IEnumerator Dash() { canDash = false; pState.dashing = true; anim.SetTrigger("Dashing"); rb.gravityScale = 0; int _dir = pState.lookingRight ? 1 : -1; rb.velocity = new Vector2(_dir * dashSpeed, 0); if (Grounded()) Instantiate(dashEffect, transform); yield return new WaitForSeconds(dashTime); rb.gravityScale = gravity; pState.dashing = false; yield return new WaitForSeconds(dashCooldown); canDash = true; } public IEnumerator WalkIntoNewScene(Vector2 _exitDir, float _delay) { // IF exit is upwards if (_exitDir.y > 0) { rb.velocity = jumpForce * _exitDir; } // IF exit direction required horizontal movement if (_exitDir.x != 0) { xAxis = _exitDir.x > 0 ? 1 : -1; Move(); } yield return new WaitForSeconds(_delay); pState.cutscene = false; } void Attack() { timeSinceAttack += Time.deltaTime; if (attack && timeSinceAttack >= timeBetweenAttack) { timeSinceAttack = 0; anim.SetTrigger("Attacking"); if (yAxis == 0 || yAxis < 0 && Grounded()) { int _recoilLeftOrRight = pState.lookingRight ? 1 : -1; Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, Vector2.right * _recoilLeftOrRight, recoilXSpeed); Instantiate(slashEffect, SideAttackTransform); } else if (yAxis > 0) { Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, Vector2.up, recoilYSpeed); SlashEffectAtAngle(slashEffect, 80, UpAttackTransform); } else if (yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, Vector2.down, recoilYSpeed); SlashEffectAtAngle(slashEffect, -90, DownAttackTransform); } } } void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilBool, Vector2 _recoilDir, float _recoilStrength) { Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); if (objectsToHit.Length > 0) { _recoilBool = true; } for (int i = 0; i < objectsToHit.Length; i++) { if (objectsToHit[i].GetComponent<Enemy>() != null) { objectsToHit[i].GetComponent<Enemy>().EnemyHit(damage, _recoilDir, _recoilStrength); if (objectsToHit[i].CompareTag("Enemy")) { Mana += manaGain; } } } } void SlashEffectAtAngle(GameObject _slashEffect, int _effectAngle, Transform _attackTransform) { _slashEffect = Instantiate(_slashEffect, _attackTransform); _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle); _slashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y); } void Recoil() { if (pState.recoilingX) { if (pState.lookingRight) { rb.velocity = new Vector2(-recoilXSpeed, 0); } else { rb.velocity = new Vector2(recoilXSpeed, 0); } } if (pState.recoilingY) { rb.gravityScale = 0; if (yAxis < 0) { rb.velocity = new Vector2(rb.velocity.x, recoilYSpeed); } else { rb.velocity = new Vector2(rb.velocity.x, -recoilYSpeed); } airJumpCounter = 0; } else { rb.gravityScale = gravity; } // Stop Recoil if (pState.recoilingX && stepsXRecoiled < recoilXSteps) { stepsXRecoiled++; } else { StopRecoilX(); } if (pState.recoilingY && stepsYRecoiled < recoilYSteps) { stepsYRecoiled++; } else { StopRecoilY(); } if (Grounded()) { StopRecoilY(); } } void StopRecoilX() { stepsXRecoiled = 0; pState.recoilingX = false; } void StopRecoilY() { stepsYRecoiled = 0; pState.recoilingY = false; } public void TakeDamage(float _damage) { if(pState.alive) { Health -= Mathf.RoundToInt(_damage); if(Health <= 0) { Health = 0; StartCoroutine(Death()); } else { StartCoroutine(StopTakingDamage()); } } } IEnumerator StopTakingDamage() { pState.invincible = true; GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, transform.position, Quaternion.identity); Destroy(_bloodSpurtParticles, 1.5f); anim.SetTrigger("TakeDamage"); yield return new WaitForSeconds(1f); pState.invincible = false; } void FlashWhileInvincible() { sr.material.color = pState.invincible ? Color.Lerp(Color.white, Color.black, Mathf.PingPong(Time.time * hitFlashSpeed, 1.0f)) : Color.white; } void RestoreTimeScale() { if (restoreTime) { if (Time.timeScale < 1) { Time.timeScale += Time.deltaTime * restoreTimeSpeed; } else { Time.timeScale = 1; restoreTime = false; } } } public void HitStopTime(float _newTimeScale, int _restoreSpeed, float _delay) { restoreTimeSpeed = _restoreSpeed; Time.timeScale = _newTimeScale; if (_delay > 0) { StopCoroutine(StartTimeAgain(_delay)); StartCoroutine(StartTimeAgain(_delay)); } else { restoreTime = true; } } IEnumerator StartTimeAgain(float _delay) { restoreTime = true; yield return new WaitForSeconds(_delay); } IEnumerator Death() { pState.alive = false; Time.timeScale = 1f; GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, transform.position, Quaternion.identity); Destroy(_bloodSpurtParticles, 1.5f); anim.SetTrigger("Death"); yield return new WaitForSeconds(0.8f); StartCoroutine(UIManager.Instance.ActivateDeathScreen()); } public void Respawned() { if(!pState.alive) { rb.constraints = RigidbodyConstraints2D.None; rb.constraints = RigidbodyConstraints2D.FreezeRotation; GetComponent<BoxCollider2D>().enabled = true; pState.alive = true; Health = maxHealth; anim.Play("player_Idle"); } } public int Health { get { return health; } set { if (health != value) { health = Mathf.Clamp(value, 0, maxHealth); if (onHealthChangedCallback != null) { onHealthChangedCallback.Invoke(); } } } } void Heal() { if (Input.GetButton("Cast/Heal") && castOrHealtimer > 0.05f && Health < maxHealth && Mana > 0 && !pState.jumping && !pState.dashing) { pState.healing = true; anim.SetBool("Healing", true); // Healing healTimer += Time.deltaTime; if (healTimer >= timeToHeal) { Health++; healTimer = 0; } // Drain mana Mana -= Time.deltaTime * manaDrainSpeed; } else { pState.healing = false; anim.SetBool("Healing", false); healTimer = 0; } } float Mana { get { return mana; } set { if (mana != value) { mana = Mathf.Clamp(value, 0, 1); manaStorage.fillAmount = Mana; } } } void CastSpell() { if (Input.GetButtonUp("Cast/Heal") && castOrHealtimer <= 0.15f && timeSinceCast >= timeBetweenCast && Mana >= manaSpellCost) { pState.casting = true; timeSinceCast = 0; StartCoroutine(CastCoroutine()); } else { timeSinceCast += Time.deltaTime; } if (!Input.GetButton("Cast/Heal")) { castOrHealtimer = 0; } if (Grounded()) { // Disable down spell if on the ground downSpellFireball.SetActive(false); } // If down spell is active, force player down until grounded if (downSpellFireball.activeInHierarchy) { rb.velocity += downSpellForce * Vector2.down; } } IEnumerator CastCoroutine() { anim.SetBool("Casting", true); yield return new WaitForSeconds(0.15f); // Side Spell Cast if (yAxis == 0 || (yAxis < 0 && Grounded())) { GameObject _fireBall = Instantiate(sideSpellFireball, SideAttackTransform.position, Quaternion.identity); // Flip Fireball if (pState.lookingRight) { _fireBall.transform.eulerAngles = Vector3.zero; // if facing right, fireball continues as per normal } else { _fireBall.transform.eulerAngles = new Vector2(_fireBall.transform.eulerAngles.x, 180); // if not facing right, rotate the fireball 180 deg } pState.recoilingX = true; } // Up Spell Cast else if (yAxis > 0) { Instantiate(upSpellExplosion, transform); rb.velocity = Vector2.zero; } // Down Spell Cast else if (yAxis < 0 && !Grounded()) { downSpellFireball.SetActive(true); } Mana -= manaSpellCost; yield return new WaitForSeconds(0.35f); anim.SetBool("Casting", false); pState.casting = false; } public bool Grounded() { if (Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, whatIsGround) || Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround) || Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround)) { return true; } else { return false; } } void Jump() { if (jumpBufferCounter > 0 && coyoteTimeCounter > 0 && !pState.jumping) { rb.velocity = new Vector3(rb.velocity.x, jumpForce); pState.jumping = true; } if (!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump")) { pState.jumping = true; airJumpCounter++; rb.velocity = new Vector3(rb.velocity.x, jumpForce); } if (Input.GetButtonUp("Jump") && rb.velocity.y > 3) { rb.velocity = new Vector2(rb.velocity.x, 0); pState.jumping = false; } anim.SetBool("Jumping", !Grounded()); } void UpdateJumpVariables() { if (Grounded()) { pState.jumping = false; coyoteTimeCounter = coyoteTime; airJumpCounter = 0; } else { coyoteTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferFrames; } else { jumpBufferCounter--; } } } </code>
GameManager.cs
<code>using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; public class GameManager : MonoBehaviour { public string transitionedFromScene; public Vector2 platformRespawnPoint; public Vector2 respawnPoint; [SerializeField] Bench bench; public static GameManager Instance { get; private set; } private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); bench = FindAnyObjectByType<Bench>(); } public void RespawnPlayer() { if(bench.interacted) { respawnPoint = bench.transform.position; } else { respawnPoint = platformRespawnPoint; } playerController.Instance.transform.position = respawnPoint; StartCoroutine(UIManager.Instance.DeactivateDeathScreen()); playerController.Instance.Respawned(); } } </code>
UIManager.cs
<code>using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEditor.SearchService; using UnityEngine; public class UIManager : MonoBehaviour { public SceneFader sceneFader; public static UIManager Instance; [SerializeField] GameObject deathScreen; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); sceneFader = GetComponentInChildren<SceneFader>(); } public IEnumerator ActivateDeathScreen() { yield return new WaitForSeconds(0.8f); StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.In)); yield return new WaitForSeconds(0.9f); deathScreen.SetActive(true); } public IEnumerator DeactivateDeathScreen() { yield return new WaitForSeconds(0.5f); deathScreen.SetActive(false); StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.Out)); } } </code>
April 22, 2024 at 6:44 pm #14157In reply to: [Part 9] My Switch between menu have some bugs
Elvin SimParticipantSceneFader Script
View post on imgur.com
April 18, 2024 at 10:27 pm #13983In reply to: [Part 6] Repititive NullReferenceException error
PeteParticipantAs I tried your “1) Move your UpdateCameraYDampForPlayerFall(); under your Move() in Update()” the character can move horizontally but other movement is not working ex) attacking, jumping, skills
and after I attached SceneFader to UIManager script, I think scene transitioning is working.
But still there are repetitive error message on console.
I’ll show the video of result.
April 18, 2024 at 6:15 pm #13964In reply to: [Part 6] Repititive NullReferenceException error
Joseph TangModeratorFor the SceneFader error: Add this code under UIManager.cs:
private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); sceneFader = GetComponentInChildren<SceneFader>(); }
As for your movement and camera issue. I’ll need to check so give me a moment.
April 18, 2024 at 6:07 pm #13963In reply to: [Part 6] Repititive NullReferenceException error
PeteParticipantHere’s my code
“UIManager.cs”
<code> using System.Collections; using System.Collections.Generic; using UnityEngine; public class UIManager : MonoBehaviour { public static UIManager Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); } public SceneFader sceneFader; private void Start() { sceneFader = GetComponentInChildren<SceneFader>(); } } </code>
“PlayerController.cs”
<code> using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; using UnityEngine.UI; using Unity.VisualScripting; public class PlayerController : MonoBehaviour { [Header("Horizontal Movement Settings:")] [SerializeField] private float walkSpeed = 1; //sets the players movement speed on the ground [Space(5)] [Header("Vertical Movement Settings")] [SerializeField] private float jumpForce = 45f; //sets how hight the player can jump private int jumpBufferCounter = 0; //stores the jump button input [SerializeField] private int jumpBufferFrames; //sets the max amount of frames the jump buffer input is stored private float coyoteTimeCounter = 0; //stores the Grounded() bool [SerializeField] private float coyoteTime; ////sets the max amount of frames the Grounded() bool is stored private int airJumpCounter = 0; //keeps track of how many times the player has jumped in the air [SerializeField] private int maxAirJumps; //the max no. of air jumps private float gravity; //stores the gravity scale at start [Space(5)] [Header("Ground Check Settings:")] [SerializeField] private Transform groundCheckPoint; //point at which ground check happens [SerializeField] private float groundCheckY = 0.2f; //how far down from ground chekc point is Grounded() checked [SerializeField] private float groundCheckX = 0.5f; //how far horizontally from ground chekc point to the edge of the player is [SerializeField] private LayerMask whatIsGround; //sets the ground layer [Space(5)] [Header("Dash Settings")] [SerializeField] private float dashSpeed; //speed of the dash [SerializeField] private float dashTime; //amount of time spent dashing [SerializeField] private float dashCooldown; //amount of time between dashes [SerializeField] GameObject dashEffect; private bool canDash = true, dashed; [Space(5)] [Header("Attack Settings:")] [SerializeField] private Transform SideAttackTransform; //the middle of the side attack area [SerializeField] private Vector2 SideAttackArea; //how large the area of side attack is [SerializeField] private Transform UpAttackTransform; //the middle of the up attack area [SerializeField] private Vector2 UpAttackArea; //how large the area of side attack is [SerializeField] private Transform DownAttackTransform; //the middle of the down attack area [SerializeField] private Vector2 DownAttackArea; //how large the area of down attack is [SerializeField] private LayerMask attackableLayer; //the layer the player can attack and recoil off of private float timeBetweenAttack, timeSinceAttck; [SerializeField] private float damage; //the damage the player does to an enemy [SerializeField] private GameObject slashEffect; //the effect of the slashs bool restoreTime; float restoreTimeSpeed; [Space(5)] [Header("Recoil Settings:")] [SerializeField] private int recoilXSteps = 5; //how many FixedUpdates() the player recoils horizontally for [SerializeField] private int recoilYSteps = 5; //how many FixedUpdates() the player recoils vertically for [SerializeField] private float recoilXSpeed = 100; //the speed of horizontal recoil [SerializeField] private float recoilYSpeed = 100; //the speed of vertical recoil private int stepsXRecoiled, stepsYRecoiled; //the no. of steps recoiled horizontally and verticall [Space(5)] [Header("Health Settings")] public int health; public int maxHealth; [SerializeField] GameObject bloodSpurt; [SerializeField] float hitFlashSpeed; public delegate void OnHealthChangedDelegate(); [HideInInspector] public OnHealthChangedDelegate onHealthChangedCallback; [Space(5)] float healTimer; [SerializeField] float timeToHeal; [Space(5)] [Header("Mana Settings")] [SerializeField] UnityEngine.UI.Image manaStorage; [SerializeField] float mana; [SerializeField] float manaDrainSpeed; [SerializeField] float manaGain; [Space(5)] [Header("Spell Settings")] [SerializeField] float manaSpellCost = 0.3f; [SerializeField] float timeBetweenCast = 0.5f; [SerializeField] float spellDamage; //upspellexplosion and downspellexplosion only [SerializeField] float downSpellForce; //desolate dive only //spell cast objects [SerializeField] GameObject sideSpellFireball; [SerializeField] GameObject upSpellFireball; [SerializeField] GameObject downSpellFireball; float timeSinceCast; float castOrHealthtimer; [Space(5)] [Header("Camera Stuff")] [SerializeField] private float playerFallSpeedThreshold = -10; [HideInInspector] public PlayerStateList pState; [HideInInspector] public Rigidbody2D rb; private Animator anim; private SpriteRenderer sr; //Input Variables private float xAxis, yAxis; private bool attack = false; private bool canFlash = true; public static PlayerController Instance; private void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); } // Start is called before the first frame update void Start() { pState = GetComponent<PlayerStateList>(); rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>(); gravity = rb.gravityScale; Mana = mana; manaStorage.fillAmount = Mana; health = maxHealth; } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea); Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea); Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea); } // Update is called once per frame void Update() { if (pState.cutscene) return; GetInputs(); UpdateJumpVariables(); UpdateCameraYDampForPlayerFall(); RestoreTimeScale(); if (pState.dashing) return; Flip(); Move(); Jump(); StartDash(); Attack(); FlashWhileInvincible(); Heal(); CastSpell(); } private void OnTriggerEnter2D(Collider2D _other) //for up and down cast spell { if(_other.GetComponent<Enemy>() != null && pState.casting) { _other.GetComponent<Enemy>().EnemyGetsHit(spellDamage, (_other.transform.position - transform.position).normalized, -recoilYSpeed); } } private void FixedUpdate() { if (pState.cutscene) return; if (pState.dashing) return; Recoil(); } void GetInputs() { xAxis = Input.GetAxisRaw("Horizontal"); yAxis = Input.GetAxisRaw("Vertical"); attack = Input.GetButtonDown("Attack"); if(Input.GetButtonDown("Cast/Heal")) { castOrHealthtimer += Time.deltaTime; } else { castOrHealthtimer = 0; } } void Flip() { if (xAxis < 0) { transform.localScale = new Vector2(-1, transform.localScale.y); pState.lookingRight = false; } else if (xAxis > 0) { transform.localScale = new Vector2(1, transform.localScale.y); pState.lookingRight = true; } } private void Move() { rb.velocity = new Vector2(walkSpeed * xAxis, rb.velocity.y); anim.SetBool("Walking", rb.velocity.x != 0 && Grounded()); } void UpdateCameraYDampForPlayerFall() { //if falling past a certain speed threshold if(rb.velocity.y < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping) { StartCoroutine(CameraManager.Instance.LerpYDamping(true)); } //if standing still or moving up if(rb.velocity.y >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping) { //reset camera function CameraManager.Instance.hasLerpedYDamping = false; StartCoroutine(CameraManager.Instance.LerpYDamping(false)); } } void StartDash() { if (Input.GetButtonDown("Dash") && canDash && !dashed) { StartCoroutine(Dash()); dashed = true; } if (Grounded()) { dashed = false; } } IEnumerator Dash() { canDash = false; pState.dashing = true; anim.SetTrigger("Dashing"); rb.gravityScale = 0; int _dir = pState.lookingRight ? 1 : -1; rb.velocity = new Vector2(_dir * dashSpeed, 0); if (Grounded()) Instantiate(dashEffect, transform); yield return new WaitForSeconds(dashTime); rb.gravityScale = gravity; pState.dashing = false; yield return new WaitForSeconds(dashCooldown); canDash = true; } public IEnumerator WalkIntoNewScene(Vector2 _exitDir, float _delay) { //If exit direction is upwards if (_exitDir.y != 0) { rb.velocity = jumpForce * _exitDir; } //If exit direction requires horizontal movement if (_exitDir.x != 0) { xAxis = _exitDir.x > 0 ? 1 : -1; Move(); } Flip(); yield return new WaitForSeconds(_delay); pState.cutscene = false; } void Attack() { timeSinceAttck += Time.deltaTime; if (attack && timeSinceAttck >= timeBetweenAttack) { timeSinceAttck = 0; anim.SetTrigger("Attacking"); if (yAxis == 0 || yAxis < 0 && Grounded()) { int _recoilLeftOrRight = pState.lookingRight ? 1 : -1; Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, Vector2.right * _recoilLeftOrRight, recoilXSpeed); Instantiate(slashEffect, SideAttackTransform); } else if (yAxis > 0) { Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, Vector2.up, recoilYSpeed); SlashEffectAtAngle(slashEffect, 80, UpAttackTransform); } else if (yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, Vector2.down, recoilYSpeed); SlashEffectAtAngle(slashEffect, -90, DownAttackTransform); } } } void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilBool, Vector2 _recoilDir, float _recoilStrength) { Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer); if (objectsToHit.Length > 0) { _recoilBool = true; } for (int i = 0; i < objectsToHit.Length; i++) { if (objectsToHit[i].GetComponent<Enemy>() != null) { objectsToHit[i].GetComponent<Enemy>().EnemyGetsHit(damage, _recoilDir, _recoilStrength); if (objectsToHit[i].CompareTag("Enemy")) { Mana += manaGain; } } } } void SlashEffectAtAngle(GameObject _slashEffect, int _effectAngle, Transform _attackTransform) { _slashEffect = Instantiate(_slashEffect, _attackTransform); _slashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle); _slashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y); } void Recoil() { if (pState.recoilingX) { if (pState.lookingRight) { rb.velocity = new Vector2(-recoilXSpeed, 0); } else { rb.velocity = new Vector2(recoilXSpeed, 0); } } if (pState.recoilingY) { rb.gravityScale = 0; if (yAxis < 0) { rb.velocity = new Vector2(rb.velocity.x, recoilYSpeed); } else { rb.velocity = new Vector2(rb.velocity.x, -recoilYSpeed); } airJumpCounter = 0; } else { rb.gravityScale = gravity; } //stop recoil if (pState.recoilingX && stepsXRecoiled < recoilXSteps) { stepsXRecoiled++; } else { StopRecoilX(); } if (pState.recoilingY && stepsYRecoiled < recoilYSteps) { stepsYRecoiled++; } else { StopRecoilY(); } if (Grounded()) { StopRecoilY(); } } void StopRecoilX() { stepsXRecoiled = 0; pState.recoilingX = false; } void StopRecoilY() { stepsYRecoiled = 0; pState.recoilingY = false; } public void TakeDamage(float _damage) { Health -= Mathf.RoundToInt(_damage); StartCoroutine(StopTakingDamage()); } IEnumerator StopTakingDamage() { pState.invincible = true; GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, transform.position, Quaternion.identity); Destroy(_bloodSpurtParticles, 1.5f); anim.SetTrigger("TakeDamage"); yield return new WaitForSeconds(1f); pState.invincible = false; } IEnumerator Flash() { sr.enabled = !sr.enabled; canFlash = false; yield return new WaitForSeconds(0.1f); canFlash = true; } void FlashWhileInvincible() { if (pState.invincible) { if (Time.timeScale > 0.2 && canFlash) { StartCoroutine(Flash()); } } else { sr.enabled = true; } } void RestoreTimeScale() { if (restoreTime) { if (Time.timeScale < 1) { Time.timeScale += Time.deltaTime * restoreTimeSpeed; } else { Time.timeScale = 1; restoreTime = false; } } } public void HitStopTime(float _newTimeScale, int _restoreSpeed, float _delay) { restoreTimeSpeed = _restoreSpeed; if (_delay > 0) { StopCoroutine(StartTimeAgain(_delay)); StartCoroutine(StartTimeAgain(_delay)); } else { restoreTime = true; } Time.timeScale = _newTimeScale; } IEnumerator StartTimeAgain(float _delay) { restoreTime = true; yield return new WaitForSeconds(_delay); } public int Health { get { return health; } set { if (health != value) { health = Mathf.Clamp(value, 0, maxHealth); if (onHealthChangedCallback != null) { onHealthChangedCallback.Invoke(); } } } } void Heal() { if(Input.GetButton("Cast/Heal") && castOrHealthtimer > 0.05f && Health < maxHealth && Mana > 0 && !pState.jumping && !pState.dashing) { pState.healing = true; anim.SetBool("Healing", true); //healing healTimer += Time.deltaTime; if(healTimer >= timeToHeal) { Health++; healTimer = 0; } //drain mana Mana -= Time.deltaTime * manaDrainSpeed; } else { pState.healing = false; anim.SetBool("Healing", false); healTimer = 0; } } float Mana { get { return mana; } set { //if mana stats change if (mana != value) { mana = Mathf.Clamp(value, 0, 1); manaStorage.fillAmount = Mana; } } } void CastSpell() { if(Input.GetButtonUp("Cast/Heal") && castOrHealthtimer <= 0.05f && timeSinceCast >= timeBetweenCast && Mana >= manaSpellCost) { pState.casting = true; timeSinceCast = 0; StartCoroutine(CastCoroutine()); } else { timeSinceCast += Time.deltaTime; } if(Grounded()) { //disable downspell if on the ground downSpellFireball.SetActive(false); } //if down spell is active, force player down until grounded if (downSpellFireball.activeInHierarchy) { rb.velocity += downSpellForce * Vector2.down; } } IEnumerator CastCoroutine() { anim.SetBool("Casting", true); yield return new WaitForSeconds(0.09f); //side cast if (yAxis == 0 || (yAxis == 0 && Grounded())) { GameObject _fireBall = Instantiate(sideSpellFireball, SideAttackTransform.position, Quaternion.identity); //flip fireball if(pState.lookingRight) { _fireBall.transform.eulerAngles = Vector3.zero; //if facing right, fireball continues as per normal } else { _fireBall.transform.eulerAngles = new Vector2(_fireBall.transform.eulerAngles.x, 180); //if not facing right, rotate the fireball 180 degree } pState.recoilingX = true; } //up cast else if (yAxis > 0) { Instantiate(upSpellFireball, transform); rb.velocity = Vector2.zero; } //down cast else if (yAxis < 0 && !Grounded()) { downSpellFireball.SetActive(true); } Mana -= manaSpellCost; yield return new WaitForSeconds(0.09f); anim.SetBool("Casting", false); pState.casting = false; } public bool Grounded() { if (Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, whatIsGround) || Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround) || Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround)) { return true; } else { return false; } } void Jump() { if (jumpBufferCounter > 0 && coyoteTimeCounter > 0 && !pState.jumping) { rb.velocity = new Vector3(rb.velocity.x, jumpForce); pState.jumping = true; } else if (!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump")) { pState.jumping = true; airJumpCounter++; rb.velocity = new Vector3(rb.velocity.x, jumpForce); } if (Input.GetButtonUp("Jump") && rb.velocity.y > 3) { rb.velocity = new Vector2(rb.velocity.x, 0); pState.jumping = false; } anim.SetBool("Jumping", !Grounded()); } void UpdateJumpVariables() { if (Grounded()) { pState.jumping = false; coyoteTimeCounter = coyoteTime; airJumpCounter = 0; } else { coyoteTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferFrames; } else { jumpBufferCounter--; } } } </code>
April 18, 2024 at 5:57 pm #13961In reply to: [Part 6] Repititive NullReferenceException error
Joseph TangModeratorAs can be seen in the video, your Canvas has nothing set as it’s Scene Fader.
As for the fact that you cannot move, I believe something went wrong with your RigidBody2D which is also causing the NullReferenceException Errors for your
UpdateCameraYDampForPlayerFall()
method.Can you copy and paste the entire code for your UIManager.cs & your PlayerController.cs?
At the same time, check if the Scene Fader game object under your Canvas has a SceneFader.cs script on it.
April 18, 2024 at 3:36 pm #13955In reply to: [Part 6] Repititive NullReferenceException error
Joseph TangModeratorHi sorry, but I’ll need more videos, particularly, you showing how the Canvas Prefab inspector is like while in game + Moving out of the camera bounds + scene transitions. You can take one video straight, selecting different objects to show their insectors.
From the looks of the normal inspectors, either there is no SceneFader set on your UIManager.cs, or it will be automatically set by a SceneFader.instance if there is one in the scene.
April 18, 2024 at 3:17 pm #13954In reply to: [Part 6] Repititive NullReferenceException error
PeteParticipantApril 18, 2024 at 11:34 am #13940In reply to: [Part 6] Repititive NullReferenceException error
Joseph TangModeratorIn regards to the camera, can you check if your Camera parent or any object has the CameraManager.cs script on it? I feel that likely the errors in the PlayerController.cs is a separate issue where it cannot find an instance of the CameraManager.cs
As for your SceneTransition, check that your Canvas Prefab has a UIManager.cs attached to it & the “Scene Fader” assigned appropriately to it. Then ensure that the SceneFader game object in the Canvas is set to Active as an inactive one will be taken as a null.
Otherwise, if both situations don’t work, could you taking some screenshots of the inspector of your UIManager, Player, SceneTransition inspectors & a video or console of what happens when you transition scenes?
As a side note, I noticed that your SceneTransition.cs calls
SceneManager.LoadScene(transitionTo);
in theprivate void OnTriggerEnter2D(Collider2D _other)
method before theStartCoroutine
. You should not need theLoadScene()
code itself as the coroutine you are casting will activate both the fade andLoadScene()
already.April 18, 2024 at 2:15 am #13938In reply to: [Part 6] Repititive NullReferenceException error
PeteParticipantThanks for your reply.
But blog.terresquall.com/community/topic/part-5-my-scenefader-cannot-function/ this case doesn’t work for me…
and try to solve with Youtube video, it also doesn’t work…
so i’ll bold all the line the error is occuring.
“SceneTransition.cs”
using System.Collections; using System.Collections.Generic; using UnityEditor.Build.Content; using UnityEngine; using UnityEngine.SceneManagement; public class SceneTransition : MonoBehaviour { [SerializeField] private string transitionTo; //Represents the scene to transition to [SerializeField] private Transform startPoint; //Defines the player's entry point in the scene [SerializeField] private Vector2 exitDirection; //Specifies the direction for the player's exit [SerializeField] private float exitTime; //Determines the time it takes for the player to exit the scene transition // Start is called before the first frame update private void Start() { if (GameManager.Instance.transitionedFromScene == transitionTo) { PlayerController.Instance.transform.position = startPoint.position; StartCoroutine(PlayerController.Instance.WalkIntoNewScene(exitDirection, exitTime)); } <strong>StartCoroutine(UIManager.Instance.sceneFader.Fade(SceneFader.FadeDirection.Out));</strong> } private void OnTriggerEnter2D(Collider2D _other) { if (_other.CompareTag("Player")) { GameManager.Instance.transitionedFromScene = SceneManager.GetActiveScene().name; PlayerController.Instance.pState.cutscene = true; SceneManager.LoadScene(transitionTo); StartCoroutine(UIManager.Instance.sceneFader.FadeAndLoadScene(SceneFader.FadeDirection.In, transitionTo)); } } }
“PlayerController.cs”
void Update() { if (pState.cutscene) return; GetInputs(); UpdateJumpVariables(); <strong>UpdateCameraYDampForPlayerFall();</strong> RestoreTimeScale(); if (pState.dashing) return; Flip(); Move(); Jump(); StartDash(); Attack(); FlashWhileInvincible(); Heal(); CastSpell(); } void UpdateCameraYDampForPlayerFall() { //if falling past a certain speed threshold <strong>if(rb.velocity.y < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping)</strong> { StartCoroutine(CameraManager.Instance.LerpYDamping(true)); } //if standing still or moving up <strong> if(rb.velocity.y >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping)</strong> { //reset camera function CameraManager.Instance.hasLerpedYDamping = false; StartCoroutine(CameraManager.Instance.LerpYDamping(false)); } }
April 17, 2024 at 11:26 pm #13932In reply to: [Part 6] Repititive NullReferenceException error
TerenceKeymasterHi Pete, for the SceneFader, can you check this topic and see if it fixes your issue? https://blog.terresquall.com/community/topic/part-5-my-scenefader-cannot-function/
I’ll need you to bold the line the error is occurring on for your
PlayerController
script. The null reference exception is specific to certain lines.You may also find this video useful:
April 17, 2024 at 10:44 pm #13928PeteParticipantHi, I have a trouble on part 6.
I just followed “Camera Bounds” & “Dynamic Camera Y Damping” and when I try to run the game, it just pauses and there are repetitive error msg on console.
NullReferenceException: Object reference not set to an instance of an object SceneTransition.Start () (at Assets/Scripts/SceneTransition.cs:27)
NullReferenceException: Object reference not set to an instance of an object PlayerController.UpdateCameraYDampForPlayerFall () (at Assets/Scripts/PlayerController.cs:253) PlayerController.Update () (at Assets/Scripts/PlayerController.cs:184)
NullReferenceException: Object reference not set to an instance of an object PlayerController.UpdateCameraYDampForPlayerFall () (at Assets/Scripts/PlayerController.cs:258) PlayerController.Update () (at Assets/Scripts/PlayerController.cs:184)
I don’t know how to deal with “NUllReferenceException” error.
this is my error console img below.
“Scenetransition.cs”
<code>public class SceneTransition : MonoBehaviour { [SerializeField] private string transitionTo; //Represents the scene to transition to [SerializeField] private Transform startPoint; //Defines the player's entry point in the scene [SerializeField] private Vector2 exitDirection; //Specifies the direction for the player's exit [SerializeField] private float exitTime; //Determines the time it takes for the player to exit the scene transition // Start is called before the first frame update private void Start() { if (GameManager.Instance.transitionedFromScene == transitionTo) { PlayerController.Instance.transform.position = startPoint.position; StartCoroutine(PlayerController.Instance.WalkIntoNewScene(exitDirection, exitTime)); } StartCoroutine(UIManager.Instance.sceneFader.Fade(SceneFader.FadeDirection.Out)); } private void OnTriggerEnter2D(Collider2D _other) { if (_other.CompareTag("Player")) { GameManager.Instance.transitionedFromScene = SceneManager.GetActiveScene().name; PlayerController.Instance.pState.cutscene = true; SceneManager.LoadScene(transitionTo); StartCoroutine(UIManager.Instance.sceneFader.FadeAndLoadScene(SceneFader.FadeDirection.In, transitionTo)); } } } </code>
“PlayerController.cs”
<code> void Update() { if (pState.cutscene) return; GetInputs(); UpdateJumpVariables(); UpdateCameraYDampForPlayerFall(); RestoreTimeScale(); if (pState.dashing) return; Flip(); Move(); Jump(); StartDash(); Attack(); FlashWhileInvincible(); Heal(); CastSpell(); } void UpdateCameraYDampForPlayerFall() { //if falling past a certain speed threshold if(rb.velocity.y < playerFallSpeedThreshold && !CameraManager.Instance.isLerpingYDamping && !CameraManager.Instance.hasLerpedYDamping) { StartCoroutine(CameraManager.Instance.LerpYDamping(true)); } //if standing still or moving up if(rb.velocity.y >= 0 && !CameraManager.Instance.isLerpingYDamping && CameraManager.Instance.hasLerpedYDamping) { //reset camera function CameraManager.Instance.hasLerpedYDamping = false; StartCoroutine(CameraManager.Instance.LerpYDamping(false)); } } </code>
April 17, 2024 at 7:49 pm #13922Joseph TangModeratorQuestion 1: Slash effect sprite not properly changing directions.
By right, the normal code should work as the way it works is that for your side attacks, they are callingInstantiate
slash effect under theSide Attack Transform
game object on the Player. And since they are underneath a child of the player, whenever your player flips, the slash effect should flip too. That brings me to my theory of what the issue is: I think your side attack is callingSlashEffectAtAngle()
instead of Instantiate. Check that your code in PlayerController.cs is as follows:void Attack() { timeSinceAttck += Time.deltaTime; if(attack && timeSinceAttck >= timeBetweenAttack) { timeSinceAttck = 0; anim.SetTrigger("Attacking"); if (yAxis == 0 || yAxis < 0 && Grounded()) { int _recoilLeftOrRight = pState.lookingRight ? 1 : -1; Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, Vector2.right * _recoilLeftOrRight, recoilXSpeed); Instantiate(slashEffect, SideAttackTransform); } else if (yAxis > 0) { Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, Vector2.up, recoilYSpeed); SlashEffectAtAngle(slashEffect, 80, UpAttackTransform); } else if (yAxis < 0 && !Grounded()) { Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, Vector2.down, recoilYSpeed); SlashEffectAtAngle(slashEffect, -90, DownAttackTransform); } } }
If this doesn’t work, I’ll need some screenshots or a video of the inspector of both PlayerController.cs in the scene, or the attack transforms + Slash Effect clones while attacking.
Question 2: Zombie not recoiling.
This was an issue that occurred to me as well. After testing now. I can tell you that the recoil should be working. If you crank the enemy speed down to 1 or 0, you can see that they are still being recoiled, just to a lesser extent than they had been before setting interpolate. While this is an additional issue due to interpolate, I’d say we can fix that by changing the code.public virtual void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitForce) { health -= _damageDone; if (!isRecoiling) { rb.velocity = _hitForce * recoilFactor * _hitDirection; isRecoiling = true; } }
The
isRecoiling
bool was never set to true in our code, thus makingRecoilLength
a useless variable, but doing this will prevent your enemy from moving while being recoiled, which should cancel out the interpolate issue in general.Question 3: Spellcast after heal
This is a common issue that others have experienced and in our bugfixes in Part 6. Check this to see if it helps (Second last comment):
[Part 5] My SceneFader cannot function
April 17, 2024 at 5:23 pm #13917Alberto FogliParticipantHi everyone,
When i try to save the “bench” coordinates and die to see if i respawn back at the correct point, it load for a second at the correct position, but then i get teleported back at starting point and an error appears
<code>NullReferenceException: Object reference not set to an instance of an object UIManager+<DeactivateDeathScreen>d__8.MoveNext () (at Assets/Scripts/UIManager.cs:45) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)</code>
Here is the code:
Bench code:
<code>using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class SavePoint : MonoBehaviour { [SerializeField]public bool interacted; private void OnTriggerStay2D(Collider2D collision) { if(collision.CompareTag("Player") && Input.GetButtonDown("Interact")) { interacted = true; SaveData.Instance.stoneSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.stonePos = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y); SaveData.Instance.SaveStone(); } } } </code>
Save data code:
<code>using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; [System.Serializable] public struct SaveData { public static SaveData Instance; //stone data public string stoneSceneName; public Vector2 stonePos; //player data public int playerHealth; public Vector2 playerPos; public string lastScene; public void Initialize() { if(!File.Exists(Application.persistentDataPath + "/save.stone.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.stone.data")); } } public void SaveStone() { using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.stone.data"))) { writer.Write(stoneSceneName); writer.Write(stonePos.x); writer.Write(stonePos.y); } } public void LoadStone() { string savePath = Application.persistentDataPath + "/save.stone.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.stone.data"))) { stoneSceneName = reader.ReadString(); stonePos.x = reader.ReadSingle(); stonePos.y = reader.ReadSingle(); } } } }</code>
Game manager code:
<code>using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { public string transitionedFromScene; public static GameManager Instance { get; private set; } public Vector2 respawnPoint; [SerializeField] SavePoint stone; private void Awake() { SaveData.Instance.Initialize(); if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); stone = FindObjectOfType<SavePoint>(); } public void RespawnPlayer() { SaveData.Instance.LoadStone(); if(SaveData.Instance.stoneSceneName != null) { SceneManager.LoadScene(SaveData.Instance.stoneSceneName); } Debug.Log(SaveData.Instance.stonePos); if(SaveData.Instance.stonePos.x != 0 && SaveData.Instance.stonePos.y != 0) { respawnPoint.y = SaveData.Instance.stonePos.y + 1.358f; respawnPoint.x = SaveData.Instance.stonePos.x; } else { respawnPoint = new Vector2(-3f, -2.58f); } PlayerMovement.Instance.transform.position = respawnPoint; StartCoroutine(UIManager.Instance.DeactivateDeathScreen()); PlayerLife.pl.Respawn(); } } </code>
UIManager code:
<code>using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class UIManager : MonoBehaviour { [SerializeField]Slider slider; [SerializeField]PlayerLife player; public static UIManager Instance; [SerializeField] GameObject deathScreen; public GameObject inventory; public SceneFader sceneFader; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); sceneFader = GetComponentInChildren<SceneFader>(); } public IEnumerator ActivateDeathScreen() { yield return new WaitForSeconds(0.8f); StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.In)); yield return new WaitForSeconds(0.8f); deathScreen.SetActive(true); } public IEnumerator DeactivateDeathScreen() { yield return new WaitForSeconds(0.2f); deathScreen.SetActive(false); StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.Out)); slider.value = player.maxHealth; } // Start is called before the first frame update void Start() { slider.maxValue = player.maxHealth; slider.value = player.maxHealth; } public void UpdateUIHealtbar(int currentHealth) { slider.value = currentHealth; } } </code>
Thanks in advance to everyone
April 2, 2024 at 1:54 pm #13692In reply to: [Request] New Game
Joseph TangModeratorI will have to get back to you on the Reset data button.
As for reloading the game to only the Bench position I can help. I’m assuming this means pausing the game then exiting to main menu and quitting, rather than closing the game mid playthrough. Also, I’m assuming you have completed the scripts until Part 9.
In your SaveData.cs, try out this:
public void SavePlayerData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) { playerHealth = PlayerController.Instance.Health; writer.Write(playerHealth); playerHeartShards = PlayerController.Instance.heartShards; writer.Write(playerHeartShards); playerMana = PlayerController.Instance.Mana; writer.Write(playerMana); playerHalfMana = PlayerController.Instance.halfMana; writer.Write(playerHalfMana); playerManaOrbs = PlayerController.Instance.manaOrbs; writer.Write(playerManaOrbs); playerOrbShard = PlayerController.Instance.orbShard; writer.Write(playerOrbShard); playerOrb0fill = PlayerController.Instance.manaOrbsHandler.orbFills[0].fillAmount; writer.Write(playerOrb0fill); playerOrb1fill = PlayerController.Instance.manaOrbsHandler.orbFills[1].fillAmount; writer.Write(playerOrb1fill); playerOrb2fill = PlayerController.Instance.manaOrbsHandler.orbFills[2].fillAmount; writer.Write(playerOrb2fill); playerUnlockedWallJump = PlayerController.Instance.unlockedWallJump; writer.Write(playerUnlockedWallJump); playerUnlockedDash = PlayerController.Instance.unlockedDash; writer.Write(playerUnlockedDash); playerUnlockedVarJump = PlayerController.Instance.unlockedVarJump; writer.Write(playerUnlockedVarJump); playerUnlockedSideCast = PlayerController.Instance.unlockedSideCast; writer.Write(playerUnlockedSideCast); playerUnlockedUpCast = PlayerController.Instance.unlockedUpCast; writer.Write(playerUnlockedUpCast); playerUnlockedDownCast = PlayerController.Instance.unlockedDownCast; writer.Write(playerUnlockedDownCast);
playerPosition = PlayerController.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene);} } public void LoadPlayerData() { if (File.Exists(Application.persistentDataPath + "/save.player.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { playerHealth = reader.ReadInt32(); playerHeartShards = reader.ReadInt32(); playerMana = reader.ReadSingle(); playerHalfMana = reader.ReadBoolean(); playerManaOrbs = reader.ReadInt32(); playerOrbShard = reader.ReadInt32(); playerOrb0fill = reader.ReadSingle(); playerOrb1fill = reader.ReadSingle(); playerOrb2fill = reader.ReadSingle(); playerUnlockedWallJump = reader.ReadBoolean(); playerUnlockedDash = reader.ReadBoolean(); playerUnlockedVarJump = reader.ReadBoolean(); playerUnlockedSideCast = reader.ReadBoolean(); playerUnlockedUpCast = reader.ReadBoolean(); playerUnlockedDownCast = reader.ReadBoolean();playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); lastScene = reader.ReadString();benchPos.x = reader.ReadSingle(); benchPos.y = reader.ReadSingle(); benchSceneName = reader.ReadString();SceneManager.LoadScene(lastScene); PlayerController.Instance.transform.position = playerPosition;SceneManager.LoadScene(benchSceneName); PlayerController.Instance.transform.position = benchPos; PlayerController.Instance.halfMana = playerHalfMana; PlayerController.Instance.Health = playerHealth; PlayerController.Instance.heartShards = playerHeartShards; PlayerController.Instance.Mana = playerMana; PlayerController.Instance.manaOrbs = playerManaOrbs; PlayerController.Instance.orbShard = playerOrbShard; PlayerController.Instance.manaOrbsHandler.orbFills[0].fillAmount = playerOrb0fill; PlayerController.Instance.manaOrbsHandler.orbFills[1].fillAmount = playerOrb1fill; PlayerController.Instance.manaOrbsHandler.orbFills[2].fillAmount = playerOrb2fill; PlayerController.Instance.unlockedWallJump = playerUnlockedWallJump; PlayerController.Instance.unlockedDash = playerUnlockedDash; PlayerController.Instance.unlockedVarJump = playerUnlockedVarJump; PlayerController.Instance.unlockedSideCast = playerUnlockedSideCast; PlayerController.Instance.unlockedUpCast = playerUnlockedUpCast; PlayerController.Instance.unlockedDownCast = playerUnlockedDownCast; } }Under
SavePlayerData()
you can comment out/remove theplayerPosition
&lastScene
codes as you won’t need it for this purpose. While in yourLoadPlayerDate()
replaceplayerPosition
codes withbenchPos
&lastScene
codes tobenchSceneName
. Doing this will allow your player to load into the game with the correct health, mana and etc, while loading at the Bench position and scene you last saved in.However, you will also need a way to save the data as the only codes saving it now is the unlocks, the shade and death.
In your SceneFader, try this:
public void CallFadeAndLoadScene(string _sceneToLoad) { SaveData.Instance.SavePlayerData(); StartCoroutine(FadeAndLoadScene(FadeDirection.In, _sceneToLoad)); }
Under
CallFadeAndLoadScene()
, addSaveData.Instance.SavePlayerData();
before starting the coroutine. This allows your player’s data to be saved upon entering any scene and main menu exit button.However, I do not advise these method of loading the game. If the player were able to exit and re-enter the game by going back to the bench, this allows what is essentially a fast travel or get out of trouble mechanic for the player by just simply quitting the game. Or in another case it could accidentally reset the player’s progress.
If the code does not work, feel free to tell me as this is simply theory and I have not yet tested the code.
-
AuthorSearch Results
Advertisement below: