The code below works Except for the Instancated objects moving on their own. I want my Instancated objects to move back and fourth between pointA and pointB at a speed 0.5f.
Note: Im not trying to use the commented code in Start() and Update() because this file is attached to the camera.
With current code: My objectList objects are moving as expected just not their instantiated objects. I would like the Instantiated objects to move like ping-pong with their off-set
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectsSpawner : MonoBehaviour {
public GameObject[] objectList;
public GameObject[] objectSpawns;
int val;
public float speed = 0.5f;
Vector3 pointA;
Vector3 pointB;
// Use this for initialization
void Start () {
val = PlayerPrefs.GetInt("CannonPowerVal");
addToList();
for (int i = 1; i < objectSpawns.Length; i++){
pointA = new Vector3(-3.8f, objectSpawns[i].transform.localPosition.y, 0);
pointB = new Vector3(3.8f, objectSpawns[i].transform.localPosition.y, 0);
}
//pointA = new Vector3(-3.8f, transform.localPosition.y, 0);
//pointB = new Vector3(3.8f, transform.localPosition.y, 0);
}
// Update is called once per frame
void Update()
{
//PingPong between 0 and 1
float time = Mathf.PingPong(Time.time * speed, 1);
//transform.position = Vector3.Lerp(pointA, pointB, time);
for (int i = 1; i < objectSpawns.Length; i++)
{
objectSpawns[i].transform.position = Vector3.Lerp(pointA, pointB, time);
}
}
public void addToList(){
objectSpawns = new GameObject[val];
int max = objectList.Length;
int counter = 8; // set first object out of screen sight
// Adds Scene Objects from objectList to objectSpawns
// Size of SceneObjects determined by CannonPowerVal
for (int i = 0; i < PlayerPrefs.GetInt("CannonPowerVal"); i++){
objectSpawns.SetValue(objectList[Random.Range(0, max)], i);
// Random x spawn(-2.8f, 2.8f)
Instantiate(objectSpawns[i], new Vector2(transform.localPosition.x + Random.Range(-2.8f,2.8f), transform.localPosition.y + counter), Quaternion.identity);
counter = counter + 5;
}
}
}
after instantiating the object, you forgot to add the reference to the list of objectSpawns.
In addToList() method do:
GameObject object = Instantiate(objectSpawns[i],...);
objectSpawns.Add(object)
Related
I am generating gameobjects (spheres) based on coordinates, which are stored in a .csv file. I have a Gameobject with a Single Sphere as primitive childobject. Based on the data the Object will clone this sphere 17 times and move them around. I can move the whole thing around like i want it to by accessing the parent object, but in editing mode the position of the root sphere makes it uneasy to use.
The following Code makes this possible.
public GameObject parentObj;
public TextAsset csvFile;
[SerializeField]
private float scaleDownFactor = 10;
private int index = 0;
//class Deck : MonoBehaviour
//{
[SerializeField]
private GameObject[] deck;
private GameObject[] instanciatedObjects;
private void Start()
{
Fill();
}
public void Fill()
{
instanciatedObjects = new GameObject[deck.Length];
for (int i = 0; i < deck.Length; i++)
{
instanciatedObjects[i] = Instantiate(deck[i]) as GameObject;
}
}
//}
// Update is called once per frame
void Update()
{
readCSV();
}
void readCSV()
{
string[] frames = csvFile.text.Split('\n');
int[] relevant = {
0
};
string[] coordinates = frames[index].Split(',');
for (int i = 0; i < 17; i++)
{
float x = float.Parse(coordinates[relevant[i] * 3]) / scaleDownFactor;
float y = float.Parse(coordinates[relevant[i] * 3+1]) / scaleDownFactor;
float z = float.Parse(coordinates[relevant[i] * 3+2]) / scaleDownFactor;
//objectTest.transform.Rotate(float.Parse(fields[1]), float.Parse(fields[2]), float.Parse(fields[3]));
//objectTest.transform.Translate(x, y, z);
//parentObj.transform.position = new Vector3(x, y, z);
instanciatedObjects[i].transform.position = new Vector3(parentObj.transform.position.x, parentObj.transform.position.y, parentObj.transform.position.z);
instanciatedObjects[i].transform.eulerAngles = new Vector3(parentObj.transform.eulerAngles.x, parentObj.transform.eulerAngles.y, parentObj.transform.eulerAngles.z);
//instanciatedObjects[i].transform.position = new Vector3(x, y, z);
instanciatedObjects[i].transform.Translate(x, y, z);
}
if (index < frames.Length - 1)
{
index++;
}
if (index >= frames.Length -1)
{
index = 0;
}
}
Here is a Screenshot:
So my question is:
How can I set the Position of this Sphere to one of the moving points, without changing the position of the cloned objects? Since all behave based on the BaseSphere?
Is it possible to make the BaseSphere not visible While the Objects are getting cloned or generated?
I am looking for a solution, that makes it easier to move the datagenerated Object around in Editor.
I would appreciate any kind of input.
Make all Spheres children of Empty Gameobject (for example. Sphere_root) and use this for moving Spheres.
Also check Scriptable Objects. It is simple and very quick method to manage data in Unity.
#Edit
public void Fill()
{
instanciatedObjects = new GameObject[deck.Length];
for (int i = 0; i < deck.Length; i++)
{
instanciatedObjects[i] = Instantiate(deck[i]) as GameObject;
instanciatedObjects[i].transform.parent = Baumer; // or Sphere Root or somehing else.
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
public GameObject stairsPrefab;
public int delay = 3;
public int stairsNumber = 5;
public int stairsHeight = 0;
public Vector3 stairsPosition;
public Vector2 stairsSize;
// Use this for initialization
void Start ()
{
StartCoroutine(BuildStairs());
}
// Update is called once per frame
void Update ()
{
}
private IEnumerator BuildStairs()
{
for (float i = 0; i <= stairsSize.x; i++)
{
for (float k = 0; k <= stairsSize.y; k++)
{
stairsPosition = new Vector3(i, stairsHeight, k);
GameObject stairs = Instantiate(stairsPrefab, stairsPosition, Quaternion.identity);
stairs.transform.localScale = new Vector3(stairsSize.x, 1 , stairsSize.y);
stairsHeight += 1;
yield return new WaitForSeconds(delay);
}
}
}
private void CalculateNextStair()
{
}
}
I messed it up. For example I want to build 5 stairs but the loops are over the stairs size and not number of stairs.
Second it's creating 10 sets of stairs not 5 stairs:
Another problem is how can I make that each stair will be build slowly ? Now it's just Instantiate slowly with delay but how can I generate each stair with delay?
Screenshot of the script inspector:
My current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
public GameObject stairsPrefab;
public float delay = 0.3f;
public int stairsNumber = 5;
public int stairsPositions = 0;
public int stairsStartPositionHeight = 0;
public float stairsScalingHaight = 1;
public Vector2 stairsPosition;
public Vector2 stairsSize;
// Use this for initialization
void Start()
{
StartCoroutine(BuildStairs());
}
// Update is called once per frame
void Update()
{
}
private IEnumerator BuildStairs()
{
for (float i = 0; i <= stairsNumber; i++)
{
// x=0f, y=z=stairsHeight
stairsPosition = new Vector3(0f, stairsPositions, stairsPositions);
GameObject stairs = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stairs.transform.localScale = new Vector3(
stairsSize.x,
stairsScalingHaight,
stairsSize.y);
stairsStartPositionHeight += 1;
yield return new WaitForSeconds(delay);
}
}
private void CalculateNextStair()
{
}
}
There's no reason to loop over the size of the stairs at all; you want to loop over stairsNumber, which is yet unused in your code.
Also, you don't need to change the x component of your stairs' positions. Keep it at 0f (or whatever you need).
The y and z components of your stairs positions (relative to the starting point) should both be factors of stairHeight. In this particular case, you want them to be equal to stairHeight, so that you get "square" step shapes.
private IEnumerator BuildStairs()
{
for (int i = 0; i <= stairsNumber ; i++) {
// x=0f, y=z=stairsHeight
stairsPosition = new Vector3(0f, stairsHeight, stairsHeight);
GameObject stairs = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stairs.transform.localScale = new Vector3(
stairsSize.x,
1f ,
stairsSize.y);
stairsHeight += 1f;
yield return new WaitForSeconds(delay);
}
}
If you change stairSize to be a Vector3, then you can just use stairSize directly as the localScale, and increment stairsHeight by stairsSize.y instead of just 1f.
If you want to offset the starting position of your stairs, you need to include an offset. I recommend keeping it separate from the height counter until you need to add them.
Also, if you want to have rectangular sized steps, keep a widthFactor to multiply by the height to find how far each step moves horizontally.
Combining these changes might look like this:
Vector3 stairSize;
float stepWidthFactor=1f;
Vector3 stairsStartPosition;
private IEnumerator BuildStairs() {
for (int i = 0; i <= stairsNumber ; i++) {
stairsPosition = new Vector3(
stairsStartPosition.x,
stairsStartPosition.y + stairsHeight,
stairsStartPosition.z + stairsHeight*stepWidthFactor);
GameObject stairs = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stairsHeight += stairsSize.y;
stairs.transform.localScale = stairSize;
yield return new WaitForSeconds(delay);
}
}
In the manager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FormationsManager : MonoBehaviour
{
public Transform squadMemeberPrefab;
public int numberOfSquadMembers = 20;
public int columns = 4;
public int gaps = 10;
public Formations formations;
private int numofmembers;
// Use this for initialization
void Start()
{
numofmembers = numberOfSquadMembers;
formations.Init(numberOfSquadMembers, columns, gaps);
GenerateSquad();
}
// Update is called once per frame
void Update()
{
if (numofmembers != numberOfSquadMembers)
{
GenerateSquad();
}
}
private void GenerateSquad()
{
Transform go = squadMemeberPrefab;
for (int i = 0; i < formations.newpositions.Count; i++)
{
go = Instantiate(squadMemeberPrefab);
go.position = formations.newpositions[i];
go.tag = "Squad Member";
go.transform.parent = gameObject.transform;
}
}
}
And the Formations script:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Formations : MonoBehaviour
{
public List<Vector3> newpositions;
private int numberOfSquadMembers;
private int columns;
private int gaps;
private List<Quaternion> quaternions;
private Vector3 FormationSquarePositionCalculation(int index)
{
float posX = (index % columns) * gaps;
float posY = (index / columns) * gaps;
return new Vector3(posX, posY);
}
private void FormationSquare()
{
newpositions = new List<Vector3>();
quaternions = new List<Quaternion>();
for (int i = 0; i < numberOfSquadMembers; i++)
{
Vector3 pos = FormationSquarePositionCalculation(i);
Vector3 position = new Vector3(transform.position.x + pos.x, 0, transform.position.y + pos.y);
newpositions.Add(position);
}
}
public void Init(int numberOfSquadMembers, int columns, int gaps)
{
this.numberOfSquadMembers = numberOfSquadMembers;
this.columns = columns;
this.gaps = gaps;
FormationSquare();
}
}
What I want to do is in the FormationsManager in the Update not only just calling GenerateSquad but to add the new once to the last/next position of the existing already formation.
void Update()
{
if (numofmembers != numberOfSquadMembers)
{
GenerateSquad();
}
}
If the value of numberOfSquadMembers is 20 first time and then I changed it to 21 add new object to the end of the formation and same if I change the value of numberOfSquadMembers for example from 20 to 19 or from 21 to 5 destroy the amount of objects from the end and keep the formation shape.
The soldiers the last line is on the right side.
So if I change the value to add more then add it to the right and if I change to less destroy from the right side. The most left line of soldiers is the first.
It is possible if you keep GameObject instances inside FormationsManager class, and then reuse them in GenerateSquad method.
In FormationsManager class, add and modify code as follows.
public GameObject squadMemeberPrefab;
List<GameObject> SquadMembers = new List<GameObject>();
void Update()
{
if (numofmembers != numberOfSquadMembers)
{
numofmembers = numberOfSquadMembers;
formations.Init(numberOfSquadMembers, columns, gaps);
GenerateSquad();
}
}
private void GenerateSquad()
{
Transform go = squadMemeberPrefab;
List<GameObject> newSquadMembers = new List<GameObject>();
int i = 0;
for (; i < formations.newpositions.Count; i++)
{
if (i < SquadMembers.Count)
go = SquadMembers[i];
else
{
go = Instantiate(squadMemeberPrefab);
newSquadMembers.Add(go);
}
go.position = formations.newpositions[i];
go.tag = "Squad Member";
go.transform.parent = gameObject.transform;
}
for (; i < SquadMembers.Count; i++)
Destroy(SquadMembers[i]);
SquadMembers = newSquadMembers;
}
However, I recommend you to consider GameObject Pool (Object Pool), which can thoroughly resolve such object recycle problem. For this purpose, you can use ClientScene.RegisterSpawnHandler. Go to this Unity Documentation page and search text "GameObject pool". You can see an example code there.
I have a canvas and inside it a panel. I want to spawn different image UI object at random position inside my panel (on screen). I took x and y min and max limits of the panel in order to generate a random position (withing these limts) but the problem is object are not instantiating at desired position. This is my code.
public class ImageSpawnerScreen : MonoBehaviour {
public float waitTime = 2;
public float cubeSpawnTotal = 10;
public List<GameObject> cubePrefabList;
float xPosMinLimit = -347;
float xPosMaxLimit = 340;
float yPosMinLimit = -458f;
float yPosMaxLimit = 450f;
public GameObject panel;
void Start()
{
StartCoroutine(SpawnCube());
}
IEnumerator SpawnCube()
{
for (int i = 0; i < cubeSpawnTotal; i++)
{
GameObject prefabToSpawn = cubePrefabList[Random.Range(0, cubePrefabList.Count - 1)];
//Vector3 spawnPosition = Camera.main.ScreenToViewportPoint(new Vector3(Random.Range(0,Screen.width),0,Random.Range(0,Screen.height))); //Random.Range(xPosMinLimit, xPosMaxLimit);
float xPos = Random.Range(xPosMinLimit, xPosMaxLimit);
float yPos = Random.Range(yPosMinLimit, yPosMaxLimit);
Vector3 spawnPosition = new Vector3(xPos, yPos, 0f);
GameObject spwanObj = Instantiate(prefabToSpawn, spawnPosition, Quaternion.identity) as GameObject;
spwanObj.transform.parent = panel.transform;
spwanObj.transform.position = spawnPosition;
yield return new WaitForSeconds(waitTime);
}
}
}
I checked instantiated object positions are far away from the given random range position. What I am doing wrong? I think it is Rect Transform so i have to set its position differently.
Indeed, you need to use RectTransform inside a Canvas.
You also don't need the -1 for you List.Count. Check the link in the comment below.
I think the following script will do what you are looking for:
public class ImageSpawnerScreen : MonoBehaviour
{
public float waitTime = 2;
public float cubeSpawnTotal = 10;
public List<GameObject> imagesList;
public RectTransform panel;
void Start()
{
StartCoroutine(SpawnImage());
}
IEnumerator SpawnImage()
{
for (int i = 0; i < cubeSpawnTotal; i++)
{
GameObject imageToSpawn = imagesList[Random.Range(0, imagesList.Count)]; // Remove -1 after count since is exclusive for int (https://docs.unity3d.com/ScriptReference/Random.Range.html)
Vector3 spawnPosition = GetBottomLeftCorner(panel) - new Vector3(Random.Range(0, panel.rect.x), Random.Range(0, panel.rect.y), 0);
print("Spawn image at position: " + spawnPosition);
GameObject spwanObj = Instantiate(imageToSpawn, spawnPosition, Quaternion.identity, panel);
yield return new WaitForSeconds(waitTime);
}
}
Vector3 GetBottomLeftCorner(RectTransform rt)
{
Vector3[] v = new Vector3[4];
rt.GetWorldCorners(v);
return v[0];
}
}
Let me know if you need more explanations.
To manage Canvas object's position you should definitely use RectTransform instead of regular transform. In your case you have to do something like :
m_RectTransform = GetComponent<RectTransform>();
As for setting position - coordinates you see on the object inside Canvas is not .position but RectTransform.anchoredPosition, so you should use it in your code. Here is an official documentation on anchoredPosition.
public class ImageSpawnerScreen : MonoBehaviour {
public float waitTime = 2;
public float cubeSpawnTotal = 10;
public List<GameObject> cubePrefabList;
public GameObject panel;
void Start()
{
StartCoroutine(SpawnCube());
}
IEnumerator SpawnCube()
{
for (int i = 0; i < cubeSpawnTotal; i++)
{
GameObject prefabToSpawn = cubePrefabList[Random.Range(0, cubePrefabList.Count - 1)];
//Vector3 spawnPosition = Camera.main.ScreenToViewportPoint(new Vector3(Random.Range(0,Screen.width),0,Random.Range(0,Screen.height))); //Random.Range(xPosMinLimit, xPosMaxLimit);
float xPos = Random.Range(0, Screen.width);
float yPos = Random.Range(0, Screen.height);
Vector3 spawnPosition = new Vector3(xPos, yPos, 0f);
GameObject spwanObj = Instantiate(prefabToSpawn, spawnPosition, Quaternion.identity) as GameObject;
spwanObj.transform.parent = panel.transform;
spwanObj.transform.position = spawnPosition;
yield return new WaitForSeconds(waitTime);
}
}
}
This should help u out.
I was trying to generate a grid Unity3d and store all the tiles in an array. I want to use the created array also in others function.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class createGridClean : MonoBehaviour {
public GameObject tilePrefab = null;
public int numberOfTiles = 10;
public int tilesPerColumn = 4;
public float distanceBetweenTiles = 2.0f;
public Material newmat = null;
// Use this for initialization
void Start () {
CreateTiles ();
}
// Update is called once per frame
void Update () {
}
public ArrayList[] CreateTiles(){
GameObject[] allTiles = new GameObject[numberOfTiles*tilesPerColumn];
float xOffset = 0.0f;
float zOffset = 0.0f;
for (int createdTiles = 0; createdTiles <= numberOfTiles; createdTiles++) {
xOffset += distanceBetweenTiles;
if ( createdTiles % tilesPerColumn == 0){
zOffset += distanceBetweenTiles;
xOffset = 0.0f;
}
allTiles[createdTiles] = Instantiate (tilePrefab, new Vector3 (0f + xOffset, 0f, 0f + zOffset), Quaternion.identity) as GameObject;
}
return allTiles;
}
}
But here's the output:
Assets/my/Script/createGridClean.cs(34,17): error CS0029: Cannot implicitly convert type `UnityEngine.GameObject[]' to `System.Collections.ArrayList[]'
I have have even a problem with the grid, everytime an additional and unwanted extra cube were generated!
(here the original code that I've translated in C#)
function CreateTiles()
{
var xOffset: float = 0.0;
var zOffset: float = 0.0;
for(var tilesCreated: int = 0; tilesCreated < numberOfTiles; tilesCreated += 1)
{
xOffset += distanceBetweenTiles;
if(tilesCreated % tilesPerRow == 0)
{
zOffset += distanceBetweenTiles;
xOffset = 0;
}
Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation);
}
}
Any help will be fantastic!
Thanks,
Marco
Try changing
public ArrayList[] CreateTiles()
{
GameObject[] allTiles = new GameObject[numberOfTiles*tilesPerColumn];
...
return allTiles;
}
to:
public GameObject[] CreateTiles()
{
GameObject[] allTiles = new GameObject[numberOfTiles*tilesPerColumn];
...
return allTiles;
}
The error message you're getting: Cannot implicitly convert type X to Y refers to the fact that you're implicitly converting your GameObject[] to an ArrayList[]. You must either explicitly cast to an ArrayList[] (e.g. return (ArrayList[]) allTiles, although I'm not sure that's what you're after), or change your method to return a GameObject[].
Your question is a duplicate of all these other questions: https://stackoverflow.com/search?q=cannot+implicitly+convert