I'm having trouble trying to destroy the Enemy game object with Script 2 from Script 1, which is a script containing common enemy data.
Script 1:
public class BaseEnemy : MonoBehaviour
{
[SerializeField]
public int health = 4;
public int speed = 0;
public void TakeDamage(int damage)
{
health -= damage;
Debug.Log("Damage Taken");
if (health <= 0)
{
Destroy(??);
}
}
}
Script 2:
public class EnemyPlayerFollow : BaseEnemy
{
public Transform player;
private Rigidbody2D rb;
private Vector2 movement;
void Start()
{
rb = this.GetComponent<Rigidbody2D>();
}
void Update()
{
Vector3 direction = player.position - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
rb.rotation = angle;
direction.Normalize();
movement = direction;
//if (health <= 0)
//{
// Destroy(gameObject);
//}
}
private void FixedUpdate()
{
moveCharacter(movement);
}
//public void TakeDamage(int damage)
//{
// health -= damage;
// Debug.Log("Damage Taken");
//}
void moveCharacter(Vector2 direction)
{
rb.MovePosition((Vector2)transform.position + (direction * speed * Time.deltaTime));
}
}
What I want to know, is how to modify Script 1 to Destroy Script 2 (Basically what to put here --> ??) when health <=0.
ANSWER:
Was as easy to put Destroy(this.gameObject); on Script 1.
Thanks to "Chronicle" for the guidance.
Related
InvalidCastException: Specified cast is not valid (wrapper castclass) System.Object.__castclass_with_cache(object,intptr,intptr) || Unity
I'm trying to make a script for the enemy sprite to respawn when it is destroyed. This script does work for the most part as the sprite does respawn, however, its clone after its destroyed only has its Sprite Renderer component activated and it just gives me this error message:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMovement : MonoBehaviour
{
[Header("Health")]
[Header("Movement")]
[Header("Attack")]
[SerializeField] private float attackDamage = 10f;
[SerializeField] private float attackSpeed = 0.5f;
[SerializeField] private float maxHealth;
[SerializeField] private Transform respawnPoint;
public float speed = 3f;
public Transform trans;
private float canAttack;
private Transform target;
private float health;
public GameObject enemyObj;
Vector3 enemyPosition = new Vector3 (7.71339989f, -3.26340008f, 0f);
private void Start()
{
health = maxHealth;
}
public void TakeDamage(float dmg) {
health -= dmg;
Debug.Log("Enemy Health: " + health);
if (health <= 0)
{
speed = speed * 2f;
Destroy(gameObject);
StartCoroutine(Respawn());
}
}
private void Update()
{
if (target != null)
{
float step = speed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, target.position, step);
}
}
private void OnCollisionStay2D(Collision2D other)
{
if (other.gameObject.tag == "Player")
{
if(attackSpeed <= canAttack)
{
other.gameObject.GetComponent<General>().UpdateHealth(-attackDamage);
canAttack = 0f;
}
else
{
canAttack += Time.deltaTime;
}
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
target = other.transform;
}
}
IEnumerator Respawn()
{
enemyObj = (GameObject)Instantiate (enemyObj, enemyPosition, Quaternion.identity);
yield return null;
}
}
I have an enemy prefab with and a bullet prefab with rigidbody2D and boxcolliders to both of them. I have made a TakeDamage function for the enemy when i made meelee combat and also a bullet shooting script. I made a simple OnCollisionEnter2D on the enemy(code is below) and they do collide and give the collision effect but the function doesn't work, it doesn't give any errors either... What do I do now?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class enemy : MonoBehaviour
{
public Transform player;
private Rigidbody2D rb;
[SerializeField] private SpriteRenderer sr;
private Vector2 movement;
public float moveSpeed = 5f;
public int maxHealth = 100;
int currentHealth;
Color32 colorRes = new Color32(255, 100, 50, 255);
public ParticleSystem deathParticles;
public GameObject projectile;
public int enemyDamage = 50;
public LayerMask rock;
// Start is called before the first frame update
void Start()
{
rb = this.GetComponent<Rigidbody2D>();
sr = GetComponent<SpriteRenderer>();
currentHealth = maxHealth;
}
// Update is called once per frame
void Update()
{
sr.flipX = player.position.x - transform.position.x > 0;
Vector3 direction = player.position - transform.position;
direction.Normalize();
movement = direction;
}
private void FixedUpdate()
{
moveCharacter(movement);
}
void moveCharacter(Vector2 direction)
{
rb.MovePosition((Vector2)transform.position + (direction * moveSpeed));
}
public void TakeDamage()
{
currentHealth -= enemyDamage;
if(currentHealth <= 0)
{
Die();
}
StartCoroutine(BecomeRed());
}
void Die()
{
Instantiate(deathParticles, transform.position, Quaternion.identity);
Destroy(gameObject);
}
IEnumerator BecomeRed()
{
sr.color = colorRes;
yield return new WaitForSeconds(0.6f);
sr.color = Color.white;
}
void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log("test");
if (coll.gameObject.name == "rock")
{
TakeDamage();
Destroy(projectile);
}
}
}
I would like the Enemy(Monster) to shoot players in Shooting Range of the Enemy and return closest players within the Range
I'm quite new to Unity and currently using Unity 2017,2D at the moment, for now.
Thanks so much for your Help Guys!
public class Monster : MonoBehaviour {
[SerializeField]
GameObject Bullet;
public float fireRate;
float nextFire;
// Use this for initialization
void Start () {
fireRate = 1f;
nextFire = Time.time;
}
// Update is called once per frame
void Update () {
CheckIfTimeToFire ();
}
void CheckIfTimeToFire()
{
if (Time.time > nextFire)
{
Instantiate (Bullet, transform.position, Quaternion.identity);
nextFire = Time.time + fireRate;
}
}
}
Here is the Bullet Script
public class Bullet : MonoBehaviour {
public float moveSpeed = 3f;
Rigidbody2D rb;
PlayerAI target;
Vector2 moveDirection;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody2D> ();
target = GameObject.FindObjectOfType<PlayerAI>();
moveDirection = (target.transform.position - transform.position).normalized * moveSpeed;
rb.velocity = new Vector2 (moveDirection.x, moveDirection.y);
Destroy (this.gameObject, 2);
}
void OnTriggerEnter2D (Collider2D col)
{
if (col.gameObject.name.Equals ("Player"))
{
Debug.Log ("Hit!");
Destroy (gameObject);
}
}
}
Assuming you have a small number of players, a convenient method would be to hold a reference to players as a collection and iterate to get transform.position of each player. Then you can check the distance to the monster to get the minimum distance.
I also suggest doing the logical check on Monster rather than on Bullet, and pass target to Bullet. So that you can choose not to instantiate a bullet if no player is in range.
public class Monster : MonoBehaviour
{
...
public float range;
private PlayerAI[] players;
...
private void Awake()
{
players = FindObjectsOfType<PlayerAI>();
}
...
private void CheckIfTimeToFire()
{
if (Time.time < nextFire)
{
return;
}
PlayerAI closestPlayer = null;
float closestPlayerDistance = float.MaxValue;
foreach (PlayerAI player in players)
{
float playerDistance = Vector3.Distance(transform.position, player.transform.position);
if (playerDistance > range ||
playerDistance > closestPlayerDistance)
{
// Skip to next player.
continue;
}
closestPlayer = player;
closestPlayerDistance = playerDistance;
}
if (closestPlayer == null)
{
// No player in range. Do nothing.
return;
}
GameObject bullet = Instantiate (Bullet, transform.position, Quaternion.identity);
bullet.GetComponent<Bullet>().Initialize(closestPlayer.transform);
nextFire = Time.time + fireRate;
}
...
}
public class Bullet : MonoBehaviour
{
...
private Transform target;
...
public void Initialize(Transform target)
{
this.target = target;
}
...
}
In the example, I get the players on Awake() of a Monster, but if you are instantiating them in runtime you can hold the PlayerAI collection in a separate manager class. In this case a list could be more useful.
public void PlayerManager : MonoBehaviour
{
public List<PlayerAI> Players { get; private set; }
...
private void Awake()
{
while (playerCount < totalPlayerCount)
{
SpawnPlayer();
}
}
private void SpawnPlayer()
{
PlayerAI player = Instantiate(player, ...);
Players.Add(player);
}
// Remove a dead player, etc.
private void OnPlayerDied(PlayerAI player)
{
Players.Remove(player);
}
...
}
public class Monster : MonoBehaviour
{
...
private PlayerManager playerManager;
...
private void Awake()
{
playerManager = FindObjectOfType<PlayerManager>();
}
void CheckIfTimeToFire()
{
...
foreach (PlayerAI player in playerManager.Players)
{
...
}
...
}
}
I Have been trying to figure out how the Enemy doesn't return multiple GameObjects it only returns one.Im not sure whether it is my Bullet script that it allows only one object to return. I'm currently trying to develop a Game with multiple players like Slither.io so I'm not sure if the performance is affected I would like to use (List Function) but dont know where to start and I'm using a later version Unity 2017.3.1f1. Much Appreciated for your help.The scripts are below.
public class RandomAIProjectile
{
private GameObject[] target;
public float speed;
Rigidbody2D bulletRB;
public GameObject explosionEffect;
// Find Targets Section.
void Start ()
{
if (target == null)
target = GameObject.FindGameObjectsWithTag("Player");
for (int i = 0; i < target.Length; i++)
{
bulletRB = GetComponent<Rigidbody2D> ();
Vector2 moveDir = (target[i].transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2 (moveDir.x, moveDir.y);
Destroy (this.gameObject, 2);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
// Decoy Script To Destroy Players.
if (other.gameObject.GetComponent<BlackthronpodDiePlayer>() != null)
{
Destroy (other.gameObject);
Destroy (gameObject);
}
// Damage Effect.
if (other.gameObject.tag == "Player") {
Instantiate (explosionEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
// Player (Bullet) Destroy Enemy.
if (other.CompareTag ("Bullet"))
{
Destroy (other.gameObject);
Destroy (gameObject);
}
}
}
Here is the Player Script
public class RandomAIEnemy
{
//Random Movement
public float speed;
public float waitTime;
public float startWaitTime;
public Transform moveSpots;
public float minX;
public float minY;
public float maxX;
public float maxY;
//Enemy AI Shooting
public float lineOfSite;
public float shootingRange;
public float fireRate = 1f;
private float nextFireTime;
public GameObject bullet;
public GameObject bulletParent;
// My Current Player
private BlackthronpodPlayerX playerX;
// Player AI
private GameObject[] player;
public GameObject blood;
Vector3 respawn = new Vector3 (-34f,0,0);
//Additional Info
void FixedUpdate ()
{
EnemyS ();
}
// Use this for initialization
void Start ()
{
//My Player AI Tag.
player = GameObject.FindGameObjectsWithTag("Player");
waitTime = startWaitTime;
//My Current Player Tag.
playerX = GameObject.FindGameObjectWithTag ("Player").GetComponent<BlackthronpodPlayerX>();
//Random Movement Reference
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
}
//Closest (My Player Including Player AI.)
private bool TryGetClosestPlayer(out GameObject closest)
{
var playersSortedByDistance = player.OrderBy(p => ((Vector2)p.transform.position - (Vector2)transform.position).sqrMagnitude);
closest = playersSortedByDistance.FirstOrDefault();
return closest;
}
void EnemyS ()
{
GameObject closestPlayer = null;
if(TryGetClosestPlayer (out closestPlayer))
{
var distanceFromPlayer = Vector2.Distance (closestPlayer.transform.position, transform.position);
if (distanceFromPlayer <= shootingRange && nextFireTime < Time.time)
{
Instantiate (bullet, bulletParent.transform.position, Quaternion.identity);
nextFireTime = Time.time + fireRate;
}
}
}
// Range And Shooting Boundary For Player Including Player AI.
private void OnDrawGizmosSelected ()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere (transform.position, lineOfSite);
Gizmos.DrawWireSphere (transform.position, shootingRange);
}
// Random Movement (I).
void RandomMove ()
{
//Rotate Movement Of Enemy.
transform.position = Vector2.MoveTowards (transform.position, moveSpots.position, speed * Time.deltaTime);
if (Vector2.Distance (transform.position, moveSpots.position) < 0.2f)
{
if(waitTime <= 0)
{
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
waitTime = startWaitTime;
} else {
waitTime -= Time.deltaTime;
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
// Damage Effect On Enemy.
if (collision.gameObject.tag.Equals ("Player"))
{
Instantiate(blood,transform.position, Quaternion.identity);
}
// My Players Health.
if (collision.CompareTag ("Player"))
{
playerX.health --;
Debug.Log(playerX.health);
Destroy(gameObject);
}
// Player Score Manager.
if (collision.tag == "Bullet")
{
Game.AddToScore(1);
Destroy(gameObject);
}
}
}
Make sure that you have Rigidbody2d attached on your enemy and player. And also, is there any error coming in the code?
I want my wepons to have a shooting range in my 2D game.For example if the bullet is out of range then destroy the bullet.Is it a problem if i don't use RayCast?
My script for the Wepon:
//Initialization
public GameObject Bullet;
public Transform FirePoint;
//WeponStats
public float BulletSpeed;
public int Damage;
public float Range;
private float TimeBtwShots;
public float StartTimeBtwShots;
private void Start()
{
}
private void Update()
{
if (TimeBtwShots <= 0)
{
if (Input.GetButton("Fire1"))
{
Shoot();
TimeBtwShots = StartTimeBtwShots;
}
}
else
{
TimeBtwShots -= Time.deltaTime;
}
}
void Shoot()
{
GameObject bullet2 = Instantiate(Bullet, FirePoint.position, FirePoint.rotation);
Rigidbody2D rb = bullet2.GetComponent<Rigidbody2D>();
rb.AddForce(FirePoint.right * BulletSpeed, ForceMode2D.Impulse);
}
And for the bullet:
public float Delay;
void Start()
{
Destroy(gameObject, Delay);
}
public void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Enemy"))
{ //take damage function, nothing important
Destroy(gameObject);
Wepon_Script script_W = GameObject.FindGameObjectWithTag("Wepon").GetComponent<Wepon_Script>(); //Wepon script
Enemy_Core script_E = GameObject.FindGameObjectWithTag("Enemy").GetComponent<Enemy_Core>(); //Enemy script
script_E.TakeDamage(script_W.Damage);
}
}
enter image description here
It seems you're already destroying the bullet after a delay:
Destroy(gameObject, Delay);
If you want the bullet to be destroyed after a distance traveled you could divide the distance by the speed.
Destroy(gameObject, Range / BulletSpeed);
If you want to measure dynamic distance traveled you could keep a track of it inside the bullet.
void FixedUpdate()
{
var distanceDelta = (transform.position - lastPos).magnitude;
distanceTravelled += distanceDelta;
lastPos = transform.position;
if (distanceTravelled > Range) Destroy(gameObject);
}