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
Related
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
in my game im trying to make text appear on the ui when entering a specific room,but when i try to go into that room nothing happens
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Room_trigger : MonoBehaviour
{
public GameObject UiObject;
public GameObject cube;
void Start()
{
UiObject.SetActive(false);
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "player")
{
UiObject.SetActive(true);
}
}
void Update()
{
}
void OnTriggerExit(Collider other)
{
UiObject.SetActive(false);
Destroy(cube);
}
}
the player controller is based of of brakeys fps controller tutorial.
Three things you will need to check:
Does the player object (the one that the player capsule collider component is attached to) have the tag "player" assigned to it? Is it definitely "player" and not "Player" or "Player1". Note - the TAG of an object is not the same as the NAME of an object.
Is the "Is Trigger" on the capsule collider on the player object ticked/checked? If the player capsule collider is not a trigger then it won't cause OnTriggerEnter to be fired by your Room_trigger attached object. Also check the next point.
If you don't want your player capsule collider to be a trigger (which is highly likely), then make sure that the object your Room_trigger script is attached to has:
a collider that is set to Is Trigger
a Rigidbody component
A couple of other possibilities are that you haven't dragged GameObjects into the UiObject and/or cube fields in the Unity Editor UI but that should throw NullReference errors in the console when you run the game.
Whilst Vasmos is correct, you should compare strings using the Equals() method, that's not going to be the cause of your trouble in this specific case. Comparing strings using == as you've done here will work.
replace
if (other.tag == "player")
with
if (other.tag.Equals("player"))
always use .Equals for comparing strings, otherwise its just comparing if its the same variable
#HumanWrites i figured out what the problem was, the cube wasn't set as trigger, the i watched a different tutorial and he sayed "dont forget to set the collider as trigger" and that fixed it.
As the title suggests, I've literally just started learning Unity recently and I'm practising by making a side scrolling shooter. I've been following a Udemy course about it and (to my knowledge) I've been following the tutor's instructions to the letter, but at the point where he tests his and it works fine, by projectiles go straight through my enemies.
I'm a bit stumped at this point and so I thought I'd post here to see what you guys thought. I bet it's something really simple I've not done.
Please see my projectile code below:
using UnityEngine; using System.Collections;
public class DestroyEnemyAndProjectile : MonoBehaviour {
public GameObject WhiteExplosion;
public GameObject OrangeExplosion;
void Start()
{
}
void Update()
{
}
void OnCollisionEnter2D (Collision2D tempCollision)
{
if (tempCollision.gameObject.tag == "Collision")
{
spawnParticles(tempCollision.transform.position);
Destroy(tempCollision.gameObject);
}
}
void spawnParticles(Vector2 tempPosition)
{
Instantiate(WhiteExplosion, tempPosition, Quaternion.identity);
Instantiate(OrangeExplosion, tempPosition, Quaternion.identity);
}
}
Thanks for your help!
I did post a question to them which got a response, they suggested that perhaps the projectile is going too fast and check there was a Rigidbody 2D attached - both of which were already collect
make sure that the object you're colliding with has the tag "Collision", with the same capitalisation.
If it's not, you can do this by:
1. Selecting the GameObject to be collided with
2. In the top-right, select the Tag property
3. Add tag, click the plus and type in "Collision"
4. Select the GameObject again, and select the "Collision" tag from the Tag property dropdown
Otherwise, if that's not the issue. Make sure the projectile has a type of Collider2D component, and that the projectile, or the object being collided with, has a Rigidbody2D.
First I would like to know what the behaviour of this script curently is. Is the collision method being called, and the projectile goes through the enemy anyway? Or the collision method is not being called at all?
That being said, these are things that you should check in order for collision to work:
Make sure that the projectile and the enemy have Collider2D components attached to them.
Make sure that the projectile and/or the enemy (at least one of them must) have a Rigidbody2D attached to it.
Make sure that the layer of the projectiles and the layer of the enemies are set to collide in the collision matrix (You can find the collision matrix in Edit->ProjectSettings->Physics)
Make sure that the enemy GameObject has its tag set to "Collision".
P.S: Welcome to Unity where issues like this are, in fact, usually caused by something super simple that you probably missed.
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.
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