Instantiate creates multiple clones in Unity - c#

I have the following code:
public Rigidbody2D ball;
Vector2 sp = new Vector2(0f, 2.1f);
void Update() {
if (Input.GetKeyDown("w")) {
SpawnBall();
DestroyBall();
}
}
void SpawnBall()
{
Instantiate(ball, sp, transform.rotation);
}
void DestroyBall()
{
if (ball.transform.position.y >= -5.7f)
{
Destroy(ball);
}
}
and the code is supposed to generate a new ball every time when "w" is pressed, but for some reason it creates multiple clones and it crashes the engine. How can I create a single clone only?
And also the destroy method doesn't do anything, although it should remove the clone when it passes -5.7 on the y-axis.
Thanks in advance

Create a new script named "SpawnRigidbody" and copy and paste the below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnRigidbody : MonoBehaviour
{
public Rigidbody2D ball;
Vector2 sp = new Vector2(0f, 2.1f);
void Update()
{
if (Input.GetKeyDown("w")) {
SpawnBall();
}
}
void SpawnBall()
{
Debug.Log ("spawn");
GameObject go = Instantiate(ball, sp, transform.rotation).gameObject;
go.AddComponent<DestroyAfterPosition> ();
}
}
Now create another script named "DestroyAfterPosition" and copy and paste the below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyAfterPosition : MonoBehaviour
{
void Update ()
{
if (transform.position.y <= -5.7f)
{
Destroy(gameObject);
}
}
}
Create an empty game object and attach the SpawnRigidbody and then assign your ball in the inspector.
Hope this help you.

There are a couple problems with your Destroy() statement. First, it is destroying ball which is the Rigidbody2D. You will instead want to destroy the gameobject attached to the ball:
Destroy(ball.gameObject);
Second, you are trying to destroy the ball immediately after it is created, but only if y>=-5.7f. I think instead what you are looking to do is continuously check if the ball is above that point and destroy it if it is. Since you are creating multiple balls, they will all need their own check, which means you need to create a script for the ball prefab and in the Update() check its position and Destroy(gameObject) as necessary.
I think you may want to declare ball as a GameObject at the beginning of your script as well, so you are instantiating a gameobject and not just a Rigidbody2D:
public GameObject ball;

Object.Instantiate creates a clone of the provided object, so each time it is called a new object is created. MonoBehaviour.Update is called every frame, which means it's called at least 30 times per second (usually 60 or more on a PC).
So 30+ times per second, your code checks if the w key is held down, and, if so:
A clone of ball is created
Destroy the original ball if it is beyond -5.7 on the y-axis.
Thus, you're creating 30+ ball clones per second, and none will be deleted (because the DestroyBall method only looks at the original ball, not the clones).
If you want to work with the cloned object, assign the result of Instantiate to a field:
ballClone = Instantiate(ball, sp, transform.rotation);
Then you can check if ballClone exists and skip the SpawnBall call if the clone already exists. You can also use ballClone in the DestroyBall method.
ryemoss' answer seems like it's
also important. This answer is just based on looking at your code and the public Unity docs; I don't have a lot of experience with Unity.

Your destroy call is being called once, and only immediately after creating the object.
So it's currently doing this...
User clicks button...
Create ball...
Check to see if the ball is a certain height. It's not, so ignore...
Ball drops down based on gravity or whatever force compels it.
... and is never deleted.
If you want the ball to be destroyed when it reaches a certain point, either...
Have SpawnBall return the game object, which you store and check / delete later in Update,
...or...
Create a script that just checks the object's transform.position and blows up if it's where it needs to be. Attach that to the prefab of the ball you're creating a duplicate of.

Related

