Unity - Destroying one duplicated enemy leads to can't attack anymore - unity3d

I've created a "game" where you can attack enemies with a sword. All damages applies to only one enemy, even if i attack the other one. Also when I destroy the first I get this message
MissingReferenceException: The object of type 'RectTransform' has been destroyed but you are still trying to access it.
How do I fix it?
Here's my code:
Attached to the enemy
public class EnemyHealth : MonoBehaviour
{
private Transform healthBar;
private Transform canvas;
public float maxHealth = 100f;
public float damage = 10f;
float currentHealth;
float barLength;
private void Start()
{
currentHealth = maxHealth;
GameObject gfx = gameObject.transform.Find("GFX").gameObject;
canvas = gfx.transform.Find("Health Bar");
GameObject canv = canvas.gameObject;
healthBar = canv.transform.Find("Green Bar");
barLength = canvas.GetComponent<RectTransform>().rect.width * canvas.localScale.x;
}
public void GetStruck()
{
currentHealth -= damage;
if (currentHealth < 0) currentHealth = 0;
healthBar.localScale = new Vector3(currentHealth / maxHealth, 1f, 1f);
Vector3 p = healthBar.position;
p -= damage / (maxHealth * 2) * barLength * transform.right * -1;
healthBar.position = p;
if(currentHealth == 0)
{
Destroy(gameObject);
}
}
}
And the sword attack
using UnityEngine;
public class SwordAttack : MonoBehaviour
{
public Animator animator;
private EnemyHealth enemyHealth;
private bool isAttacking;
private void Start()
{
enemyHealth = GameObject.FindGameObjectWithTag("Enemy").GetComponent<EnemyHealth>();
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
isAttacking = true;
animator.Play("swordSwing", -1, 0f);
}
else if(animator.GetCurrentAnimatorStateInfo(0).normalizedTime > 1)
{
isAttacking = false;
}
animator.SetBool("isAttacking", isAttacking);
}
private void OnTriggerEnter(Collider other)
{
if(isAttacking && other.CompareTag("Enemy"))
{
enemyHealth.GetStruck();
}
}
}

private void Start()
{
enemyHealth = GameObject.FindGameObjectWithTag("Enemy").GetComponent<EnemyHealth>();
}
This is your mistake. You are only getting 1 enemy's health at your start method and you are always decreasing from that enemy's health. Instead you can get the hitted enemy's health in your OnTriggerEnter method and apply damage to that enemy.

Related

rpc method not found on object with photonview

