Search Unity

Question Problems with detecting change in variable permanantly after colliding with object (2D platformer)

Discussion in '2D' started by Death052, Feb 11, 2023.

  1. Death052

    Death052

    Joined:
    Aug 25, 2021
    Posts:
    3
    Hello, I only started learning Unity a month ago, and I am stuck in this code I've been thinking for hours.
    This is a basic (probably inefficient) sript that controls the player's health. There is a health_bar_shake variable that should be set to true after the player is hit by some spikes, so that the health_bar will shake after touching the spikes. However I realized in this code, the health_bar_shake is only made true when the player is colliding with the spike, but immediately set to false once they are not colliding. I need to make the code so that its health_bar_shake is made true even after they stopped colliding.

    This is my script for the player's health, along with the health_bar_shake variable
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3.  
    4. public class Player_health : MonoBehaviour
    5. {
    6.     public int health;
    7.     private bool response;
    8.     public float response_time;
    9.     //Importing Scripts
    10.     public GameObject Spike;
    11.     public bool health_bar_shake;
    12.     public float shake_time;
    13.     // Start is called before the first frame update
    14.     void Start()
    15.     {
    16.  
    17.         health = 4;
    18.         response = true;
    19.         response_time = 2f;
    20.         shake_time = 0.5f;
    21.         health_bar_shake = false;
    22.     }
    23.     private void Update()
    24.     {
    25.         if (response == false)
    26.         {
    27.             Reload_Time();
    28.         }
    29.        
    30.  
    31.         if (health_bar_shake == true)
    32.         {
    33.             Shake_Time();
    34.         }
    35.  
    36.     }
    37.    
    38.  
    39.  
    40.     private void OnTriggerStay2D(Collider2D collision)
    41.     {
    42.         if (collision.gameObject.tag == "Dmg_Object")
    43.         {
    44.             if (response == true)
    45.             {
    46.                 Health_Decrease();
    47.                 health_bar_shake = true;
    48.             }
    49.         }
    50.     }
    51.  
    52.     private void Reload_Time()
    53.     {
    54.         if (response_time > 0)
    55.         {
    56.             response_time = response_time - Time.deltaTime;
    57.         }
    58.         if (response_time < 0)
    59.         {
    60.             response = true;
    61.             response_time = 2;
    62.         }
    63.     }
    64.  
    65.     private void Shake_Time()
    66.     {
    67.         if (shake_time > 0)
    68.         {
    69.             health_bar_shake = true;
    70.             shake_time = shake_time - Time.deltaTime;
    71.         }
    72.         if (shake_time < 0)
    73.         {
    74.             health_bar_shake = false;
    75.             shake_time = 0.5f;
    76.         }
    77.     }
    78.     private void Health_Decrease()
    79.     {
    80.         health = health - 1;
    81.         response = false;
    82.     }
    83.  
    84. }
    85.  
    It will be very appericiated even someone can help. I also heard about event systems which can help solve the issue, but I am not sure how it works. Any solution is appreciated though.

    Just for reference, I have another script controlling the health bar. Not sure if its useful information, but I will paste it in anyways.

    Script for health bar:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Helath_bar : MonoBehaviour
    6. {
    7.     public GameObject Player_Health;
    8.     private Player_health player_health_script;
    9.     public Animator ani;
    10.     public Rigidbody2D rb2D;
    11.     private Vector2 original_pos;
    12.     private int[] coods_loop;
    13.     public float startTime;
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         ani = GetComponent<Animator>();
    18.         player_health_script = Player_Health.GetComponent<Player_health>();
    19.         rb2D = gameObject.GetComponent<Rigidbody2D>();
    20.         original_pos = rb2D.position;
    21.         startTime = 1f;
    22.         coods_loop = new int[] {2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -4};
    23.     }
    24.  
    25.     // Update is called once per frame
    26.     void Update()
    27.     {
    28.         if (player_health_script.health == 3)
    29.         {
    30.             ani.SetInteger("Health", 3);
    31.         }else if (player_health_script.health == 2)
    32.         {
    33.             ani.SetInteger("Health", 2);
    34.         }else if (player_health_script.health == 1)
    35.         {
    36.             ani.SetInteger("Health", 1);
    37.         }
    38.     }
    39.     void FixedUpdate()
    40.     {
    41.  
    42.        
    43.         if (player_health_script.health_bar_shake == true)
    44.         {
    45.             for(int i = 0; i< coods_loop.Length; i++)
    46.             {
    47.                 if(startTime > 0)
    48.                 {
    49.                     startTime = startTime - Time.deltaTime;
    50.                     Debug.Log(startTime = startTime - Time.deltaTime);
    51.  
    52.                 }
    53.                 if(startTime < 0)
    54.                 {
    55.                     rb2D.MovePosition(new Vector2((original_pos.x + coods_loop[i]), original_pos.y));
    56.                     Debug.Log(coods_loop[i]);
    57.                     startTime = 0.1f;
    58.                 }
    59.              
    60.             }
    61.          
    62.         }
    63.         if(player_health_script.health_bar_shake == false)
    64.         {
    65.             rb2D.position= original_pos;
    66.         }
    67.     }
    68. }
    69.  
     
  2. flasker

    flasker

    Joined:
    Aug 5, 2022
    Posts:
    193
    its prob the shake time that is setting it to false

    you should increase the shake time by a lot and see what happen
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    You have a LOT of extra complexity (flags and whatnot) in there for shaking that you really don't need.

    For instance you really only need one
    float
    variable for a shaking effect.

    When you want to shake, set it equal to the duration of the shake you want.

    Now every frame, if that variable is nonzero, shake, otherwise zero out your shake offset.

    Code (csharp):
    1. private float shakeTime;
    2.  
    3. void Update()
    4. {
    5.   if (shakeTime > 0)
    6.   {
    7.     shakeTime -= Time.deltaTime;
    8.     shakeOffsetTransform.localPosition = ... (whatever you choose for your random shake offset)
    9.   }
    10.   else
    11.   {
    12.     // stabilize
    13.     shakeOffsetTransform.localPosition = Vector3.zero;
    14.   }
    15. }
    To shake it, simply set shakeTime to how long you want to shake.

    Once you have an ULTRA simple setup like the above, stop and commit it to source control.

    Now decide if you want more complexity, such as a shake intensity control, or use an AnimationCurve to control how intense the shaking is over the duration.

    If you build it up in nice simple layers you can have success at each stage.
     
  4. Death052

    Death052

    Joined:
    Aug 25, 2021
    Posts:
    3


    Sorry, may I ask what you mean by shakeOffsetTransform.localPosition? Since the script is for the object itself, so i simply did transform.localPosition. However, if I do transform.localPosition = some Vector2, it will only move to that position, and revert back to its original position once the shakeTime < 0. I need it to move from one position to another position continuously when shakeTime is > 0, for which both positions aren't the original position, how can I do that?
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    The easiest simplest method is to parent empty GameObjects together.

    One example:

    BaseCameraRigGameObject <--- move this around your level
    CameraShakeOffset <--- move this .localPosition slightly to shake
    TheActualCamera


    Give your camera controller a reference to the root to move the camera around.

    Give your shake controller a reference to the shake offset and only set the .localPosition (See my script above)

    That way you can move it around anywhere you want, and shake it anywhere and anytime you want. You can even shake it while it is moving.

    Also, before you go too much further into fiddling with cameras, know that camera stuff is pretty tricky... you may wish to consider using Cinemachine from the Unity Package Manager.

    There's even a dedicated forum: https://forum.unity.com/forums/cinemachine.136/
     
  6. Death052

    Death052

    Joined:
    Aug 25, 2021
    Posts:
    3
    Ah I see, but if I am to use your method, wouldn't it shake the whole screen instead of just the specific health bar object? I don't intend everything to shake, just the healthbar.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    Ooop, you're right! I was thinking you were moving the camera.

    Well, same structure still applies to your health bars actually: have a sub-object you wiggle, not the top-level object.