Getting more than one possition though code (unity c#)

i made a "turret" in unity that shoots automatically on enemies it works with one enemy but when i put 2 it shoots in the midle of then dont know why it does that
public transform enemy;
public void Update() {
enemy = Gameobject.FindgameObjectWithTag("Enemy").getComponent<Transform>;
//just put the getting the possition part because the shooting works just fine
}
Your script is refreshing the enemy position every Update() iteration.
Try to have the turret stick to the enemy until it gets out of range, or until it is dead. Before doing your variable assignation, check if enemy != null, if it is the case, then you can write :
enemy = Gameobject.FindgameObjectWithTag("Enemy").getComponent<Transform>;
Also, try to avoid refreshing every Update() call, instead, use a different function that you call every half second.
I recommend you checking this project by Brackeys, that handles the situation perfectly. Here
GLHF

How can I reuse my objects instead of destroying them?

hi guys I just started with unity, c # ... I created a script that should make a writing appear and disappear ... the problem is that once the writing appears, then it never reappears since I destroy the object " gameObject "and therefore can no longer be recreated ... How can I fix the code ??
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Com : MonoBehaviour
{
public GameObject uiObject ;
void Start(){
uiObject.SetActive(false);
}
void OnTriggerEnter(Collider player)
{
if(player.gameObject.tag=="Player"){
uiObject.SetActive(true);
StartCoroutine("WaitForSec");
}
}
IEnumerator WaitForSec(){
yield return new WaitForSeconds(5);
Destroy(uiObject);
Destroy(gameObject);
}
}
You need to understand first what is Object pooling, which is making a pool of object that are stored in memory, and then you access them when need one, this will save the hiccup of creating a new instance.
With regard to your code, to reuse the same game object again, you do not need to destroy it, destroy method means it will remove the object from memory. what you need to do is to use gameobject.SetActive(false);
when you need to reuse the same gameobject again, just use gameObject.SetActive(true);
Keep in mind you may need to reset some of its properties like its rotation or position OnEnable

Unity Spawning way to much objects on collision

im working on an demolition/simulator type game. im working on the basics but my scripts doesnt seem to be working. the idea of the script is, that if the objects encounters an "hard" enough force, it will get replaced by a destroyed version of that object. it works in on small structures. but when the structures get bigger instead of spawning 1 destroyed object, it seems to spawn waaaayy more. and thus the game starts to lag. I think it is becouse some objects hit other objects. when i destroy them by clicking it doesn't happen, only when they hit each other
hope anyone can help.
here's the code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Destructible : MonoBehaviour {
public GameObject debrisPrefab;
void OnCollisionEnter( Collision collision )
{
if (collision.relativeVelocity.magnitude > 3f)
{
Destroy(gameObject);
Destroy();
}
}
void OnMouseDown()
{
Destroy(gameObject);
Destroy();
}
void Destroy()
{
if (debrisPrefab)
{
Instantiate(debrisPrefab, transform.position, transform.rotation);
}
Destroy(gameObject);
}
}
Does you debris prefab contain other destructible object? Maybe the newly instantiated debris are all destroyed if the spawn and have a collision right away.
Another thing to check is how many elements can trigger the collision. If you have many colliders on your object, onCollisionEnter will be called several times. Also, are you sure you added your script only once to the object?
Finally, if this doesn't help, try using debug lines:
Debug.Log(name + " collision enter");
to print lines in the console with the name of the colliding object, to try to identify which object causes too many collisions

Unity3D - Instantiated gameobject loses method?

