Would like to know if it is possible to destroy an object if not in collision with anything?
When I start the game I generate a grid randomly, on each GridSquare I've made a collider2D. In the editor, I add some objects on this grid manually, with a collider2D too and a rigidbody2D to detect the collision.
I know how to destroy the object if in a collision, what I want is "when the game start, if this object is not in collision with anything, then destroy it"
I've tried to tell unity "if in collision with grid square then destroy object (just for testing), else destroy object"
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.name == "GridSquare")
{
Destroy(gameObject);
}
else {
Destroy(gameObject);
}
}
So actually it destroys well the object when it is on a GridSquare, and it should destroy object if it is not in collision with GridSquare too but apparently not...
private var collisionCount = 0;
void OnCollisionEnter () {
collisionCount++
}
void OnCollisionExit () {
collisionCount--;
}
void checkForCollision(){
if(0 == collisionCount) Destroy(gameObject);
}
If the gameObject is not colliding, OnTriggerEnter2D method wont be activated for that specific gameObject. Bear in mind that method only triggers on collision event.
For that case you might have in your gameObjects a boolean _isColliding which you can change with the OnTriggerEnter2D method to check the ones that are colliding, setting that to true.
bool _isColliding = false;
void OnTriggerEnter2D(Collider2D collision)
{
_isColliding = true;
}
Then you loop through all of the gameObjects and destroy only the ones that have the _isColliding == false.
Hope that helps!
Related
So I am taking a class in basic game development and am currently working on a game with Unity. My game worked perfectly up until now when I updated my unity version. In order for the player to actually take damage I have a method that can only be reached if explicitly called by a script. Somehow the ground, that has no script attached, damages my player.
I have posted the code below.
This one is part of the player script
3 references
public void Hurt(int dmg, string yep)
{
HP -= dmg;
Debug.Log($"took {dmg} damage from{yep}. You now have {HP} HP left");
if (HP <= 0)
{
SceneManagement.Death();
}
}
This one is part of the script attatched to my flame object
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag != "FlameTurret" && collision.gameObject.tag != "flame")
{
player.GetComponent<PlayerController>().Hurt(damage, collision.gameObject.tag);
Destroy(this.gameObject);
}
}
This one is attatched to a projectile fired by the enemy
if (collision.gameObject.CompareTag("Player"))
{
if (!called)
{
collision.gameObject.GetComponent<PlayerController>().Hurt(damage, collision.gameObject.tag);
called = true;
}
}
This one is attatched to an enemy
if (collision.gameObject.CompareTag("Player"))
{
if (!called)
{
collision.gameObject.GetComponent<PlayerController>().Hurt(damage, collision.gameObject.tag);
called = true;
}
Destroy(this.gameObject);
}
Console output
Nothing with the tag "Ground" has a script and nothing else than the methods i've posted are supposed to reference my Hurt() method but the ground still damages my player. Any help would be greatly appreciated!
Your problem seems to be that this function here
private void OnCollisionEnter2D(Collision2D collision)
Will be run whenever any collider (game object with a collider component attached - the game object does not need to have any scripts attached to it) intersects with your player
This code here
if (collision.gameObject.tag != "FlameTurret" && collision.gameObject.tag != "flame")
Will pass so long as the object that collides does not have the tag of "FlameTurret" or "flame", which I assume your ground does not.
It seems to me a little odd that everything in your game will damage your player except for flames... is this an error?
Either way a simple fix would be to tag your ground with something like environment and then add under your OnCollisionEnter2D() have a check along the lines of
if (collision.gameObject.tag == "environment"){
return; // do nothing
}
I assigned a projectile to my enemy that shoots at the player, and this projectile has a collider2d which I marked as a trigger. And it doesn't seem to recognize my player collider. The projectile just goes through my player.
void OnTriggerEnter2d (Collider2D other)
{
Player _player = other.GetComponent<Player>();
if (_player != null)
_player.ChangeHealth(1);
Destroy(gameObject);
}
My Player Components:
There is a small typo in your method name. The "d" in "2d" needs to be capitalized.
onTriggerEnter2d ---> onTriggerEnter2D
void OnTriggerEnter2D (Collider2D other)
{
Player _player = other.GetComponent<Player>();
if (_player != null)
_player.ChangeHealth(1);
Destroy(gameObject);
}
Without seeing your code, I will make the assumption that your 'player' object does not have a Rigidbody2D attached to it.
I strongly suggest you read the docs on colliders and how they interact with each other but as a very brief summary; In order for collisions to occur between two objects, at least one of them must have a Rigidbody or Rigidbody2D attached to them.
Attach a Rigidbody2D component to your player (you may want to mark it as kinematic so collisions don't affect it's position/rotation etc.) and it should then work as you expect.
I would change your code in OnTriggerEnter2D to this:
void OnTriggerEnter2D (Collider2D other)
{
// In your scene you have just two objects, so not really required now
// may be interesting for you when you have more objects there
if(other.gameObject.CompareTag("Player"))
{
//Here add .gameObject to refer the GameObject which contains the collider2D
Player _player = other.gameObject.GetComponent<Player>();
if (_player != null)
_player.ChangeHealth(1);
Destroy(gameObject);
}
}
Besides that. You have added an image of the components in the GameObject Player. Add the same for the Bullet, or at least check this two things:
The bullet is also in position Z = 0
The bullet has got a collider2D with the isTrigger feature as
true (checked), to detect the player.
In the game you controll a ball (Sphere) and two types of boxes falling down: deathCube and goldCube. When the Sphere hit the DeathCube, then the Sphere is destroyt, but it not get destroyed and I don't know why. The cubes are prefabs and they have a tag(DeathCube, GoldCube).
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "DeathCube")
{
Destroy (gameObject);
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "GoldCube")
{
gold++;
}
}
If the Sphere hit the goldCube you get points, but this doesn't work too.
Try merging the two OnTriggerEnter's into one.
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "DeathCube")
{
Destroy (gameObject);
}
if (other.gameObject.tag == "GoldCube")
{
gold++;
}
}
I believe that the second one is overriding the first, never allowing the Destroy() to be called. I would've assumed the compiler would throw an error with this, but you don't seem to have indicated that.
If you don't have a rigidbody attached to at least one of the objects in the collision (ball or cube), then the trigger event won't be initiated.
From the documentation:
Notes: Trigger events are only sent if one of the colliders also has a rigidbody attached
Source: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTriggerEnter.html
I kinda stuck with my script right now. When a gameObject, with my script attached to it, has a trigger event with a specific gameObject, I want to destroy the specific gameObject after an amount of time.
So i came to this:
void OnTriggerEnter ( Collider other) {
if (other.gameObject.tag == "leaf1"){
StartCoroutine (LeafDestruction ());
}
}
IEnumerator LeafDestruction(){
yield return new WaitForSeconds (5);
Destroy (gameObject);
}
I know it's a noob mistake but i think i miss something, because when i run this script, it destroys the gameObject with the script attached to it, and not the specific gameObject(with tags).
How can i fix that?
A simpler solution is to use the optional 2nd parameter of the Destroy method:
The object obj is destroyed immediately after the current Update loop, or t seconds from now if a time is specified.
Given the official parameters:
Parameters
obj
The object to destroy.
t
The optional amount of time to delay before destroying the object.
You can adjust your if statement to:
if (other.gameObject.tag == "leaf1")
Destroy(other.gameObject, 5.0f);
Basically you need to tell your coroutine that it should destroy the other.gameObject and not the gameObject that is running this script.
So what you could do is add a parameter to your coroutine, passing in the gameObject that it should really be destroyed:
void OnTriggerEnter ( Collider other) {
if (other.gameObject.tag == "leaf1")
{
IEnumerator coroutine = LeafDestruction(other.gameObject);
StartCoroutine (coroutine);
}
}
IEnumerator LeafDestruction(GameObject toDestroy){
yield return new WaitForSeconds (5);
Destroy (toDestroy);
}
You destroyed the object instead of the leaf. The gameObject is an alias of this.gameObject, which is the game object this script component is attached to. Note MonoBehaviour inherits from Behaviour and Behaviour inherits from Component.
GameObject leafObject;
void OnTriggerEnter ( Collider other) {
if (other.gameObject.tag == "leaf1"){
leafObject = other.gameObject;
StartCoroutine (LeafDestruction ());
}
}
IEnumerator LeafDestruction(){
yield return new WaitForSeconds (5);
Destroy (leafObject);
}
What I'm after in my game is when a collision happens with the player and a planet, for the player to disappear, leaving behind an explosion effect in the form of a particle system. Just afterwards (maybe half a second) I want the "game over" scene to appear in its place. Here's what I have so far:
void OnCollisionEnter2D (Collision2D col) {
if (col.gameObject.tag == "enemyPlanet") {
Instantiate (explosion, thingToMove.transform.position, thingToMove.transform.rotation);
ui.gameOverActivated ();
Destroy (gameObject);
am.rocketBang.Play();
Application.LoadLevel ("gameOverScene2");
}
}
The problem I have is that the particles appear but don't move as they should like an explosion. I guess that's either because the game over scene is loading or because its position is the player (thingToMove) which is being destroyed.
I tried this:
public void Awake() {
DontDestroyOnLoad (transform.gameObject);
}
But the same thing happens. If it's because the player is being destroyed, how would I make it be in the place of the player at the time of it being destroyed?
I hope this makes sense and thanks in advance.
You can use the Invoke method to call the game over after a specified delay.
void OnCollisionEnter2D (Collision2D col) {
if (col.gameObject.tag == "enemyPlanet") {
Instantiate (explosion, thingToMove.transform.position, thingToMove.transform.rotation);
ui.gameOverActivated ();
am.rocketBang.Play();
Invoke( "over", 2.0f );
}
}
void over(){
Destroy (gameObject);
Application.LoadLevel ("gameOverScene2");
}