i tried using a debug log and it works but im still getting these errors at random places:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
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));
}
StartCoroutine(UIManager.Instance.sceneFader.Fade(SceneFader.FadeDirection.Out));
}
private void OnTriggerEnter2D(Collider2D _other)
{
if (_other.CompareTag("Player"))
{
GameManager.Instance.transitionedFromScene = SceneManager.GetActiveScene().name;
SceneManager.LoadScene(transitionTo);
PlayerController.Instance.pState.cutscene = true;
StartCoroutine(UIManager.Instance.sceneFader.FadeAndLoadScene(SceneFader.FadeDirection.In, transitionTo));
Debug.Log("scene fader works");
}
}
}
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("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("Vertical Movement Settings")]
[SerializeField] private float jumpForce = 45;
private int jumpBufferCounter = 0;
[SerializeField] private int jumpBufferFrames;
private float coyoteTimeCounter = 0;
[SerializeField] private float coyoteTime;
[SerializeField] private float airJumpsCounter = 0;
[SerializeField] private int maxAirJumps;
[Space(5)]
[Header("recoil")]
[SerializeField] int recoilXSteps = 5;
[SerializeField] int recoilYSteps = 5;
[SerializeField] float recoilXSpeed = 100;
[SerializeField] float recoilYSpeed = 100;
private int stepsXRecoiled, stepsYRecoiled;
[Space(5)]
[Header("Attack Settings")]
private bool attack = false;
private float timeBetweenAttack, timeSinceAttack;
[SerializeField] Transform SideAttackTransform, BehindAttackTransform, UpAttackTransform, DownAttackTransform;
[SerializeField] Vector2 SideAttackArea, BehindAttackArea, UpAttackArea, DownAttackArea;
[SerializeField] LayerMask attackableLayer;
[SerializeField] float damage;
[SerializeField] GameObject slashEffect;
[SerializeField] GameObject upSlashEffect;
[SerializeField] GameObject downSlashEffect;
bool restoreTime;
float restoreTimeSpeed;
[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("Health")]
public int health;
public int maxHealth;
[SerializeField] GameObject bloodSpurt;
[SerializeField] GameObject crackeffect;
[SerializeField] float hitFlashSpeed;
public delegate void OnHealthChangedDelegate(); // delegate voids can be used on multiple methods
[HideInInspector] public OnHealthChangedDelegate onHealthChangedCallBack;
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")]
//spell stats
[SerializeField] float manaSpellCost;
[SerializeField] float timeBetweenCast = 0.5f;
float timeSinceCast;
[SerializeField] float spellDamage;
//spell cast objects
[SerializeField] GameObject upSpellExplosion;
[Space(5)]
[HideInInspector] public playerStatesList pState;
private float xAxis, yAxis;
private Rigidbody2D rb;
private float gravity;
private Animator anim;
private SpriteRenderer sr;
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<playerStatesList>();
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
gravity = rb.gravityScale;
Mana = mana;
manaStorage.fillAmount = Mana;
Health = maxHealth;
}
//draw out hitboxes for basic attacks
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea);
Gizmos.DrawWireCube(BehindAttackTransform.position, BehindAttackArea);
Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea);
Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea);
}
// Update is called once per frame
void Update()
{
if (pState.cutscene) return;
GetInputs();
updateJumpVariable();
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>().EnemyHit(spellDamage, (_other.transform.position - transform.position).normalized, -recoilYSpeed);
}
}
private void FixedUpdate()
{
if (pState.cutscene) return;
if (pState.dashing) return;
Recoil();
}
//basic inputs for movement
void GetInputs()
{
xAxis = Input.GetAxisRaw("Horizontal");
yAxis = Input.GetAxisRaw("Vertical");
attack = Input.GetButtonDown("Attack");
}
// flip player on x axis when left or right is picked
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;
}
}
//move left and right
private void Move()
{
rb.velocity = new Vector2(walkSpeed * xAxis, rb.velocity.y);
anim.SetBool("walking", rb.velocity.x != 0 && Grounded());
}
//allows for dashing and air dashing
void StartDash()
{
if(Input.GetButtonDown("Dash") && canDash && !dashed)
{
StartCoroutine(Dash());
dashed = true;
}
if (Grounded())
{
dashed = false;
}
}
//stops middair infinite dashing
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 you exit upwards
if(_exitDir.y > 0)
{
rb.velocity = jumpForce * _exitDir;
}
//horizontal exiting
if(_exitDir.x != 0)
{
xAxis = _exitDir.x > 0 ? 1 : -1;
Move();
}
Flip();
yield return new WaitForSeconds(_delay);
pState.cutscene = false;
}
//create hitboxes for attacks
void Attack()
{
timeSinceAttack += Time.deltaTime;
if(attack && timeSinceAttack >= timeBetweenAttack)
{
timeSinceAttack = 0;
//side attack
if (yAxis == 0 || yAxis < 0 && Grounded())
{
Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingx, recoilXSpeed);
Instantiate(slashEffect, SideAttackTransform);
anim.SetTrigger("Attacking");
}
//up air attack
else if (yAxis > 0 && !Grounded())
{
Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingy, recoilYSpeed);
Instantiate(upSlashEffect, UpAttackTransform);
anim.SetTrigger("Attacking");
}
//down air attak
else if (yAxis < 0 && !Grounded())
{
Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingy, recoilYSpeed);
Instantiate(downSlashEffect, DownAttackTransform);
anim.SetTrigger("Attacking");
}
if (yAxis > 0 && Grounded())
{
Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingy, recoilYSpeed);
Instantiate(upSlashEffect, UpAttackTransform);
anim.SetTrigger("upAttack");
}
}
}
//hitting the enemy and adding recoil to attacks
void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilDir, float _recoilStrength)
{
Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer);
if(objectsToHit.Length > 0)
{
_recoilDir = true;
}
for(int i = 0; i < objectsToHit.Length; i++)
{
if (objectsToHit[i].GetComponent<Enemy>() != null)
{
objectsToHit[i].GetComponent<Enemy>().EnemyHit
(damage, (transform.position - objectsToHit[i].transform.position).normalized, _recoilStrength);
if (objectsToHit[i].CompareTag("Enemy"))
{
Mana += manaGain;
}
}
}
}
//changes the direction of attack based on aerial positions
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 UpSlashEffectAtAngle(GameObject _upSlashEffect, int _effectAngle, Transform _attackTransform)
{
_upSlashEffect = Instantiate(_upSlashEffect, _attackTransform);
_upSlashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle);
_upSlashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y);
}
void DownSlashEffectAtAngle(GameObject _downSlashEffect, int _effectAngle, Transform _attackTransform)
{
_downSlashEffect = Instantiate(_downSlashEffect, _attackTransform);
_downSlashEffect.transform.eulerAngles = new Vector3(0, 0, _effectAngle);
_downSlashEffect.transform.localScale = new Vector2(transform.localScale.x, transform.localScale.y);
}
//directional player recoil based on main slash attacks, x and y axis movement
void Recoil()
{
//recoiling in the x axis
if (pState.recoilingx)
{
if (pState.lookingRight)
{
rb.velocity = new Vector2(-recoilXSpeed, 0);
}
else
{
rb.velocity = new Vector2(recoilXSpeed, 0);
}
}
//recoil in the y axis
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);
}
airJumpsCounter = 0;
}
else
{
rb.gravityScale = gravity;
}
//stop recoiling
if (pState.recoilingx && stepsXRecoiled < recoilXSteps)
{
stepsXRecoiled++;
}
else
{
StopRecoilX();
}
if (pState.recoilingy && stepsYRecoiled < recoilYSteps)
{
stepsYRecoiled++;
}
else
{
StopRecoilY();
}
if (Grounded())
{
StopRecoilY();
}
}
//stop recoiling forever
void StopRecoilX()
{
stepsXRecoiled = 0;
pState.recoilingx = false;
}
void StopRecoilY()
{
stepsYRecoiled = 0;
pState.recoilingy = false;
}
//take damage, set health and gives some invinicibility frames
public void TakeDamage(float _damage)
{
Health -= Mathf.RoundToInt(_damage);
StartCoroutine(StopTakingDamage());
}
IEnumerator StopTakingDamage()
{
pState.invincible = true;
anim.SetTrigger("takeDamage");
GameObject _bloodSpurtParticles = Instantiate(bloodSpurt, transform.position, Quaternion.identity);
GameObject _crack = Instantiate(crackeffect, transform.position, Quaternion.identity);
Destroy(_crack, 0.1f);
Destroy(_bloodSpurtParticles, 1.5f);
yield return new WaitForSeconds(1f);
pState.invincible = false;
}
//flash black and white when hit for i frames
void FlashWhileInvincible()
{
sr.material.color = pState.invincible ?
Color.Lerp(Color.white, Color.black, Mathf.PingPong(Time.time * hitFlashSpeed, 1.5f)) : Color.white;
}
void RestoreTimeScale()
{
if (restoreTime)
{
if (Time.timeScale < 1)
{
Time.timeScale += Time.deltaTime * restoreTimeSpeed;
}
else
{
Time.timeScale = 1;
restoreTime = false;
}
}
}
//create invincibility frames
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;
}
}
//begin taking damage again
IEnumerator StartTimeAgain(float _delay)
{
restoreTime = true;
yield return new WaitForSeconds(_delay);
}
//health and removing health
public int Health
{
get { return health; }
set
{
if (health != value)
{
health = Mathf.Clamp(value, 0, maxHealth);
if (onHealthChangedCallBack != null)
{
onHealthChangedCallBack.Invoke();
}
}
}
}
//heal with mana with a
void Heal()
{
if (Input.GetButton("Heal") && 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;
}
}
//create mana
float Mana
{
get { return mana; }
set
{
//if mana stats change
if (mana != value)
{
mana = Mathf.Clamp(value, 0, 1);
manaStorage.fillAmount = Mana;
}
}
}
//cast up spell explosion when u have enough mana and its been a long time since your last kaboom
void CastSpell()
{
if (Input.GetButtonDown("CastSpell") && timeSinceCast >= timeBetweenCast && Mana >= manaSpellCost && yAxis > 0)
{
pState.casting = true;
timeSinceCast = 0;
StartCoroutine(CastCoroutine());
}
else
{
timeSinceCast += Time.deltaTime;
}
}
IEnumerator CastCoroutine()
{
anim.SetBool("Casting", true);
yield return new WaitForSeconds(0.2f);
//up cast
if (yAxis > 0)
{
Instantiate(upSpellExplosion, transform);
rb.velocity = Vector2.zero;
}
Mana -= manaSpellCost;
yield return new WaitForSeconds(0.2f);
anim.SetBool("Casting", false);
pState.casting = false;
}
//checks if you are grounded
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;
}
}
//makes you jump when pressing spacebar
void Jump()
{
if (jumpBufferCounter > 0 && coyoteTimeCounter > 0 && !pState.jumping)
{
rb.velocity = new Vector3(rb.velocity.x, jumpForce);
pState.jumping = true;
}
if (!Grounded() && airJumpsCounter < maxAirJumps && Input.GetButtonDown("Jump"))
{
pState.jumping = true;
airJumpsCounter++;
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;
}
//animate jumping double jump and falling animation
anim.SetBool("jumping", !Grounded() && rb.velocity.y > -15 && airJumpsCounter == 0);
anim.SetBool("doublejump", !Grounded() && airJumpsCounter == 1);
anim.SetBool("falling", !Grounded() && rb.velocity.y < -10);
}
//coyote time and jump buffering
void updateJumpVariable()
{
//coyote time
if (Grounded())
{
pState.jumping = false;
coyoteTimeCounter = coyoteTime;
airJumpsCounter = 0;
}
else
{
coyoteTimeCounter -= Time.deltaTime;
}
//jump buffering
if (Input.GetButtonDown("Jump"))
{
jumpBufferCounter = jumpBufferFrames;
}
else
{
jumpBufferCounter--;
}
}
}