Unity C# Script, Vector3 not updating - c#

Here is my code, brick_col is updating itself as it should be, print(brick_col), tells me once the loop is complete brick_col is +1 itself, but, print (positions[i]), tells me my y value is always 0) the Vector3 isn't being updated with the value. Any ideas? Many thanks
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Brick_Spawn_Test : MonoBehaviour {
List<Vector3> positions = new List<Vector3>();
private int bricks_in_row=9;
public GameObject Brick;
private int no_in_row=9;
private int brick_col=0;
private int number_of_brick_col=2;
void Start(){
Check_Bricks ();
}
void Check_Bricks(){
if (brick_col != number_of_brick_col) {
print ("not enough bricks");
Create_Bricks ();
}
}
void Create_Bricks(){
for (int i = 0; i <= bricks_in_row-1; i++)
{
for (int a = -4; a <= no_in_row/2; a++)
{
positions.Add(new Vector3(a,brick_col,0f));
}
print (brick_col);
print (positions [i]);
transform.position = positions[i];
Instantiate(Brick,transform.position, transform.rotation);
}
brick_col = brick_col + 1;
Check_Bricks ();
}
}

In your code you use the following variable as your y value
private int brick_col=0;
In your inner loop you add elements to your positions list with
positions.Add(new Vector3(a,brick_col,0f));
Without updating the brick_col until you are outside both loops.
Move this brick_col = brick_col + 1;
to where you want the update to really happen and if you put it into the inner loop you will probably also want to reset it just before entering again.

Alright honestly, you are doing some unnecessary things I will explain why as I go over it, I do things like this at times as well when I am trying to figure out what is going on, or when I am in a rush to build something I am excited to try, so starting out I will use your code and explain, then the fix then I will show another way to do this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Brick_Spawn_Test : MonoBehaviour {
List<Vector3> positions = new List<Vector3>();
private int bricks_in_row=9;
public GameObject Brick;
private int no_in_row=9; // No need for a number in row because you have bricks in row which is the same thing.
private int brick_col=0; // No need for this variable, as you are going to be counting anyways (in this case your i variable)
private int number_of_brick_col=2;
void Start(){
Check_Bricks ();
}
void Check_Bricks(){ // This function is unnessary, it appears it may have been added when you were trying to fix your y issue.
if (brick_col != number_of_brick_col) {
print ("not enough bricks");
Create_Bricks ();
}
}
void Create_Bricks(){
for (int i = 0; i <= bricks_in_row-1; i++) // This will run 9 times.
{
for (int a = -4; a <= no_in_row/2; a++) // This will also run 9 times
{
positions.Add(new Vector3(a,brick_col,0f));
}
// Move all this into the inner loop.
print (brick_col);
print (positions [i]); // By this point you will have 9 then 18 then 27... as your inner loop this position would be positons[i * bricks_in_row + (a +4)] with how you are looping
transform.position = positions[i]; /// This positions should be based off of the individual brick, next time around you are setting this position to the second index but by this time you have 18.
Instantiate(Brick,transform.position, transform.rotation);
//
// brick_col = brick_col + 1; This will be in the outter loop
}
brick_col = brick_col + 1; // This should be before the closing bracket. not outside the loop
Check_Bricks ();
}
}
This is how it would look, if I kept your variables and just fixed your y and positioning problems:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Brick_Spawn_Test : MonoBehaviour {
List<Vector3> positions = new List<Vector3>();
private int bricks_in_row=9;
public GameObject Brick;
private int no_in_row=9;
private int brick_col=0;
private int number_of_brick_col=2;
void Start(){
Check_Bricks ();
}
void Check_Bricks(){
if (brick_col != number_of_brick_col) {
print ("not enough bricks");
Create_Bricks ();
}
}
void Create_Bricks(){
for (int i = 0; i <= bricks_in_row-1; i++)
{
for (int a = -4; a <= no_in_row/2; a++)
{
positions.Add(new Vector3(a,brick_col,0f));
print (brick_col);
print (positions [i * bricks_in_row + a +4]);
transform.position = positions[i * bricks_in_row + a +4];
Instantiate(Brick,transform.position, transform.rotation);
}
brick_col = brick_col + 1;
}
Check_Bricks ();
}
}
This is a way to handle this, you can ignore the way I name variables as it is a matter of preference:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Brick_Spawn_Test : MonoBehaviour {
[SerializeField]
private int totalBrickColumns = 9; // Serializing it so I can use this for multiple test cases and edit the variable in the inpsector.
[SerializeField]
private int totalBrickRows = 2;
[SerializeField]
private Vector2 startingPoint = new Vector2(-4, 0);
[SerializeField]
private GameObject Brick;
void Start()
{
CreateBricks();
}
void CreateBricks()
{
Vector2 spawnPosition = startingPoint;
for(int x = 0; x < totalBrickColumns; ++x) // x is my column
{
spawnPosition.x = startingPoint.x + x; // the x is my offset from the startingPoint.x so if I wanted to start at -4 i just set the startingPoint.x to -4
for(int y = 0; y < totalBrickColums; ++y) // y is my row
{
spawnPosition.y = startingPoint.y + y; // the y is my offset from the startingPoint.y
print("Brick Location: " + spawnPosition.toString());
Instantiate(Brick,spawnPosition, transform.rotation);
}
}
}
}
In regards to why your y isn't updating, is because you are not updating the variable inside of your first loop. See the comment in your code on brick_col in the Create_Brick() function.
EDIT: I noticed something I wasn't considering when I said you needed to update your outter loop, I also added a fix using only your code, with your variables.

