I have create a simple script that instantiates a Cube. I need to know its location (x and z). However, when the script instantiates the cube, its x and z positions are 0. What am I doing wrong?
Instantiate Script Example:
public GameObject cube;
float xPos, zPos;
int randomPos;
void Start()
{
randomPos = Random.Range(10,20);
Instantiate(cube, new Vector3(1,0,randomPos),Quaternion.identity);
xPos = cube.transform.position.x;
zPos = cube.transform.position.z;
}
This is an example, i need to know the "cube.transform.position.x and z" But the output is always zero Thanks guys
You have to get the position not of your cube, but from the new one created by Instantiate.
Instantiate clones the object original and returns the clone.
void Start(){
randomPos = Random.Range(10,20);
var newCube = Instantiate(cube, new Vector3(1,0,randomPos),Quaternion.identity);
xPos = newCube.transform.position.x;
zPos = newCube.transform.position.z;
}
Related
so I'm making a 2D platformer and I would like to spawn enemies on the whole map but not in the camera range.
I have to mention I am using Cinemachine to follow the player.
This is my script for the spawner:
*public class MobSpawner : MonoBehaviour
{
public GameObject Mob;
float randX;
Vector2 whereToSpawn;
public float spawnRate = 2f;
float nextSpawn = 0.0f;
public GameObject Camera;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Time.time > nextSpawn)
{
nextSpawn = Time.time + spawnRate;
randX = Random.Range(-36f, 62);
whereToSpawn = new Vector2(randX, transform.position.y);
Instantiate(Mob, whereToSpawn, Quaternion.identity);
}
}
}*
As you can see I'm taking 2 points and in between them I spawn enemies. As this range would basically be the entire map, the camera will always be in it.
I want enemies to NOT spawn inside the camera yet spawn outside of it. How can I manage to do this?
I'd say the simplest solution would be to just calculate vector distance between the player position and spawning position. Since this is a 2d space and you are spawning them only on one axis it should be fine.
So you could do
float distanceAwayFromCameraView = 5;
// you will need a method, reference or just get the object via tag
var playerPos = GameObject.Find("Player").transform.position;
randX = Random.Range(-36f, 62);
whereToSpawn = new Vector2(randX, transform.position.y);
while ((Vector2.Distance(whereToSpawn, playerPos) < distanceAwayFromCameraView){
randX = Random.Range(-36f, 62);
whereToSpawn = new Vector2(randX, transform.position.y);
}
Instantiate...
I'm not at my pc to test this right now, please let me know if there's errors
Ive been at it all day trying to solve this, because I dont want to make a separate script for every bullet, instead I want to have a single EnemyBulletMovement script, that can move each bullet in a different way, depending on the BulletType int that I feed into it when I instantiate it.
The problem is that if I fire multiple bullets at the same time, they will all change BulletType as soon as another bullet is instantiated, because they are all sharing the same script.
My goal is to have all bullets have a private script, but no matter what I try the variable will still be changed for all active bullets every time I try to change it for just one of them.
EnemyController script that Instantiates the bullets and gives them a BulletType value:
GameObject enemyBullet = ObjectPooler.SharedInstance.GetPooledEnemyBullet();
if (enemyBullet != null)
{
Quaternion rotationAmount = Quaternion.Euler(0, 0, 0);
Quaternion postRotation = transform.rotation * rotationAmount;
enemyBullet.transform.position = transform.position;
enemyBullet.transform.rotation = postRotation;
enemyBullet.SetActive(true);
enemyBullet.GetComponent<EnemyBulletMovement>().SetBullet(2);
}
GameObject enemyBullet2 = ObjectPooler.SharedInstance.GetPooledEnemyBullet();
if (enemyBullet2 != null)
{
Quaternion rotationAmount = Quaternion.Euler(0, 3, 0);
Quaternion postRotation = transform.rotation * rotationAmount;
enemyBullet2.transform.position = transform.position;
enemyBullet2.transform.rotation = postRotation;
enemyBullet2.SetActive(true);
enemyBullet2.GetComponent<EnemyBulletMovement>().SetBullet(0);
}
Shared EnemyBulletMotion script, that gets the bulletType from the above script. This is the problem:
public void SetBullet(int typeIndex)
{
bulletType = typeIndex;
Debug.Log(bulletType);
}
private void BulletMotion()
{
if (bulletType == 0)
{
rb.velocity = pos;
}
if (bulletType == 1)
{
axis = Mathf.Sin(Time.deltaTime * -frequency) * magnitude * transform.up; // Up down Wave motion
transform.Rotate(Vector3.forward * sideMag); // Side Sway Motion (+ Wave = Spiral Motion)
rb.velocity = pos + axis; // Combine all Motions
}
if (bulletType == 2)
{
Debug.Log("Shootin");
axis = Mathf.Sin(Time.deltaTime * -frequency) * magnitude * transform.up; // Up down Wave motion
transform.Rotate(Vector3.forward * -sideMag); // Side Sway Motion (+ Wave = Spiral Motion)
rb.velocity = pos + axis; // Combine all Motions
}
}
EDIT: This Debug Shootin never appears in my console though, so maybe the bulletType is not being read correctly here after all? For Clarification, the first Debug.Log(bulletType); return a 0 or a 2 so it is working. But the second Debug.Log("Shootin"); does not get printed, ever.
I tried private, static, and made an Instance out of the whole EnemyBulletMovement script but nothing works.
When I debug this code, the script works, the bulletType will change from 2 to 0 and back, but when it does it will change both bullets, so both will fly the same way, when what I want is to have each bullet follow its own motion. If there is no way to do this I will have to create a separate script for each bulletmotion, but im only showing 2 here and I already have a lot of them, thats why I wanted to try this out and make it work with if statements and then use case statements later.
EDIT: Added ObjectPooler script below.
public List<GameObject> pooledEnemyBullets;
public GameObject EnemyBulletToPool;
public int EnemyBulletAmountToPool;
pooledEnemyBullets = new List<GameObject>();
public static ObjectPooler SharedInstance;
void Awake()
{
SharedInstance = this;
}
void Start()
{
for (int i = 0; i < EnemyBulletAmountToPool; i++)
{
GameObject obj3 = (GameObject)Instantiate(EnemyBulletToPool);
obj3.SetActive(false);
pooledEnemyBullets.Add(obj3);
}
}
public GameObject GetPooledEnemyBullet()
{
//1
for (int i = 0; i < pooledEnemyBullets.Count; i++)
{
//2
if (!pooledEnemyBullets[i].activeInHierarchy)
{
return pooledEnemyBullets[i];
}
}
//3
return null;
}
}
Bullet type should be declared as private int bulletType. If you declare bullet type as private static int bulletType it will be same for all bullets.
If it is already declared as private int bulletType, then you should check the logic where you use object pooler. You may be processing the same bullet over and over, or processing all bullets in the pool.
I am trying to get my GameObject (asteroid) to spawn continuously in the game. I looked up and followed this tutorial: https://pressstart.vip/tutorials/2018/09/25/58/spawning-obstacles.html. To make the asteroid move, I created this script (AsteroidObject) and to spawn the objects, I created this script (DeployAsteroids). There are no errors and the Debug.Log appears in the console. But the asteroid game object cannot be seen and will not spawn. Anyone can help? Thanks in advance!
Asteroid Object Codes:
public class AsteroidObject : MonoBehaviour
{
public float speed = 10.0f; //how fast the asteroid will move
private Rigidbody2D rb;
private Vector2 screenBounds; //screenbounds calculation
// Start is called before the first frame update
void Start()
{
rb = this.GetComponent<Rigidbody2D>(); //find rigidbody 2d and set it to rb reference by using the getcomponent
rb.velocity = new Vector2(-speed, 0); //moving the asteroid from right to left by setting the x value, leaving the y value 0 so that it will not move up and down
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z)); //defines the boundaries of the screen on the x and y axis
}
// Update is called once per frame
void Update()
{
//transform.position = new Vector3(Mathf.Clamp(transform.position.x, -9f, 9f),
//Mathf.Clamp(transform.position.y, -4f, 4f), transform.position.z);
if (transform.position.x < screenBounds.x) //check if it is moving to the left of the screen
{
Destroy(this.gameObject);
Debug.Log("hello world");
}
}
}
DeployAsteroid codes:
public class DeployAsteroids : MonoBehaviour
{
public GameObject asteroidPrefab;
public float respawnTime = 1.0f;
private Vector2 screenBounds;
// Start is called before the first frame update
void Start()
{
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
StartCoroutine(asteroidWave());
}
private void spawnEnemy()
{
GameObject a = Instantiate(asteroidPrefab) as GameObject;
a.transform.position = new Vector2(screenBounds.x * -2, Random.Range(-screenBounds.y, screenBounds.y));
}
IEnumerator asteroidWave()
{
while (true)
{
yield return new WaitForSeconds(respawnTime);
spawnEnemy();
//Debug.Log("Hello World");
}
}
}
You even say it yourself
the Debug.Log appears in the console.
Well, you log in the moment you destroy your object => it is already gone.
Destroy(this.gameObject);
Debug.Log("hello world");
Unless you mean the out commented log after the spawn method. You still immediately destroy the object. I think you would spot it immediately if you would use useful logs and not twice the same one
Debug.Log("Spawned a new object");
and
Debug.Log("Destroyed an object");
So what exactly is happening then?
You immediately destroy the new spawned objects!
you do
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
which stores the position at the right border of the screen.
Let's say e.g. somewhere at x = 2; (total random imaginary example number).
Then right after spawning you set it to
a.transform.position = new Vector2(screenBounds.x * -2, Random.Range(-screenBounds.y, screenBounds.y));
So for the x you set it to (using our example value) x = -4;
This is not even the left boarder of the screen but even beyond!
Additionally you tell the asteroid to move
rb.velocity = new Vector2(-speed, 0);
so assuming the value speed is positive even more into negative x direction.
And finally you do
// Even without the Rigidbody this is already comparing
// if(-2 * screenBounds.x < screenBounds.x)
// Or with our example numbers
// if(-4 < 2)
if (transform.position.x < screenBounds.x)
{
Destroy(this.gameObject);
Debug.Log("hello world");
}
=> This condition will always be true and immediately destroys your objects in the next frame.
So what should I do instead?
I assume you are trying to spawn the asteroid at the right boarder.
And want to destroy it after it passed the left boarder. So it should probably be
private void spawnEnemy()
{
GameObject a = Instantiate(asteroidPrefab);
Vector3 rightEdgeWorldPoint = Camera.main.ScreenToWorldPoint(
new Vector3(Screen.width, Random.Range(0, Screen.height),
Camera.main.nearClipPlane);
rightEdgeWorldPoint.z = 0f;
a.transform.position = rightEdgeWorldPoint;
}
And in the asteroid
if (Camera.main.WorldToScreenPoint(transform.position).x < 0)
{
Destroy(this.gameObject);
Debug.Log("Left the screen -> destroyed");
}
Note: Typed on smartphone but I hope the idea gets clear
Go to the scene hierarchy and check if the asteroids can be seen there. May be you do not see them within the game or the scene camera, but if they are in the scene they are spawn somewhere. It would be interesting info to update in the question.
I did not dig into the code but if they are there, you need to check or set the position in which they are spawned respect to the camera, for the asterioids to be in the field of view.
Check the posistion given in this line: a.transform.position = new Vector2(screenBounds.x * -2, Random.Range(-screenBounds.y, screenBounds.y)); and if it fits in the camera field of view.
I have one really big issue with my game . When i try press play when he spawn first prefab everything is correct X position is -0.604f , z is -1.49f..But when i spawn second object the second and the third object get spawned on wrong position of x and z.
On the second object X position is not good ( in this case second Z position of object is -1.208 and i need here same value as before -0.604) I really don't know why this happens and I don't know how i can change Z position when i spawn third object in other side so if first two objects are on right and left and when i spawn third object he get Z position of -4.968 which is not correct because I need on third position on Z = -1.655984 and i am getting on third object z position of ~-5f.
Here is my code to spawn objects..
public class StackPiecesSpawner : Singleton<StackPiecesSpawner> {
public GameObject stackPrefab;
[SerializeField] public Transform StackPieceSpawnPoint;
[SerializeField] public float PieceSpawnSize = 0.1f;
[SerializeField] public float PieceSpawnWidth = 1.0f;
[SerializeField] private float speed = 1f;
public Vector3 OriginalSpawnPointPosition;
protected override void Awake()
{
base.Awake();
OriginalSpawnPointPosition = StackPieceSpawnPoint.position;
}
public void SpawnNextStackPiece()
{
//StackPieceSpawnPoint.position += new Vector3(0f,PieceSpawnSize,0f);
StackPieceSpawnPoint.position += new Vector3(0.604f, 0.1f, -1.656f);
//GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
GameObject go = GameObject.Instantiate(stackPrefab);
//go.transform.localScale = new Vector3(PieceSpawnWidth,PieceSpawnSize,PieceSpawnWidth);
go.transform.localScale = new Vector3(0.4f, 0.4f,0.05f);
go.transform.position = nextSpawnPosition();
go.AddComponent<Rigidbody>();
go.GetComponent<Rigidbody>().isKinematic = true;
go.AddComponent<StackPiece>();
go.transform.parent = transform;
go.transform.name = "StackPiece_" + (StackPiecesManager.StackPieces.Count + 1);
StackPiece piece = go.GetComponent<StackPiece>();
piece.TargetTransform = StackPieceSpawnPoint;
piece.Speed = speed;
StackPiecesManager.Instance.AddNewPiece(piece);
}
private Vector3 nextSpawnPosition()
{
System.Random rnd = new System.Random();
int num = rnd.Next(0, 100);
Vector3 modifier = new Vector3();
modifier = num < 50 ? Vector3.back : Vector3.left;
modifier *= StackPiecesManager.Instance.SpawnDistance;
Vector3 returned = (StackPieceSpawnPoint.position - modifier) + Vector3.up * (StackPiecesManager.Instance.ExtraHeight);
// returned = (StackPieceSpawnPoint.position) + Vector3.up * (StackPiecesManager.Instance.ExtraHeight);
return returned;
}
public void Reset()
{
StackPieceSpawnPoint.position = OriginalSpawnPointPosition;
}
}
I cannot completely answer this question as not all the code and context is available, however, I could maybe point you in the right direction.
Parent-child relationship
In the SpawnNextStackPiece you instantiate a prefab and have its current parent transform equal the current transform(of the object this script is attached to), check if the transform you're changing the parent to is shifting each time a prefab is instantiated. I tend to avoid changing parent transforms, I usually try to attach it to different parents and change the actual objects offset not the parents, it can be easier to manage. I suspect go.transform.parent = transform; is causing a problem.
Diagnosing the problem through zeroing out values
Try forcefully making the z-axis 0 so you can see how much it is getting offset by each time it spawns, that may make diagnosing the problem much easier. Do this with StackPieceSpawnPoint.position = new Vector3(0.604f, 0.1f,0f);
I writing simple runner game.
I have game object (quad).
I want it to generate.
I wrote spawnscript:
using UnityEngine;
using System.Collections;
public class SpawnScript : MonoBehaviour {
public GameObject[] obj;
//public GameObject obj;
public float spawnMin = 1f;
public float spawnMax = 2f;
// Use this for initialization
void Start () {
Spawn();
}
void Spawn()
{
//for (int i = 0; i < 10; i++)
// Instantiate(obj, new Vector3(i * 2.0f, 0, 0), Quaternion.identity);
Instantiate(obj[Random.Range(0, obj.GetLength(0))], transform.position, Quaternion.identity);
Invoke("Spawn", Random.Range(spawnMin, spawnMax));
}
}
But my quad spawning one time.I need it to spawn multiple times.
Where is my problem?
Use InvokeRepeating instead of Invoke in start event:
// Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
InvokeRepeating("Spawn", 3, 3);
If you do InvokeRepeating("Function", 1.0f, 1.0f), it will call Function one second after the InvokeRepeating call and then every one second thereafter.
Hence, you can control the spawn timings.
Update
As asked in comments:
You can also cancel InvokeRepeating any time by calling below code. More information here.
CancelInvoke("Spawn");
There is no problem with code. All GameObjects instantiated same position so you can use code below:
public float spawnDistanceFactor = 2f; //Value is your choice. You can change it.
void Spawn()
{
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
Instantiate(obj, spawnPos, Quaternion.identity);
startPosX+=spawnDistanceFactor;
}
}
It is only moves positions on X axis you can move it x,y,z.
Also
You can use Random function for moving spawn position
public float randomMin = 2f;
public float randomMax = 4f;
void Spawn()
{
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
Instantiate(obj, spawnPos, Quaternion.identity);
float randomX = Random.Range(randomMin,randomMax);
startPosX+=randomX;
}
}
You can do a lot of things.
For destroying prefabs you can add Destroy script to object (You should create prefab with script) Like:
void DestroyObject(){
Destroy(this.gameObject);
}
or use list to hold pointers to the GameObjects. Like:
using System.Collections.Generic; // For list
private List<GameObject> objectList;
public float randomMin = 2f;
public float randomMax = 4f;
void Start(){
objectList = new List<GameObject>();
Spawn();
}
void Spawn()
{
objectList.Clear(); ///For multiple spawn purpose dont dublicate items.
float startPosX = 0f; // I assume your camera look at 0,0,0 point.
for (int i = 0; i < 10; i++){
Vector3 spawnPos = new Vector3(startPosX,0f,0f);
GameObject newObject = Instantiate(obj, spawnPos, Quaternion.identity) as GameObject;
objectList.Add(newObject);
float randomX = Random.Range(randomMin,randomMax);
startPosX+=randomX;
}
}
void DestroyObject(){
for(int i=0;i<objectList.Count;i++){
Destroy(objectList[i]);
}
}