can not render after camera deleted - c#

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

Related

Unity. Script does not working with clones

I have created a script who will spawn objects and give tag and color for one element of prefab. But script not working with clones. This 2 scripts, GameManager( he must spawn objects) and
RandomTagAndColor( he give to element of prefab tag and name). And in scene of game, where objects is spawning, script give tag and colour only to first prefab. In game those prefabs 10. Well, I'm sorry if question is stupid, this first thing, what i doing without books,guides.
GameManager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class GameManager : MonoBehaviour
{
// Start is called before the first frame update
public GameObject firstBarrier;
public GameObject secondBarrier;
public int numOfBarriers = 0;
System.Random rnd = new System.Random();
System.Random rndY = new System.Random();
Vector3 vector = new Vector3(5, 1/3 , 1);
void Start()
{
for (numOfBarriers = 0; numOfBarriers < 10; numOfBarriers++)
{
int ewq = rnd.Next(1, 20);
int rY = rndY.Next(1, 4);
if(ewq <= 10)
{
Instantiate(firstBarrier, vector, Quaternion.identity);
}
else
{
Instantiate(secondBarrier, vector, Quaternion.identity);
}
vector.x -= 7;
vector.y = rY;
}
}
void Update()
{
}}
RandomColorAndTag script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class RandomColorAndTag : MonoBehaviour
{
GameObject Bar;
System.Random randomElement = new System.Random();
int el = 0 ;
void Start()
{
el = randomElement.Next(2, 6);
GameObject.Find($"Cube ({el})").GetComponent<Renderer>().material.color = Color.green;
if (GameObject.Find($"Cube ({el})").GetComponent<Renderer>().material.color == Color.green)
{
GameObject.Find($"Cube ({el})").transform.tag = "Green";
}
}
void Update()
{
}
}
As mentioned there are lot of unclear issues in your codes.
I will assume the RandomColorAndTag is attached to the objects you spawn. In that case don't use Find but rather simply assign the random color and tag to yourself
what is a random value between 1 and 19 good for, of all you ever do with it is check whether it is bigger or smaller than 10? => Simply use only a random 0 or 1 and check whether it is 0 ;)
I'm unsure exactly what items should be green now .. I assume among the 10 spawned items you want to pick one and make it special..
finally I wouldn't even let the objects assign their own tag and color but let the GameManager trigger it
So I would do something like
public class GameManager : MonoBehaviour
{
public TagAndColorController fortBarrier;
public TagAndColorController secondBarrier;
public int numOfBarriers = 10;
public Vector3 vector = new Vector3(5, 1f/3f , 1);
public Color specialColor = Color.Green;
public string specialTag = "Green";
private void Start()
{
var specialIndex = Random.Range(0, numberOfBarriers);
for (var i = 0; i < numOfBarriers; i++)
{
// upper bound is exclusive -> this returns 0 or 1
var rndBarrier = Random.Range(0, 2);
// not sure if intended but again: upper bound is exclusive -> this return 1, 2, or 3
var rY = Random.Range(1, 4);
var tagAndColor = Instantiate(rndBarrier == 0 ? firstBarrier : secondBarrier, vector, Quaternion.identity);
if(i == numberOfBarriers)
{
tagAndColor.SetColorAndTag(specialColor, specialTag);
}
vector.x -= 7;
vector.y = rY;
}
}
}
And the other script has no logic whatsoever but rather only is a quick access to the objects renderer and bundles the behavior
public class TagAndColorController : MonoBehaviour
{
[SerializeField] private Renderer _renderer;
public void SetColorAndTag(Color newColor, string newTag)
{
gameObject.tag = newTag;
if(!_renderer) _renderer = GetComponent<Renderer>();
_renderer.material.color = newColor;
}
}

Overwriting variable in Unity C#

I'm making a script in Unity using C#. I'm trying to use the Update() method to detect once the Camera position is past a certain point and then Instantiate an object into the scene and overwrite the variable "x" to something else so this only happens once.
The problem is I cant overwrite this "x" variable.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour{
public GameObject GroundSprite;
public int x = 1;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (((Camera.main.transform.position.x) < -4) && ( x == 1))
{
Instantiate(GroundSprite, transform.position, Quaternion.identity);
int x = 2;
}
}
}
Please remove int from below code, your value will be overwritten.
// Update is called once per frame
void Update()
{
if (((Camera.main.transform.position.x) < -4) && ( x == 1))
{
Instantiate(GroundSprite, transform.position, Quaternion.identity);
//int x = 2;
x=2;
}
}

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.

Unity C# Script, Vector3 not updating

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.

I have a for loop in C#, which works in conjuction with Unity engine. But how do i make it so it only calls the loop once?

To give some context:
In unity I have 2 boxes, which are both tagged "box"
One box is on a plane and the other in the air, when the game is played on box falls on the other.
Here is the console for the engine:
Material 1 (UnityEngine.Material)
UnityEngine.Debug:Log(Object)
colourChangeArray:OnCollisionEnter(Collision) (at Assets/colourChangeArray.cs:28)
With material 1 changing to material 2, 3, 4 to 5 and then doing the 1-5 cycle 10-20 times
Below is the code i'm using
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class colourChangeArray : MonoBehaviour
{
public int trigger = 1;
public Material[] material;
Renderer rend;
// Use this for initialization
void Start()
{
rend = GetComponent <Renderer> ();
rend.enabled = true;
rend.sharedMaterial = material[0];
}
// Update is called on collision
void OnCollisionEnter(Collision col)
{
if (col.gameObject.tag == "box")
{
for(int i = 0; i <material.Length; i++){
rend.sharedMaterial = material[i];
Debug.Log(rend.sharedMaterial);
}
}
else
{
rend.sharedMaterial = material[0];
Debug.Log(rend.sharedMaterial);
}
}
}
The cycle between materials happen a few times because of the internal bounciness of the objects in unity. You can decrease it somehow (which I don't remember) but, I had a similar case once and no matter how much you decrease that it happens. So the best approach would be to store a value indicating it has been done before like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class colourChangeArray : MonoBehaviour
{
public int trigger = 1;
public Material[] material;
Renderer rend;
private bool changeMaterialDone;
// Use this for initialization
void Start()
{
rend = GetComponent <Renderer> ();
rend.enabled = true;
rend.sharedMaterial = material[0];
changeMaterialDone = false;
}
// Update is called on collision
void OnCollisionEnter(Collision col)
{
if (!changeMaterialDone && col.gameObject.tag == "box")
{
changeMaterialDone = true;
for(int i = 0; i <material.Length; i++)
{
rend.sharedMaterial = material[i];
Debug.Log(rend.sharedMaterial);
}
}
else
{
rend.sharedMaterial = material[0];
Debug.Log(rend.sharedMaterial);
}
}
}
I hope it helps you :)

Categories

Resources