Related

can not render after camera deleted

in the problem of today is about unity
well i 'm always in the beginnings so i just took a full asset from the store
so while applying some changes i just get a crazy error saying that no cameras rendering
in the start of the project everything work smoothly
this is the script linked to the camera
this script just trying to make a map generator not completed yet
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGen : MonoBehaviour
{
public GameObject[] flats=new GameObject[4];
public GameObject flat;
public int x;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = flat.transform.position;
x = pos.x;
Debug.Log("position :: "+ x );
if(x%26 == 0)
{
Destroy(flats[0]);
for(int i = 0; i < 3; i++)
{
flats[i] = flats[i + 1];
}
flats[3] = flat;
Debug.Log("position "+x);
}
}
}
all works great but when trying this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGen : MonoBehaviour
{
public GameObject[] flats=new GameObject[4];
public GameObject flat;
public int x;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = flat.transform.position ;
x=(int) pos.x;
Debug.Log("position :: "+ x );
if(x%26 == 0)
{
Destroy(flats[0]);
for(int i = 0; i < 3; i++)
{
flats[i] = flats[i + 1];
}
flats[3] = flat;
Debug.Log("position "+x);
}
}
}
it just give me the error after running the game just like if the camera was destroyed and as you can see it is just this expression that was changed
x=pos.x;
to
x=(int) pos.x;
by the way the variable flat is referring to the main camera
you end up assigning your camera to the array and end up moving it up to [0] position and destroying it
flats[3] = flat;
flats[i] = flats[i + 1];
Destroy(flats[0]);

How can I generate stairs?

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);
}
}

Unity Moving Instantiated Objects

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)

How can I add/destroy new objects to existing formation?

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.

Start/Update variable scoping

I have a SceneController that's supposed to initialize a set of empty GameObject spawners, each working together at the same rhythm. The RockSpawners receive an array of time delays and wait the X seconds between spawning another rock.
I set the _nextSpawn = float.maxValue when the spawners start and plan to overwrite this after "Initializing" them (my own method), however even though my debug logs say I've overwritten my _nextSpawn value while initializing, the update loop is still reporting float.maxValue and nothing ends up spawning because _timeSinceLastSpawn hasn't exceeded float.maxValue seconds.
Is there something I'm missing with the scope of my _nextSpawn variables? It doesn't seem to be a "this" vs "local" issue, at least at first glance.
Debug output: 0 0 3 3. 0's stay the same, 3's will vary based on rng.
SceneController.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneController : MonoBehaviour {
[SerializeField] private GameObject _rockSpawnerPrefab;
public int numRocks = 6;
public int minSpawnDelaySec = 1;
public int maxSpawnDelaySec = 3;
private bool spawnersInitialized = false;
void Start () {
InitializeSpawners();
}
void Update () {
}
void InitializeSpawners() {
float[] pattern = new float[numRocks];
for (int i = 0; i < numRocks; i++) {
// Generate delays at half second increments within bounds
float delay = Mathf.Floor(Random.value * ((float)(maxSpawnDelaySec + 0.5f - minSpawnDelaySec) / 0.5f));
delay = delay * 0.5f + minSpawnDelaySec;
pattern[i] = delay;
}
GameObject spawner = Instantiate(_rockSpawnerPrefab) as GameObject;
spawner.transform.position = new Vector3(0, 4, 0);
RockSpawner rockSpawnerScript = spawner.GetComponent<RockSpawner>();
rockSpawnerScript.Initialize(pattern);
}
}
RockSpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RockSpawner : MonoBehaviour {
[SerializeField] private GameObject _rockPrefab;
public float minSpawnDelay = 3f;
public float maxSpawnDelay = 6f;
private float[] _pattern;
private int _currentPattern;
private float _timeSinceLastSpawn;
private float _nextSpawn;
void Start () {
_currentPattern = -1;
_nextSpawn = float.MaxValue;
}
void Update () {
if (_pattern == null) return;
_timeSinceLastSpawn += Time.deltaTime;
if (_timeSinceLastSpawn > _nextSpawn) {
GameObject rock = Instantiate(_rockPrefab) as GameObject;
rock.transform.position = transform.position;
NextTimer();
}
}
public void Initialize(float[] pattern) {
_pattern = pattern;
NextTimer();
}
private void NextTimer() {
_timeSinceLastSpawn = 0;
_currentPattern += 1;
Debug.Log(_nextSpawn);
Debug.Log(this._nextSpawn);
this._nextSpawn = _pattern[_currentPattern];
Debug.Log(_nextSpawn);
Debug.Log(this._nextSpawn);
}
}
It's not about scoping, it's about call order. When you create a GameObject its Start method is called on the frame it's enabled, not when the object is created. So your code will call Initialize first, then Start which overwrites the values.
Remove the code in Start and handle everything in Initialize and it should work as you want.

Categories

Resources