- Home /
How to check who shot whom
I have a game where 25 agents are fighting against 25 other. But I have also a problem that I don't know how to check wich enemy shot the other one. I am instantiating bullets and the bullets have a tag "bullet" for the 25 agents and "counterbullet" tag for the other 25. And also use one bullet script for the 25 agents and one script for the other 25. Do you know how I could do a check?
Answer by Hellium · Jul 18, 2019 at 07:54 AM
How are we supposed to help you if you don't provide your current code?
A simple way to do this is to inject a reference of the shooter into the bullet somehow. I've done this when the bullet is instantiated by the Weapon
class which is responsible to shoot. The reference of the Shooter is injected by the PlayerController at Start.
// PlayerController
public Weapon Weapon;
private void Start()
{
Weapon.Shooter = this;
}
private void Update()
{
if( Input.GetMouseButtonDown(0))
Weapon.Shoot();
}
// Weapon
public PlayeController Shooter { get ; set ;}
public Bullet BulletPrefab;
public void Shoot()
{
Bullet bullet = Instantiate( BulletPrefab );
bullet.Shooter = Shooter;
}
// Bullet
public PlayeController Shooter { get ; set ;}
private void OnCollisionEnter( Collision collision )
{
PlayerHealth playerHealth = collision.transform.GetComponentInParent<Health>();
if( playerHealth != null )
{
playerHealth.Hurt( damages, Shooter );
}
}
// PlayerHealth
public void Hurt( int damages, PlayerController shooter )
{
Debug.Log("The player " + shooter.name + " has hurt me for " + damages + " HP" ) ;
}
@Hellium I have the class EnemyController and EnemyBulletController:
public class EnemyBulletController : $$anonymous$$onoBehaviour {
public float speed;
[HideInInspector]
/// <summary>
/// The associated agent.
/// This will be set by the agent script on Initialization.
/// Don't need to manually set.
/// </summary>
EnemyController agent;
static Animator anim;
Game$$anonymous$$anager instanceG$$anonymous$$;
private void Awake()
{
instanceG$$anonymous$$ = Game$$anonymous$$anager.instance;
agent = EnemyController.instance;
anim = instanceG$$anonymous$$.player.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
Destroy(gameObject, 2); //8
}
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "counterAgent")
{
try
{
col.gameObject.GetComponent<PlayerController>().GetGame$$anonymous$$anager().PlayerIsDead();
}
catch(Exception e)
{
Debug.Log(col.gameObject.name);
}
}
if (col.gameObject.CompareTag("wall"))
{
Destroy(gameObject);
}
}
And this in EnemyController I instantiate the bullet:
if (timeBtwShots <= 0)
{
EnemyBulletController newBullet =
Instantiate(bullet, firePoint.position, firePoint.rotation)
as EnemyBulletController;
timeBtwShots = startTimeBtwShots;
newBullet.speed = bulletSpeed;
}
else
{
timeBtwShots -= Time.deltaTime;
}
How can I change my code so that I can detect which agent shot the player
I hope you guys can help me. I struggle with this since some days
There is something very strange with your code:
private void Awake()
{
instanceG$$anonymous$$ = Game$$anonymous$$anager.instance;
agent = EnemyController.instance;
anim = instanceG$$anonymous$$.player.GetComponent<Animator>();
}
Why EnemyController
is a Singleton? Don't you have several ennemies?
Try this:
// EnemyBulletController
public EnemyController agent;
static Animator anim;
Game$$anonymous$$anager instanceG$$anonymous$$;
private void Awake()
{
instanceG$$anonymous$$ = Game$$anonymous$$anager.instance;
anim = instanceG$$anonymous$$.player.GetComponent<Animator>();
}
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "counterAgent")
{
try
{
Debug.Log( "Bullet shot by " agent.name, agent );
col.gameObject.GetComponent<PlayerController>().GetGame$$anonymous$$anager().PlayerIsDead();
}
catch(Exception e)
{
Debug.Log(col.gameObject.name);
}
}
if (col.gameObject.CompareTag("wall"))
{
Destroy(gameObject);
}
}
// EnemyController
if (timeBtwShots <= 0)
{
EnemyBulletController newBullet =
Instantiate(bullet, firePoint.position, firePoint.rotation)
as EnemyBulletController;
timeBtwShots = startTimeBtwShots;
newBullet.speed = bulletSpeed;
newBullet.agent = this;
}
@Hellium So I did like you said and it is working. The code I have send you was from the main game where I have a player. I alsoo have a unity project where I train the agents. And the code looks like this now:
if (col.gameObject.tag == "counterAgent")
{
try
{
//Debug.Log("Bullet shot by: " + agent.name,agent);
col.gameObject.GetComponent<CounterEnemyController>().GetGame$$anonymous$$anager().CounterAgentDead(col.gameObject,agent.name);
}
catch(Exception e)
{
Debug.Log(col.gameObject.name);
}
}
And in Game$$anonymous$$anager I do this:
public void AgentDead(GameObject opponent, string killedBy)
{
if (listOfAgent.Contains(opponent))
{
agentsDeadsPerRound++;
scoreCounterEnemy.IncreaseScore();
opponent.GetComponent<EnemyController>().Done();
for (int i = 0; i < listOfCounterAgent.Count; i++)
{
if (listOfAgent[i].name == killedBy)
{
listOfAgent[i].GetComponent<CounterEnemyController>().AddReward(1.0f);
break;
}
}
}
The code enters the catch block everytime when I use agent.name. I get this output:
System.NullReferenceException: Object reference not set to an instance of an object
at EnemyBulletController.OnTriggerEnter (UnityEngine.Collider col) [0x00039]
Do you maybe know why it is like this? And it is not entering this if statement: if (listOfAgent[i].name == killedBy)
Oh sorry my bad, it is entering the if statement. At first I placed a debug.log after the addReward() statement. And there was no output. Then I placed it before the the statement and it worked. It is a strange behaviour.
At first I placed a debug.log after the addReward() statement. And there was no output. Then I placed it before the statement and it worked. It is a strange behaviour.
You may have an exception.
for (int i = 0; i < listOfCounterAgent.Count; i++)
{
if (listOfAgent[i].name == killedBy)
It's strange you use listOfCounterAgent.Count
as a limit of your loop, but you check against listOfAgent[i].name
@Hellium Yes you are absolutely right! But I still get the error. Could the null refence appear because I set the EnemyController agent to public and it is awaiting an instance? I also got the error, when I did not pass the agent.name parameter to game$$anonymous$$anager. When I did Debug.Log(agent.name) I also got the null reference exception
Could it be that when the bullet touches the agent it gets destroyed. When it is destroyed it does not have the instance anymore
The agent is public
indeed but does not need to be set in the inspector. It should be set in the EnemyController
when the bullet is instantiated as I have indicates.
EnemyBulletController newBullet =
Instantiate(bullet, firePoint.position, firePoint.rotation)
as EnemyBulletController;
timeBtwShots = startTimeBtwShots;
newBullet.speed = bulletSpeed;
newBullet.agent = this; // here
Answer by DropoutGamer · Jul 18, 2019 at 07:15 AM
I think i got your question , you have 1 script using on 50 objects, in 2 25 25 group with same tag names .. i think you can get name of gameobjects ... i dont it think it matters that all 50 gameobject names are different .. u can simply use a debug to get names of gameobject from which ray cast is initiated and which game object got hit hit.collider.gameObject.name;
So one agent1 hs shot agent2. And I want to check which of the 25 agents shot agent2. Is it still the same then?
yeah .. if all 50 agent have different names, u can simply get the names to understand who is killing whom .
Answer by sir_ver · Jul 26, 2019 at 07:35 AM
@Hellium This is the EnemyBulletController code:
using UnityEngine;
using System.Collections;
using System;
public class EnemyBulletController : MonoBehaviour {
public float speed;
[HideInInspector]
public EnemyController agent;
static Animator anim;
GameManager instanceGM;
private void Awake()
{
instanceGM = GameManager.instance;
//agent = EnemyController.instance;
anim = instanceGM.player.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
//Destroy(gameObject, 2); //8
}
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "counterAgent")
{
try
{
//Debug.Log("Bullet shot by: " + agent.name);
col.gameObject.GetComponent<CounterEnemyController>().GetGameManager().CounterAgentDead(col.gameObject,agent.name);
Destroy(gameObject);
}
catch(Exception e)
{
Debug.Log(e);
}
}
if (col.gameObject.CompareTag("wall"))
{
Destroy(gameObject);
}
}
}
And this is the CounterEnemyBulletController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class CounterEnemyBulletController : MonoBehaviour {
public float speed;
[HideInInspector]
public CounterEnemyController agent;
static Animator anim;
GameManager instanceGM;
private void Awake()
{
instanceGM = GameManager.instance;
//agent = CounterEnemyController.instance;
anim = instanceGM.player.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.forward * speed * Time.deltaTime);
Destroy(gameObject, 2); //8
}
void OnTriggerEnter(Collider col)
{
if (col.gameObject.tag == "agent")
{
try
{
//Debug.Log("Bullet shot by: " + agent.name);
col.gameObject.GetComponent<EnemyController>().GetGameManager().AgentDead(col.gameObject,agent.name);
}
catch(Exception e)
{
Debug.Log(e);
}
}
if (col.gameObject.CompareTag("wall"))
{
Destroy(gameObject);
}
}
}
What is this CounterEnemyBulletController
class? It is almost identical to EnemyBulletController
. Are you sure it is instantiated the same way as a EnemyBulletController
and that the agent is correctly set? I don't believe you should have two classes with so much in common.
I have two types of agents: One is CounterEnemy and the other one is just Enemy. So I created then the scripts for both of the type of agents to differentiate the shooting and movement etc. I am using the ml agents toolkit, where I have to train the agents. Later on I will replace the counterEnemy with the Player and the player will be played by the user.
Last chance: $$anonymous$$aybe because this GetGame$$anonymous$$anager() ? This also returns an instance like that:
public Game$$anonymous$$anager GetGame$$anonymous$$anager()
{
return instanceG$$anonymous$$;
}
I really don't know... But this error falls outside the scope of this question (and outside the scope of Unity Answers). Use the debugger of your IDE to understand what's going on and make sure all your variables are correctly initialized.