Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Prefab: assigned values disappear[solved]

Discussion in 'Scripting' started by benvanj, Jul 31, 2018.

  1. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    (I posted this in another forum but I think it belongs here:)

    I hope this is the place to ask help for my current issue:Mods, if not please move...

    I have written a script that I have attached to my enemies that cause them to fire bullets every couple of seconds...
    in this script the bullets that the enemies use in connected to a pooler system...
    I created a public objectpooler script where my enemy-bullets are assigned to...

    my problem is:

    When I assign the Enemy Bullet Object Pooler to the Enemy, as soon as I create a prefab from it, the assigned value dissappears... I tried creating a new prefab, I've tried applying the new settings to the prefab.... everytime, the objectpooler in the prefab resets to nothing....

    any advice?
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Can you post the Object Pooler and the Enemy script. Don't forget Code Tags. :)
     
  3. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    If you have something in your scene and you assign that to a value on your prefab, your prefab doesn't remember this value. Unless you assign the value when you instantiate the prefab. Basically, prefabs can't reference stuff in your scene when it's just a prefab (and it doesn't exist in your scene as well)

    Hopefully I explained that well. I'm also only guessing at what may be the issue as I wasn't sure I understood your setup.
     
    benvanj likes this.
  4. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    I don't think that can be done at all. I've just tried it as well and the Editor will not allow it.

    You may be thinking of when you select a raw script and drag a scene object into a slot on the script in the Inspector. But then, in the Inspector, Unity shows "Default references will only be applied in edit mode".
     
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    Oh sorry, maybe I didn't explain it well. If you have an gameobject in the scene with a component that has a reference to another Gameobject in the scene and then you take that first gameobject and make it a prefab, that prefab doesn't reference the object in the scene anymore.

    So thus, when instantiated, it no longer references the other object. For example, an enemy that has a target field that has the player dragged and dropped into it. Then the enemy prefab is created and used to instantiate more enemies, it no longer references the player that was dragged into the field.

    Unless something has changed and I've always been designing with this in mind, so I've never bothered to check it again.

    hmm...hopefully that better explains what I was thinking.
     
    Doug_B and benvanj like this.
  6. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    Hi, Thank you for this information .... but is there no way to recall it automatically in "void start"????

    i've tried "Getcomponent" and also "Find"....to no avail....

    Here is my Enemy Shooter script.....
    The Item = Enemy bullet
    EFirePos = Firing position

    like i've said when I link the ObjPooler it keeps on not assigning after I have made it a prefab....
    Code (CSharp):
    1. public class EShooter : MonoBehaviour
    2. {
    3.     public GameObject TheItem;
    4.     public GameObject EFirePos;
    5.  
    6.     private int IsRunning = 1;
    7.     public float NumberOfSeconds;
    8.  
    9.     public ObjPooler EShotPooler;
    10.        
    11.     // Use this for initialization
    12.     void Start ()
    13.     {
    14.         TheItem = GameObject.Find("EnemyShot");
    15.      
    16.     }
    17.    
    18.     // Update is called once per frame
    19.     void Update ()
    20.     {
    21.         if (IsRunning == 1)
    22.         {
    23.             StartCoroutine(ProcessTask());
    24.         }
    25.     }
    26.    
    27.    
    28.     public IEnumerator ProcessTask()
    29.     {
    30.         IsRunning = 0;
    31.         yield return new WaitForSeconds(NumberOfSeconds);
    32.  
    33.         GameObject newItem = EShotPooler.GetPooledObject();
    34.  
    35.         newItem.transform.position = EFirePos.transform.position;
    36.         newItem.transform.rotation = EFirePos.transform.rotation;
    37.         newItem.SetActive(true);
    38.         //Instantiate(newBullet, FirePos.transform.position, FirePos.transform.rotation);
    39.         IsRunning = 1;
    40.     }
    41. }
    42.  
     
  7. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Yes, 3 possible ways to do it would be :-
    1. Use a Singleton pattern to retrieve the objects from.
    2. Use
      Find
      (like you have already used on line 14).
    3. Use Dependency Injection. So in EShooter, there would be a method
      SetPrefabs(ObjPooler pooler, etc, etc)
      .You could have another in-scene object (e.g. GameController) that, in its
      Awake()
      method, has a reference to (or Finds) the in-scene objects and EShooter and calls SetPrefabs to give the in-scene objects to EShooter.
    This is exactly the point that Brathnann made in post #5 above. Have a re-read of that. :)
     
    benvanj likes this.
  8. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    Thanks Doug...

    1: singletons: I haven't learned anything with singletons yet, I had a look at it and wow... I am going to have to put some time into that one...
    2: I've tried find but am not sure how to code it in reference to an objectpooler....
    i've tried Find
    and all other find formats....but it says I cannot... (maybe I did it wrong...)
    3: I don't have the slightest idea what you are talking about here... I will go read up on it....

    ==> What if I run the script not on the prefab but on the objectspooler that is hidden in the background... I can reference the objectspooler in itself, and maybe just add a check that : if prefab is active in scene, run script...

    not sure how to do that either but I think it will not be too difficult...
     
  9. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Can we just review exactly what you have, so we can be clear on what is happening. As I understand it, these are the pertinent objects under discussion here :-
    1. An Enemy (presumably this is a prefab).
    2. An Enemy Bullet (again, presumably a prefab).
    3. An Enemy Bullet Pooler (presumably in-scene and not a prefab).
    Is that correct or am I missing any other objects?
     
    benvanj likes this.
  10. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    I think the best solution to this is to give whatever's spawning these shooters a reference to the ObjPooler. Then, after it spawns the shooters, it assigns the ObjPooler field on the newly spawned shooters.
     
  11. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    All that you said is correct....
    The Enemy(prefab) has 3 scripts connected:1) EnemyContrroller-controls movement
    -contols animator
    2) Itemdestoyer - sets item inactive when either shot or moves off screen
    3) EShooter - that makes enemy shoots every couple of seconds

    Enemybullet (prefab) has 2 scripts:1) Itemdestroyer...
    2) Mover -creates velocity

    EnemyBulletPooler (in-scene, child of main camera) has 1 script: 1) objPooler to pool the bulets

    What you haven't mentioned.....
    EnemyPooler...(in-scene, child of main camera)... 1) pools enemies
    EnemyGenerator... (in-scene, child of main camera)...GameObject... 1 script... ItemGeneratorscript

    .....................................................................................
     
  12. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116

    How do i do this.... any tutorials?
     
  13. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    So my question is now... can I attach the EShooter script to the EnemyGenerator?? and have the bullets Instantiate (I don't use instantiate, I re-activate the bullet in pool) from there...

    and so... how do i do it?
     
  14. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Ok, so if I understand correctly:

    The EnemyGenerator (in-scene object) has a reference to an Enemy (prefab). It will create instances from this prefab.

    Enemies are requested from the EnemyPooler (in-scene object). It checks an internal cache to see if an exisiting Enemy is available. If so, it returns it. If not, it calls the EnemyGenerator to make a new one and adds that one to its internal cache and returns it to the caller.

    An Enemy (prefab) has a reference to a BulletPooler (in-scene object). When the Enemy wants to fire, it gets a bullet from the BulletPooler.

    The BulletPooler (in-scene object) contains an EnemyBullet (prefab). When a bullet is request, if one is free it returns it. If not, it creates a new bullet from the prefab, stores it internally and returns it to the caller.
    ------

    If the above is correct, in-scene objects referencing in-scene objects can be done in the Editor. Likewise for prefabs referencing prefabs; that can also be done in the Editor.

    The issue is with the Enemy prefab needing a reference to the in-scene BulletPooler. So one solution (remember from previous post, there are other solutions) would be to give the EnemyGenerator (in-scene object) a reference to the BulletPooler (in-scene object). Now, when the EnemyGenerator makes an Enemy, it can give the BulletPooler reference to the Enemy that has just been created.

    Sorry that's a bit verbose, but does it help at all? :)
     
  15. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    That is exactly it... I don't think it is verbose ... it is very clear....

    This I believe is easy, but I will have to try and see if it works...

    How would I do this?
     
  16. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    I don't currently have access to Unity so this code comes with a health warning - it may not compile or work! But hopefully it gives some ideas :-
    Code (CSharp):
    1. public class CEnemy : MonoBehavior
    2. {
    3.     public CBulletPooler BulletCache { set; private get; }
    4.     ... other code here ...
    5. }
    6.  
    7. public class CEnemyGenerator : MonoBehavior
    8. {
    9.     public CEnemy CreateAnEnemy( )
    10.     {
    11.         CEnemy newEnemy = Instantiate(enemyPrefab);
    12.         newEnemy.BulletCache = bulletCache;
    13.         return newEnemy;
    14.     }
    15.  
    16.     [SerializeField] CEnemy enemyPrefab;
    17.     [SerializeField] CBulletPooler bulletCache;
    18. }
     
  17. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    thanks,,, let me see what I can do...
     
  18. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    HELL YEA.....Got it working....
    Doing this game is giving me grey hairs...

    So I created a new script....Enemygenerator, which is exactly the same as the Itemgenerator script but I added a bullet spooling and generation script in....


    Thanks guys
     
  19. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    spoke too soon... giving me another error...
     
  20. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    Post...the error?
     
  21. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    I've played around so much its not giving me an error anymore but it is not working....

    Background:
    Enemygenerator... has a script that creates enemies and also creates bullets firing from the enemy

    it creates the bullets but doesn't know where to fire it from as the ENEMY FIRE POSITION, is connected to the prefab:enemy...

    Now I'm trying to GetComponent(EFirePos) from the enemy,linked to the EnemyGenerator...

    Code (CSharp):
    1. EFirePos = TheItem.GetComponentInChildren<Transform>();
    doesn't seem to work....(TheItem = the object created, in this case the enemy)...
     
  22. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    how do I specify the name of the child to "GetComponent" from...
     
  23. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    You can use transform.Find to find a child by name.
     
  24. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    Solution.... I went back to the original setup... which is:
    creating a prefab with a shooting script attached to the prefab...

    The problem was that it did'nt find the spooler....

    So I attached the spooler straight to the prefab....

    So everytime the prefab is created and instantiated...the pooler is instantiated as a child of the Enemy, and it picks it up ...

    Thanks guys!!!!!!
     
  25. faisalgamesenvision

    faisalgamesenvision

    Joined:
    Sep 20, 2022
    Posts:
    2
    Here is the Solution that works in my case:
    Problem:
    The "Garage Manger" that has script and have reference to UI Objects of "Garage Canvas". When I Make "Garage Manager" a Prefab It miss reference to Garage Canvas.
    Solution:
    I made "Garage Manger" to child of "Garage Canvas" and then make prefab of "Garage Canvas". When i drop this prefab to another scene the game object that has script and has reference to "Garage Canvas" intact it.