I am trying to create a multiplayer TPS where I instantiate a bullet locally (in my editor) and apply force to it. Once it hits other player I would want to call that players TakeDamage RPC.
Sadly I am encountering this weird error message that I can't fix (already taking me days).
my projectile script:
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour
{
[SerializeField] float timeToDestroy;
[SerializeField] ParticleSystem hitEffect;
[SerializeField] TrailRenderer trailRenderer;
float timer;
private Rigidbody rb;
private Collider col;
private void Awake()
{
rb = GetComponent<Rigidbody>();
col = GetComponent<Collider>();
}
private void Update()
{
timer += Time.deltaTime;
if (timer > timeToDestroy) Destroy(gameObject);
}
private void OnCollisionEnter(Collision collision)
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
trailRenderer.enabled = false;
ShowHitEffect(collision.GetContact(0));
col.enabled = false;
if (collision.gameObject.CompareTag("Player"))
{
rb.isKinematic = true;
rb.velocity = Vector3.zero;
trailRenderer.enabled = false;
PhotonView pv = collision.gameObject.GetPhotonView();
Debug.Log("hit " + pv.Controller.NickName);
pv.RPC("DealDamage", RpcTarget.All, PhotonNetwork.LocalPlayer.NickName, .5f, PhotonNetwork.LocalPlayer.ActorNumber);
}
Destroy(gameObject, 2f);
}
private void ShowHitEffect(ContactPoint cp)
{
hitEffect.transform.position = cp.point;
hitEffect.transform.forward = cp.normal;
hitEffect.Emit(1);
}
}
weapon controller script
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponController : MonoBehaviourPunCallbacks
{
[Header("Fire Rate")]
[SerializeField] float fireRate;
float fireRateTimer;
[SerializeField] bool semiAuto;
[Header("Bullet Property")]
[SerializeField] GameObject bullet;
[SerializeField] Transform barrelPos;
[SerializeField] float bulletVelocity;
[SerializeField] byte bulletPerShot;
public AimController aim;
[SerializeField] AudioClip gunshot;
public AudioSource audioSource;
public WeaponAmmo ammo;
public ParticleSystem muzzleFlash;
public ParticleSystem hitEffect;
// Start is called before the first frame update
void Start()
{
fireRateTimer = fireRate;
}
private void Update()
{
if (!photonView.IsMine) return;
if (ShouldFire()) Fire();
}
bool ShouldFire()
{
fireRateTimer += Time.deltaTime;
if (fireRateTimer < fireRate) return false;
if (ammo.currentAmmo == 0) return false;
if (semiAuto && Input.GetKeyDown(KeyCode.Mouse0)) return true;
if (!semiAuto && Input.GetKey(KeyCode.Mouse0)) return true;
return false;
}
[PunRPC]
private void EmitMuzzleFlash()
{
muzzleFlash.Emit(1);
}
void Fire()
{
fireRateTimer = 0;
barrelPos.LookAt(aim.actualAimPos);
audioSource.PlayOneShot(gunshot);
EmitMuzzleFlash();
//photonView.RPC("EmitMuzzleFlash", RpcTarget.All);
ammo.currentAmmo--;
for (int i = 0; i < bulletPerShot; i++)
{
GameObject currentBullet = Instantiate(bullet, barrelPos.position, barrelPos.rotation);
Rigidbody rigidbody = currentBullet.GetComponent<Rigidbody>();
rigidbody.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
// Projectile Instantiate
/*{
GameObject currentProjectile = (GameObject)PhotonNetwork.Instantiate(bullet.name, barrelPos.position, barrelPos.rotation);
Rigidbody rb = currentProjectile.GetComponent<Rigidbody>();
rb.AddForce(barrelPos.forward * bulletVelocity, ForceMode.Impulse);
}*/
}
}
}
player controller script (where rpc is located)
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviourPunCallbacks
{
private PlayerStats stats = new PlayerStats();
void Start()
{
if (photonView.IsMine)
{
UIController.instance.healthSlider.maxValue = stats.maxHealth;
UIController.instance.healthSlider.value = stats.GetCurrentHealth();
}
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
FocusWindows();
}
void FocusWindows()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
}
else if (Cursor.lockState == CursorLockMode.None)
{
if (Input.GetMouseButton(0))
{
Cursor.lockState = CursorLockMode.Locked;
}
}
}
#region
[PunRPC]
public void DealDamage(string damager, float damageAmount, int actor)
{
Debug.Log("called rpc deal damage");
Debug.Log("damager " + damager + " damageAmount " + damageAmount + " actor " + actor);
TakeDamage(damager, damageAmount, actor);
}
public void TakeDamage(string damager, float damageAmount, int actor)
{
if (photonView.IsMine)
{
stats.ReduceHealth(damageAmount);
if (stats.GetCurrentHealth() == 0)
{
PlayerSpawner.Instance.Die(damager);
MatchManager.instance.UpdateStatSend(actor, 0, 1);
}
UIController.instance.healthSlider.value = stats.GetCurrentHealth();
}
}
#endregion
}
Projectile Prefab(resource)
enter image description here
Player prefab
enter image description here
Weird thing is if I go with "Instantiate Arrow in the network" the rpc is getting called. But this is not ideal since it will because it will send the transform of the projectile every time it is flying. So I just want to check in the local (arrow with no photonView) if it hits an enemy then call the rpc of that enemy to make him take damage and possibly display a fake project coming from the damager. If my approach is naive / wrong please tell me a better approach please.
I transfered the rpc call on the same script where the photonView is located as mentioned by #derHugo. I think the main problem was my understanding of RPC. I thought rpc is like a public method where you can call it outside. I think I need to reread the documentations about rpc and raise events.

Physics2D.OverlapBox shows inconsistent behaviour

