teleport to instantiated knife (clone)

Hi!
I am new to programming and I’m making my 1st game. I want to teleport my character to a knife that he threw. Please see the details below:

  1. I tried transform.position = teleknife.transform.position; but this causes him to teleport to the location of the prefab. I learned that it should teleport to the clone. I don’t know how to do this hehe.

  2. The coding is structured this way: The KNIFE is thrown by JARRED which inherits from CONTROL which inherits from CHARACTER. I’m sorry if the code seems confusing. I hope you guys can help! Please see the C# scripts below:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public abstract class Character1 : MonoBehaviour
    {

     [SerializeField]
     protected Transform knifePos;
    
     [SerializeField]
     protected float movementSpeed;
    
     protected bool facingRight;
    
     [SerializeField]
     public GameObject knifePrefab;
    
     [SerializeField]
     protected Stat healthStat;
    
     [SerializeField]
     private EdgeCollider2D swordCollider;
    
     [SerializeField]
     private List<string> damageSources;
    
     public abstract bool IsDead { get; }
    
     public bool Attack { get; set; }
    
     public bool TakingDamage { get; set;}
    
     public Animator MyAnimator { get; private set; }
    
     public EdgeCollider2D SwordCollider
     {
         get
         {
             return swordCollider;
         }
    
         
     }
    
     // Use this for initialization
     public virtual void Start ()
     {
         facingRight = true;
         MyAnimator = GetComponent<Animator>();
         healthStat.Initialize(); //initializes the health bar so that it starts at full life
     }
     
     // Update is called once per frame
     void Update () {
     	
     }
    
     public abstract IEnumerator TakeDamage();
    
     public abstract void Death();
    
     public void ChangeDirection()
     {
         facingRight = !facingRight;
         transform.localScale = new Vector3(transform.localScale.x * -1, transform.localScale.y * 1, 1);
         
     }
    
     public virtual void ThrowKnife (int value)
     {
         Physics2D.IgnoreLayerCollision(10, 11);
         if (facingRight)
         {
             GameObject tmp = (GameObject)Instantiate(knifePrefab, knifePos.position, Quaternion.Euler(new Vector3(0, 0, -90)));
             tmp.GetComponent<Knife>().Initialize(Vector2.right);
         }
         else
         {
             GameObject tmp = (GameObject)Instantiate(knifePrefab, knifePos.position, Quaternion.Euler(new Vector3(0, 0, 90)));
             tmp.GetComponent<Knife>().Initialize(Vector2.left);
    
         }
     }
    
     public virtual void MeleeAttack()
     {
         Physics2D.IgnoreLayerCollision(10, 11);
         SwordCollider.enabled = true;
     }
    
     public virtual void OnTriggerEnter2D(Collider2D other)
     {
         if (damageSources.Contains(other.tag))
         {
             StartCoroutine(TakeDamage());
         }
     }
    

    }

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public delegate void DeadEventHandler();
    public class Control : Character1
    {

     private static Control instance;
    
     public event DeadEventHandler Dead;
    
     public static Control Instance
     {
         get
         {
             if (instance == null)
             {
                 instance = GameObject.FindObjectOfType<Control>();
             }
         return instance;
         }
     }
    
    
    
     
    
     public Transform[] groundPoints; //points on the characters shoes for him to know if he is standing on solid ground
     public float groundRadius;
    
     public LayerMask whatIsGround;
    
     
     public bool airControl;
    
     public float jumpForce;
    
     private bool immortal = false;
    
     private SpriteRenderer spriteRenderer;
    
    
     [SerializeField]
     private float immortalTime;
    
     public Rigidbody2D MyRigidbody { get; set; }
     
     public bool Slide { get; set; }
     public bool Jump { get; set; }
     public bool OnGround { get; set; }
     public bool Crouch { get; set; }
    
     public override bool IsDead
     {
         get
         {
             if (healthStat.CurrentValue<= 0)
             {
                 OnDead();
    
             }
             return healthStat.CurrentValue <= 0;
         }
     }
    
     private Vector2 startPos;
    
    
     // Use this for initialization
     public override void Start()
     {
         base.Start();   
         startPos = transform.position;
         spriteRenderer = GetComponent<SpriteRenderer>();
         MyRigidbody = GetComponent<Rigidbody2D>();
         
         
     }
     private void Update()
     {
         if (!TakingDamage && !IsDead)
         {
    
             if (transform.position.y <= -14f)
             {
                 Death();
             }
         }
         HandleInput();
     }
     // Update is called once per frame
     void FixedUpdate()
     {
         if (!TakingDamage&&!IsDead)
         {
             float horizontal = Input.GetAxis("Horizontal_P1"); // "HORIZONTAL" is the name of a unity feature for movement control. You can see it in Edit>Project Settings>Input.
             OnGround = IsGrounded();
             HandleMovement(horizontal);
             Flip(horizontal);
         }
     }
    
     public void OnDead()
     {
         if(Dead!= null)
         {
             
             Dead();
         }
     }
     //METHODS:
    
     private void HandleMovement(float horizontal) // The horizontal in the parenthesis gets its value from the float Horizontal = blah blah in the fixed update
     {
        
         if(!Attack && (OnGround||airControl))
         {
             MyRigidbody.velocity = new Vector2(horizontal * movementSpeed, MyRigidbody.velocity.y);
         }
    
         if (Jump && MyRigidbody.velocity.y==0)
         {
             MyRigidbody.AddForce(new Vector2(horizontal * movementSpeed, jumpForce));
         }
         MyAnimator.SetFloat("Speed", Mathf.Abs(horizontal));
    
         if (Crouch)
         {
             MyRigidbody.velocity = new Vector2(0, MyRigidbody.velocity.y);
         }
    
     }
    
     
     public virtual void HandleInput() // where we put in controls (we can use this to make 2-3 player games
     {
         if (Input.GetKeyDown(KeyCode.W))
         {
             MyAnimator.SetTrigger("jump");
         }
    
         if (Input.GetKeyDown(KeyCode.Z))
         {
             MyAnimator.SetTrigger("attack");
         }
    
         if (Input.GetKeyDown(KeyCode.C))
         {
             MyAnimator.SetTrigger("slide");
         }
         if (Input.GetKey(KeyCode.S))
         {
             MyAnimator.SetBool("crouch", true);
         }
         if (Input.GetKeyDown(KeyCode.X))
         {
             MyAnimator.SetTrigger("throw");
         }
    
     }
     private void Flip(float horizontal)
     {
         if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
         {
             ChangeDirection();
         }
     }
     
     private bool IsGrounded()
     {
         if (MyRigidbody.velocity.y <= 0)
         {
             foreach (Transform point in groundPoints)
             {
                 Collider2D[] colliders = Physics2D.OverlapCircleAll(point.position, groundRadius, whatIsGround);
                 
                 for (int i=0;i<colliders.Length;i++)
                 {
                     if (colliders*.gameObject !=gameObject)*
    

{
return true;
}

}
}
}
return false;
}
public override void ThrowKnife (int value)
{
base.ThrowKnife(value);
}

private IEnumerator IndicateImmortal()
{
while (immortal)
{
foreach (Renderer r in GetComponentsInChildren())
r.enabled = false;
yield return new WaitForSeconds(.1f);

foreach (Renderer r in GetComponentsInChildren())
r.enabled = true;
yield return new WaitForSeconds(.1f);

}
}

public override IEnumerator TakeDamage()
{
if (!immortal)
{
healthStat.CurrentValue -= 10;
if (!IsDead)
{
MyAnimator.SetTrigger(“damage”);
immortal = true;
StartCoroutine(IndicateImmortal());
yield return new WaitForSeconds(immortalTime);
immortal = false;

}

else
{
MyAnimator.SetLayerWeight(1, 0);
MyAnimator.SetTrigger(“die”);

}
}
}

public override void Death()
{
MyRigidbody.velocity = Vector2.zero;
MyAnimator.SetTrigger(“idle”);
healthStat.CurrentValue = healthStat.MaxVal;
transform.position = startPos;
}
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Jarred : Control
{
public GameObject teleknife;

public override void HandleInput() // where we put in controls (we can use this to make 2-3 player games
{
if (Input.GetKeyDown(KeyCode.W))
{
MyAnimator.SetTrigger(“jump”);
}
if (Input.GetKeyDown(KeyCode.Z))
{
MyAnimator.SetTrigger(“attack”);
}
if (Input.GetKeyDown(KeyCode.X))
{
MyAnimator.SetTrigger(“slide”);
}
if (Input.GetKey(KeyCode.S))
{
MyAnimator.SetBool(“crouch”, true);
}
if (Input.GetKeyDown(KeyCode.C))
{
MyAnimator.SetTrigger(“throw”);
}
if (Input.GetKeyDown(KeyCode.V))
{
MyAnimator.SetTrigger(“cast”);
}
}
private void Teleport()
{

transform.position = teleknife.transform.position;

}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent (typeof(Rigidbody2D))]
public class Knife : MonoBehaviour
{
public float speed;
private Rigidbody2D myRigidbody;
private Vector2 direction;
// Use this for initialization
void Start ()
{
myRigidbody = GetComponent();

  • }*

void FixedUpdate()
{
myRigidbody.velocity = direction * speed;
}

  • // Update is called once per frame*

  • void Update () {*

  • }*
    public void Initialize(Vector2 direction)
    {
    this.direction = direction;
    }
    void OnBecameInvisible()
    {
    Destroy(gameObject);
    }
    public void OnTriggerEnter2D(Collider2D other)
    {
    if (other.gameObject.tag != “Player”)
    Destroy(gameObject);
    }
    }

You should keep a reference to the instantiated knife (a new GameObject) and use its transform to teleport the player.

In this code:

GameObject tmp = (GameObject)Instantiate(knifePrefab, knifePos.position, Quaternion.Euler(new Vector3(0, 0, -90)));

You are using tmp variable, and it has a transform value. This is the transform value you want to be transported to.

What you need to do is to assign its transform to knifePos like this:

knifePos = tmp.transform;

Thank you so much @TanselAltinel !! This worked but my new problem is that it only works once. After my knife gets destroyed (upon exiting the frame) it also destroys the transform. The error message says “MissingReferenceException: The object of type ‘Transform’ has been destroyed but you are still trying to access it.” Any Ideas?

You could store the location of the knife before destroying it, and then teleport the player to this position instead of the knife transform.

To do this, create a new Vector3 variable at the top of your script. Then, when just before you destroy the knife, save the position of the knife to the newly created Vector3 variable. When you want to teleport the player to the knife, set it’s position (Not it’s transform) to the saved position.

Little heads up, Vector3 variables have a default value of (0,0,0). So if you haven’t yet thrown a knife and teleport the player, they’ll be teleported to (0,0,0). So it might be a good idea to have a boolean variable to keep track of whether or not the player has thrown the knife.

It’s not the most ideal system, but seeing your current setup it’ll do fine :slight_smile:

Alternatively, if you want to hide the knife, you could disable all rendering components. (This is a better method if you just want to hide the knife)

Also, you could just remove the knife after the teleport. But I’m not sure how your game mechanic is designed to work so I can’t really judge :slight_smile:

~LukeWaffel

Hey @LukeWaffel,

Thanks for the advice! I’m new here and I didnt expect people to be so helpful. I’m gonna figure out how to get points so I can give em to people like you. Anyway, I still have the following problems:

  1. I have been trying to get the code right for your solution but I cant seem to get it to work (cuz I suck at coding). Do I put the new vector3 variable at the top of the code for my knife? this is the way I did it and I think I did it wrong.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    [RequireComponent (typeof(Rigidbody2D))]
    public class Knife : MonoBehaviour
    {
    Vector3 telepoint = new Vector3 (0,0,0);

     public float speed;
    
     private Rigidbody2D myRigidbody;
    
     private Vector2 direction;
    
    
     // Use this for initialization
     void Start ()
     {
         myRigidbody = GetComponent<Rigidbody2D>();
     }
     
     void FixedUpdate()
     {
         myRigidbody.velocity = direction * speed;
     }
     // Update is called once per frame
     void Update () {
     	
     }
    
     public void Initialize(Vector2 direction)
     {
         this.direction = direction;
     }
     void OnBecameInvisible()
     {
         transform.position = telepoint;
         Destroy(gameObject);
     }
     public void OnTriggerEnter2D(Collider2D other)
     {
    
         transform.position = telepoint;
         if (other.gameObject.tag != "Player")
         { Destroy(gameObject); }
     }
    

    }

  2. Will this your advice allow me to throw a 2nd, 3rd, 4th, … knife and then how will I be able to teleport to the latest knife I threw and destroy the knife once I have teleported to it?

I hope you can help me out! Thanks!! :slight_smile:

The simple way to do this is just by doing:

public virtual void ThrowKnife (int value)
{
   Physics2D.IgnoreLayerCollision(10, 11);
   GameObject tmp;
   if (facingRight)
   {
      tmp = (GameObject)Instantiate(knifePrefab, knifePos.position, Quaternion.Euler(new Vector3(0, 0, -90)));
      tmp.GetComponent<Knife>().Initialize(Vector2.right);
   }
   else
   {
   tmp = (GameObject)Instantiate(knifePrefab, knifePos.position, Quaternion.Euler(new Vector3(0, 0, 90)));
   tmp.GetComponent<Knife>().Initialize(Vector2.left);
         
   }
   transform.position=tmp.transform.position;
}

Basically tmp is your reference to the instantiated object or “clone”, and that’s the knife you just spawned, in this you teleport to the knife as soon as it is thrown. Although you may want to store the transform of tmp as a variable so you can teleport to its location later when a button is pressed or after a certain amount of time. Also this seems like quite an ambitious project, it is much easier to make a simple project like a clicker or flappy bird clone to get the fundamentals down, which you really need if you want to create original content by yourself.