Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Weird Bug/Behaviour with AddForce (ForceMode2D.Force) - Happens Twice, Only Debugs Once

Discussion in 'Physics' started by AlexHntk, Nov 19, 2023.

  1. AlexHntk

    AlexHntk

    Joined:
    May 6, 2015
    Posts:
    59
    I'm sure I'm doing something wrong, but I can't seem to track down what is happening or how I might troubleshoot this one.



    I have an explosion script:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ExplodeScript : MonoBehaviour
    6. {
    7.     public bool isStandalone;
    8.     public Vector2 movement;
    9.     public Vector2 moveDirectionPush;
    10.     public float knockback;
    11.     public GameObject thisProp;
    12.  
    13.     public int thisPropHealth;
    14.  
    15.     public float MaxDistance;
    16.  
    17.     public bool Explode;
    18.     public bool hasExploded;
    19.  
    20.     public GameObject fancy;
    21.  
    22.     public int ExpDamage = 200;
    23.  
    24.     public AudioSource sfxSource;
    25.  
    26.     GameObject player;
    27.     float playerDist;
    28.  
    29.  
    30.  
    31.  
    32.     IEnumerator CircleBoom()
    33.     {
    34.         sfxSource.PlayOneShot(SoundManager.Instance.Explosion, SoundManager.Instance.sfxVol);
    35.  
    36.         if (GFXManager.Instance.strobeSens == false)
    37.         { fancy.gameObject.SetActive(true); }
    38.         this.gameObject.GetComponent<CircleCollider2D>().enabled = true;
    39.  
    40.         yield return new WaitForSeconds(0.15f);
    41.         if (GFXManager.Instance.strobeSens == false)
    42.         { fancy.gameObject.SetActive(false); }
    43.         Explode = false;
    44.  
    45.         yield return new WaitWhile(() => sfxSource.isPlaying);
    46.  
    47.    
    48.         hasExploded = true;
    49.  
    50.     }
    51.  
    52.     private void OnEnable()
    53.     {
    54.         if (isStandalone)
    55.         {
    56.             ResetExplosion();
    57.         }
    58.  
    59.     }
    60.  
    61.     void Start()
    62.     {
    63.         hasExploded = false;
    64.         Explode = false;
    65.         this.transform.position = thisProp.transform.position;
    66.         fancy.gameObject.transform.position = thisProp.transform.position;
    67.         if(isStandalone)
    68.         { Explode = true; }
    69.    
    70.    
    71.     }
    72.  
    73. public void ResetExplosion()
    74.     {
    75.         hasExploded = false;
    76.         Explode = false;
    77.         this.enabled=true;
    78.         this.gameObject.GetComponent<CircleCollider2D>().enabled = false;
    79.         if (isStandalone == false)
    80.         { this.transform.parent.gameObject.SetActive(true); }
    81.     }
    82.  
    83.     public void Explosion()
    84.     {
    85.  
    86.             this.transform.position = thisProp.transform.position;
    87.             fancy.gameObject.transform.position = thisProp.transform.position;
    88.             Explode = true;
    89.  
    90.             this.gameObject.GetComponent<CircleCollider2D>().enabled = true;
    91.  
    92.    
    93.         StartCoroutine(CircleBoom());
    94.        
    95.             Vector3 totalDist = PlayerController.Player1.transform.position - transform.position;
    96.             playerDist = totalDist.sqrMagnitude;
    97.  
    98.  
    99.  
    100.         if (isStandalone == false)
    101.         {
    102.             if (playerDist >= 50f)
    103.             {
    104.  
    105.                 CameraShake.camShake.Exp_shakeMagnitude = 0.2f;
    106.                 CameraShake.camShake.TriggerShake();
    107.  
    108.             }
    109.             if (playerDist >= 30f && playerDist <= 49f)
    110.             {
    111.                 CameraShake.camShake.Exp_shakeMagnitude = 0.5f;
    112.                 CameraShake.camShake.TriggerShake();
    113.             }
    114.             if (playerDist <= 20f)
    115.             {
    116.                 CameraShake.camShake.Exp_shakeMagnitude = 0.9f;
    117.                 CameraShake.camShake.TriggerShake();
    118.             }
    119.         }
    120.    
    121.  
    122.  
    123.         return;
    124.  
    125.      
    126.  
    127.     }
    128.  
    129.     void OnTriggerEnter2D(Collider2D collider)
    130.     {
    131.  
    132.    
    133.             if (collider !=null && Explode == true)
    134.             {
    135.  
    136.  
    137.  
    138.                 moveDirectionPush = collider.transform.position - this.transform.position;
    139.  
    140.                 if (collider.gameObject.CompareTag("Player"))
    141.                 {
    142.                 if (isStandalone)
    143.                 {
    144.                     collider.gameObject.GetComponent<PlayerHealth>().DamagePlayer(50);
    145.                 }
    146.                 else
    147.                 {
    148.                     print("Hey");
    149.                     collider.GetComponent<Rigidbody2D>().AddForce(moveDirectionPush * (knockback * 1000), ForceMode2D.Force);
    150.                     collider.gameObject.GetComponent<PlayerHealth>().DamagePlayer(ExpDamage);
    151.                
    152.                 }
    153.                 }
    154.                 if (collider.gameObject.CompareTag("Enemy"))
    155.                 {
    156.                     collider.gameObject.GetComponent<EnemyChild>().DamageEnemy(ExpDamage);
    157.                 collider.gameObject.GetComponent<Rigidbody2D>().AddForce(moveDirectionPush.normalized * knockback * 1000, ForceMode2D.Force);
    158.                 }
    159.                 if (collider.gameObject.CompareTag("small_Enemy"))
    160.                 {
    161.                     collider.gameObject.GetComponent<EnemyChild>().DamageEnemy(ExpDamage);
    162.                 collider.gameObject.GetComponent<Rigidbody2D>().AddForce(moveDirectionPush.normalized * knockback * 1000, ForceMode2D.Force);
    163.                  }
    164.                 if (collider.gameObject.CompareTag("Props"))
    165.                 {
    166.                 collider.gameObject.GetComponent<PropsScript>().DamageProp(ExpDamage);
    167.                 collider.gameObject.GetComponent<PropsScript>().moving = true;
    168.                 collider.gameObject.GetComponent<PropsScript>().propRB.constraints = RigidbodyConstraints2D.FreezeRotation;
    169.                 collider.gameObject.GetComponent<Rigidbody2D>().AddForce(moveDirectionPush.normalized * knockback * 1800, ForceMode2D.Force);
    170.  
    171.                 }
    172.                 if (collider.gameObject.CompareTag("Doors"))
    173.                 {
    174.                     collider.gameObject.GetComponent<DoorScript>().DamageDoor(5000);
    175.                 }
    176.  
    177.  
    178.  
    179.                    if (collider.gameObject.GetComponent<Rigidbody2D>() != null && !collider.CompareTag("Bits"))
    180.                        {
    181.                             collider.gameObject.GetComponent<Rigidbody2D>().AddForce(moveDirectionPush.normalized * knockback * 100, ForceMode2D.Force);
    182.                        }
    183.                    else if (collider.gameObject.GetComponent<Rigidbody2D>() != null && collider.CompareTag("Bits"))
    184.                        {
    185.                             collider.gameObject.GetComponent<Rigidbody2D>().AddForce(moveDirectionPush.normalized * knockback * 500, ForceMode2D.Force);
    186.                        }
    187.  
    188.  
    189.  
    190.        
    191.         }
    192.     }
    193.  
    194.     void Update()
    195.     {
    196.         if(hasExploded == true)
    197.         {
    198.             StopAllCoroutines();
    199.  
    200.             if (isStandalone == false)
    201.             {
    202.                 this.transform.parent.gameObject.SetActive(false);
    203.             }
    204.             else
    205.             {
    206.                 this.gameObject.SetActive(false);
    207.             }
    208.         }
    209.     }
    210.  
    211. }
    212.  
    When the prop is destroyed, I check that the prop isExplosive, and if so, I destroy the prop and trigger the Explosion() function on the Explosion script.

    Everything is working fine, except that the AddForce on the player is happening in a weird way. There is an initial thrust of knockback, but once the player attacks, another small amount of force is being added. I've attached a video which shows that my debug line "Hey" is printing only once per explosion, I'm really unsure what might be causing this behaviour.


    The portion of code involving the Player Attack action:

    Code (CSharp):
    1.  if (ControlsManager.controlMan.controls.Player.Attack.triggered && attackTimer <=0)
    2.                 {
    3.                     if (PlayerCosmetic.playerCos.weapon_itemID == 6)
    4.                     {
    5.                         if (this.GetComponent<PlayerScore>().currentPlayerScore >= 10)
    6.                         {
    7.                             isAttacking = true;
    8.                             this.GetComponent<PlayerScore>().currentPlayerScore -= 10;
    9.                             this.GetComponent<PlayerScore>().UpdatePlayerScore();
    10.                         }
    11.                         else
    12.                         {
    13.                             return;
    14.                         }
    15.                     }
    16.                     else
    17.                     {
    18.                         isAttacking = true;
    19.                     }
    20.                
    21.                 }
    22.  
    23.                 if (isAttacking == true && !Grab_down && attackTimer == 0)
    24.                 {
    25.                     animator.SetFloat("atkSpeed", attackSpeed);
    26.  
    27.  
    28.                     Invoke("PlayerAttack", 0);
    29.                     attackTimer = attackCD;
    30.                 }
    Code (CSharp):
    1.  void PlayerAttack()
    2.     {
    3.  
    4.         if (!animator.GetCurrentAnimatorStateInfo(0).IsName("Player01_attack")) //!animator.getcurrentstate) )
    5.         {
    6.             sfxSource.volume = SoundManager.Instance.sfxVol;
    7.             sfxSource.pitch = Random.Range(0.85f, 1.15f);
    8.             sfxSource.clip = SoundManager.Instance.PlayerMiss;
    9.             sfxSource.PlayOneShot(sfxSource.clip, sfxSource.volume);
    10.  
    11.             isAttacking = true;
    12.             currentSpeed = 0;
    13.  
    14.  
    15.             StartCoroutine(ExecuteAfterTime(attackTime));
    16.             StopCoroutine(ExecuteAfterTime(attackTime));
    17.          
    18.             isCoroutineExecuting = false;
    19.  
    20.        
    21.                 animator.SetTrigger("Attacking");
    22.  
    23.  
    24.  
    25.                 if (head_anim.isActiveAndEnabled)
    26.                 {
    27.                     head_anim.SetFloat("atkSpeed", attackSpeed);
    28.                     head_anim.SetTrigger("Attack");
    29.                  
    30.                 }
    31.                 if (body_anim.isActiveAndEnabled)
    32.                 {
    33.                     body_anim.SetFloat("atkSpeed", attackSpeed);
    34.                     body_anim.SetTrigger("Attack");
    35.                  
    36.                 }
    37.                 if (weapon_anim.isActiveAndEnabled)
    38.                 {
    39.                     weapon_anim.SetFloat("atkSpeed", attackSpeed);
    40.                     weapon_anim.SetTrigger("Attack");
    41.                 }
    42.         }
    43.  
    44.     }
    Code (CSharp):
    1. IEnumerator ExecuteAfterTime(float attackTime)
    2.     {
    3.  
    4.         if (isCoroutineExecuting)
    5.             yield break;
    6.  
    7.         isCoroutineExecuting = true;
    8.  
    9.         yield return new WaitForSeconds(attackDelay);
    10.         this.GetComponentInChildren<AttackTrigger>().spray_anim.SetTrigger("Attack"); //this is new
    11.         AttackPoint.enabled = true;
    12.         currentSpeed = moveSpeed;
    13.    
    14.         isCoroutineExecuting = false;
    15.         yield return new WaitForSeconds(0.05f);
    16.         AttackPoint.enabled = false;
    17.  
    18.  
    19.     }
    20.  

    So far my only guess is related to me changing the player's speed to 0, maybe making it's rigidbody more effected by AddForce.. ? But I just have no idea. This seems to be a new behaviour as well, as this wasn't happening in the past.

    edit: Tried removing the currentSpeed = 0 to try it out, no impact (it changes the initial knockback upon the player by a small amount, possibly? but the second push still occurs)


    Second edit:
    So it seems this is ONLY affecting the player when using mouse&keyboard controls - gamepad is totally unaffected by this second-push thing.


    I'll add a second post once I've gone through anything relevant.
     
    Last edited: Nov 19, 2023
  2. AlexHntk

    AlexHntk

    Joined:
    May 6, 2015
    Posts:
    59
    EDIT:

    Okay, so this IS affecting the player when they use a Gamepad = but only if they are not also "holding down Button to aim".

    This is the explicit problem, near as I can tell:


    Code (CSharp):
    1.  if (ControlsManager.controlMan.Aim_Pressed == false && isAttacking == false)
    2.             {
    3.                 rb.MovePosition(rb.position + movement * currentSpeed * Time.deltaTime);
    4.             }

    I can confirm that the AddForce is being "stored" via the Inspector, after the initial explosion push there is still a strong Velocity vector on the player's Rigidbody2D.

    I've tried setting velocity = new Vector2(0,00) as well as angularVelocity = 0 in the explosion script, but this doesn't seem to do anything. Any ideas on how I can clear the velocity from the Rigidbody?
     
    Last edited: Nov 19, 2023
  3. AlexHntk

    AlexHntk

    Joined:
    May 6, 2015
    Posts:
    59
    Unless / Until someone has a better idea of how I might address this, I've shoved this into my player's update function.

    Works, but feels hacky.


    Code (CSharp):
    1. if (rb.velocity.magnitude >= 100 && playerHealth.beingDamaged==false)
    2.             {
    3.                 rb.velocity = new Vector2(0, 0);
    4.                 rb.angularVelocity = 0;
    5.             }