Recently I started working with Unity, this is the first time I'm trying to build a 2d platformer.
For some reason, when I press the jump button, there is a random chance that it will actually make the player jump. Probably around 1 in 50 that it actually jumps.
I just can't figure out why its doing that. Do you know what I'm doing wrong here?
using UnityEngine;
public class Player : MonoBehaviour
{
public float movespeed = 5f;
public float jumpforce = 5f;
public Rigidbody2D player;
public LayerMask layerMaskPlatforms;
private float movementHorizontalInput;
private bool jumpInput;
private float lastTimeOnGroundInSeconds = 0f;
private float lastTimePressedJump = 0f;
void OnBecameInvisible()
{
// todo: restart game
}
void Update()
{
movementHorizontalInput = Input.GetAxisRaw("Horizontal");
jumpInput = Input.GetButtonDown("Jump");
}
void FixedUpdate()
{
if (jumpInput)
{
AttemptJump();
lastTimePressedJump = 0.2f;
}
else if (lastTimePressedJump > 0)
{
AttemptJump();
lastTimePressedJump -= Time.deltaTime;
}
if (IsOnGround())
{
lastTimeOnGroundInSeconds = 0.2f;
}
else if (lastTimeOnGroundInSeconds > 0)
{
lastTimeOnGroundInSeconds -= Time.deltaTime;
}
player.velocity = new Vector2(movementHorizontalInput * movespeed * Time.deltaTime * 50f, player.velocity.y);
}
private void AttemptJump()
{
if (lastTimeOnGroundInSeconds > 0)
{
player.AddForce(new Vector2(0, jumpforce), ForceMode2D.Impulse);
lastTimeOnGroundInSeconds = 0;
}
}
private bool IsOnGround()
{
Vector2 groundedCheckPosition = (Vector2)transform.position + new Vector2(0, -0.01f);
var overlapBox = Physics2D.OverlapBox(groundedCheckPosition, transform.localScale, 0, layerMaskPlatforms);
return overlapBox;
}
}
One major issue is that the jump input is being polled every frame (Update), but the jump code is done every several frames (FixedUpdate), so if you press jump, it is most likely the FixedUpdate method will never see that jump, explaining why it happens so rarely.
You'd need to save the jump state (maybe in a boolean), so by the time Fixed Update happens, it knows that that a jump occurred. Then set that jump to false, and do the jump logic.

RayCastAll from Camera to Player Not Working

Trying to run a raycast from my camera to Z = 0 that will hit objects on the TransparentFX layer and temporarily make them transparent as they are likely blocking the view of the player. But the raycast never hits anything.
Camera
https://imgur.com/lyTo8OZ
Tree
https://imgur.com/bgNiMWR
ClearSight.cs
[RequireComponent(typeof(Camera))]
public class ClearSight : MonoBehaviour
{
[SerializeField]
private LayerMask raycastLayers;
// Update is called once per frame
void Update()
{
Vector3 forward = transform.TransformDirection(Vector3.forward) * 10;
Debug.DrawRay(transform.position, forward, Color.green);
RaycastHit2D[] hits = Physics2D.RaycastAll(transform.position, transform.TransformDirection(Vector3.forward), 10f, raycastLayers);
if(hits != null && hits.Length > 0)
{
Debug.Log("Found objects blocking player!");
foreach(RaycastHit2D hit in hits)
{
Debug.Log("Making " + hit.transform.gameObject.name + " transparent!");
AutoTransparent at = hit.transform.GetComponent<AutoTransparent>();
if(at == null)
{
at = hit.transform.gameObject.AddComponent<AutoTransparent>();
}
at.MakeTransparent();
}
}
}
}
AutoTransparent.cs
[RequireComponent(typeof(SpriteRenderer))]
public class AutoTransparent : MonoBehaviour
{
[SerializeField]
private SpriteRenderer[] renderTargets;
[SerializeField]
private float transparentRecoveryTime = 0.1f;
private bool isTransparent = false;
private float transparencyTimer = 0;
private void Update()
{
if (isTransparent)
{
UpdateTransparencyTimer();
}
}
private void UpdateTransparencyTimer()
{
transparencyTimer += Time.deltaTime / transparentRecoveryTime;
if(transparencyTimer >= 1)
{
MakeOpaque();
}
}
public void MakeTransparent()
{
transparencyTimer = 0;
if (!isTransparent)
{
isTransparent = true;
foreach (SpriteRenderer renderer in renderTargets)
{
Color c = renderer.color;
renderer.color = new Color(c.r, c.g, c.b, 0.3f);
}
}
}
public void MakeOpaque()
{
isTransparent = false;
foreach(SpriteRenderer renderer in renderTargets)
{
Color c = renderer.color;
renderer.color = new Color(c.r, c.g, c.b, 1);
}
}
}
Figured it out. I was using RaycastHit2D and Physics2D.RaycastAll, which uses Vector2 parameters so the Z forward variable was being taken out of the equation. Switched up to Box Collider and Physics.RaycastAll and it works great.

