Firstly, this is the script I'm using:
var object: GameObject;
private var obj: GameObject;
function OnTriggerEnter(other: Collider)
{
if (other.tag == "Player"){
obj = Instantiate(object, Vector3(0, 0, 0), transform.rotation);
}
}
Now, with this script, when I enter the Trigger, the Prefab is being instantiated in front of my initial Prefab, just like I wanted it...but when I move to my instantiated Prefab, when I enter the Trigger, the prefab is not being cloned in front but at the same position like the last one.
My game is an endless runner, so I need the spawned prefab to always be one tile further of my last prefab. How can I do this?!
Here's a sketch of the situation, if I'm not being quite clear with you guys
var spawnDistInFrontOfPlayer : float = 2f;
//change this to your axis direction (direction the character will run)
var spawnAxis : Vector3 = Vector3.right;
obj = Instantiate(object, other.transform.position + (spawnAxis * spawnDistInFrontOfPlayer), transform.rotation);
The code you posted instantiates the prefab always at position (0,0,0). You can simply substitute that vector with the actual world space position where you want to spawn the prefab. For example, in front of the player of a few units:
spawnDistInFrontOfPlayer = 2f;
obj = Instantiate(object, other.transform.position + other.transform.forward * spawnDistInFrontOfPlayer, transform.rotation);
Related
I'm creating a 2D racing game in Unity2D and unsure how to approach on coding my spawner for objects e.g. power-up, rewards and obstacles ahead on the right side of my moving camera. The camera follows my vehicle and moves from left to right. Currently objects spawn in the game, but only spawn on a point and continue to spawn in the same point when the camera has scrolled way past. Apologies, if the answer was simple.
Here are the scripts I used:
coin.cs is attached to my coin prefab
public class coin : MonoBehaviour
{
public Camera mainCamera;
Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
mainCamera = GameObject.FindObjectOfType<Camera>();
rb = this.gameObject.GetComponent<Rigidbody2D>();
transform.position = new Vector2(mainCamera.pixelWidth / 32, getRandomHeight());
}
float getRandomHeight(){
return Random.Range(-(mainCamera.pixelHeight / 2) / 100, (mainCamera.pixelHeight / 2) / 100);
}
private void OnTriggerEnter(Collider coll){
if (coll.gameObject.tag == "Player"){
Destroy(this.gameObject);
}
}
// Update is called once per frame
void Update()
{}
}
and coinSpawner.cs is attached to a gameObject in the scene
public class coinSpawner : MonoBehaviour
{
float LastSpawnTime = -500f;
float NextSpawnTime = 3;
public Object CoinPrefab; // declare coinPrefab
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Time.time - LastSpawnTime > NextSpawnTime)
{
NextSpawnTime = Random.Range(3, 10);
LastSpawnTime = Time.time;
Instantiate(CoinPrefab);
}
}
Instantiate(CoinPrefab);
spawns this object without any information of position or parent object. This it will always be spawned at Scene root and 0,0,0.
Then this line
transform.position = new Vector2(mainCamera.pixelWidth / 32, getRandomHeight());
in coin always places it to the absolute position depending on your pixelWidth which doesn't change over time.
You are saying the Camera is moving so you should rather take it's transform.position into account.
You have basically two(three) ways to go here:
You can make the spawner GameObject a child of your Camera - so it is automatically moved along with it - and move it to the right to have the desired offset. Then simply spawn new objects at this GameObjects position. Then you can do it in coinSpawner:
Instantiate(CoinPrefab, transform.position, Quaternion.Identity);
Or get the Camera reference and use it's position + the desired offset either also only in coinSpawner like
// reference this already via the Inspector if possible
[SerializeField] Camera _camera;
// Otherwise get the reference on runtime
void Awake()
{
if(!_camera)_camera = Camera.main;
}
float getRandomHeight => Random.Range(-(_camera.pixelHeight / 2) / 100, (_camera.pixelHeight / 2) / 100;
and then do something like
Instantiate(CoinPrefab, new Vector2(_camera.transform.position.x + mainCamera.pixelWidth / 32, getRandomHeight()), Quaternion.Identity);
This would actually be more efficient since the entire coin script would be reduced to only the OnTriggerEnter part and not every coin would use FindObjectOfType and GetComponent when spawned.
Basically the same as above but sticking to your code structure simply do
transform.position = new Vector2(mainCamera.transform.position.x + mainCamera.pixelWidth / 32, getRandomHeight());
I wouldn't do it this way though due to efficiency as said.
so recently my friends and I are trying to make a game for fun. Currently, I hit a wall and not sure how to do this. I am trying to create a simple base script where I have the character move and attack with right click. If it hits the ground, it will move there and and if in range of a target, it will send a projectile. So the game is creating the projectile but its not actually moving. Can anyone tell me what I should probably do. At first, I thought to just make it all one script but now I am thinking it be best to make another script for the projectile.
void Update()
{
if (Input.GetMouseButtonDown(1))
{
RaycastHit hit;
if(Physics.Raycast (Camera.main.ScreenPointToRay(Input.mousePosition), out hit) && hit.transform.tag == "Minion")
{
if(Vector3.Distance(this.transform.position, hit.point) <= atkRange)
{
GameObject proj = Instantiate(bullet) as GameObject;
proj.transform.position = Vector3.MoveTowards(this.transform.position, target, atkSpd);
}
}
else if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, speed))
{
agent.destination = hit.point;
}
}
}
So this is what I originally had. I am pretty sure I did something wrong here. Also I am not sure if I should have another script for the projectile itself or if it is not necessary. Thank you for any help or tips on what to do.
For starters, I'd advize using a Rigidbody component and letting physics handle movement but if you'd like to use Vector3.MoveTowards, it'll be a bit of work:
Vector3.MoveTowards is something that needs to be called every frame. I'm guessing bullet is your prefab so you'll want to make a new script for the movement and place it on that prefab:
public class MoveToTarget : MonoBehaviour
{
private float _speed;
private Vector3 _target;
public void StartMovingTowards(Vector3 target, float speed)
{
_target = target;
_speed = speed;
}
public void FixedUpdate()
{
// Speed will be 0 before StartMovingTowards is called so this will do nothing
transform.position = Vector3.MoveTowards(transform.postion, _target, _speed);
}
}
After you've attached this to your prefab, make sure you grab a reference and get it started when you instantiate a copy of your prefab:
GameObject proj = Instantiate(bullet) as GameObject;
var movement = proj.GetComponent<MoveToTarget>();
movement.StartMovingTowards(target, atkSpd);
If you instead go the physics route, add a Rigidbody component to your bullet prefab, and get a reference to that instead of making the MoveToTarget script:
GameObject proj = Instantiate(bullet) as GameObject;
var body = proj.GetComponent<Rigidbody>();
Then you can just apply a force and let physics take over:
body.AddForce(target - transform.position, ForceMode.Impulse);
Don't set the position like you currently are
proj.transform.position = Vector3.MoveTowards(this.transform.position, target, atkSpd);
Instead, add either a characterController or a rigidbody and use rb.addVelocity.
I made a tank that shoot sphere balls on mouse click.
my C# script:
GameObject prefab;
// Use this for initialization
void Start () {
prefab = Resources.Load("projectile") as GameObject;
}
// Update is called once per frame
void Update() {
if (Input.GetMouseButtonDown(0))
{
GameObject projectile = Instantiate(prefab) as GameObject;
projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * 40;
}
}
in this script im shooting a mesh named projectile. But I want to shoot a particle ball and not a mesh. I already tried to change the particle to Orbparticle on script but no object was spawned. What im doing wrong?
No object was spawned because you probably don't have a resource called Orbparticle. Check if you have any errors when you run your script. If Resources.Load doesn't find the object you want by the path you gave it, it will give null, which probably why no object is being spawned.
If you want to shoot a particle instead of a mesh then what you need to do is set prefab to a GameObject you prepared ahead of time that has the ParticleSystem you want. I'd suggest against using Resources.Load for this.
1. Using Resources.Load.
Change your code to this so that it will alert you if it doesn't find the resource:
GameObject prefab;
// Use this for initialization
void Start () {
string name = "OrbParticle";
prefab = Resources.Load<GameObject>(name);
if (prefab == null) {
Debug.Error("Resource with name " + name + " could not be found!");
}
}
// Update is called once per frame
void Update() {
if (Input.GetMouseButtonDown(0))
{
GameObject projectile = Instantiate(prefab) as GameObject;
projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * 40;
}
}
Now in order for this to work you need a prefab called "OrbParticle" or whatever string you set the variable name to. Resources.Load looks for items in paths such as Assets/Resources. So you MUST have your "OrbParticle" prefab located in that Resources folder. Unless you have a specific reason for using Resources.Load, I strongly suggest you go with solution 2.
2. Ditching Resources.Load and using the Prefab directly.
Change your code to this:
public GameObject prefab;
// Update is called once per frame
void Update() {
if (Input.GetMouseButtonDown(0))
{
GameObject projectile = Instantiate(prefab) as GameObject;
projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * 40;
}
}
Then do this:
Create a new empty GameObject.
Attach a ParticleSystem to the GameObject.
Make a new prefab asset.
Drag and drop the newly created GameObject into a Prefab asset.
Drag and drop the the prefab into prefab field in your Monobehaviour (the object doing the shooting. It will have a prefab field in the Inspector. That's why we set prefab to be a public field).
If you continue having problems, look in Unity's Hierarchy to see if no object is being created at all. It might be the case that it is instantiating a GameObject but the GameObject is invisible for some reason or not instantiating in the location you expect.
I'm making a simple character that follows the player's cursor. What I also want is for when the game object "enemy" appears the character then goes to that location to alert the player. Once the enemy is gone the character continues to follow the cursor like normal. Is there a reason why my script won't work. How else can I paraphrase it?
public class FollowCursor : MonoBehaviour
{
void Update ()
{
//transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
if (gameObject.FindWithTag == "Enemy")
{
GameObject.FindWithTag("Enemy").transform.position
}
if (gameObject.FindWithTag != "Enemy")
{
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
}
}
You are not using FindWithTag correctly, as it is a method that takes a string as parameter you need to use it like this:
GameObject.FindwithTag("Something") as stated in the Unity scripting API
Now to apply this to your code you would need to do the following to set your players position based on wether or not an enemy is found (assuming this script is on your actual player object):
if(GameObject.FindWithTag("Enemy"))
{
//If an enemy is found with the tag "Enemy", set the position of the object this script is attatched to to be the same as that of the found GameObject.
transform.position = GameObject.FindWithTag("Enemy").transform.position;
}
else
{
//when no enemy with the tag "Enemy" is found, set this GameObject its position to the the same as that of the cursor
transform.position = Camera.main.ScreenToWorldPoint( new Vector3(Input.mousePosition.x,Input.mousePosition.y,8.75f));
}
However this code will just snap your player instantly to the position of the found Enemy. If this is not the desired behaviour you could use a function like Vector3.MoveTowards instead to make the player move to it gradually.
This code also has room for optimisation as searching for a GameObject every update frame is not the ideal solution. But for now it should work.
I'm going to code coding all the function for you, I'm not pretty sure about the beavihour of your code, I understand a gameobject will be attached to the mouse position, so not really following....
Vector3 targetPosition;
public float step = 0.01f;
void Update()
{
//if there is any enemy "near"/close
//targetPosition = enemy.position;
//else
//targetPosition = MouseInput;
transform.position = Vector3.MoveTowards(transform.position, targetPosition , step);
}
For the f you can use a SphereCast and from the enemies returned get the closest one.
I'm trying to implement a tower defense game in Unity, and I can't figure out how can I assign a velocity or a force to a new instantiated object (in the creator object's script)
I have a tower which is supposed to shoot a bullet towards the enemy which triggered its collider. This is the script of the towers:
function OnTriggerEnter(other:Collider){
if(other.name=="Enemy")
{
ShootBulletTo(other.transform);
}
}
function ShootBulletTo(target:Transform)
{//public var Bullet:Transform
var BulletClone = Instantiate(Bullet,transform.position, Quaternion.identity); // ok
BulletClone.AddForce(target.position); //does not compile since Transform.AddForce() does not exist.
}
I guess the problem is I have to use a Transform variable for instantiate but I need a GameObject variable for velocity, force etc. So how can I instantiate the bullet with initial velocity?
Thanks for help.
You have to acces the rigidbody component of your bullet clone to change the force, not the transform.
Here's how your code should look:
function OnTriggerEnter(other:Collider)
{
if(other.name=="Enemy")
{
ShootBulletTo(other.transform);
}
}
function ShootBulletTo(target:Transform)
{
var Bullet : Rigidbody;
BulletClone = Instantiate(Bullet, transform.position, Quaternion.identity);
BulletClone.AddForce(target.position);
}
There's also a good example in the unity script reference
http://docs.unity3d.com/Documentation/ScriptReference/Object.Instantiate.html
[EDIT] I'm pretty sure, that you don't want to add the enemies position as a force, instead you should add a direction that goes towards the enemies position.
You subtract two positions to gain a direction vector between them, so the ShootBulletTo function should look like this:
function ShootBulletTo(target:Transform)
{
// Calculate shoot direction
var direction : Vector3;
direction = (target.position - transform.position).normalized;
// Instantiate the bullet
var Bullet : Rigidbody;
BulletClone = Instantiate(Bullet, transform.position, Quaternion.identity);
// Add force to our bullet
BulletClone.AddForce(direction);
}