Hey everyone and thanks for taking the time.
I'm currently working on a 2D something in Unity and have the following problem:
We have a spawner that periodically creates 'thing':
public float spawnTime = 3;
public Object thing; //public GameObject thing;
// Use this for initialization
void Start () {
InvokeRepeating("spawn", spawnTime, spawnTime);
}
void spawn ()
{
Vector3 pos = new Vector3(-14, 0, 0);
Quaternion ori = new Quaternion(0, 0, 0, 0);
Instantiate(thing, pos, ori);
}
And it does a good job. Meet 'thing':
void Start () {
InvokeRepeating("move", 0.1f, 0.1f);
}
void move()
{
transform.Translate(0.2f, 0, 0);
if (this.transform.position.x > 14)
{
Destroy(this); //Destroy(GameObject);
So basically a 'thing' is created, hauls itself from -14 to 14 and then suffocates.
Problem: As soon as the first 'thing' is deleted the newly created (not the ones already moving) dont ever move from -14.
I guess I haven't properly specified which method to call periodically but wasn't able to find a proper solution in the unity3d top-down-shooter or similar examples.
Thanks again.
€: After applying the proposed changes the spawner stops creating 'thing's after 3 cycles of creation.
€: My mistake was not using the 'thing' as a prefab (dragging it into "assets" as described in the beautiful answer) so I was referencing a soon to be deleted instance of my 'thing'. Dragged it to hell (assets) and was happy ever after.
I recreated you setup with just these scripts and what I got is that the objects just didn't get destroyed, but newly spawned moved properly until 14.
The reason they didn't get destroyed though is, that you called Destroy(this); which destroys the script component, not the gameobject. So this should be Destroy(gameObject); instead. With this fix it runs just fine for me.
Also, if there is no special reason to use object, your public Object thing; should better be public GameObject thing;.
Edit:
How I set it up:
Created a Empty (renamed it to Spawner)
Created a Sphere (as my thing, renamed it to Ball)
Made Ball a prefab by dragging it into the assets folder
Deleted the Ball from the scene
Created a Spawner script and put your spawning code into it
Created a Ball script and put your move code into it
Made the two changes to the scripts
Put the Spawner script on the spawner gameobject
Dragged the Ball prefab on into the public GameObject thing of Spawner
Put the Ball script on the ball prefab
Done.

Spawning Player at certain Point in Unity

I am making a small 2d click'n'point in Unity, and what I want to do is: I want to move towards the door and when my Player steps on a game Object with an attached SceneSwitcher Script he shall go through the door, into another scene. That works fine so far. Now I don't want him to appear in the middle of the room, but on the door, where he entered the room.
using UnityEngine;
using System.Collections;
using PixelCrushers.DialogueSystem;
public class ScenSwitcher : MonoBehaviour {
public string SceneName = "";
void OnTriggerEnter2D(Collider2D other) {
SwitchScene();
}
void SwitchScene(){
LevelManager levelManager = DialogueManager.Instance.GetComponent<LevelManager>();
levelManager.LoadLevel (SceneName);
changePosition ();
Debug.Log ("Scene Wechseln nach: " + SceneName);
}
void changePosition(){
GameObject player = GameObject.Find("Player");
player.transform.position = new Vector3(12,12,0);
}
}
That is my code, it does change Scenes, but not change the position. I would appreciate any help :)
On your ChangePosition() method you are passing hardcoded values to player position and it will assume always (12,12,0) on your scene space.
You need to define a spawn manager where you will get dynamically witch spawn point in your scene you want to use.
edited:
1: Try to create a singleton GameManager ( you can find singleton pattern examples here ) (IMPORTANT: Add DontDestroyOnLoad on your GameManager Awake).
2: In your GameManager define a Vector3 NextPosition property or something like this.
3: Declare a public Vector3 Destination on your "teleport" script to set it per teleport on inspector/editor.
4: Before this line levelManager.LoadLevel (SceneName) of code set GameManager.NextPosition = this.Destination;
5: If you are not persisting your character between scenes just call on one of hes behaviours Awake() or, if he persists create a method void OnLevelWasLoaded(int level) and chage players position setting GameManager.NextPosition ( wisely testing if it is valid for the current level before ;) ).
I cant try or do better coding now because I don't have access to unity editor so I hope it helps at last start a good research to solve your problem =/.
I would think the loadLevel function destroys the current script so changePosition does not get executed? I could be wrong.
Even if it is getting executed, there is a good chance it is executed before the level load and the properties for the next scene override where it got moved to.
I forget the exact syntax but look into getting GameObjects to not be destroyed on scene change.
EDIT
Object.DontDestroyOnLoad

Categories