Trying to add buff to my game

I'm new at programming. I started a Unity3D course at udemy, I already finished the course, but I'm trying to add a buff to my game. What I want is when my player gets that buff, his shot speed inscreases, I tried to do it but im getting this error when I collide with it
NullReferenceException: Object reference not set to an instance of an object
Powerup.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/Galaxy Shooter/Scripts/Powerup.cs:54)
EDIT
Album With usefull images
Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
public bool canTripleShoot = false;
public bool movSpeedBoost = false;
public bool shield = false;
[SerializeField]
private GameObject _laserPrefabs;
[SerializeField]
private GameObject _tripleShootPrefab;
[SerializeField]
private GameObject _shieldGameObject;
[SerializeField]
private GameObject _explosionPrefab;
[SerializeField]
private float _speed = 5.0f;
[SerializeField]
private GameObject[] _engines;
[SerializeField]
private float _fireRate = 0.25f;
private float _canFire = 0.0f;
public int playerHp = 3;
public int _hitcount = 0;
private UIManager _uiManager;
private GameManager _gameManager;
private SpawnManager _spawnManager;
private AudioSource _audioSource;
// Use this for initialization
void Start () {
_audioSource = GetComponent<AudioSource>();
_spawnManager = GameObject.Find("Spawn_Manager").GetComponent<SpawnManager>();
_uiManager = GameObject.Find("Canvas").GetComponent<UIManager>();
_gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
transform.position = new Vector3(0, 0, 0);
if(_uiManager != null)
{
_uiManager.UpdateLives(playerHp);
}
if(_spawnManager != null)
{
_spawnManager.StartSpawn();
}
}
// Update is called once per frame
void Update ()
{
Movement();
//ativar ao pressionar espaço ou botão esquerdo do mouse
if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButton(0))
{
Shoot();
}
}
//renderização e cooldown dos tiros
private void Shoot()
{
if (Time.time > _canFire)
{
_audioSource.Play();
if (canTripleShoot== true)
{
Instantiate(_tripleShootPrefab, transform.position, Quaternion.identity);
}
else
{
Instantiate(_laserPrefabs, transform.position + new Vector3(0, 0.95f, 0), Quaternion.identity);
}
_canFire = Time.time + _fireRate;
}
}
//calculo de dano
public void Damage()
{
if(shield == true)
{
shield = false;
_shieldGameObject.SetActive(false);
return;
}
_hitcount++;
if(_hitcount == 1)
{
_engines[0].SetActive(true);
}
if(_hitcount == 2)
{
_engines[1].SetActive(true);
}
playerHp--;
_uiManager.UpdateLives(playerHp);
if(playerHp < 1)
{
Instantiate(_explosionPrefab, transform.position, Quaternion.identity);
_gameManager.gameOver = true;
_uiManager.ShowTitleScreen();
Destroy(this.gameObject);
}
}
public void ShieldUp()
{
shield = true;
_shieldGameObject.SetActive(true);
}
//controle da velocidade de movimento e teleporte
private void Movement()
{
float controleHorizontal = Input.GetAxis("Horizontal");
float controleVertical = Input.GetAxis("Vertical");
//velocidade de movimento
if(movSpeedBoost == true)
{
transform.Translate(Vector3.up * _speed * controleVertical * Time.deltaTime * 2.0f);
transform.Translate(Vector3.right * _speed * controleHorizontal * Time.deltaTime * 2.0f);
}else
{
transform.Translate(Vector3.up * _speed * controleVertical * Time.deltaTime);
transform.Translate(Vector3.right * _speed * controleHorizontal * Time.deltaTime);
}
//limita jogar até o centro da tela
if (transform.position.y > 0)
{
transform.position = new Vector3(transform.position.x, 0, 0);
}
//limita jogar até a borda inferior
else if (transform.position.y < -4.2f)
{
transform.position = new Vector3(transform.position.x, -4.2f, 0);
}
//teleporta jogar se sair da tela na horizontal
else if (transform.position.x < -9.45f)
{
transform.position = new Vector3(9.45f, transform.position.y, 0);
}
else if (transform.position.x > 9.45f)
{
transform.position = new Vector3(-9.45f, transform.position.y, 0);
}
}
//duração triple shot
public IEnumerator TripleShotPowerDownRoutine()
{
yield return new WaitForSeconds(5.0f);
canTripleShoot = false;
}
public void TripleShotPowerUpOn()
{
canTripleShoot = true;
StartCoroutine(TripleShotPowerDownRoutine());
}
//duração boost de movimento
public IEnumerator MovSpeedBoostDownRoutine()
{
yield return new WaitForSeconds(5.0f);
movSpeedBoost = false;
}
//ativa boost de movimento e inicia contagem de duração
public void MovSpeedBoost()
{
movSpeedBoost = true;
StartCoroutine(MovSpeedBoostDownRoutine());
}
}
Laser
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Laser : MonoBehaviour {
[SerializeField]
public float _speed = 10.0f;
[SerializeField]
public bool _laserBoost = false;
// Use this for initialization
void Start () {
_laserBoost = false;
if (_laserBoost == true)
{
_speed = 100f;
}
}
// Update is called once per frame
void Update () {
//código gigante e dificil de decifrar ~irony
transform.Translate(Vector3.up * _speed * Time.deltaTime);
if (transform.position.y > 6f)
{
if(transform.parent != null)
{
Destroy(transform.parent.gameObject);
}
Destroy(gameObject);
}
}
public IEnumerator LaserBoostDuration()
{
yield return new WaitForSeconds(10f);
_laserBoost = false;
}
public void LaserBoost()
{
_laserBoost = true;
StartCoroutine(LaserBoostDuration());
}
}
Powerup
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Powerup : MonoBehaviour
{
[SerializeField]
private float _speed = 3.0f;
[SerializeField]
private int powerupID;
[SerializeField]
private AudioClip _clip;
// Update is called once per frame
void Update ()
{
//movimenta o powerup para baixo
transform.Translate(Vector3.down * _speed * Time.deltaTime);
//destroy o power ao sair da tela
if (transform.position.y <-7)
{
Destroy(this.gameObject);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.tag == "Player")
{
//acessa o player
Player player = other.GetComponent<Player>();
if(player != null)
{
if(powerupID == 0)
{
//ativa tripleshoot
player.TripleShotPowerUpOn();
}
else if(powerupID == 1)
{
//ativa speedboost
player.MovSpeedBoost();
}
else if(powerupID == 2)
{
//ativar shield
player.ShieldUp();
}
else if (powerupID == 3)
{
Laser laser = GameObject.Find("laser").GetComponent<Laser>();
laser.LaserBoost();
}
}
//detroy powerup
AudioSource.PlayClipAtPoint(_clip, transform.position);
Destroy(this.gameObject);
}
}
}
The error is occuring at
laser.LaserBoost();
One of the two:
1) you don't have a object named "laser" in Scene hierarchy;
2) this object exists but doesn't have a component of type Laser attached to it.
Edit: Now that I saw your image, I can confirm it is the case 1) above. You have a Prefab named "laser", but is doesn't exist in the Scene hierarchy. If you want it to come to existence only when needed, you must instantiate the Prefab in scene.
If you want to search for the Prefab by its name, there is a way, but you'll need to have a folder named Resources inside another named Assets... More info here
Instead, I suggest you another approach. First, you will need a reference to your Prefab in some object, depending on the logic of your program. You seem to have a GameManager class, there could be a good place. Add a new field inside there (if it is the case) like this:
[SerializeField]
public Laser laser
// (...)
Then, change the code that generates the error. GameObject.Find tries to find an object that already exists in scene. In your case, you want to instantiate a clone of a Prefab, by passing a reference to it. Something like this:
else if (powerupID == 3)
{
// I don't know for sure how can you access your GameManager in your program. I will suppose your player have a reference to it.
// You shall change the position depending on your game logic
Laser laserClone = (Laser) Instantiate(player.gameManager.laser, player.transform.position, player.transform.rotation);
laserClone.LaserBoost();
}
Now, select the object in Scene that will have the reference (again, I am supposing it is gameManager) to see its inspector, than fill the laser field with a reference to your Prefab that has a Laser component. Just be sure the clone object will be destroyed when it is not needed.
But... To be very honest, I don't think you will get the result you are expecting anyway. If what you want is just faster shoot rate, the way you're trying to do it now seems pretty convoluted to me. Why don't you do it just like the triple shoot you have? Add a flag inside your player, when it is true the fireRate value changes.

