I am trying to spawn prefabs (clone object) AGAIN with random position after it's SetActive(false).
What I want :
After Swimmer Object enter trigger with Prefabs (clone object),
set Prefabs (clone object) to SetActive(false) and then it must spawn in random position.
What I have done :
Swimmer.cs <-- This is make clone abject SetActive(false) when trigger
void OnTriggerEnter2D (Collider2D other) {
if (other.gameObject.tag == "Trash") {
other.gameObject.SetActive (false);
}
}
Trash.cs
public GameObject columnPrefab;
public int columnPoolSize = 5;
public float spawnRate = 3f;
public float columnMin = -1f;
public float columnMax = 3.5f;
private GameObject[] columns;
private int currentColumn = 0;
private Vector2 objectPoolPosition = new Vector2 (-15,-25);
private float spawnXPosition = 10f;
private float timeSinceLastSpawned;
void Start()
{
timeSinceLastSpawned = 0f;
columns = new GameObject[columnPoolSize];
for(int i = 0; i < columnPoolSize; i++)
{
columns [i] = (GameObject)Instantiate (columnPrefab, objectPoolPosition, Quaternion.identity);
}
}
void Update()
{
timeSinceLastSpawned += Time.deltaTime;
if (GameControl.instance.gameOver == false && timeSinceLastSpawned >= spawnRate) {
timeSinceLastSpawned = 0f;
float spawnYPosition = Random.Range (columnMin, columnMax);
// This part what I am using to set it active
columns [currentColumn].SetActive(true);
columns [currentColumn].transform.position = new Vector2 (spawnXPosition, spawnYPosition);
currentColumn++;
if (currentColumn >= columnPoolSize) {
currentColumn = 0;
}
}
}
What I have got :
Prefabs (Clone Object) succeed spawn but on wrong position (float on right)
You can take a look at this image
So, how to SetActive clone object and spawn it for random position? Thanks
There isn't actually a problem, and everything in your game is working like it should.
You have your Scene View scrolled out slightly further than your Game View. You can see that if you look at the green seaweed on the left of your screen. See how your Scene View shows more leaves?
The Scene View is purely for the Unity editor, and you can zoom and scroll around independently of where your camera is in your Game View. If you want to move the camera within your Game View, you have to either change the camera parameters on the Main Camera object in your Hierarchy, or you can update Camera.main through code.
Related
I have almost finished my first game in Unity, which is a simple maze with characters collecting different coins. As it was a hassle to manually put all the different coins in the terrain, I decided to try and make a random generator for the coins.
The script is largely working, but the problem is that it's spawning objects most of the time inside walls. So I tried to add rigid bodies to coins, but this is messing with the coins position as the coins have a script for rotation. I also have the coins collision triggered because they perform a certain action when colliding with the character.
So after some research I saw that I need to check in my generator script for a near object collision and somehow change the spawn position of the coin if it's true. I'm trying to figure out how I can do that. My script is attached to my terrain and it looks like this:
using System.Collections;
using CustomArrayExtensions;
using UnityEngine;
public class ObjectSpawner : MonoBehaviour
{
[SerializeField] public GameObject[] letters;
GameObject selectedObject;
private int amount = 0;
public int limit;
void Start()
{
StartCoroutine(SpawnObjects());
}
IEnumerator SpawnObjects()
{
selectedObject = letters.GetRandom();
while (amount < limit)
{
Instantiate(selectedObject, new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f)), Quaternion.identity);
yield return new WaitForSeconds(5.0f);
amount++;
}
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == "Fox_Main")
{
Debug.Log("Collision Detected");
}
}
}
So i tried both answers and they didn't help me.Coins and other objects is still spawning close/inside the walls.My boxes have box collider and rigidbody with all positions/rotations locked(i need it that way so that i can destroy it later without moving it with the character),walls have box collider.So i tried to modify your solutions following Unity Documentation.I failed too.Here is what i have done so far.
See here
using System.Collections;
using UnityEngine;
public class RandomCrates : MonoBehaviour
{
public GameObject[] crates;
private GameObject selectedCrate;
public int limit = 0;
public float x, y, z;
public float forX_From,forX_To,forZ_From,forZ_To;
private int mask = 1 << 7;
void Start()
{
StartCoroutine(SpawnObjects());
}
IEnumerator SpawnObjects()
{
for (int i = 0; i < crates.Length; i++)
{
for (int j = 0; j < limit; j++)
{
Vector3 freePos = GetFreePosition();
Instantiate(crates[i], freePos, Quaternion.identity);
yield return new WaitForSeconds(0.0f);
}
}
}
Vector3 GetFreePosition()
{
Vector3 position;
Collider[] collisions = new Collider[1];
do
{
position = new Vector3(Random.Range(forX_From, forX_To), 10.0f, Random.Range(forZ_From, forZ_To));
} while (Physics.OverlapBoxNonAlloc(position, new Vector3(x, y, z), collisions, Quaternion.identity, mask) > 0);
return position;
}
}
Unity provides a simple way to detect collisions in specific position with Physics.OverlapSphere:
public class ObjectSpawner : MonoBehaviour
{
[SerializeField] public GameObject[] letters;
GameObject selectedObject;
private int amount = 0;
public int limit;
private float radius = 2f; //Radius of object to spawn
void Start()
{
StartCoroutine(SpawnObjects());
}
IEnumerator SpawnObjects()
{
selectedObject = letters[Random.Range(0, letters.Length)];
while (amount < limit)
{
Vector3 spawnPos = new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f));
//Check collisions
if (DetectCollisions(spawnPos) > 0)
continue;
Instantiate(selectedObject, spawnPos, Quaternion.identity);
yield return new WaitForSeconds(5.0f);
amount++;
}
}
private int DetectCollisions(Vector3 pos)
{
Collider[] hitColliders = Physics.OverlapSphere(pos, radius);
return hitColliders.Length;
}
}
In this way, if there is a collision in spawn position, the coin will not be spawned.
There are different ways of approaching this problem and given more information one could come up with a smarter approach. However, to provide you with a simple solution to your problem: You could just pick random positions until you find a "free spot".
Assuming your coins to have a size of 1, you could do something like:
IEnumerator SpawnObjects()
{
selectedObject = letters.GetRandom();
while(amount < limit)
{
Vector3 freePos = GetFreePosition();
Instantiate(selectedObject, freePos), Quaternion.identity);
yield return new WaitForSeconds(5.0f);
amount++;
}
}
Vector3 GetFreePosition()
{
Vector3 position;
Collider[] collisions = new Collider[1];
do
{
position = new Vector3(Random.Range(35.0f, 950.0f), 13.0f, Random.Range(35.0f, 950.0f));
}
while(Physics.OverlapSphereNonAlloc(position, 1f, collisions) > 0);
return position;
}
Please note that Physics.OverlapSphereNonAlloc() can also accept a LayerMask for filtering collisions based on layers. You might want to look into this, to prevent detecting collision with your terrain, which may well keep the do-while loop from exiting and freeze Unity.
Im working on unity2D game and im working on instantiating prefabs, im generating my prefabs in a good way but the problem is that i want a space between them when they are generated, i meant when prefabs are generating i want to add space between them in position x, there is my code:
public class WaveSpawn : MonoBehaviour
{
public GameObject[] easyWaves;
public GameObject[] mediumWaves;
public GameObject[] hardWaves;
public GameObject Player;
// Start is called before the first frame update
void Start()
{
SpawnWave();
}
// Update is called once per frame
void Update()
{
}
public void SpawnWave()
{
float CharacSpeed = Player.GetComponent<charachter>().moveSpeed;
float spacing = 0.1f;
if(CharacSpeed < 11){
Instantiate(easyWaves[Random.Range(0,easyWaves.Length)], new Vector3(gameObject.transform.position.x, gameObject.transform.position.y,0) , Quaternion.identity);
}
else if(CharacSpeed >= 11 && CharacSpeed < 14){
Instantiate(mediumWaves[Random.Range(0,mediumWaves.Length)], new Vector3(gameObject.transform.position.x , gameObject.transform.position.y,0), Quaternion.identity);
}
else if(CharacSpeed >= 14){
Instantiate(hardWaves[Random.Range(0,hardWaves.Length)], new Vector3(gameObject.transform.position.x, gameObject.transform.position.y,0), Quaternion.identity);
}
}
}
any help please? notice that my prefabs are generating correctly, the problem is only on position x
It looks to me like your code will only spawn a single prefab from one of your GameObject arrays. What it does is:
Look at the CharacSpeed
Based on the CharacSpeed, instantiate a single randomly selected GameObject from either easyWaves, mediumWaves or hardWaves.
So, I'm not sure what you mean by spacing your prefabs since there is only one prefab spawned.
Try this:
public void SpawnWave()
{
GameObject[] selectedWaves = new GameObject[];
float CharacSpeed = Player.GetComponent<charachter>().moveSpeed;
float spacing = 0.1f;
if(CharacSpeed < 11){
selectedWaves = easyWaves;
}
else if(CharacSpeed >= 11 && CharacSpeed < 14){
selectedWaves = mediumWaves;
}
else if(CharacSpeed >= 14)
{
selectedWaves = hardWaves;
}
for (int i = 0; i < selectedWaves.Length; i++) {
Instantiate(selectedWaves[Random.Range(0,selectedWaves.Length)], new Vector3(gameObject.transform.position.x + (spacing * i), gameObject.transform.position.y,0) , Quaternion.identity);
}
}
You should then be able to adjust the amount of spacing by changing the float spacing = 0.1f value.
This assumes that you want to spawn as many prefabs as are contained in your GameObject arrays (and may want to spawn the same one multiple times). If not, change selectedWaves.Length in the for loop to whatever number of prefabs you want spawned.
I have Array Elements I got them on an Empty GameObject, I mean [SerializeField] and added through the script (C# Ofcourse), So the Objects are not really there they are being Generated when the Game begins. How can I clone the Collider from the Empty GameObject onto the clones in order to make them clickable? So far as of right now only the first one works witch is also the possition of the empty GameObject who has the colider on it now I need them onto the Clones as well... but,...How?
I tried to apply the collider to the sprites I even tried turning them into Prefab Its All hopeless. I do think It has to be on the script but I cannot find a code example of it....
public class Controll : MonoBehaviour {
public const int gridRows = 6;
public const int gridCols = 6;
public const float offsetX = 1.70f;
public const float offsetY = 0.97f;
[SerializeField] private GameObject[] cardBack;
[SerializeField] private GameObject[] positioner;
public AudioSource sound;
public void OnMouseDown()
{
if (Input.GetMouseButtonDown(0))
{
sound.Play();
}
}
//AudioSource audioSource;
// Use this for initialization
void Start ()
{
// audioSource = GetComponent<AudioSource>();
Vector3 startPos = positioner[0].transform.position;
for (int i = 0; i < gridRows; i++)
{
for (int j = 0; j < gridCols; j++)
{
var position = transform.position + new Vector3(offsetX * j, offsetY * i * -1, -0.1f);
Instantiate(cardBack[i], position, Quaternion.identity, transform);
}
}
}
I need to be able to click on these elements so they be playing a sound when i click and disappear....
I figured out a solution...
# BugFinder
I had cut out the function "on mouse down" and pasted it onto a separated script with just that function and applied that to all the prefabs while the other script with all other functions has stayed on the game-object. So that seems to work well so far.....
I am trying to instantiate a number of planes to use as my terrain and give them OnMouseOver() to change them to some color and OnMouseExit() to change them back to the original color.
I attached a plane instantiation script to the main camera to generate the plane prefab and a mouse event script to the plane prefab. I get them all instantiated and the events pass to them, but in-game the mouse events are being applied to either long strips of planes, an entire quadrant, or a random single plane not at the location of the mouse cursor.
I made a new material and applied it to the place prior to turning it into a prefab to replace the standard material set upon creation of the plane.
I have started attempting to use the mouse position to apply the color change to the plane at the current mouse position with Physics.CheckSphere, but I don't fully understand how to tell specifically what gameObject is at a specific position.
public class TerrainGeneration : MonoBehaviour {
[SerializeField]
private Transform groundTile;
private Vector3 row;
private int max = 10;
// Use this for initialization
void Start () {
for ( int i = 0; i <= max; i++)
{
for (int x = 0; x <= max; x++) {
row = new Vector3(i, 0, x);
Instantiate(groundTile, row, Quaternion.identity);
}
}
}
}
public class MouseEvents : MonoBehaviour {
private Color isTargeted;
private Color notTargeted;
private MeshRenderer groundTileMeshRenderer;
private Vector3 mousePosition;
private float mouseX;
private float mouseY;
void Start () {
groundTileMeshRenderer = gameObject.GetComponent<MeshRenderer>();
isTargeted = Color.cyan;
notTargeted = groundTileMeshRenderer.material.color;
}
void Update()
{
mouseX = Mathf.RoundToInt(Input.GetAxis("Mouse X"));
mouseY = Mathf.RoundToInt(Input.GetAxis("Mouse Y"));
mousePosition = new Vector3(mouseX, 0, mouseY);
if (Physics.CheckSphere(mousePosition, 1))
{
**//Get the specific gameObject located at the current mouse position
//Set the gameObject as the target for the color change**
}
}
void OnMouseOver()
{
groundTileMeshRenderer.material.color = isTargeted;
}
void OnMouseExit()
{
groundTileMeshRenderer.material.color = notTargeted;
}
}
So, I found out what the answer is thanks to the Unity forums. My error was in the instantiation transform script. Because I was using the plane primitive 3d object I was not accounting for the size of the plane correctly. The following code snippet for instantiation of each row removes the overlapping that was occurring as the planes are too large to simply place at (0,0,0), (0,0,1), (0,0,2) for example.
row = new Vector3(i * 10, 0, x * 10);
Instantiate(groundTile, row, Quaternion.identity);
tag your gameObjects as necessary and then you can identify them.
If you do, then you can use them like so (purely for example):
public virtual void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "planeA")
{
//do something
}
}
I created a Quad. I assigned this script to the Quad that contains an array of Game Objects:
public class ShapeGrid : MonoBehaviour {
public GameObject[] shapes;
void Start(){
GameObject[,] shapeGrid = new GameObject[3,3];
StartCoroutine(UpdateGrid());
}
IEnumerator UpdateGrid(){
while (true) {
SetGrid ();
yield return new WaitForSeconds(2);
}
}
void SetGrid(){
int col = 3, row = 3;
for (int y = 0; y < row; y++) {
for (int x = 0; x < col; x++) {
int shapeId = (int)Random.Range (0, 4.9999f);
GameObject shape = Instantiate (shapes[shapeId]);
Vector3 pos = shapes [shapeId].transform.position;
pos.x = (float)x*3;
pos.y = (float)y*3;
shapes [shapeId].transform.position = pos;
}
}
}
}
I cloned those Game Objects so that they appear on a grid like this:
When the user clicks an object, it should disappear. What I did was place this script on every element in my array of Game Objects:
public class ShapeBehavior : MonoBehaviour {
void Update(){
if(Input.GetMouseButtonDown(0)){
Destroy(this.gameObject);
}
}
}
But what happens is when I click on an object to destroy it, every clone of that object will be destroyed. I want only the specific clone to be destroyed, not everything. How do I do that?
The problem is on your Input call, "Input.GetMouseButtonDown(0)" is true in every script when you click the button on mouse, no matter the position of mouse. Attach any kind of collider to gameObject and set it up and put the script with OnMouseDown() method, look here for more info : http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
You can also use raycasting but that's more advanced way of solving this.
Also replace this.gameObject with just gameObject.