- Home /
How to teleport the player to the location of an instantiated projectile?
I want the player to be able to fire three slow moving projectiles with the right mouse button and then teleport to them, one after the other (as long as they still exist) using the left mouse button. This is presenting two specific challenges for me. First, I don't know how to access/store the position of the instantiated projectiles, so that my player can teleport to them.
You'll see below that I tried using a tag to find the object but I'm very new to Unity and C# and I am having difficulty.
Secondly, I want to have it so that there can be a maximum of three projectiles at any point. Creating a new projectile once there are already three should destroy the oldest and replace it with the new one. The tricky part for me (even the logic) is that if, say the second projectile is prematurely destroyed (by say colliding with an object), how do I maintain the proper order when adding a new one. In other words, I always want to teleport to the oldest projectile.
Eg. I fire all three projectiles. Projectile1 and Projectile3 both still exist but Projectile two was triggered when it collided with an object and destroyed itself. Now I fire another projectile. I need it to be come after Projectile1 and Projectile3 so that they'll be used first.
After doing some research I'm thinking an array may be the answer but again, I'm just too new to this to know quite how to approach the problem.
using UnityEngine;
using System.Collections;
public class FireSynapse : MonoBehaviour {
public float cooldown = 1f;
float cooldownRemaining = 0;
public GameObject SynapsePrefab;
//used for initialization
void Start () {
}
//update called once per frame
void Update () {
cooldownRemaining -= Time.deltaTime;
if (Input.GetMouseButtonDown(1) && cooldownRemaining <= 0) {
cooldownRemaining = cooldown;
Instantiate(SynapsePrefab, Camera.main.transform.position, Camera.main.transform.rotation);
}
if (Input.GetMouseButtonDown (0)) {
GameObject Portal = GameObject.FindWithTag("Portal");
Debug.Log (transform.position = new Vector3(SynapsePrefab.transform.position.x, SynapsePrefab.transform.position.y, SynapsePrefab.transform.position.z));
}
}
}
Thank you in advance for your help.
PS: I hope that didn't count as two questions. I apologize if it did and I can re-post that second part of my dilemna elsewhere if need be. Thanks again.
Answer by ChristianLinnell · May 04, 2014 at 09:55 PM
Question 1
Instantiate() actually returns the object that was created. So you can do this:
GameObject newProjectile = (GameObject)Instantiate(SynapsePrefab, Camera.main.transform.position, Camera.main.transform.rotation);
Note that I've put "(GameObject)" before "Instantiate". That's called "casting", and you use it when you're changing something from one type to another (doesn't work so simply for everything!). We have to do it here because Instantiate returns an "Object" type, and you need to store the result as a GameObject.
Question 2
To answer your second question, yep, you can use an array, but we're going to make it easier and use a List. This is going to get a little bit more involved, so bear with me! You're going to need:
A list that stores the projectiles
A way to add to it
A way to remove the oldest projectile
A way to move the projectiles down the list
So, two things for 1... Firstly, after "using System.Collections;" add
using System.Collections.Generic;
Then, after where you've got "float cooldownRemaining = 0;" add:
private List<GameObject> projectiles = new List<GameObject>();
Now let's make a way to add stuff to it:
void AddProjectile(GameObject newProjectile){
//Run through the list and remove any objects that have been destroyed already.
//You might be better running a master list of projectiles and having the projectile remove itself from the list when it's destroyed, but this will do for now.
foreach(GameObject projectile in projectiles){
if (projectile == null){
projectiles.Remove (projectile);
}
}
//If the list still has the maximum number of projectiles (i.e. none were removed in the last step, destroy the first one and remove it from the list. List<> is cool because it automatically moves the other items down the list!
if (projectiles.Count == maxProjectiles){
//I'm just destroying it here, but you might have an explosion animation to run? If so, now would be the time to call it. Let me know if you have trouble with this, and I'll explain briefly.
Destroy(projectiles[0]);
projectiles.RemoveAt(0);
}
//Now we can add the new one
projectiles.Add(newProjectile);
}
Finally, after the line where you instantiated the new projectile, add this:
AddProjectile(newProjectile);
Oh, and then you're want to teleport to them one after the other. I'm not sure how you want that behaviour to work, but you can get to the oldest one like this:
transform.position = projectiles[0].transform.position;
And you're done!
Just answering the second part now, give me a $$anonymous$$!
Thanks so much for the help. I really appreciate it. I tried adding your line of code and it accepts that okay. I'm getting an error when I try to port to the new game object though.
using UnityEngine;
using System.Collections;
public class FireSynapse : $$anonymous$$onoBehaviour {
public float cooldown = 1f;
float cooldownRemaining = 0;
public GameObject SynapsePrefab;
//used for initialization
void Start () {
}
//update called once per frame
void Update () {
cooldownRemaining -= Time.deltaTime;
//shoots synapse projectile
if (Input.Get$$anonymous$$ouseButtonDown(1) && cooldownRemaining <= 0) {
cooldownRemaining = cooldown;
//Instantiate(SynapsePrefab, Camera.main.transform.position, Camera.main.transform.rotation);
GameObject newProjectile = (GameObject)Instantiate(SynapsePrefab, Camera.main.transform.position, Camera.main.transform.rotation);
}
//ports to projectile
if (Input.Get$$anonymous$$ouseButtonDown (0)) {
gameObject.transform.position = newProjectile.transform.position;
}
}
}
I'm getting this error: Assets/Scripts/FireSynapse.cs(33,57): error CS0103: The name `newProjectile' does not exist in the current context
Sorry I was being non-specific! That's because (my fault) you created "GameObject newProjectile" within that if statement. If you think about it, when you try to access it on line 33, you can't guarantee that it exists, so C# just assumes that it doesn't.
The concept here is "context". If you declare a variable inside curly brackets, it's only available within those curly brackets, including other curly brackets inside those ones (the exception being non-private variables at the class level).
$$anonymous$$y update fixes the problem, but you could also fix it by putting "GameObject newProjectile;" just inside Update(), and then just saying the newProjectile = (GameObject)Instantiate... bit (without the "GameObject" bit). $$anonymous$$ake sense?
Thank you. Thank you so very much. You're my hero right now!
Your code worked beautifully. I didn't notice right away that you used a new variable (maxProjectiles), but that was great because it reinforced what you said about context and when I got that error I knew exactly where to look.
Just in case anyone else ever needs similar help, I'll point out that I added two lines underneath the transform, using what I learned from you about the lists. Now the projectile is always destroyed after teleport:
Destroy(projectiles[0]);
projectiles.RemoveAt(0);
Thank you again so much. This worked beautifully.
No worries!
Sorry I forgot to mention the maxProjectiles thing, but I'm glad it worked out well!
Your answer
Follow this Question
Related Questions
Instantiated script does not teleport 0 Answers
How can I get the x position for the left(and right) of the screen? 2 Answers
How do I make a clone of a prefab appear on the correct layer? [5.2.2f1] 1 Answer
Object reference not set to an instance of an object 1 Answer
What can I do to make the objects I instantiated move with the background? 1 Answer