how to stop continous firing of automatic turrets after the enemies cross the collider?

i have a turret,as a game object when a enemy enters it's collison box,the turret starts firing towards it,the logic is when the enemy exits the collider,it should stop its firing ,and other problem is that when again an enemy enters the collison box i.e the second enemy,it gives me an exception ,"MissingReferenceException :the object of type 'transform' has been destroyed but you are still trying to access it.Your script should eihter be check if it is null or you should not destroy it",but i am checking if the list in not null in my code.here is my code
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class TurretScript : MonoBehaviour {
public float shotInterval = 0.2f; // interval between shots
public GameObject bulletPrefab; // drag the bullet prefab here
public float bulletSpeed;
private float shootTime = 0.0f;
private List<Transform> targets;
private Transform selectedTarget;
private Transform myTransform;
private Transform bulletSpawn;
void Start(){
targets = new List<Transform>();
selectedTarget = null;
myTransform = transform;
bulletSpawn = transform.Find ("bulletSpawn"); // only works if bulletSpawn is a turret child!
}
void OnTriggerEnter2D(Collider2D other){
if (other.tag == "enemy"){ // only enemies are added to the target list!
targets.Add(other.transform);
}
}
void OnTriggerExit2D(Collider2D other){
if (other.tag == "enemy"){
targets.Remove(other.transform);
Debug.Log("gone out");
}
}
void TargetEnemy(){
if (selectedTarget == null){ // if target destroyed or not selected yet...
SortTargetsByDistance(); // select the closest one
if (targets.Count > 0) selectedTarget = targets[0];
}
}
void SortTargetsByDistance(){
targets.Sort(delegate(Transform t1, Transform t2){
return Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position));
});
}
void Update(){
TargetEnemy(); // update the selected target and look at it
if (selectedTarget)
{
// if there's any target in the range...
Vector3 dir = selectedTarget.position - transform.position;
float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);// aim at it
if (Time.time >= shootTime){// if it's time to shoot...
// shoot in the target direction
Vector3 lookPos = new Vector3(bulletSpawn.position.x,bulletSpawn.position.y,0);
lookPos = lookPos - transform.position;
float ang = Mathf.Atan2(lookPos.y,lookPos.x)*Mathf.Rad2Deg;
GameObject b1 = Instantiate(bulletPrefab,new Vector3(transform.position.x,transform.position.y,5),transform.rotation)as GameObject;
b1.rigidbody2D.velocity = new Vector3(Mathf.Cos(ang*Mathf.Deg2Rad),Mathf.Sin(ang*Mathf.Deg2Rad),0)*bulletSpeed;
shootTime = Time.time + shotInterval; // set time for next shot
}
}
}
}
here is my enemy script
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class EnemyScript : MonoBehaviour {
public Transform target;
public float speed = 2f;
public int Health;
public float GetHealth()
{
return Health;
}
void Update ()
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
void TakeDamage(int damage){
Health -= damage;
if (Health <= 0)
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D otherCollider)
{
PlayerControl shot = otherCollider.gameObject.GetComponent<PlayerControl>();
if (shot != null)
{
SpecialEffectsHelper.Instance.Explosion(transform.position);
Destroy(shot.gameObject);
}
}
}
you need to check if the selected target is the target leaving the collider. You remove the target from the targets list but the selectedTarget var is still populated.
For the null ref exception. Are you using Destroy() to kill the target? Destroy() doesn't cause an OnTriggerExit() or OnCollisionExit() event call, the object is just gone.
edit: you can get around the lack of a call by adding an OnDestroy() function to the dying object that sets it's position to something well outside the level/view of the player. This way the target leaves the collider and then disappears rather than just disappearing in place.