Forum begins after the advertisement:

 


[Part 10] Boss Issues

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #18482
    Rafael Santos
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    My Boss doesnt flip;

    Boss doesnt walk;

    when he jumps to dive he like get stuck on air looping on jump anim on animator (the animation is not set with loop), i watched the 10.5 of boss issues and add:

    if (!Boss.Instance.Grounded())
    {
        rb.linearVelocity = new Vector2(rb.linearVelocity.x, -25);
    }

    on Boss_Idle but doesnt worked.

    main Boss script:

    using System.Collections;
    using TMPro;
    using UnityEditor.SceneManagement;
    using UnityEngine;
    using UnityEngine.SocialPlatforms;
    
    public class Boss : Enemy
    {
        public static Boss Instance;
    
        [SerializeField] GameObject attackEffect;
    
        public Transform SideAttacktransform;
        public Vector2 SideAttackArea;
    
        public Transform UpAttacktransform;
        public Vector2 UpAttackArea;
    
        public Transform DownAttacktransform;
        public Vector2 DownAttackArea;
    
        public float attackRange;
        public float attackTimer;
    
        [HideInInspector] public bool facingRight;
    
        [Header("Ground Check Settings")]
        [SerializeField] private Transform groundCheckPoint;
        [SerializeField] private Transform wallCheckPoint;
        [SerializeField] private float groundCheckY = 0.2f;
        [SerializeField] private float groundCheckX = 0.5f;
        [SerializeField] private LayerMask whatIsGround;
    
        int hitCounter;
        bool stunned, canStun;
        bool alive;
    
        [HideInInspector] public float runSpeed;
    
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
        }
    
        // Start is called once before the first execution of Update after the MonoBehaviour is created
        protected override void Start()
        {
            base.Start();
            sr = GetComponentInChildren<SpriteRenderer>();
            anim = GetComponentInChildren<Animator>();
            ChangeState(EnemyStates.Boss_stage1);
            alive = true;
        }
    
        public bool 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))
            {
                grounded = true;
                return true;
            }
            else
            {
                grounded = false;
                return false;
            }
        }
    
        public bool TouchedWall()
        {
            if (Physics2D.Raycast(wallCheckPoint.position, Vector2.down, groundCheckY, whatIsGround)
                || Physics2D.Raycast(wallCheckPoint.position + new Vector3(groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround)
                || Physics2D.Raycast(wallCheckPoint.position + new Vector3(-groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        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
        protected override void Update()
        {
            base.Update();
    
            if (health <= 0 && alive)
            {
                Death(0);
            }
            if (!attacking)
            {
                attackCountDown -= Time.deltaTime;
            }
    
            if (stunned)
            {
                rb.linearVelocity = Vector2.zero;
            }
        }
    
        public void Flip()
        {
            if (PlayerController.Instance.transform.position.x < transform.position.x && transform.position.x > 0)
            {
                transform.eulerAngles = new Vector2(transform.eulerAngles.x, 180);
                facingRight = false;
            }
            else
            {
                transform.eulerAngles = new Vector2(transform.eulerAngles.x, 0);
                facingRight = true;
            }
        }
    
        protected override void UpdateEnemyStates()
        {
            if (PlayerController.Instance !=null)
            {
                switch(GetCurrentEnemyState)
                {
                    case EnemyStates.Boss_stage1:
                        canStun = true;
                        attackTimer = 6;
                        runSpeed = speed;
                        break;
    
                    case EnemyStates.Boss_stage2:
                        canStun = true;
                        attackTimer = 5;
                        break;
    
                    case EnemyStates.Boss_stage3:
                        canStun = false;
                        attackTimer = 8;
                        break;
    
                    case EnemyStates.Boss_stage4:
                        canStun = false;
                        attackTimer = 10;
                        runSpeed = speed / 2;
                        break;
                }
            }
        }
    
        protected override void OnCollisionStay2D(Collision2D _other)
        {
            base.OnCollisionStay2D(_other);
        }
        #region attacking
        #region variables
    
        [HideInInspector] public bool attacking;
        [HideInInspector] public float attackCountDown;
        [HideInInspector] public bool damagedPlayer = false;
        [HideInInspector] public bool parrying;
    
        [HideInInspector] public Vector2 moveToPosition;
        [HideInInspector] public bool diveAttack;
        public GameObject divingCollider;
        public GameObject pillar;
    
        [HideInInspector] public bool barrageAttack;
        public GameObject barrageFireball;
        [HideInInspector] public bool outbreakAttack;
    
        [HideInInspector] public bool bounceAttack;
        [HideInInspector] public float rotationDirectionToTarget;
        [HideInInspector] public int bounceCount;
    
    
        #endregion
    
        #region Control
    
        public void AttackHandler()
        {
            if (currentEnemyState == EnemyStates.Boss_stage1)
            {
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(TripleSlash());
                }
                else
                {
                    StartCoroutine(Lunge());
                }
            }
    
            if (currentEnemyState == EnemyStates.Boss_stage2)
            {
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(TripleSlash());
                }
                else
                {
                    int _attackChosen = Random.Range(1, 3);
                    if (_attackChosen == 1)
                    {
                        StartCoroutine(Lunge());
                    }
                    if (_attackChosen == 2)
                    {
                        DiveAttackJump();
                    }
                    if (_attackChosen == 3)
                    {
                        BarrageBendDown();
                    }
                }
            }
    
            if (currentEnemyState == EnemyStates.Boss_stage3)
            {
                int _attackChosen = Random.Range(1, 3);
                if (_attackChosen == 1)
                {
                    OutbreakBendDown();
                }
                if (_attackChosen == 2)
                {
                    DiveAttackJump();
                }
                if (_attackChosen == 3)
                {
                    BarrageBendDown();
                }
                if (_attackChosen == 4)
                {
                    BounceAttack();
                }
            }
    
            if (currentEnemyState == EnemyStates.Boss_stage4)
            {
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(Slash());
                }
                else
                {
                    BounceAttack();
                }
            }
        }
        public void ResetAllattack()
        {
            attacking = false;
    
            StopCoroutine(TripleSlash());
            StopCoroutine(Lunge());
            StopCoroutine(Parry());
            StopCoroutine(Slash());
    
            diveAttack = false;
            barrageAttack = false;
            outbreakAttack = false;
            bounceAttack = false;
        }
        #endregion
    
        #region Stage 1
    
        IEnumerator TripleSlash()
        {
            attacking = true;
            rb.linearVelocity = Vector2.zero;
    
            anim.SetTrigger("Attack");
            SlashAngle();
            yield return new WaitForSeconds(0.3f);
            anim.ResetTrigger("Attack");
    
            anim.SetTrigger("Attack");
            SlashAngle();
            yield return new WaitForSeconds(0.5f);
            anim.ResetTrigger("Attack");
    
            anim.SetTrigger("Attack");
            SlashAngle();
            yield return new WaitForSeconds(0.2f);
            anim.ResetTrigger("Attack");
    
            ResetAllattack();
        }
    
        void SlashAngle()
        {
            if (PlayerController.Instance.transform.position.x > transform.position.x ||
                PlayerController.Instance.transform.position.x < transform.position.x)
            {
                Instantiate(attackEffect, SideAttacktransform);
            }
            else if (PlayerController.Instance.transform.position.y > transform.position.y)
            {
                SlashEffectAtAngle(attackEffect, 80, UpAttacktransform);
            }
            else if (PlayerController.Instance.transform.position.y < transform.position.y)
            {
                SlashEffectAtAngle(attackEffect, -90, UpAttacktransform);
            }
        }
    
        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);
        }
    
        IEnumerator Lunge()
        {
            Flip();
            attacking = true;
    
            anim.SetBool("Lunge", true);
            yield return new WaitForSeconds(1f);
            anim.SetBool("Lunge", false);
            damagedPlayer = false;
            ResetAllattack();
        }
    
        IEnumerator Parry ()
        {
            attacking = true;
            rb.linearVelocity = Vector2.zero;
            anim.SetBool("Parry", true);
            yield return new WaitForSeconds(0.8f);
            anim.SetBool("Parry", false);
            parrying = false;
            ResetAllattack();
        }
    
        IEnumerator Slash()
        {
            attacking = true;
            rb.linearVelocity = Vector2.zero;
    
            anim.SetTrigger("Attack");
            SlashAngle();
            yield return new WaitForSeconds(0.3f);
            anim.ResetTrigger("Attack");
    
            ResetAllattack();
        }
    
        #endregion
        #region Stage 2
        void DiveAttackJump()
        {
            attacking = true;
            moveToPosition = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y + 5);
            diveAttack = true;
            anim.SetBool("Jump", true);
        }
        public void Dive()
        {
            anim.SetBool("Dive", true);
            anim.SetBool("Jump", false);
        }
        private void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.GetComponent<PlayerController>() != null && (diveAttack || bounceAttack))
            {
                _other.GetComponent<PlayerController>().TakeDamage(damage * 2);
                PlayerController.Instance.pState.recoilingX = true;
            }
        }
        public void DivingPillars()
        {
            Vector2 _impactPoint = groundCheckPoint.position;
            float _spawnDistance = 5;
    
            for (int i = 0; i < 10; i++)
            {
                Vector2 _pillarSpawnPointRight = _impactPoint + new Vector2(_spawnDistance, 0);
                Vector2 _pillarSpawnPointLeft = _impactPoint - new Vector2(_spawnDistance, 0);
                Instantiate(pillar, _pillarSpawnPointRight, Quaternion.Euler(0, 0, -90));
                Instantiate(pillar, _pillarSpawnPointLeft, Quaternion.Euler(0, 0, -90));
    
                _spawnDistance += 5;
            }
            ResetAllattack();
        }
    
        void BarrageBendDown()
        {
            attacking = true;
            rb.linearVelocity = Vector2.zero;
            barrageAttack = true;
            anim.SetTrigger("BendDown");
        }
    
        public IEnumerator Barrage()
        {
            rb.linearVelocity = Vector2.zero;
    
            float _currentAngle = 30f;
    
            for (int i = 0; i < 10; i++)
            {
                GameObject _projectile = Instantiate(barrageFireball, transform.position, Quaternion.Euler(0, 0, _currentAngle));
                if (facingRight)
                {
                    _projectile.transform.eulerAngles = new Vector3(_projectile.transform.eulerAngles.x, 0, _currentAngle);
                }
                else
                {
                    _projectile.transform.eulerAngles = new Vector3(_projectile.transform.eulerAngles.x, 180, _currentAngle);
                }
    
                _currentAngle += 5f;
    
                yield return new WaitForSeconds(0.4f);
            }
            yield return new WaitForSeconds(0.1f);
            anim.SetBool("Cast", false);
            ResetAllattack();
        }
    
        #endregion
        #region Stage 3
        void OutbreakBendDown()
        {
            attacking = true;
            rb.linearVelocity = Vector2.zero;
            moveToPosition = new Vector2(transform.position.x, rb.position.y + 5);
            outbreakAttack = true;
            anim.SetTrigger("BendDown");
        }
    
        public IEnumerator Outbreak()
        {
            yield return new WaitForSeconds(1f);
            anim.SetBool("Cast", true);
    
            rb.linearVelocity = Vector2.zero;
            for (int i = 0; i < 30; i++)
            {
                Instantiate(barrageFireball, transform.position, Quaternion.Euler(0, 0, Random.Range(110, 130))); //downwards
                Instantiate(barrageFireball, transform.position, Quaternion.Euler(0, 0, Random.Range(50, 70))); //diagonal direitda
                Instantiate(barrageFireball, transform.position, Quaternion.Euler(0, 0, Random.Range(260, 280))); //diagonal esquerda
    
                yield return new WaitForSeconds(0.2f);
            }
            yield return new WaitForSeconds(0.1f);
            rb.constraints = RigidbodyConstraints2D.None;
            rb.constraints = RigidbodyConstraints2D.FreezeRotation;
            rb.linearVelocity = new(rb.linearVelocity.x, -10);
            yield return new WaitForSeconds(0.1f);
            anim.SetBool("Cast", false);
            ResetAllattack();
        }
    
        void BounceAttack()
        {
            attacking = true;
            bounceCount = Random.Range(2, 5);
            BounceBendDown();
        }
        int _bounces = 0;
    
        public void CheckBounce()
        {
            if (_bounces < bounceCount - 1)
            {
                _bounces++;
                BounceBendDown();
            }
            else
            {
                _bounces = 0;
                anim.Play("Walk");
            }
        }
    
        public void BounceBendDown()
        {
            rb.linearVelocity = Vector2.zero;
            moveToPosition = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y + 10);
            bounceAttack = true;
            anim.SetTrigger("BendDown");
        }
    
        public void CalculateTargetAngle()
        {
            Vector3 _directionToTarget = (PlayerController.Instance.transform.position - transform.position).normalized;
    
            float _angleOfTarget = Mathf.Atan2(_directionToTarget.y, _directionToTarget.x) * Mathf.Rad2Deg;
            rotationDirectionToTarget = _angleOfTarget;
        }
    
        #endregion
    
        #endregion
    
        public override void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitforce)
        {
            if (!stunned)
            {
                if (!parrying)
                {
                    if (canStun)
                    {
                        hitCounter++;
                        if (hitCounter >= 3) //o jogo original é 13, aqui é apenas para teste
                        {
                            ResetAllattack();
                            StartCoroutine(Stunned());
                        }
                    }
                    base.EnemyHit(_damageDone, _hitDirection, _hitforce);
    
                    if (currentEnemyState != EnemyStates.Boss_stage4)
                    {
                        ResetAllattack();
                        StartCoroutine(Parry());
                    }
                }
                else
                {
                    StopCoroutine(Parry());
                    parrying = false;
                    ResetAllattack();
                    StartCoroutine(Slash()); //riposte
                }
            }
            else
            {
                StopCoroutine(Stunned());
                anim.SetBool("Stunned", false);
                stunned = false;
            }
    
            #region health to state
            if (health > 20)
            {
                ChangeState(EnemyStates.Boss_stage1);
            }
            if (health <= 15 && health < 10)
            {
                ChangeState(EnemyStates.Boss_stage2);
            }
            if (health <= 10 && health < 5)
            {
                ChangeState(EnemyStates.Boss_stage3);
            }
            if (health < 5)
            {
                ChangeState(EnemyStates.Boss_stage4);
            }
            if (health <= 0 && alive)
            {
                Death(0);
            }
            #endregion
        }
        public IEnumerator Stunned()
        {
            stunned = true;
            hitCounter = 0;
            anim.SetBool("Stunned", true);
    
            yield return new WaitForSeconds(6f);
            anim.SetBool("Stunned", false);
            stunned = false;
    
        }
    
        protected override void Death(float _destroyTime)
        {
            ResetAllattack();
            alive = false;
            rb.linearVelocity = new Vector2(rb.linearVelocity.x, -25);
            anim.SetTrigger("Die");
        }
        public void DestroyAfterDeath()
        {
            Destroy(gameObject);
        }
    }
    
    Boss events script:
    
    using System.Collections;
    using UnityEngine;
    
    public class BossEvents : MonoBehaviour
    {
        void SlashDamagePlayer()
        {
            if (PlayerController.Instance.transform.position.x > transform.position.x ||
                PlayerController.Instance.transform.position.x < transform.position.x)
            {
                Hit(Boss.Instance.SideAttacktransform, Boss.Instance.SideAttackArea);
            }
            else if (PlayerController.Instance.transform.position.y > transform.position.y)
            {
                Hit(Boss.Instance.UpAttacktransform, Boss.Instance.UpAttackArea);
            }
            else if (PlayerController.Instance.transform.position.y < transform.position.y)
            {
                Hit(Boss.Instance.DownAttacktransform, Boss.Instance.DownAttackArea);
            }
        }
        void Hit(Transform _attackTransform, Vector2 _attackArea)
        {
            Collider2D[] _objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0);
            for (int i = 0; i < _objectsToHit.Length; i++)
            {
                if (_objectsToHit[i].GetComponent<PlayerController>() != null && !PlayerController.Instance.pState.invincible)
                {
                    _objectsToHit[i].GetComponent<PlayerController>().TakeDamage(Boss.Instance.damage);
                    if (PlayerController.Instance.pState.alive)
                    {
                        PlayerController.Instance.HitStopTime(0, 5, 0.5f);
                    }
                }
            }
        }
    
        void Parrying ()
        {
            Boss.Instance.parrying = true;
        }
    
        void BendDownCheck()
        {
            if (Boss.Instance.barrageAttack)
            {
                StartCoroutine(BarrageAttackTransition());
            }
            if (Boss.Instance.outbreakAttack)
            {
                StartCoroutine(OutbreakAttackTransition());
            }
            if (Boss.Instance.bounceAttack)
            {
                Boss.Instance.anim.SetTrigger("Bounce1");
            }
        }
        void BarrageOrOutbreak()
        {
            if (Boss.Instance.barrageAttack)
            {
                Boss.Instance.StartCoroutine(Boss.Instance.Barrage());
            }
            if (Boss.Instance.outbreakAttack)
            {
                Boss.Instance.StartCoroutine(Boss.Instance.Outbreak());
            }
        }
    
        IEnumerator BarrageAttackTransition()
        {
            yield return new WaitForSeconds(1f);
            Boss.Instance.anim.SetBool("Cast", true);
        }
    
        IEnumerator OutbreakAttackTransition()
        {
            yield return new WaitForSeconds(1f);
            Boss.Instance.anim.SetBool("Cast", true);
        }
    
        void DestroyAfterDeath()
        {
            //SpawnBoss.Instance.IsNotTrigger();
            Boss.Instance.DestroyAfterDeath();
            GameManager.Instance.BossDefeated = true;
            SaveData.Instance.SaveBossData();
            SaveData.Instance.SavePlayerData();
        }
    }

    SaveData Script:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    using UnityEngine.SceneManagement;
    
    
    [System.Serializable]
    public struct SaveData
    {
        public static SaveData Instance;
    
        //map stuff
        public HashSet<string> sceneNames;
    
        //tree stuff
        public string treeSceneName;
        public Vector2 treePos;
    
        //Player Stuff
        public int playerHealth;
        public int playerMaxHealth;
        public int playerHeartShards;
        public float playerMana;
    
        public Vector2 playerPosition;
        public string lastScene;
    
        public bool playerUnlockedWallJump;
        public bool playerUnlockedDash;
        public bool playerUnlockedDoubleJump;
    
        public bool playerUnlockedFireBall;
        public bool playerUnlockedUpSpell;
        public bool playerUnlockedDownSpell;
    
        //Boss
        public bool BossDefeated;
    
    
        public void Initialize()
        {
            if (!File.Exists(Application.persistentDataPath + "/save.tree.data"))
            {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.tree.data"));
            }
            if (!File.Exists(Application.persistentDataPath + "/save.player.data"))
            {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data"));
            }
            if (!File.Exists(Application.persistentDataPath + "/save.boss.data"))
            {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.boss.data"));
            }
    
            if (sceneNames == null)
            {
                sceneNames = new HashSet<string>();
            }
        }
    
        public void SaveTree()
        {
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.tree.data")))
            {
                writer.Write(treeSceneName);
                writer.Write(treePos.x);
                writer.Write(treePos.y);
            }
        }
    
        public void LoadTree()
        {
            if (File.Exists(Application.persistentDataPath + "/save.tree.data"))
            {
                using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.tree.data")))
                {
                    treeSceneName = reader.ReadString();
                    treePos.x = reader.ReadSingle();
                    treePos.y = reader.ReadSingle();
                }
            }
        }
    
        public void SavePlayerData()
        {
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data")))
            {
                playerHealth = PlayerController.Instance.Health;
                writer.Write(playerHealth);
                playerMaxHealth = PlayerController.Instance.maxHealth;
                writer.Write(playerMaxHealth);
                playerHealth = PlayerController.Instance.heartShards;
                writer.Write(playerHeartShards);
    
                playerMana = PlayerController.Instance.Mana;
                writer.Write(playerMana);
    
                playerUnlockedWallJump = PlayerController.Instance.unlockedWallJump;
                writer.Write(playerUnlockedWallJump);
                playerUnlockedDash = PlayerController.Instance.unlockedDash;
                writer.Write(playerUnlockedDash);
                playerUnlockedDoubleJump = PlayerController.Instance.unlockedDoubleJump;
                writer.Write(playerUnlockedDoubleJump);
    
                playerUnlockedFireBall = PlayerController.Instance.unlockedFireBall;
                writer.Write(playerUnlockedFireBall);
                playerUnlockedUpSpell = PlayerController.Instance.unlockedUpSpell;
                writer.Write(playerUnlockedUpSpell);
                playerUnlockedDownSpell = PlayerController.Instance.unlockedDownSpell;
                writer.Write(playerUnlockedDownSpell);
    
                playerPosition = PlayerController.Instance.transform.position;
                writer.Write(playerPosition.x);
                writer.Write(playerPosition.y);
    
                lastScene = SceneManager.GetActiveScene().name;
                writer.Write(lastScene);
            }
            Debug.Log("Saved player data");
        }
    
        public void LoadPlayerData()
        {
            Debug.Log(Application.persistentDataPath);
            if (File.Exists(Application.persistentDataPath + "/save.player.data"))
            {
                using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data")))
                {
                    playerHealth = reader.ReadInt32();
                    playerMaxHealth = reader.ReadInt32();
                    playerHeartShards = reader.ReadInt32();
    
                    playerMana = reader.ReadSingle();
    
                    playerUnlockedWallJump = reader.ReadBoolean();
                    playerUnlockedDash = reader.ReadBoolean();
                    playerUnlockedDoubleJump = reader.ReadBoolean();
    
                    playerUnlockedFireBall = reader.ReadBoolean();
                    playerUnlockedUpSpell = reader.ReadBoolean();
                    playerUnlockedDownSpell = reader.ReadBoolean();
    
                    playerPosition.x = reader.ReadSingle();
                    playerPosition.y = reader.ReadSingle();
    
                    lastScene = reader.ReadString();
    
                    SceneManager.LoadScene(lastScene);
                    PlayerController.Instance.transform.position = playerPosition;
                    PlayerController.Instance.Health = playerHealth;
                    PlayerController.Instance.maxHealth = playerMaxHealth;
                    PlayerController.Instance.heartShards = playerHeartShards;
                    PlayerController.Instance.Mana = playerMana;
    
                    PlayerController.Instance.unlockedWallJump = playerUnlockedWallJump;
                    PlayerController.Instance.unlockedDash = playerUnlockedDash;
                    PlayerController.Instance.unlockedDoubleJump = playerUnlockedDoubleJump;
    
                    PlayerController.Instance.unlockedFireBall = playerUnlockedFireBall;
                    PlayerController.Instance.unlockedUpSpell = playerUnlockedUpSpell;
                    PlayerController.Instance.unlockedDownSpell = playerUnlockedDownSpell;
                }
            }
            else
            {
                Debug.Log("File doesn't exist");
                PlayerController.Instance.Health = PlayerController.Instance.maxHealth;
                PlayerController.Instance.Mana = 0.5f;
                PlayerController.Instance.heartShards = 0;
    
                PlayerController.Instance.unlockedWallJump = false;
                PlayerController.Instance.unlockedDash = false;
                PlayerController.Instance.unlockedDoubleJump = false;
            }
        }
        public void SaveBossData()
        {
            using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.boss.data")))
            {
                BossDefeated = GameManager.Instance.BossDefeated;
    
                writer.Write(BossDefeated);
            }
        }
    
        public void LoadBossData()
        {
            if (File.Exists(Application.persistentDataPath + "/save.boss.data"))
            {
                using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.boss.data")))
                {
                    BossDefeated = reader.ReadBoolean();
    
                    GameManager.Instance.BossDefeated = BossDefeated;
                }
            }
            else
            {
                Debug.Log("Boss doesn't exist");
            }
        }
    }

    Walk script:

    using UnityEngine;
    
    public class Boss_Walk : StateMachineBehaviour
    {
        Rigidbody2D rb;
        // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            rb = animator.GetComponentInParent<Rigidbody2D>();
        }
    
        // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            TargetPlayerPosition(animator);
    
            if (Boss.Instance.attackCountDown <= 0)
            {
                Boss.Instance.AttackHandler();
                Boss.Instance.attackCountDown = Random.Range(Boss.Instance.attackTimer - 1, Boss.Instance.attackTimer + 1);
            }
        }
    
        void TargetPlayerPosition(Animator animator)
        {
            if (Boss.Instance.Grounded())
            {
                Boss.Instance.Flip();
                Vector2 _target = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y);
                Vector2 _newPos = Vector2.MoveTowards(rb.position, _target, Boss.Instance.runSpeed * Time.fixedDeltaTime);
                rb.MovePosition(_newPos);
            }
            else
            {
                rb.linearVelocity = new Vector2(rb.linearVelocity.x, -25);
            }
    
            if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= Boss.Instance.attackRange)
            {
                animator.SetBool("Walk", false);
            }
            else
            {
                return;
            }
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            animator.SetBool("Walk", false);
        }
    }

    Jump Script:

    using Unity.VisualScripting.Dependencies.NCalc;
    using UnityEngine;
    
    public class Boss_Jump : StateMachineBehaviour
    {
        Rigidbody2D rb;
        // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            rb = animator.GetComponentInParent<Rigidbody2D>();
        }
    
        //OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            DiveAttack();
        }
    
        void DiveAttack()
        {
            if (Boss.Instance.diveAttack)
            {
                Boss.Instance.Flip();
    
                Vector2 _newPos = Vector2.MoveTowards(rb.position, Boss.Instance.moveToPosition,
                    Boss.Instance.speed * 3 * Time.fixedDeltaTime);
                rb.MovePosition(_newPos);
    
                if (Boss.Instance.TouchedWall())
                {
                    Boss.Instance.moveToPosition.x = rb.linearVelocity.x;
                    _newPos = Vector2.MoveTowards(rb.position, Boss.Instance.moveToPosition,
                    Boss.Instance.speed * 3 * Time.fixedDeltaTime);
                }
    
                float _distance = Vector2.Distance(rb.position, _newPos);
                if (_distance < 0.1f)
                {
                    Boss.Instance.Dive();
                }
            }
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
    
        }
    }

    Dive Script:

    using UnityEngine;
    
    public class Boss_Dive : StateMachineBehaviour
    {
        Rigidbody2D rb;
        bool callOnce;
        // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            rb = animator.GetComponentInParent<Rigidbody2D>();
        }
    
        //OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            Boss.Instance.divingCollider.SetActive(true);
    
            if (Boss.Instance.Grounded())
            {
                Boss.Instance.divingCollider.SetActive(false);
    
                if (!callOnce)
                {
                    Boss.Instance.DivingPillars();
                    animator.SetBool("Dive", false);
                    Boss.Instance.ResetAllattack();
                    callOnce = true; 
                }
    
            }
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            callOnce = false;
        }
    }

    Bounce 1 script:

    using UnityEngine;
    
    public class Boss_Bounce1 : StateMachineBehaviour
    {
        Rigidbody2D rb;
        // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            rb = animator.GetComponentInParent<Rigidbody2D>();
        }
    
        // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            if (Boss.Instance.bounceAttack)
            {
                Vector2 _newPos = Vector2.MoveTowards(rb.position, Boss.Instance.moveToPosition,
                    Boss.Instance.speed * Random.Range(2, 4) * Time.fixedDeltaTime);
                rb.MovePosition(_newPos);
    
                if (Boss.Instance.TouchedWall())
                {
                    Boss.Instance.moveToPosition.x = rb.linearVelocity.x;
                    _newPos = Vector2.MoveTowards(rb.position, Boss.Instance.moveToPosition,
                    Boss.Instance.speed * Random.Range(2, 4) * Time.fixedDeltaTime);
                }
    
                float _distance = Vector2.Distance(rb.position, _newPos);
                if (_distance < 0.1f)
                {
                    Boss.Instance.CalculateTargetAngle();
                    animator.SetTrigger("Bounce2");
                }
            }
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            animator.ResetTrigger("Bounce1"); 
        }
    }

    Bounce2 script:

    using UnityEngine;
    
    public class Boss_Bounce2 : StateMachineBehaviour
    {
        Rigidbody2D rb;
        bool callOnce;
        // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            rb = animator.GetComponentInParent<Rigidbody2D>();
        }
    
        // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            Vector2 _forceDirection = new Vector2(Mathf.Cos(Mathf.Deg2Rad * Boss.Instance.rotationDirectionToTarget),
                Mathf.Sin(Mathf.Deg2Rad * Boss.Instance.rotationDirectionToTarget));
            rb.AddForce(_forceDirection * 3, ForceMode2D.Impulse);
    
            Boss.Instance.divingCollider.SetActive(true);
    
            if (Boss.Instance.Grounded())
            {
                Boss.Instance.divingCollider.SetActive(false);
    
                if (!callOnce)
                {
                    Boss.Instance.ResetAllattack();
                    Boss.Instance.CheckBounce();
                    callOnce = true;
                }
                animator.SetTrigger("Grounded");
            }
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            animator.ResetTrigger("Bounce2");
            animator.ResetTrigger("Grounded");
            callOnce = false;
        }
    }

    BendDown script:

    using UnityEngine;
    
    public class Boss_BendDown : StateMachineBehaviour
    {
        Rigidbody2D rb;
        // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            rb = animator.GetComponentInParent<Rigidbody2D>();
        }
    
        // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            OutBreakAttack();
        }
    
        void OutBreakAttack()
        {
            if (Boss.Instance.outbreakAttack)
            {
                Vector2 _newPos = Vector2.MoveTowards(rb.position, Boss.Instance.moveToPosition,
                    Boss.Instance.speed * 1.5f * Time.fixedDeltaTime);
                rb.MovePosition(_newPos);
    
                if (Boss.Instance.TouchedWall())
                {
                    Boss.Instance.moveToPosition.x = rb.linearVelocity.x;
                    _newPos = Vector2.MoveTowards(rb.position, Boss.Instance.moveToPosition,
                    Boss.Instance.speed * 1.5f * Time.fixedDeltaTime);
                }
    
                float _distance = Vector2.Distance(rb.position, _newPos);
                if (_distance < 0.1f)
                {
                    Boss.Instance.rb.constraints = RigidbodyConstraints2D.FreezePosition;
                }
            }
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            animator.ResetTrigger("BendDown");
        }
    }

    i hope you can help me

    #18483
    Ser Apustaja
    Level 6
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    It sounds like you are facing a few issues with the Boss character’s behavior in your game. Let’s break down the issues and see how we can help you resolve them.

    1. Boss Does Not Flip

    The Flip() function appears to check the position of the player relative to the boss and change the boss’s direction accordingly. Ensure that this function is being called at the appropriate time, such as when the boss is moving towards the player.

    You may want to add more conditions to ensure the boss only flips when necessary. For example, you should only flip the boss if it’s not currently attacking or in a state that shouldn’t flip:

    public void Flip()
    {
        if (!attacking) // Only flip when not attacking
        {
            if (PlayerController.Instance.transform.position.x < transform.position.x)
            {
                transform.eulerAngles = new Vector2(0, 180);
                facingRight = false;
            }
            else
            {
                transform.eulerAngles = new Vector2(0, 0);
                facingRight = true;
            }
        }
    }

    2. Boss Does Not Walk

    In your Boss_Walk script, you may need to ensure that the boss is moving towards the player. The TargetPlayerPosition method should be invoked correctly, and it should check if the boss is grounded before attempting to move.

    Make sure that the Grounded() method is returning true when it should. You can add debug logs to verify if the boss is grounded:

    void TargetPlayerPosition(Animator animator)
    {
        if (Boss.Instance.Grounded())
        {
            Debug.Log("Boss is grounded."); // Debug log
            Boss.Instance.Flip();
            Vector2 _target = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y);
            Vector2 _newPos = Vector2.MoveTowards(rb.position, _target, Boss.Instance.runSpeed * Time.fixedDeltaTime);
            rb.MovePosition(_newPos);
        }
        else
        {
            rb.velocity = new Vector2(rb.velocity.x, -25); // Apply a downward force
            Debug.Log("Boss is not grounded."); // Debug log
        }
    }

    3. Boss Gets Stuck in Jump Animation

    If the boss is getting stuck in the jump animation, make sure that the transition conditions in your Animator are set correctly. The jump animation should only play when the boss is actually jumping, and you need to ensure it transitions back to the idle state or walking state when the boss lands.

    In your Boss_Dive script, you can handle landing conditions:

    if (Boss.Instance.Grounded())
    {
        Boss.Instance.divingCollider.SetActive(false);
        if (!callOnce)
        {
            Boss.Instance.DivingPillars();
            animator.SetBool("Dive", false);
            Boss.Instance.ResetAllattack();
            callOnce = true; 
        }
    }
    else
    {
        // Optionally handle a downward force or velocity here
        rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y); // Maintain current x velocity
    }

    Additional Suggestions

    • Check your Animator transitions for the jump and dive animations to ensure they are set up correctly. Make sure there are conditions for transitioning out of the jump state when grounded.
    • Implement more debug logs throughout your scripts to help identify where things might be going wrong.
    • Make sure your Rigidbody2D settings (like mass and gravity scale) are set correctly to allow for expected movement behavior.

    With these adjustments and checks, you should be able to fix the issues with the boss character's behavior. Let me know if you have any further questions or need additional help!

    #18484
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Can you record a video of the bugs on your boss script and post them here? You can use ScreenToGif to record the video: https://www.screentogif.com/

Viewing 3 posts - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: