How to you set a transform variable's target in a prefab?

I've made a prefab for a shell that launches into the air from the launcher, then turns off screen and heads back downwards towards where the player was when it turns. How do I set the player as its target?

2 answers

  • answered 2019-03-13 21:03 derHugo

    As said you can't.

    Prefabs live in the Assets and you simply can't have Scene-references in the assets. (The same problem exists btw for the AnimatorController)

    There are however a lot of ways for getting the references on runtime.


    ScriptableObject

    Use a ScriptableObject for storing the reference and have an according Setter component on the regarding Transform GameObject in the Scene.

    [CreateAssetMenu(fileName = "TransformReference", menuName = "SceneReferences/Transform", order = 1)]
    public class ScriptableTransformReference : ScriptableObject 
    {
        public Transform value; 
    }
    

    In the ProjectView (Assets) do right-mouse-click -> Create -> SceneReferences -> Transform to create a new instance of ScriptableTransformReference.

    And than on your player have this setter

    // By adding ExecuteInEditMode this is already executed 
    // without entering PlayMode
    [ExecuteInEditMode]
    public class TransformReferenceSetter : MonoBehaviour
    {
        // Reference the created ScriptableObject here via the Inspector
        public ScriptableTransformReference TargetScriptableObject;
    
        private void Awake()
        {
            TargetScriptableObject.value = transform;
        }
    }
    

    Than whenever you need that reference in another component simply again make a field

    // Reference this in the Inspector
    public ScriptableTransformReference SourceScriptableObject;
    

    and access it's value .. to be sure in Start so the setters Awake was already executed. This time you can have a reference in the prefab since the ScriptableObject resides in the Assets as well.


    Find

    You can use Find to get an object by name and do e.g.

    var playerTransform = Find("Player").transform;
    

    but I would recommend to not use this .. ever. It is performance intense and if you ever change the GameObject's name it brakes your code. It also only works for finding a GameObject which is active in thw hierarchy the moment it is executed.


    FindObjectOfType

    However, if there is only one player anyway create a dedicated class on the player like

    public class Player : MonoBehaviour {}
    

    it doesn't have to do anything. Now you simply can use FindObjectOfType<Type>() to get its reference which is way more efficient and reliable

    var playerTransform = FindObjectOfType<Player>().transform;
    

    in any other components in the Scene (e.g. after Instantiating the prefab). But again it also only works if the according GameObject and component are active and enabled in the hierarchy the moment this is executed.


    Singleton

    Or (ab)use the Singleton-pattern

    public class Player : MonoBehaviour 
    {
        public static Player Singleton;
    
        private void Awake ()
        {
            Singleton = this;
        }
    }
    

    and use

    var playerTransform = Player.Singleton.transform;
    

    anywhere else.


    Dependency Injection

    You might want to get into Zenject or similar kinds of dependency injection. Though this is a bit more completecated to set it up, once you have it working once it is a very powerfull tool for providing references even across various scenes and context based.

  • answered 2019-03-14 06:12 Vishal K M

    Use Projectile Motion

    This is not a Complete answer, you just work it out by changing stuffs, that will be fun.

    var pos = Vector3.MoveTowards(transform.position, _target.transform.position , _projectileSpeed * Time.deltaTime);
      rigidbody.MovePosition(pos);
    

    try with transform.LookAt(targetXZPos); to make the tip of shell point to target.

    If this code didnt give you required output you should consider Launch Velocity, Launch Angle, Distance to Target and make the projectile formula work out, will be little more tough but will create more originality and will give the player more interesting feel to try angles (if required), launch velocity can be constant based on different shells( which is again a good idea to sell different range shells to players).