I have created a prefab of a Terrain.
I pass it on to script where it gets instantiated (hundreds of times).
The problem is that the prefab itself gets changed with every instantiation. (its name and its translation).
How do I prevent this?
Sample code :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LandCrafter : MonoBehaviour {
public Terrain parentPiece;
public Terrain randomPiece;
void Start () {
for (int i = 0; i<=maxLandBlocks; i++) {
if (currentPlacedBlocks.Count <= maxLandBlocks) {
pieceList = GameObject.FindGameObjectsWithTag ("randomTerrainPiece");
LandCraft ();
} else {
randomPiece.name = "randomPieceOfLand";
charCraft ();
}
}
}
void LandCraft(){
someExistingLandPiece = (GameObject)pieceList [(int)Random.Range(0.0f,pieceList.Length)];
test = someExistingLandPiece.transform.position;
if (!currentPlacedBlocks.Contains (someExistingLandPiece.transform.position + Vector3.forward)) {
Instantiate (randomPiece);
randomPiece.name = "The" + i++;
randomPiece.transform.position = someExistingLandPiece.transform.position + Vector3.forward;
currentPlacedBlocks.Add (randomPiece.transform.position);
}
}
Turns out, you actually have to instantiate the prefab and "feed" that instance to the script. If you feed the prefab directly, everything you do automatically applies to it..
Related
I have 10 meshes that are each basically freeze-"frames" of an animation of a whale swimming.
If I were to loop through displaying these meshes then it would create a pseudo-animation, which is what I want.
How can this be achieved? Currently I have GameObject AnimTest, and I've placed the 10 mesh .obj files as children to it. I've started with this code on a script changeMeshes for the GameObject:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class changeMeshes : MonoBehaviour
{
//Create array of the meshes
public float[] currentMesh;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
for (int i = 0; i < 10; i++)
{
currentMesh[i].gameObject.GetComponent<MeshRenderer>().enabled = true;
}
}
}
This is obviously very wrong since I'm new and confused, so I'm getting errors with script like float does not contain a definition for gameObject. Can anyone help lead me down the correct path?
Edit: Here's my better try at it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class changeMeshes : MonoBehaviour
{
//Create array of the meshes
public GameObject[] whaleMeshes;
void FindWhales()
{
whaleMeshes = GameObject.FindGameObjectsWithTag("WhaleMesh");
print(whaleMeshes.Length);
}
void CycleWhales()
{
for (int i = 0; i < whaleMeshes.Length; i++)
{
if (i > 0)
{
whaleMeshes[i - 1].gameObject.GetComponentInChildren<MeshRenderer>().enabled = false;
}
whaleMeshes[i].gameObject.GetComponentInChildren<MeshRenderer>().enabled = true;
}
}
// Start is called before the first frame update
void Start()
{
FindWhales();
}
// Update is called once per frame
void Update()
{
CycleWhales();
}
}
The result now is that only the last Mesh is permanently rendered, rather than the script cycling through the meshes on a loop. How do I get the meshes to loop?
Well .. a float has no property .gameObject .. not even Mesh would
Since you say the objects are children of this component you can simply iterate through them.
And then I would simply activate and deactivate the entire GameObject.
Sounds like what you would want to do is something like
public class changeMeshes : MonoBehaviour
{
// How long should one mesh be visible before switching to the next one
[SerializeField] private float timePerMesh = 0.2f;
public UnityEvent whenDone;
private IEnumerator Start()
{
// Get amount of direct children of this object
var childCount = transform.childCount;
// Get the first child
var currentChild = transform.GetChild(0);
// Iterate through all direct children
foreach(Transform child in transform)
{
// Set all objects except the first child to inactive
child.gameObject.SetActive(child == currentChild);
}
// Iterate though the rest of direct children
for(var i = 1; i < childCount; i++)
{
// Wait for timePerMesh seconds
yield return new WaitForSeconds(timePerMesh);
// Set the current child to inactive
currentChild.gameObject.SetActive(false);
// Get the next child
currentChild = transform.GetChild(i);
// Set this one to active
currentChild.gameObject.SetActive(true);
}
// Optionally do something when done like e.g. destroy this GameObject etc
yield return new WaitForSeconds(timePerMesh);
whenDone.Invoke();
}
}
I currently have some objects spawning from a prefab and am attempting to destroy only one of the spawned items of that prefab. I was searching online and I found tons of different examples but I have been unable to get any of them to work. I tried setting up an instance of the Instantiate and destroying that instance but I am unable to get it to work. The spawn/collision script is attached to the main camera if that matters. Collision with other items in my game work and the prefab does have a box collider set to isTrigger. Again, I know there are plenty of examples explaining this etc, but I can't get it to work and maybe I am not understanding what I actually should be doing.
Spawner code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bloodVialSpawner : MonoBehaviour
{
public GameObject vialOfBlood;
private GameObject vialss;
private int hunger =10;
public int numOfVials;
public int minSpawnRange, maxSpawnRange;
public int minSpawnRange2, maxSpawnRange2;
// Start is called before the first frame update
float timeSpawns = 2;
List<GameObject> vialsInstantiated = new List<GameObject>();
void Start()
{
StartCoroutine(becomeHungry());
InvokeRepeating("SpawnVials", timeSpawns, timeSpawns);
}
private void Update()
{
if (hunger == -1)
{
Debug.Log("sigh");
}
}
void SpawnVials()
{
for (int i = 0; i < numOfVials; i++)
{
vialsInstantiated.Add(Instantiate(vialOfBlood, SpawnPosition(), Quaternion.identity) as GameObject);
}
}
Vector3 SpawnPosition()
{
int x, y, z;
y = 59;
x= UnityEngine.Random.Range(minSpawnRange, maxSpawnRange);
z = UnityEngine.Random.Range(minSpawnRange2, maxSpawnRange2);
return new Vector3(x, y, z);
}
IEnumerator becomeHungry()
{
while (true)
{
hunger -= 1;
yield return new WaitForSeconds(1);
Debug.Log(hunger);
}
}
}
Spawner Script is on the Main Camera. Player used is the First Person Player Unity provides.
Code for destroying spawned object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class destroyVial : MonoBehaviour
{
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "vials")
{
Destroy(col.gameObject);
Debug.Log("yell");
}
}
}
Destroy code is on prefab. Note prefab is not in hierarchy as it should not be.
Firstly,
I see that you're spawning things in a for-loop and overwriting the vialss variable every time:
for (int i = 0; i < numOfVials; i++)
{
vialss = Instantiate(vialOfBlood,
SpawnPosition(),
Quaternion.identity) as GameObject;
}
And then, on collision, you're Destroying vialss, which in this case will be the latest spawned object. And if you collide with anything after 1 collision, vialss will already be deleted and probably throw an exception. Maybe that's fine in your game, but the logic looks a bit flawed.
Also, I'm assuming you want to destroy the object you're colliding with? Does something like this not work?
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "vials")
{
Destroy(col.gameObject); // <== Remove colliding object
Debug.Log("yell");
}
}
If you, for some unrelated reason, need a list of all your spawned vials, maybe you'd like to convert that to a list instead:
List<GameObject> spawnedVials = new List<GameObject>();
void SpawnVials()
{
for (int i = 0; i < numOfVials; i++)
{
var vial = Instantiate<GameObject>(vialOfBlood,
SpawnPosition(),
Quaternion.identity)
spawnedVials.Add(vial);
}
}
Finally,
make sure that the collision detection is working. You're saying that the script is attached to your camera. please make sure you have a Collider on the camera. But you're saying that other colliders are working, so I'm guessing you have this under control.
I'd guess your issue lies in the flawed logic I initially described.
OnTriggerEnter needs to be on a script attached to the object it's colliding with, or the vial itself. It can't be on the main camera as OnTriggerEnter will never get called.
I would recommend you to keep scripts to one job, you should split that script into a Spawn script and a Collider script. And create a empty GameObject with the sole purpose of spawning prefabs.
Also there's some errors in your code:
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "vials")
{
Destroy(col.gameObject); // Destroy the gameObject you're colliding with
Debug.Log("yell");
}
}
Also the variable vialss isn't doing what you're expecting, vialss is only referencing to the last instantiated vial, so better save all vials in a List:
List<GameObject> vialsInstantiated = new List<GameObject>();
And then:
void SpawnVials()
{
for (int i = 0; i < numOfVials; i++)
{
vialsInstantiated.Add(Instantiate(vialOfBlood, SpawnPosition(), Quaternion.identity) as GameObject);
}
}
I'm a complete unity novice. I want to make a simple scene where you have three lives and you lose a live if you collide with a cube. This is my script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Lives : MonoBehaviour {
public Transform player;
public static int lives;
public Image live1;
public Image live2;
public Image live3;
// Use this for initialization
void Start () {
lives = 3;
live1.enabled = true;
live2.enabled = true;
live3.enabled = true;
}
void Update () {
DisplayOfHearts();
}
public static void Damage() {
lives -= 1;
}
public void OnCollisionEnter(Collision col) {
if (col.gameObject.tag == "cube") {
Lives.Damage();
}
}
public void DisplayOfHearts() {
if (lives == 2) {
live3.enabled = false;
}
else if (lives == 1) {
live2.enabled = false;
}
else if (lives == 0) {
live1.enabled = false;
}
}
}
What happens is the player can't move through the cube but the amount of lives stays three. Is there something I'm missing?
The problem is you have attached the script to a wrong game object. The script and the collider must be attached to the same game object.
Unity methods inside a MonoBehaviour script (such as OnEnable, Update, FixedUpdate, Awake, Start, OnTriggerEnter, OnCollisionStay, etc..) only work for the game object which the script is attached to.
If you attach the script to another game object don't expect any of those to work. Update only works while that game object is active. OnCollisionEnter only works when a collision occurs on a collider which is attached directly to that game object. (it doesn't even work when a child has the collider instead of the actual game object where script is attached to)
I finish making running game. But I placed obstacle like this :
This way makes phone frozen often. So I make a prefeb is made of obstacle object like this :
I want to use function SetActive(bool) to appear/disappear obstacle. Finally, How it works is My runner is at a standstill and background, obstacle, coin, juwel is moved. But My creator script has a big problem.
My Prolem :
As you see, This code create blank(red box) between two obstacle prefebs. I can't find problem. Plz help me...
Creator Script :
using UnityEngine;
using System.Collections;
public class CsPartCreator : MonoBehaviour {
int count = 1;
float timer = 0.0f;
// Use this for initialization
void Start () {
for (int i = 1; i < 26; i++)//set Deactive all object excluding first object (Because This object is watched at first.)
transform.GetChild(i).gameObject.SetActive(false);
}
// Update is called once per frame
void Update () {
timer += Time.deltaTime;
if (timer > 5f && count < 23)//every 5 seconds and count is smaller than the number of prefeb
{
transform.GetChild(count).gameObject.SetActive(true);//
count++;
timer = 0;
}
}
}
This is my Hierarchy :
I think , That missing prefab's Z value is more negative than background , Or you have used a sorting layer which is set to be behind background.
And Check if all obstacle gameobjects correctly orderered in Hirachy Part0, Part1, Part2, Part3 like that. Let me know if those are in correct order
Please check that :)
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
public class CsPartCreator : MonoBehaviour
{
private GameObject player;
float timer = 0.0f;
private List<GameObject> obstacles;
void Awake()
{
player = GameObject.FindWithTag("Player");
obstacles = new List<GameObject>();
}
// Use this for initialization
void Start()
{
for (int i = 0; i < 26; i++)//set Deactive all object excluding first object (Because This object is watched at first.)
{
obstacles.Add(transform.GetChild(i).gameObject);
transform.GetChild(i).gameObject.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
if (obstacles == null || obstacles.Count() == 0)
return;
var toActivate = obstacles.Where(x => x.transform.position.x > transform.position.x && x.transform.position.x < transform.position.x + 10).ToList(); // +10 is the range
foreach (GameObject go in toActivate)
{
go.SetActive(true);
obstacles.Remove(go);
}
}
}
Set player gameobject to "Player" tag as in image below
I am trying to change the order of a sorting layer in unity for a 2D game but the below script isn't working for me:
using UnityEngine;
using System.Collections;
public class LevelManager : MonoBehaviour {
public GameObject player;
public SpriteRenderer deadGuy;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (player.transform.position.y < deadGuy.transform.position.y)
{
deadGuy.sortingOrder = 0;
} else
{
deadGuy.sortingOrder = 2;
}
}
}
The objects have been linked in the inspector window unity before running the game.
EDIT
This is now my code:
using UnityEngine;
using System.Collections;
public class LevelManager : MonoBehaviour {
public GameObject player;
public GameObject deadGuy;
public bool belowTheY;
// Use this for initialization
void Start () {
deadGuy.GetComponent<SpriteRenderer>().sortingOrder = 2;
}
// Update is called once per frame
void Update () {
if (player.transform.localPosition.y < deadGuy.transform.localPosition.y)
{
belowTheY = true;
deadGuy.GetComponent<SpriteRenderer>().sortingOrder = 0;
} else
{
belowTheY = false;
deadGuy.GetComponent<SpriteRenderer>().sortingOrder = 2;
}
}
}
bekowTheY is activating if the user goes below deadGuy's Y position so I know the if statement is executing correctly. However the sorting layer is not being changed
It seems that the player object was on sorting order 0 also, so when the deadGuy object was scripted to go to sorting order 0, it was still showing in front due to taking precedence.