Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Accessing scripts from an instantiated object.

Discussion in '2D' started by Dmumzo, Dec 18, 2019.

  1. Dmumzo

    Dmumzo

    Joined:
    Nov 28, 2019
    Posts:
    16
    Hello,
    I instantiate an apple object from an apple_prefab this way:

    apple=Instantiate(apple_prefab, new Vector 3......etc);

    Now I want to access a variable is_edible which is located in a script in the apple_prefab, named also "apple", and change it to "true", so I do the following:

    apple.GetComponent<apple>().is_edible=true;

    So far so good.

    What I want to do is to retrieve that script without directly typing "apple" between the < >. Since the instantiated object has the same name as the script, I tried things like:

    string name=apple.name;
    apple.GetComponent(name).is_edible=true;
    But it doesnt work.

    Can you help me, please?
     
  2. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    There's probably a way to do what you want, but I'm not quite sure what you're trying to do.

    Can you explain with a more specific example? Why can't you use the component type, and why is the name of the instantiated object significant?
     
  3. Dmumzo

    Dmumzo

    Joined:
    Nov 28, 2019
    Posts:
    16
    Ok, I will try.
    Imagine a projectile. When that projectile hits a box, that box loses damage equal to a damage value "damage_value" stored in a script in the object "projectile".
    The script of the projectile looks like:
    Code (csharp):
    1.  
    2.  public float damage_value= 2f;
    3.  
    4.     void OnCollisionEnter2D(Collision2D collision)
    5.     {
    6.         if (collision.gameObject.layer == LayerMask.NameToLayer("boxes"))
    7.         {          
    8.             collision.gameObject.GetComponent<Chest>().damage_taken = damage_value;
    9.         }
    10.     }
    11.  
    So basically when the projectile hits an object in the layer "boxes", it tells the hit object to change its value "damage_taken" to "damage_value". In the case above, I used the word "Chest" because I know that the object being hit in the scene is a chest (which is in the layer of boxes), which has a script component named "Chest". But instead of a specific word, I would like the code to automatically find the script component associated with the hit object.
     
  4. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    I see. So you have many different objects, all of which can take damage, so you don't want to specifically use "Chest", because it could be some other type.

    There are two straightforward approaches I would recommend to make this more generic.

    The first way
    is creating a component that handles health or damage, and you put that on any objects that are damageable, for example:
    Code (CSharp):
    1. public class DamageHandler : MonoBehaviour
    2. {
    3.     public float health;
    4.  
    5.     public void TakeDamage(float damage)
    6.     {
    7.         health -= damage;
    8.         if (health <= 0)
    9.         {
    10.             health = 0;
    11.             Destroy(gameObject);
    12.         }
    13.     }
    14. }
    Then get that component in the collision:
    Code (CSharp):
    1. DamageHandler damageHandler = collision.gameObject.GetComponent<DamageHandler>();
    2. if (damageHandler != null)
    3. {    
    4.     damageHandler.TakeDamage(damage_value);
    5. }

    The second way is to use an interface, which defines some function signatures. Any class that implements that interface is required to have those functions:
    Code (CSharp):
    1. public interface IDamageable
    2. {
    3.     void TakeDamage(float damage);
    4. }
    Then implement that interface on the Chest, or any other class that should be able to take damage, for instance:
    Code (CSharp):
    1. public class Chest : MonoBehaviour, IDamageable
    2. {
    3.     public float health = 1;
    4.  
    5.     public void TakeDamage(float damage)
    6.     {
    7.         health -= damage;
    8.         if (health <= 0)
    9.         {
    10.             health = 0;
    11.             Destroy(gameObject);
    12.         }
    13.     }
    14. }
    Then get the interface in the collision:
    Code (CSharp):
    1. // get a component that implements IDamageable
    2. IDamageable damageHandler = collision.gameObject.GetComponent<IDamageable>();
    3. if (damageHandler != null)
    4. {    
    5.     damageHandler.TakeDamage(damage_value);
    6. }
     
    Last edited: Dec 20, 2019
  5. Dmumzo

    Dmumzo

    Joined:
    Nov 28, 2019
    Posts:
    16
    Thank you!
     
    LiterallyJeff likes this.