Forum begins after the advertisement:


[part 10] dive causes unity to freeze completely

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [part 10] dive causes unity to freeze completely

Viewing 20 posts - 1 through 20 (of 46 total)
  • Author
    Posts
  • #15948
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    So the boss will move above my player, drop down , but when it hits the ground, the entire unity engine freezes….. i have to open task manager to reset unity as i already waiting 10 mins and the whole thing was frozen.Ive tested it and its happened 4 times in a row?? Im not sure if this has something to do with too many pillars being generated? maybe unity cant handle it?? my laptop is high spec so idk if its a processing issue

    ive included code for the dive(animation), my main boss and the pillar

    dive script:

    `

    <code>public class WoodenBotDive : 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>();
        }
    
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            WoodenBot.Instance.divingCollider.SetActive(true);
    
            if (WoodenBot.Instance.Grounded())
            {
                WoodenBot.Instance.divingCollider.SetActive(false);
    
                if (!callOnce)
                {
                    WoodenBot.Instance.DivingPillars();
                    animator.SetBool("Dive", false);
                    WoodenBot.Instance.ResetAllAttacks();
                    callOnce = true;
                }
    
            }
        }
    
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            callOnce = false;
        }
    
    }</code>

    THeHollowKnightScript – (my boss is called woodenBot instead of TheHollowKnight)

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class WoodenBot : Enemy
    {
    
        public static WoodenBot Instance;
    
        [Header("Ground Check Settings")]
        [SerializeField] private Transform groundCheckPoint;
        [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 bool facingRight;
        [HideInInspector] public float runSpeed;
        [HideInInspector] public bool damagePlayer = false;
        [HideInInspector] public bool parrying;
    
        [HideInInspector] public Vector2 moveToPosition;
        [HideInInspector] public bool diveAttack;
        public GameObject divingCollider;
        public GameObject pillar;
        [Space(5)]
    
        [Header("attack settings")]
        [SerializeField] public Transform SideAttackTransform, UpAttackTransform, DownAttackTransform;
        [SerializeField] public Vector2 SideAttackArea, UpAttackArea, DownAttackArea;
        [SerializeField] public GameObject slashEffect;
    
        public float attackRange;
        public float attackTimer;
    
        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;
            }
        }
    
        private void OnDrawGizmos()
        {
            Gizmos.color = Color.red;
    
            Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea);
            Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea);
            Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea);
    
        }
    
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
    
        }
    
        // Start is called before the first frame update
        protected override void Start()
        {
            base.Start();
            sr = GetComponentInChildren<SpriteRenderer>();
            anim = GetComponentInChildren<Animator>();
    
            ChangeState(EnemyStates.woodenBot_stage1);
            alive = true;
        }
    
        // Update is called once per frame
        protected override void Update()
        {
            base.Update();
    
            if (!attacking)
            {
                attackCountdown -= Time.deltaTime;
            }
    
        }
    
        public void Flip()
        {
            if (PlayerController.Instance.transform.position.x < transform.position.x && transform.localScale.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.woodenBot_stage1:
                        break;
    
                    case EnemyStates.woodenBot_stage2:
                        break;
    
                    case EnemyStates.woodenBot_stage3:
                        break;
    
                    case EnemyStates.woodenBot_stage4:
                        break;
                }
    
            }
        }
    
        protected override void OnCollisionStay2D(Collision2D _other)
        {
    
        }
    
        #region attacking
        #region variables
        [HideInInspector] public bool attacking;
        [HideInInspector] public float attackCountdown;
    
        #endregion
        #endregion
    
        #region AttackHandler
    
        public void AttackHandler()
        {
            if (currentEnemyState == EnemyStates.woodenBot_stage1)
            {
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(TripleSlash());
                }
                else
                {
                    //StartCoroutine(Lunge());
                    DiveAttackJump();
                }
            }
        }
    
        public void ResetAllAttacks()
        {
            attacking = false;
            StopCoroutine(Lunge());
            StopCoroutine(Parry());
            StopCoroutine(TripleSlash());
            StopCoroutine(Slash());
    
            diveAttack = false;
        }
    
        #endregion
    
        #region Stage 1
    
        IEnumerator TripleSlash()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            anim.SetTrigger("Slash");
            SlashAngle();
            yield return new WaitForSeconds(2);
            anim.SetTrigger("Slash 2");
            SlashAngle();
            yield return new WaitForSeconds(2);
            anim.SetTrigger("Slash 3");
            SlashAngle();
            yield return new WaitForSeconds(2);
    
            ResetAllAttacks();
    
        }
    
        void SlashAngle()
        {
            if (PlayerController.Instance.transform.position.x > transform.position.x ||
                PlayerController.Instance.transform.position.x < transform.position.x)
            {
                Instantiate(slashEffect, SideAttackTransform);
            }
            else if (PlayerController.Instance.transform.position.y > transform.position.y)
            {
                SlashEffectAtAngle(slashEffect, 80, UpAttackTransform);
            }
            else if (PlayerController.Instance.transform.position.y < transform.position.y)
            {
                SlashEffectAtAngle(slashEffect, -90, DownAttackTransform);
            }
    
        }
    
        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(1);
            damagePlayer = false;
            anim.SetBool("Lunge", false);
    
            ResetAllAttacks();
        }
    
        IEnumerator Parry()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            anim.SetBool("Parry", true);
            yield return new WaitForSeconds(0.8f);
            anim.SetBool("Parry", false);
            parrying = false;
            ResetAllAttacks();
        }
    
        IEnumerator Slash()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            anim.SetTrigger("Slash");
            SlashAngle();
            yield return new WaitForSeconds(2);
    
            ResetAllAttacks();
        }
    
        #endregion
    
        #region Stage 2
    
        void DiveAttackJump()
        {
            attacking = true;
            moveToPosition = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y + 10);
            diveAttack = true;
            anim.SetBool("Jump", true);
        }
    
        public void Dive()
        {
            anim.SetBool("Dive", true);
            anim.SetBool("Jump", false);
    
        }
    
        public void DivingPillars()
        {
            Vector2 _impactPoint = groundCheckPoint.position;
    
            float _spawnDistance = 5;
    
            for(int i = 0; 1 < 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;
            }
            ResetAllAttacks();
        }
    
        private void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.GetComponent<PlayerController>() != null && diveAttack)
            {
                _other.GetComponent<PlayerController>().TakeDamage(damage * 2);
                PlayerController.Instance.pState.recoilingx = true;
            }
        }
    
        #endregion
    
        public override void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitForce)
        {
            if (!parrying)
            {
                base.EnemyHit(_damageDone, _hitDirection, _hitForce);
    
                if(currentEnemyState != EnemyStates.woodenBot_stage4)// parry isnt used in final form for a frantic ending
                {
                    ResetAllAttacks();
                    StartCoroutine(Parry());
    
                }
    
            }
            else
            {
                StopCoroutine(Parry());
                ResetAllAttacks();
                parrying = false;
                //parry attack
                StartCoroutine(Slash());
    
            }
    
        }
    }</code>

    Code for the pillar:

    <code>public class DivingPillar : MonoBehaviour
    {
        // Start is called before the first frame update
       void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.CompareTag("Player"))
            {
                _other.GetComponent<PlayerController>().TakeDamage(WoodenBot.Instance.damage);
            }
    
        }
    }</code>
    #15949
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    1
    ::

    So ive done some debugging and realised that the game only crashes when the Diving collider isnt selected in the inspector? so the diving collider is somehow causing the crash. However without the diving collidrer, the pillars dont spawn in

    has upvoted this post.
    #15951
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Hi Niyam, it’s very likely that you are trying to spawn unlimited Diving Pillars because the code is cycling between OnStateUpdate() and OnStateExit(). Even though OnStateUpdate() is only coded to execute the diving pillars once, if your animator for the boss is leaving the state and re-entering, it will cause the callOnce variable to switch back to false, which causes Diving Pillars to execute once again.

    You may want to check your Animator to see if the boss’s animations are bouncing between 2 states.

    In the meantime, you can update the Diving Pillars to track the number of pillars on the screen and prevent diving pillars from spawning if there are too many.

    public class DivingPillar : MonoBehaviour
    {
    
        public static int count = 0;
        // To track how many pillars exist.
        void Start() { count++; }
        void OnDestroy() { count--; }
    
        // Start is called before the first frame update
        void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.CompareTag("Player"))
            {
                _other.GetComponent<PlayerController>().TakeDamage(WoodenBot.Instance.damage);
            }
    
        }
    }

    And then in OnStateUpdate(), don’t call DivingPillars() if there are already too many:

        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            WoodenBot.Instance.divingCollider.SetActive(true);
    
            if (WoodenBot.Instance.Grounded())
            {
                WoodenBot.Instance.divingCollider.SetActive(false);
    
                if (!callOnce && DivingPillars.count < 10)
                {
                    WoodenBot.Instance.DivingPillars();
                    animator.SetBool("Dive", false);
                    WoodenBot.Instance.ResetAllAttacks();
                    callOnce = true;
                }
    
            }
        }

    Hope this makes sense!

    The boss scripts are too messy. I’m hoping to simplify it in a future stream.

    #15953
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    Thanks for your help -the engine no longer freezes but the pillars wont spawn? ive narrowed down the problem area to the WoodenBotDive script

    From the debug logs in place, “callOnce is true” doesnt play however, “callOnce is false” does play about 2 seconds after my boss lands on the ground

    The main error is the ‘if (!callOnce && DivingPillar.count > 10)’, more specifically the ‘DivingPillar.count > 10)’ part as this is the reason it doesnt work – removing it crashes the game, changing the > to a < crashes the game so idk what to do??

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class WoodenBotDive : 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>();
        }
    
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            WoodenBot.Instance.divingCollider.SetActive(true);
    
            if (WoodenBot.Instance.Grounded())
            {
                WoodenBot.Instance.divingCollider.SetActive(false);
    
                if (!callOnce && DivingPillar.count > 10)
                {
                    Debug.Log("callOnce is true");
                    WoodenBot.Instance.DivingPillars();
                    animator.SetBool("Dive", false);
                    WoodenBot.Instance.ResetAllAttacks();
                    callOnce = true;
                }
    
            }
        }
    
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            callOnce = false;
            Debug.Log("CallOnce is false");
        }
    
    }</code>
    #15954
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    Sorry, I got the code wrong. It should be DivingPillar.Count < 10, not DivingPillarCount > 10.

    I’ve corrected my post above.

    #15956
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    Unfortunately that still causes unity to freeze???

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

    Let’s look into this and see whether DivingPillars() is the line that causes the freeze. Comment it out from your code and try again:

                if (!callOnce && DivingPillar.count > 10)
                {
                    Debug.Log("callOnce is true");
                    //WoodenBot.Instance.DivingPillars();
                    animator.SetBool("Dive", false);
                    WoodenBot.Instance.ResetAllAttacks();
                    callOnce = true;
                }

    Does it still crash?

    #15962
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    Nope my game doesn’t crash when this happens

    Must be a fault of the “diving pillars” function but from what I’ve seen it’s word for word with ur code?

    #15963
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    Also there’s a weird yellow error that says ResetAllAttacks() was unreachable code so I moved it above??? Just in this diving pillars function?

    <code>public void DivingPillars()
        {
            Vector2 _impactPoint = groundCheckPoint.position;
    
            float _spawnDistance = 5;
    
    ResetAllAttacks();
    
            for(int i = 0; 1 < 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;
            }
    
        }</code>
    #15964
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::

    I found the issue. Your DivingPillars() is the problem:

            for(int i = 0; 1i < 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;
            }

    It shouldn’t be 1 < 10. It should be i < 10. 1 < 10 will always be true, hence the crashing and the unreachable code.

    #15965
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    ah yes silly me – it works now

    for the pillars are u able to give an explanation of how to change the scale of the pillar with the animation as the video went through this really quickly and i didnt understand it fully?? this is just so my box collider aligns with the pillar size

    #15966
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    never mind – works completely fine

    I have a question though – this doesnt effect anyhting with the boss but the entire time ive been gettin an error saying “Animation event has no function name specified”

    idk what that means but my boss does work perfectly fine and all animation events are set correctly?? will this be a problem later on or nah

    #15967
    Terence
    Level 31
    Keymaster
    Helpful?
    Up
    0
    ::
    I have a question though – this doesnt effect anyhting with the boss but the entire time ive been gettin an error saying “Animation event has no function name specified”
    This just means that you have some Animation Events in your Animations without a function assigned. Check all your Animation Events and remove all of them without a function assigned, since they don’t do anything.
    #15968
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    Ah ok yeah I think I spammed the button when I didn’t know how it worked lol

    Thanks for the help!

    I have a 2 small unrelated issues – I moved my unity project to my new computer and everythin was fine except for 2 things-

    the bat enemy now moves extremely slowly despite the speed (it needs to go in a fixed update function but idk how to do that since it comes up with errors?

    and the camera is very jittery when following the player? I’ve tried changing follow speed and everything but nothing changes?? My camera is identical to the final camera in the videos- just wondering why?

    I heard ur thinking of ideas for part11 and beyond so I got some ideas:

    Simple cutscenes More enemy types (ai with enemies similar to the boss ai) A combat system with combos and such(I’ve already made this myself but it’ll be cool to show) And maybe some deeper polish updates such smoother movement and time manipulation to make attacks feel powerful

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

    What are the errors on the bat?

    For the jittery camera, let me know if this article helps: https://blog.terresquall.com/2021/12/fix-jittery-camera-movement-in-unity-with-rigidbody-interpolate/

    We are going to be doing a Save system for Part 11, but thanks for the ideas! Will keep it in mind for future parts.

    #15975
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    forget what i said about the bat i just fixed it.

    i have some questions about the boss:

    so this boss is fairly early on in my game so my player doesnt have the double jump unlocked, the boss is also quite a bit larger than the player so when dashing, im wondering if you can decrease the size of the box collider so my player can jump over it? ive tried changing it wiht key frames in the animator but since the box collider is on the boss handler and not the animate boss its not possible?? any way to do that?

    Also wondering if i can increase frequency of attacks since i am able to walkk upto my boss and wait there for a 5-8 seconds before it attacks me?

    #15976
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    i also have an odd issue:

    i watched your 10.5 bug fixing update but the dive is a bit bugged? when my player is nearby, the boss will be raised a tiny bit off the ground and loop only the first half of the diving animation. When hit in this state, the boss will perform parry and riposte animations but will then return to looping the diving anim. ive chcked the inspaector and the diving animation doesnt loop and idk whats wrong? ive even tried reverting my code to before i fixed it and it still stays like this

    this only happens when im really close to the boss

    diving script:

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class WoodenBotDive : 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>();
        }
    
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            WoodenBot.Instance.divingCollider.SetActive(true);
    
            if (WoodenBot.Instance.Grounded())
            {
                WoodenBot.Instance.divingCollider.SetActive(false);
    
                if (!callOnce && DivingPillar.count < 10)
                {
                    Debug.Log("callOnce is true");
                    WoodenBot.Instance.DivingPillars();
                    animator.SetBool("Dive", false);
                    WoodenBot.Instance.ResetAllAttacks();
                    callOnce = true;
                }
    
            }
        }
    
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            callOnce = false;
            Debug.Log("CallOnce is false");
        }
    
    }</code>

    idle script:

    <code>using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class WoodenBotIdle : 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)
        {
            rb.velocity = Vector2.zero;
            RunToPlayer(animator);
    
            if(WoodenBot.Instance.attackCountdown <= 0)
            {
                WoodenBot.Instance.AttackHandler();
                WoodenBot.Instance.attackCountdown = Random.Range(WoodenBot.Instance.attackTimer - 1, WoodenBot.Instance.attackTimer + 1);
            }
    
            if (!WoodenBot.Instance.Grounded())
            {
    
                rb.velocity = new Vector2(rb.velocity.x, -25);
            }
    
        }
    
        void RunToPlayer(Animator animator)
        {
            if(Vector2.Distance(PlayerController.Instance.transform.position, rb.position) > WoodenBot.Instance.attackRange)
            {
                animator.SetBool("Run", true);
            }
            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)
        {
    
        }
    
    }</code>

    diving functions from wooden bot script:

    <code>
        void DiveAttackJump()
        {
            attacking = true;
            moveToPosition = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y + 10);
            diveAttack = true;
            anim.SetBool("Jump", true);
        }
    
        public void Dive()
        {
            anim.SetBool("Dive", true);
            anim.SetBool("Jump", false);
    
        }
    
        public void DivingPillars()
        {
            Vector2 _impactPoint = groundCheckPoint.position;
    
            float _spawnDistance = 5;
    
            for (int i = 0; i < 10; i++)
            {
                Vector2 _pillarSpawnPointRight = _impactPoint + new Vector2(_spawnDistance, -0.25f);
                Vector2 _pillarSpawnPointLeft = _impactPoint - new Vector2(_spawnDistance, -0.25f);
    
                Instantiate(pillar, _pillarSpawnPointRight, Quaternion.Euler(0, 0, 0));
                Instantiate(pillar, _pillarSpawnPointLeft, Quaternion.Euler(0, 0, 0));
                Debug.Log("pillars spawned");
    
                _spawnDistance += 7;
    
            }
    
            ResetAllAttacks();
        }</code>

    sorry abt all the questions- its my first game and all

    #15977
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::

    side note – just had a look at the link for fixing my camera:

    extrapolate makes my movement feel really good but doesnt fix the camera jitter

    interpolate makes my camera very very jittery and also makes my character move increadibly slow? it feels like all values for my characters movememnts have been divided by 1000? gravity, walkspeed, jumpforce, everything is slower

    #15988
    Joseph Tang
    Level 13
    Moderator
    Helpful?
    Up
    0
    ::

    Sorry, but can we get a video of the Dive attack error? I can’t quite picture what the issue is exactly.

    In the case that it’s completing the dive attack, and then going for another dive attack infinitely, Then this might be an issue with your AttackHandler.

    If it’s that your Boss is stuck in the Dive animation, Does it ever complete the dive? Or can it perform otehr actions like moving horizontally too?

    Could you also show your Boss script, just in case?


    Here’s a suggestion for the Dashing through the Boss.

    You could try the Changing of Layers for the Player only during dash, like in Part 6.5 with the Bat.

    [Part 6 Bug Fixes] Infinite Recoil Bat, Spikes Freeze Game, Optimized Bat Corpse

    Essentially, you will want to change your Player’s Layer to something that cant touch the boss yet can still collide with terrain, while you are dashing. Then turn it back to normal once you get out of dashing.


    As for the Camera, you could you take a look at your Camera’s settings once more, perhaps it was not set correctly during the transition?

    You can cross-reference with the video at this point:

    #15990
    Niyam Shah
    Level 8
    Participant
    Helpful?
    Up
    0
    ::
    View post on imgur.com

    this is a link and shows the error, my camera jitter and the inspector settings for my camera

    i checked my inspector and the camera seems to be set right??

    ive also noticed, while testing, my barrage will sometimes just not activate and ill be stuck on the bendown animation, however if attacked, my boss will reset its attack and resume as normal unlike getting stuck in the dive

    code for my boss::

    <code>ng System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class WoodenBot : Enemy
    {
    
        public static WoodenBot Instance;
    
        [Header("Ground Check Settings")]
        [SerializeField] private Transform groundCheckPoint;
        [SerializeField] private float groundCheckY = 0.2f;
        [SerializeField] private float groundCheckX = 0.5f;
        [SerializeField] private LayerMask whatIsGround;
    
        [SerializeField] private Transform wallCheckPoint;
    
        int hitCounter;
        bool stunned, canStun;
        bool alive;
    
        [HideInInspector] public bool facingRight;
        [HideInInspector] public float runSpeed;
        [HideInInspector] public bool damagePlayer = false;
        [HideInInspector] public bool parrying;
    
        [HideInInspector] public Vector2 moveToPosition;
    
        [Space(5)]
    
        [Header("attack settings")]
        [SerializeField] public Transform SideAttackTransform, UpAttackTransform, DownAttackTransform;
        [SerializeField] public Vector2 SideAttackArea, UpAttackArea, DownAttackArea;
        [SerializeField] public GameObject slashEffect;
    
        public float attackRange;
        public float attackTimer;
    
        [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;
    
        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;
            }
        }
    
        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);
    
        }
    
        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
    
        }
    
        // Start is called before the first frame update
        protected override void Start()
        {
            base.Start();
            sr = GetComponentInChildren<SpriteRenderer>();
            anim = GetComponentInChildren<Animator>();
    
            ChangeState(EnemyStates.woodenBot_stage1);
            alive = true;
        }
    
        // 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.velocity = Vector2.zero;
            }
    
        }
    
        public void Flip()
        {
            if (PlayerController.Instance.transform.position.x < transform.position.x && transform.localScale.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.woodenBot_stage1:
                        attackTimer = 6;
                        canStun = true;
                        runSpeed = speed;
                        break;
    
                    case EnemyStates.woodenBot_stage2:
                        canStun = true;
                        attackTimer = 3;
                        break;
    
                    case EnemyStates.woodenBot_stage3:
                        canStun = false;
                        attackTimer = 3;
                        break;
    
                    case EnemyStates.woodenBot_stage4:
                        canStun= false;
                        attackTimer = 3;
                        break;
                }
    
            }
        }
    
        protected override void OnCollisionStay2D(Collision2D _other)
        {
    
        }
    
        #region attacking
        #region variables
        [HideInInspector] public bool attacking;
        [HideInInspector] public float attackCountdown;
    
        #endregion
        #endregion
    
        #region AttackHandler
    
        public void AttackHandler()
        {
            if (currentEnemyState == EnemyStates.woodenBot_stage1)
            {
                Debug.Log("Stage 1");
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(TripleSlash());
                }
                else
                {
                    StartCoroutine(Lunge());
                }
            }
    
            if (currentEnemyState == EnemyStates.woodenBot_stage2)
            {
    
                Debug.Log("Stage 2");
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(TripleSlash());
    
                }
                else
                {
                   int _attackChosen = Random.Range(1, 4);
                    if(_attackChosen == 1)
                    {
    
                        BarrageBendDown();
                        Debug.Log("barrage chosen");
                    }
                    if (_attackChosen == 2)
                    {
                        DiveAttackJump();
                        Debug.Log("dive chosen");
                    }
                    if (_attackChosen == 3)
                    {
                        StartCoroutine(Lunge());
                        Debug.Log("lunge chosen");
                    }
                }
            }
    
            if (currentEnemyState == EnemyStates.woodenBot_stage3)
            {
                Debug.Log("Stage 3");
                int _attackChosen = Random.Range(1, 5);
                if (_attackChosen == 1)
                {
                    OutBreakBendDown();
                }
                if (_attackChosen == 2)
                {
                    DiveAttackJump();
                }
                if (_attackChosen == 3)
                {
                    BarrageBendDown();
                }
                if (_attackChosen == 4)
                {
                    BounceAttack();
                }
    
            }
    
            if (currentEnemyState == EnemyStates.woodenBot_stage4)
            {
    
                Debug.Log("Stage 4");
                if (Vector2.Distance(PlayerController.Instance.transform.position, rb.position) <= attackRange)
                {
                    StartCoroutine(Slash());
                }
                else
                {
                    BounceAttack();
                }
            }
        }
    
        public void ResetAllAttacks()
        {
            attacking = false;
            StopCoroutine(Lunge());
            StopCoroutine(Parry());
            StopCoroutine(TripleSlash());
            StopCoroutine(Slash());
    
            diveAttack = false;
            barrageAttack = false;
            outbreakAttack = false;
            bounceAttack = false;
        }
    
        #endregion
    
        #region Stage 1
    
        IEnumerator TripleSlash()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            anim.SetTrigger("Slash");
            SlashAngle();
            yield return new WaitForSeconds(2);
            anim.SetTrigger("Slash 2");
            SlashAngle();
            yield return new WaitForSeconds(2);
            anim.SetTrigger("Slash 3");
            SlashAngle();
            yield return new WaitForSeconds(2);
    
            ResetAllAttacks();
    
        }
    
        void SlashAngle()
        {
            if (PlayerController.Instance.transform.position.x > transform.position.x ||
                PlayerController.Instance.transform.position.x < transform.position.x)
            {
                Instantiate(slashEffect, SideAttackTransform);
            }
            else if (PlayerController.Instance.transform.position.y > transform.position.y)
            {
                SlashEffectAtAngle(slashEffect, 80, UpAttackTransform);
            }
            else if (PlayerController.Instance.transform.position.y < transform.position.y)
            {
                SlashEffectAtAngle(slashEffect, -90, DownAttackTransform);
            }
    
        }
    
        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(1);
            damagePlayer = false;
            anim.SetBool("Lunge", false);
    
            ResetAllAttacks();
        }
    
        IEnumerator Parry()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            anim.SetBool("Parry", true);
            yield return new WaitForSeconds(0.8f);
            anim.SetBool("Parry", false);
            parrying = false;
            ResetAllAttacks();
        }
    
        IEnumerator Slash()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            anim.SetTrigger("Slash");
            SlashAngle();
            yield return new WaitForSeconds(2);
    
            ResetAllAttacks();
        }
    
        #endregion
    
        #region Stage 2
    
        void DiveAttackJump()
        {
            attacking = true;
            moveToPosition = new Vector2(PlayerController.Instance.transform.position.x, rb.position.y + 10);
            diveAttack = true;
            anim.SetBool("Jump", true);
        }
    
        public void Dive()
        {
            anim.SetBool("Dive", true);
            anim.SetBool("Jump", false);
    
        }
    
        public void DivingPillars()
        {
            Vector2 _impactPoint = groundCheckPoint.position;
    
            float _spawnDistance = 5;
    
            for (int i = 0; i < 10; i++)
            {
                Vector2 _pillarSpawnPointRight = _impactPoint + new Vector2(_spawnDistance, -0.25f);
                Vector2 _pillarSpawnPointLeft = _impactPoint - new Vector2(_spawnDistance, -0.25f);
    
                Instantiate(pillar, _pillarSpawnPointRight, Quaternion.Euler(0, 0, 0));
                Instantiate(pillar, _pillarSpawnPointLeft, Quaternion.Euler(0, 0, 0));
                Debug.Log("pillars spawned");
    
                _spawnDistance += 7;
    
            }
    
            ResetAllAttacks();
        }
    
        void BarrageBendDown()
        {
            attacking = true;
            rb.velocity = Vector2.zero;
            barrageAttack = true;
            anim.SetTrigger("BendDown");
    
        }
    
        public IEnumerator Barrage()
        {
            rb.velocity = Vector2.zero;
    
            float _currentAngle = 30f;
    
            for (int i = 0; i < 10; i++)
            {
                GameObject _projectile = Instantiate(barrageFireball, DownAttackTransform.position, Quaternion.Euler(0, 0, _currentAngle));
    
                if (facingRight)
                {
                    _projectile.transform.eulerAngles = new Vector3(_projectile.transform.eulerAngles.x, 0, _currentAngle + 45);
                }
                else
                {
                    _projectile.transform.eulerAngles = new Vector3(_projectile.transform.eulerAngles.x, 180, _currentAngle + 45);
                }
    
                _currentAngle = 5f;
    
                yield return new WaitForSeconds(0.4f);
            }
            yield return new WaitForSeconds(0.1f);
            anim.SetBool("Barrage", false);    
            ResetAllAttacks();
        }
    
        private void OnTriggerEnter2D(Collider2D _other)
        {
            if (_other.GetComponent<PlayerController>() != null && (diveAttack || bounceAttack))
            {
                _other.GetComponent<PlayerController>().TakeDamage(damage * 2);
                PlayerController.Instance.pState.recoilingx = true;
            }
        }</code>
Viewing 20 posts - 1 through 20 (of 46 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: