Detecting collisions between two separate animations - c#

My animations enters a state and it's collision with enemy projectiles either defends himself or gets hurt depending on what animation he is currently in. I'm trying to detect collisions with the ONTRIGGERENTER function and boxcollider2D's but it's not having any affect. I want to figure out how to correctly facilitate trigger enters and collisions between these animations.
I've already tried giving my sprite a tag and calling that tag when the ONTRIGGERENTER function is called but it didn't work. I also tried a more complicated way of calling the tag of the collider but that didn't work either. How do you access the trigger when it's an animation?
string DefenceAnimTag = "Defending";
string DestroyEnemTag = "Eliminated";
//This code is connected to the enemy projectile and trying to
//sense when it's collided with the player
void OnTriggerEnter(Collider2D col)
{
if (col.tag == Defending)
{
GetComponent<Animator>().SetBool("Elim", true);
}
else { //deal damage to the player }
}
//The first method didn't work so I tried a second method.
//Here is an alternative attempt at detecting triggers in
//animations.
void OnCollisionStay2D(Collider2D col)
{
if (col.gameobject.CompareString("Defending"))
{
GetComponent<Animator>().SetBool("Elim", true);
}
}
//This method didn't work either even though the Animation
//WOULD be Defending
I expected enemy projectiles to collide with my player when he was defending himself and get defeated. I knew that it was working when the Enemy projectiles transition into their Elim state, where they get defeated by enemy defenses, however they made collisions and then continued unaffected.

Okay, okay, I figured it out. Because a Gameobject can have many animations to it, you cannot go by the tag that the GameObject in the inspector has. You have to go by the title of the Animations that is currently playing. In order to access the animation currently playing we must use the following code:
AnimatorClipInfo[] m_AnimClipInf;
string m_ClipName;
void Start()
{
//Set up our projectile for possible Elimination
//upon Collision
Getcomponent<Animator>().SetBool("Elim", false);
}
void OnTriggerEnter2D(Collider2D col)
{
m_AnimClipInf = col.GetComponent<Animator>
().GetCurrentAnimatorClipInfo(0);
m_ClipName = m_AnimClipInf[0].clip.name;
if (m_ClipName == "Defending")
{
GetComonent<Animator>().SetBool("Elim", true);
//Projectile gets eliminated
}
}

Related

Having problems with OnBecameVisible (sees through walls and is visible on scene view)

I'm trying to make a script that has an enemy chase the player only if the enemy is viewable by the player camera and the player hits the space key. I've been trying to use render.isVisible but run in to two MAJOR problems:
isVisible is enabled even if the enemy is visible in the scene view, making testing impossible.
isVisible works through walls, so if the player is looking at a wall and the enemy is behind it, it still registers as isVisible.
Please help I'm losing my mind. Thank you!
public NavMeshAgent enemy;
public Transform player;
Renderer m_Renderer;
private void Start()
{
m_Renderer = GetComponent<Renderer>();
}
private void OnBecomeInvisible()
{
enabled = false;
}
void OnBecameVisible()
{
enabled = true;
if (Input.GetKey(KeyCode.Space) && m_Renderer.isVisible)
{
Debug.Log("is visible");
enemy.SetDestination(player.position);
}
}
private void Update()
{
OnBecameVisible();
}
I'm honestly not sure what to try, thank you so much for any help!
IsVisible is really not designed for that usage. It just means object is being rendered by any camera. See the documentation here: https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
To determine whether something is actually visible from one entity by another, you typically have to do a frustum check followed by one or more raycasts to determine whether the target is blocked.

Lives Implementation in Unity2D

I begun the trek into Unity2D development a few months ago, so i'm still fairly new to all the unity engine jargon. In my game, I decided to implement the use of 'Lives'. I scripted out what (in my eyes) should work but every time the player dies instead of decrementing the lives counter and restarting it at the scene, it immediately loads the scene 1 (i.e. the GameOver screen) Is my logic here on this page incorrect or is there just a better way overall to handle lives than PlayerPrefs? (ALSO: Its worth mentioning that the Lives are instantiated/sent to playerprefs in the player script, I don't figure I need to include that one here)
This is the main block of code on my destroyer objects' script to account for 'death':
public static int lives;
void Start()
{
lives = PlayerPrefs.GetInt("lives");
}
void OnTriggerEnter2D(Collider2D other)
{
//If the trigger happens to be tagged as a 'Player', does this.
if (other.tag == "Player")
{
lives--;
if (lives < 0)
{
PlayerPrefs.DeleteAll();
SceneManager.LoadScene(1);
} else
{
SceneManager.LoadScene(0);
PlayerPrefs.SetInt("lives", lives);
}
}
if (other.gameObject.transform.parent)
{
Destroy(other.gameObject.transform.parent.gameObject);
}
else {
Destroy(other.gameObject);
}
}
As I mentinoned in comment, I think you forget to swithOn isTrigger field from Inspector which is under the Collider area.
Probably you thought like you are using onCollisionEnter. Also if you check the differences between OnTriggerEnter and OnCollisionEnter it will be very helpful.
As #Ugur Tufekci answers, But make sure to add BoxCollider2d not Box Collider.The simple box collider is 3d but your are detecting that onTriggerEnter2D that means 2d box collider has to be added

