I need to be able to detect if 2 separate object are touching each other. I have no idea if there is a specific piece of code to do this.
so i made some code that detects if the object the code is attached to is touching something but i don't know how to make it detect if 2 objects with different tags are touching
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Rocket")
{
istouchingrocket = true;
}
if (other.gameObject.tag == "Ground3")
{
Isend = true; //Ground three is the ending platform. This piece of code is attached to oil which is not touching this. I need to detect if the player is touching "Ground3".
}
}
void OnCollisionExit(Collision other)
{
if (other.gameObject.tag == "Rocket")
{
istouchingrocket = false;
}
}
So the code is attached to the oil and when the player touches "ground3" they gain the ability to destroy the oil. The code needs to detect remotely if 2 separate objects are touching.
It's probably better for the player script to have a field that keeps track of if it has gained the ability to destroy oil:
public bool canDestroyOil;
Be sure to set it to false in Start():
canDestroyOil=false;
Then when player detects if it touches "ground3" then set it to true:
canDestroyOil = true;
And then in the oil script, when it touches player it destroys itself if the player can destroy oil:
if (player.canDestroyOil) {
gameObject.Destroy();
}
Take a look at IsTouching() function.
It does exactly what you're asking.
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
}
Context
I'm developing an AbstractAliveEntity, which have basically three functions:
Sight: Detect interactable objects. (Collider + Raycast)
Detection: Detect anothers AbstractAliveEntities (Collider + Raycast)
Hearing: Hear noises (Collider)
Currently i'm creating via script empty gameObjects with these colliders.
What i want
I want to know which collider was trigger in OnTriggerEnter and OnTriggerExit
Code
Creating the Sphere collider
private void Start() {
// Creating empty gameObject
sightGameObject = new GameObject("Sight");
sightGameObject.transform.parent = transform;
sightGameObject.transform.localPosition = new Vector3(0, 0, 0);
// Add Component Sphere
_sightInteractable = sightGameObject.AddComponent<SphereCollider>();
// _sightInteractable = gameObject.AddComponent<SphereCollider>();
_sightInteractable.radius = radiusInteractableDetection;
_sightInteractable.isTrigger = true;
}
Detecting
private void OnTriggerEnter(Collider other) {
// How can i detect which collider was?? this.gameObject = "Player" (i want "Sight")
}
Since Unity is originally designed around a component based approach my approach would be to split up the three separate "detection" systems into separate GameObjects with their own collider and script.
AliveEntity
SightController
ColliderA
DetectionController
ColliderB
HearingController
ColliderC
Then you can use the OnTrigger in each separate script to fire a notification to the main AbstractAliveEntity which then handles them on a case by case basis.
Main Script
OnSight(Collider other) {
// Do sight related actions here
}
OnDetection(Collider other) {
// Do detetction related actions here
}
OnHearing(Collider other) {
// Do hearing related actions here
}
Then for each respetive detector:
// reference to master script
public AbstractAliveEntity aae;
OnTriggerEnter(Collider other) {
// replace function with whatever you want to use
aae.OnSight(other)
}
The Added advantage here is that you are now also free to design 'blind' or 'deaf' Entities without all too much hassle. (You simply do not add the respective components)
other.gameObject to get the gameObject the other collider is attached to.
Check unity documentation about collider here for more info.
I am creating a video game where the character has to travel within literal art canvases (the ones that you use for painting) to reach the end goal.
Note that the "canvas" I am referring is not the UI element, but the actual canvases you would see in real life.
I based my code off the concepts of portals. This may not be the most efficient way of dealing with it and I will consider all advices.
This is my current code:
public Transform PortalB;
public CharacterController2D Player;
public GameObject PlayerObject;
private GameObject CloneTemporary;
public Queue<GameObject> Clones = new Queue<GameObject>();
private bool isCreated = false;
// Use this for initialization
void Start () {
Clones.Enqueue(PlayerObject);
}
// Update is called once per frame
void Update () {
// Portal adapts to the player's current position
if (Player == null) {
Player = GameObject.FindWithTag("Player").GetComponent<CharacterController2D>();
PlayerObject = GameObject.FindWithTag("Player");
}
}
void OnTriggerEnter2D (Collider2D other) {
if (other.gameObject.tag == "Player") {
if (Vector2.Distance(transform.position, other.transform.position) > 0.7f) {
if (!isCreated) {
CloneTemporary = Instantiate(PlayerObject, new Vector2 (PortalB.position.x, PortalB.position.y), Quaternion.identity) as GameObject;
Clones.Enqueue(CloneTemporary);
isCreated = true;
}
}
}
}
void OnTriggerExit2D (Collider2D other) {
if (Vector2.Distance(transform.position, other.transform.position) > 0.7f) {
print(Clones.Count);
if (Clones.Count > 1) {
UnityEngine.Object.Destroy(Clones.Dequeue());
}
}
isCreated = false;
}
The "original character" will collide with the portal's box collider and create a copy on the other end of the portal. The box collider is annotated in red in the first image below. Note that the sizes are exactly the same.
Note that it technically is not a portal, but since it's a box which brings a character from one place to another, I might as well call it a portal.
Once the original leaves the box collider, it will get deleted, and the clone will then become the "original".
I am using a queue system to determine which "clone" gets deleted first.
There are a few problems with this:
It is very inefficient. I have to create portals manually for every intersection point in the canvases. Imagine a level full of canvases, and imagine a game with full of levels...
When it touches the portal, a duplicate will get spawned by the original character. There are three characters, but the Clones.Count only registers two.
I am not sure how well the code will work for vertical traverses.
When the character crosses the portal, it should be able to turn back. In this code, the character would glitch through the floor if he were to turn back and not get deleted by the OnExit function. I suspect this has something to do with the size of the portal, but I can foresee that even if it were to be bigger, the character would immediately disappear if he turns back.
I think the OnTriggerEnter function gets activated when the character is teleported on the other side. This might have an effect on the errors I just stated, but it may cause more in the near future.
I havent found any Way to check for an Tag or something similiar to differenciate various IsTrigger Colliders. For example, i have a Ladder with an IsTrigger in my Game that lets me climb it once i am inside the Collider. Now i want to have another Object with an IsTrigger(like an Item / a Pickup), but i couldnt find a Way to tell my Script that it should let me climb upon entering a Ladder-IsTrigger and let me gain Health upon entering an Item-IsTrigger (Right now its doing BOTH at the same time for both IsTriggers).
Some of my CharacterScript that i use for the Movement and Interaction with Objects:
void OnTriggerStay2D(Collider2D other)
{
if (Input.GetKeyDown("w"))
{
GetComponent<Rigidbody2D>().gravityScale = -0.2f;
}
if (Input.GetKeyUp("w"))
{
GetComponent<Rigidbody2D>().gravityScale = 3;
}
}
void OnTriggerExit2D(Collider2D other)
{
GetComponent<Rigidbody2D>().gravityScale = 3;
}
In "Trigger2D" or "Collision2D" functions, you can check whether other.gameObject.tag == "someTag". Just be sure you've tagged the other game object with someTag.
I am using unity 5 c# and I have a gameobject with 2 trigger colliders one of them is in a different location.
I need to be able to use OnTriggerStay2D and OnTriggerEnter2D for them but I need to find what trigger is being entered. Right now if I enter the 1st(polygon) trigger the OnTriggerEnter activates for the 2nd(box).
How can I Tell the two colliders apart???
public void OnTriggerEnter2D(Collider2D other) //2nd collider trigger
{
if (other.tag == "Player") {
Found = true; //if the player is in shooting range
Idle = false;
}
}
public void OnTriggerStay2D(Collider2D other) //1st collider trigger
{
if (Found != true) {
if (other.tag == "Player") {
Shield = true;
Idle = false;
}
}
}
public void OnTriggerExit2D(Collider2D other) //2nd collider trigger
{
if (other.tag == "Player") {
Found = false;
Shield = false;
Shooting = false;
Idle = true;
}
}
I have tried making the 1st trigger public void OnTriggerStay2D(PolygonCollider2D other) but it says "This message parameter has to be of type: Collider2D
The message will be ignored."
What I am trying to do is have a polygon trigger in front of the gameobject and a different box trigger closer to the gameobject so when you go near the gameobject you enter the 1st trigger and it puts its shield up but when you get close to it (within shooting range of it) it will put its shield down and start shooting you.
Well collider2d detects all types of 2d colliders. It doesn't matter if it's polygon or just a box. As the documentation suggestions it doesn't need to be public or private. It only takes a collider2d as it's argument however.
For debugging purposes why not use print?
Print("you've entered the trigger function");
Also I wouldn't use 2 different trigger colliders on the same GameObject. Why not just make 2 separate gameobjects so you can have more thorough detection. Each GameObject with its own trigger collider can have different tags.
If you have to use 2 trigger colliders on one object. Which isn't the best idea. You could use shapeCount to determine which one it's hitting. Although like I said I would warrant against doing 2 trigger colliders on the same object when whatever you're trying to do can be easier on two separate objects.
However links aren't usually prohibited I think. I would watch and study these videos. They're very useful for explaining the engine and they really aren't even that long.
https://unity3d.com/learn/tutorials/modules/beginner/2d
They even have a video explaining 2d colliders.
This is my fix. In one of my games I have a boulder, I have a trigger which will delete a block below it so it falls, I then have another trigger which tells the boulder to start moving left or right I then also have another trigger which will delete the boulder once the boulder comes in contact.
So what you can do is create 2 new game objects, create a new CS file and name them appropriately, then with those two new classes allow them to take in the gameobject you are referring to in your question.
Then when they are triggered you can use code from their class.
So your first class would become something like this
public void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player") {
Enemy.Found = true; //if the player is in shooting range
Enemy.Idle = false;
}
}
public void OnTriggerExit2D(Collider2D other)
{
if (other.tag == "Player") {
Enemy.Exit2DTrigger();
}
}
Then the other class would be something like this
public void OnTriggerStay2D(Collider2D other)
{
if (Enemy.Found != true) {
if (other.tag == "Player") {
Enemy.Shield = true;
IEnemy.dle = false;
}
}
}
public void OnTriggerExit2D(Collider2D other)
{
if (other.tag == "Player") {
Enemy.Exit2DTrigger();
}
}
Then in your Enemy class you would have
public void Exit2DTrigger()
{
Found = false;
Shield = false;
Shooting = false;
Idle = true;
}
P.S. also don't you need to use other.gameObject.tag == "Player" ?