- Home /
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[i].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<Renderer>())
r.enabled = false;
yield return new WaitForSeconds(.1f);
foreach (Renderer r in GetComponentsInChildren<Renderer>())
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<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()
{
Destroy(gameObject);
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag != "Player")
Destroy(gameObject);
}
}
@lancecheng I'll give you some guidelines on how to properly use this forum:
Please don't post your comments as replies! it is very confusing. Now, I converted your "replies" to comments for you. But in the future, please click on the "Add Comment" below a reply, ins$$anonymous$$d of adding a new Reply. "Replies" are for providing solutions to the Question.
Please mark the most helpful Response as "Accepted", by clicking on the green check-mark. You can also up-vote replies that you find helpful too. You "Accept" only one Reply, but up-vote as many as you like, including the reply you accepted. You can also up-vote comments.
Of course you can also down-vote replies and comments, but that would cost you points, and will cost the other member points. So in this case, also take into consideration, that the other member has put some effort to help you, and every one makes a mistake now and then...
It is very considerate of you, and in the correct spirit of the Unity community, that you want to give points to members that help you. Well, they will get points when you accept replies, and up-vote replies and comments. This is also how you earn points.
It would be very helpful to you if you took some Unity tutorials, where you can also find a "Scripting" section:
Answer by Darkwinger · Nov 05, 2017 at 08:02 PM
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.
Answer by TanselAltinel · Oct 31, 2017 at 11:05 AM
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;
Jus to add a little something to the original comment. I advise adding a vertical offset to the position you teleport the player to. If you set the position of the player to the position of the knife, the player will most likely be inside the ground and potentially fall through it.
That's all, the original comment says it all. Totally correct!
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 "$$anonymous$$issingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it." Any Ideas?
If you can convert your answer to comment, that would be better for future visitors to see what's going on and in what order.
To answer your question, @LukeWaffel provided a great answer and solution in his comment. You might as well give it a try.
I converted my comment to an answer :) You can now all vote for it to be the correct answer!
Would appreciate it if you guys did. Thanks!
~LukeWaffel
Answer by LukeWaffel · Oct 31, 2017 at 03:46 PM
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 :)
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 :)
~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 $$anonymous$$nife : $$anonymous$$onoBehaviour
{
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!! :)