OnTriggerEnter2D Called Twice in Unity

Hi guys I am having a problem in unity with OnTriggerEnter2D.
The player has 2 bullets, any time the player bullet hits the enemy it should increment the score by 100, but for some reason it is incrementing the score by 200 if two player bullets hit the enemy. Both bullets fire at the same time and are at either side of the players gun. So it should only ever increment the score by 100 and not 200.
Here is my code:
void OnTriggerEnter2D(Collider2D col)
{
if(col.tag == "PlayerBullet")
{
this.score += 100;
}
}
Other information:
My player bullet and enemy both have Box Collider and RigidBody2D attached to them. They both have the isTrigger option checked.
If you want it to work just once you can ignore collision after first increment of the score(aka after first collision) like this:
void OnTriggerEnter2D(Collider2D col)
{
if(col.tag == "PlayerBullet")
{
this.score += 100;
Physics2D.IgnoreCollision(col, GetComponent<Collider2D>())
}
}
Note that After this point all collisions between PlayerBullet and Enemy will be ignored.
If I understand it correctly, the player has two guns, and I assume they are fired at the same time.
In this case, we can make it more beautiful with condition-condition statements.
I'm leaving the code block below.
if (Input.GetMouseButtonDown(0) && Input.GetMouseButtonDown(1))
{
Debug.Log("Fire Metod(Score)");
}
else
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("Fire Metod(Score)");
}
if (Input.GetMouseButtonDown(1))
{
Debug.Log("Fire Metod(Score)");
}
}
Often times you can set a flag to tell the game to only increment once. A flag is just a bool value, and can be private within the scope of the class. Sort of like:
if(canHit)
{
canHit = false;
//add score
canHit = true;
}
That basic formula should get you the results you want.
I'm upgrading my comment to an answer because after reading your question and the comment responses I believe you need a non-code answer.
You want two objects to work together and count as one 'hit' when they collide with another object. That sounds to me like a situation where you should be placing those objects inside another one, let's call it a 'shot' object, and you should be doing collisions and whatnot based on that. That way, if both bullets hit only one 'shot' hit, so it will count with the code as-is and it sounds like it will be implemented more as you've expected it to be.

Alternatives to Destroy() or SetActive()

