Delete gameObject before the end of the frame - unity3d

I have two gameObjects really close to each others (let's call them A and B), an other one is coming with a certain speed (let it be C). And what I want is: that the object C delete itself and at the same time it delete the object A which it is colliding with.
I am using the onTriggerEnter function with the Delete() method to do it but unfortunatly this delete both gameObjects at the end of the frame. And within this very short time (collision -> delete) the object C which is moving can collide with the object B
So do anyone have a solution to delete the object C which is moving before it collides with the object B?

You have a number of options available to you.
The first, and most drastic, is to use DestroyImmediate. The documents here describe why it might be used, but also warn against its use in general, unless you have a specific reason.
Another option would be to change the Layer of the object, so that the collision of C won't happen during the next FixedUpdate. That should be applied straight away, and stop your objects from colliding. To accomplish this, you'll have to make sure you have a new Layer, and in your physics ( or physics2D ) settings, you'll need to make sure that the layer Object C is on doesn't collide with the new Layer. You can find more about the collision matrix here at the Unity Docs.
A quick code example might look something like this:
public LayerMask noCollisionLayer;
public GameObject ObjectB;
private void OnCollisionEnter ( Collision other )
{
ObjectB.layer = noCollisionLayer;
}

Related

How do I use OnTriggerEnter() on a non-moving object?

I'm a new to game developing, and I'm making my first game in Unity, which is a top-down, 2D survival type game. In order to detect when the player hits a tree or other world object, I added invisible triggers on each side of the player, which I set active whenever you click. Whenever either the player or the target is moving, this system works perfectly, however, when the target is not moving, like a tree, the collision is not detected. I figure that the OnTriggerEnter function only works when a moving object collides with the trigger, however, I have no idea how to do it otherwise. Is there another function I can use, or some way I can fix this?
void OnTriggerEnter2D(Collider2D other)
{
Debug.Log("hit");
if (other.gameObject.tag == "Tree")
{
Debug.Log("hit tree");
other.gameObject.GetComponent<TreeScript>().treeHealth--;
}
}
You can try the:
private void OnCollisionEnter2D(Collision2D col)
{
}
If 2 objects collide with each other without using the "Trigger" option, the OnCollisionEnter2D will be called.
A quick example where to use the 2 different methods are as follow:
Use the OnTriggerEnter2D() method in a racing game where you want to detect when a car goes through the finish line and you want to use a trigger because you don't actually care for the collision.
Use the OnCollisionEnter2D method to detect when 2 cars collide with each other and you don't want the 2 object to go through each other.

In Unity how can I set a value to property while initializing a prefab with Instantiate() method like OOP constructor with parameters?

I am a newbie in Unity and game development. I want to make a mobile stack jump game with primitives. I have a player in the center of the screen. The enemy is approaching the player from the right and left of the screen. The player tries to sit on the enemy by jumping as in Mario Game. If the enemy hits the player from the side, the game is over. I create enemies with a SpawnMan. There is a prefab for an enemy game object. SpawnMan creates them at certain time intervals with the Instantiate() method. I want to store data on whether the enemy is approaching from right or left. I even want to store this information by creating an enum type. In summary, I want to have enemy objects with the left and the right types. How do I set this property (left enemy or right enemy) when calling the Instantiate() method in SpawnMan as in OOP constructor with parameters.
enum EnemyType
{
Left,
Right
}
// ...
Instantiate(enemyPrefab(EnemyType.Left), spawnPos, enemyPrefab.transform.rotation);
Assign a GameObject while instantiating first :
GameObject enemy1 = Instantiate(...)
Then, we can use the player transform and the enemy transform vectors to get a direction (+ value and a minus value)?
As Chandradhar said, addition to that, you can use Mathf.Sign(player.position.x- enemy.position.x); to see if the enemy comes from the left or the right of the player.
You can't really pass it in exactly that way, as Instantiate doesn't call a constructor on the instantiated prefab's scripts. Or I guess enemyPrefab could be a method that returns an actual prefab object with set script values, but that would be a somewhat odd way to get what you want.
But presumably you just want the enemy object to have that information about left/right, in that case the easiest would be to get the attached script and then assign the left/right property. So you would add something like this to your enemy script (the one that is attached to enemy prefab)
public class MyEnemyScript : MonoBehaviour
{
public EnemyType Type;
... your enemy code here...
}
And then use it like that:
var enemyGameObj = Instantiate(enemyPrefab, spawnPos, enemyPrefab.transform.rotation);
enemyGameObj.GetComponent<MyEnemyScript>().Type = EnemyType.Left;
Note that this is not really good practice, as GetComponent is an expensive call, but then again neither is Instantiating all those enemies - it would be nicer to use pooling.
I'm assuming an enum for left and right is overkill, but if you have some design reason that the enemies need to do have some special logic depending on what side they're on, you can still handle that in a simpler fashion.
In your MyEnemyScript(), you have Awake() and OnEnable() methods that will be automatically called by Unity just like Start and Update. In one of them (use OnEnable if you use object pooling), put something like this:
public EnemyType type;
private void Awake()
{
if (transform.position.x > PlayerInfo.playerPosition.x)
type = EnemyType.right;
else
type = EnemyType.left;
}
Now you can just spawn enemies as normal without thinking about it. PlayerInfo can be a static class or a singleton or however you prefer making that information available.
Then in your update loop, just have two logic paths (which I assume is similar to what you're doing anyway).
private void Update()
{
if(type = EnemyType.left)
//do left enemy stuff
else
//do right enemy stuff
}

how to get reference of an object in unity

I am working on a game and came to a point where I had nothing in my mind. want to take reference of an object by collider frequently. I don't know how to make so please help.
Thanks in advance
Take Object A with script As and script 2As and collider Ac
Object B with script Bs and collider Ac
Their might be 3 different things you are looking to achieve here:
Reference Script Bs from script As:
First you need to reference the Game Object that Bs is on (B) from script As
At the very top of script As you would add:
public GameObject objectB;
Then later in your code when you want to reference the script on objectB you can do:
int value = objectB.GetComponent<Bs>().score;
Where score is a variable in Bs
Reference Script 2As from As:
In this case we already are on the same gameobject so we can simply do
int value = gameObject.GetComponent<2As>().Score;
Where Score is a integer in the Script 2As
The reason we can just say gameObject.GetComponent here instead of having to reference the other object is because gameObject with a lower case g refers the object that the script is sitting on. So effectively we just say "get the other script on this gameobject"
Lastly (I think you are trying to do this maybe?)
Take a collider and get the GameObject on this collider then get the script on that GameObject:
public Collider coll;
int val = coll.GameObject.GetComponent<script>().value;|
I hope that helps, I didn't really understand your question so if this doesn't answer your question let me know :)
Also join my discord if you have any other questions: discord.io/gamedev
We really need more info about what you're trying to accomplish. Are you trying to know what an object collided with recently? trying to raycast? Depending on what you want to do with it, you might need to reference different components on the gameobject. etc.
But here's an example:
//Component on a gameobject with a collider attached.
public class RefByCollision : MonoBehaviour
{
[SerializeField] //makes it show in inspector
private GameObject lastCollisionGO;
//Called everytime this gameobject collides with another that has a collider (non trigger)
private void OnCollisionEnter(Collision other)
{
lastCollisionGO = other.gameObject; //replaces reference with the newly collided object.
}
}
This component on a gameobject with a collider attached will replace the reference stored in lastCollisionGO everytime the object collides with another object.
Note: If you try to query the value of lastCollisionGO before it collides with something, it will be empty and give you a null reference exception.

Use the collider of multiple objects as one collider

In my fps level (Unity), targets spawn at a random position. I want to make sure targets can't spawn behind objects or inside objects.
To make sure they don't spawn behind an object, I've made a raycast going from the player to the target. If it's obstructed I recalculate the spawn point. This works fine, but, since the targets are spheres the raycast won't be obstructed when a target is 50% inside an object, for example the floor. I don't want that, obviously.
To determine whether or not the target is in the bounds of another object, I tried using OnCollisionEnter and OnCollisionExit. While this works when simply moving a target inside another object, it seems to be unreliable when one script's Update cycle is recalculating the spawn position while the target's Update cycle is keeping track of the Collision.
So I looked for a different approach. Here's what I came up with (from the Unity docs):
m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
}
The Game Object world is the parent in which I put all the objects of my gaming world.
The problem is that he only takes into account the collider of the first object. I basically want to use one big collider, which is composed by all the level objects.
Is this possible? Or does anyone know a different approach on how I can achieve this?
You should use the GetComponentsInChildren method instead of GetComponentInChildren, so that you can get from it an array of colliders on which you can execute a foreach to check if the bounds are intersecting.
I.E.:
m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
if (objCollider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
But, this way of doing things is very heavy for the CPU, since GetComponent methods are really slow, so their use should be limited inside Awake and Start methods if possible.
Another approach to the problem would be to create a List<Collider> at the start, and add to it the starting children of your World game object. If another one is instantiated, just Add it to your list, if it's destroyed, just Remove it.
Then, just before instantiation, you can check the bounds by looping inside the List with a foreach, the check will be a lot more faster.
==================================
EDIT:
Ok, here's the deal. First of all, add these lines to your World game object script (I guess you called the class World):
using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type
public class World : MonoBehaviour {
//The list which will hold references to the children game objects colliders
public List<Collider> childrenColliders;
private void Start() {
//Code used to populate the list at start
childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
}
Now, since in the script which spawns a new object has already a world variable which holds a reference to the World class:
foreach(Collider coll in world.childrenColliders) {
if (coll.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
And, of course, as I said before remember to add a newly spawned game object's collider to the list with:
void AddNewGameObject() {
// spawnPoint is the transform.position Vector3 you'll use for the new game object
var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}
That's pretty much it. ;)

Talking to GameObject and components, what is the logic?

I am trying to attain the legendary skill of mastering how to make my scripts talk with any GameObject and their components wherever they are. To do that, i watched a couple of tutorials like https://www.youtube.com/watch?v=LrkfSqxz4jU, but my brain still seem to resist to smartness :(.
So far, i have understood than in order to do that i first need my
script to find the right gameobject in my scene (if the script is not
attached directly to it), and assign it to a variable, with for
example:
myVariable = GameObject.Find ("MyGameObjectName");
Then, when i have found this gameobject (and eventually summoned it if it was not in my scene), i find myself at loss to figure out how to call the right component (and inherently, how to call the right sub-element.
For example, i have at the moment a game object for my UI with :
RectTransform, CanvasRenderer,UI Controller (Script),Grid Layout Group (Script)
In order to modify the RectTransform 's Pivot X for example, my logic tells me to add to my script:
myVariable.GetComponent<RectTransform> ();
myVariable.RectTransform.Pivot.x = 0.75;
...Which get all red and bad, and i don't understand why. I am also not knowing how i am supposed to call the component GridLayoutGroup. I suppose there is a even dirtier trick in the sense that it is written (script)...
To give you another example that i find confusing, if i would type myVariable.transform.position.x , is it changing the RectTransform, or another hidden transform that i don't know of ?
It is confusing because i would think that logically, this should be called instead myVariable.RectTransform.position.x or something.
So the point of all that is: What's the big idea ? What is the core concept that i am missing ?
I am confused ! :D
Because having public fields is bad practice (accessible from everywhere) you should use serialized fields.
I'll just use the example Vancete made up, but with a serialized field instead of a public field.
[SerializeField] GameObject myGo; // a space to drop a GameObject will appear in the inspector too,
// with the benefit of not having a public field
// (not specifying public, private, protected etc. makes the field private in C#)
void Start() {
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}
At the bottom of this page, you'll find a nice table, comparing these modifiers.
These people here are all proving my concept. As the user, who wrote the last answer on the linked page, points out, even Unity is using [SerializeField] in their example project.
You'll find another proof in this article.
The fastest and best way to access a GameObject is declaring it as public and drag&dropping in the inspector.
GameObject.Find is slow (since it requires a tree search) and impractical (you will have problems if you rename the GameObject or change its hierarchy), things that can be avoided linking it in the mentioned way above.
For example, using GameObject.Find inside the Update is a real performance killer.
Also, if you are going to access to a GameObject component more than once, it's recommended to reference it before using it.
public GameObject myGo; // a space to drop a GameObject will appear in the inspector
void Start(){
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}