I have a problem with my script. I'm really looking for a solution without having to post code. ( I'm using Unity 2019 with C#. )
Here's the dilemma:
I have two scripts
1) EnemyDamage
2) EnemySpawn
Both scripts work fine until one of the enemies is killed.
Basically when my enemy('s) die I use Destroy(gameObject) which ultimately is causing the error on my spawn script because the EnemySpawn is still trying to access the destroyed enemy.
The way my spawn script works is multiple enemies can be chosen from a list. Then using coroutines, the enemies appear on screen and then disappear using SetActive(true/false). So even if I elect to set the enemy to false in EnemyDamage, the EnemySpawn will just set it back to true.
So what I need is another way to hide my enemy. ( And I can't just move it out of camera sight because the EnemySpawn will just put it back on a random spawn point in camera view again )
What are some alternatives to Destroy(), SetActive(), or moving out of camera range?
Try adding this in the the spawn enemy script. It should remove an enemy from the list when that enemy is destroyed .The enemysToRemove variable is there because you cant edit a list while iterating through it (thanks Hristo).
public List<GameObject> enemys;
List<GameObject> enemysToRemove = new List<GameObject>();
void Update () {
foreach(GameObject enemy in enemys){
if (enemy == null) {
enemysToRemove.Add (enemy);
}
}
foreach (GameObject item in enemysToRemove) {
enemys.Remove (item);
}
}
Alternatively, put try and catch in-front of everything you do to the enemy`s in the spawn enemy script. Like this:
public List<GameObject> enemys;
foreach(GameObject enemy in enemys){
try{
//thing I want to do to this enemy
}catch{
Debug.Log ("enemy destroyed");
}
}

Identify a selected enemy prefab to play death particle system

I am trying to play a particle effect when an enemy is killed but it seems to play on a randomly selected one rather than the one that was hit. However the enemy that was hit still disappears and still add points to the score.
At the moment I have three scripts to carry this out (All have been shortened so I'm only showing the relevant code):
One which is attached to boxes that are thrown at enemies that detects if they have collided with an enemy prefab.
void OnCollisionEnter (Collision theCollision) {
if (canProjectileKill == true) {
// If the projectile hits any game object with the tag "Enemy" or "EnemyContainer".
if (theCollision.gameObject.tag == "Enemy") {
GameObject.Find("EnemyExplosion").GetComponent<enemyDeath>().ProjectileHasHitEnemy();
// Destroy the projectile itself.
Destroy (gameObject);
// Destroy the game object that the projectile has collided with (E.g. the enemy).
Destroy (theCollision.gameObject);
GameObject.Find("Manager").GetComponent<projectileSpawner>().deleteProjectile();
}
}
}
Another that is attached to the enemy prefabs which detects if they have been hit by a box.
void OnCollisionEnter (Collision theCollision) {
if(theCollision.gameObject.tag == "Projectile") {
GameObject.Find("EnemyExplosion").GetComponent<enemyDeath>().EnemyHasBeenHit();
}
}
I then run an if statement asking if both the box has hit the enemy prefab AND if the enemy prefab has been hit by the box in an attempt to identify a single prefab rather than all of them. However this still doesn't work.
public bool HasProjectileHitEnemy;
public bool HasEnemyBeenHitByProjectile;
void Start () {
gameObject.particleSystem.Stop();
HasProjectileHitEnemy = false;
HasEnemyBeenHitByProjectile = false;
}
public void ProjectileHasHitEnemy () {
// From projectile.
HasProjectileHitEnemy = true;
}
public void EnemyHasBeenHit () {
// From enemy.
HasEnemyBeenHitByProjectile = true;
PlayParticleSystem();
}
public void PlayParticleSystem () {
if (HasEnemyBeenHitByProjectile == true && HasProjectileHitEnemy == true) {
gameObject.particleSystem.Play();
HasProjectileHitEnemy = false;
HasEnemyBeenHitByProjectile = false;
}
}
}
I am aware this is a long question but I have been stuck on this for over a week, so any help would be much appreciated. Thank you :)
I'm not sure what kind of object EnemyExplosion is, but your problem seems to be the search for this object. During OnCollisionEnter you know exactly between which objects the collision occurred. But now you're starting a search for any object that is called EnemyExplosion. That's the reason your particles appear random.
Update:
Ok, with your structure something like that
EnemyContainer
- EnemyExplosion
- Particle System
- EnemyModel
- Collider
If EnemyModel contains the collider, you can get to EnemyExplosion and finally enemyDeath the following way.
var explosion = theCollision.transform.parent.gameObject.GetComponent<EnemyExplosion>();
explosion.GetComponent<enemyDeath>().ProjectileHasHitEnemy();
Now that you're accessing the correct object, you can remove some of your double checks and rely on one collider event.
I seem to have found a way around this. Instead I've just set it to instantiate the particle system whenever an enemy detects that it has collided with a projectile. I then use a Coroutine to delete the particle system 2 seconds after.

Categories