How to make a shooting range for guns in unity2D? - c#

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);
}

Related

How to make Enemy FLIP and ATTACK in Unity2D?

I was following a tutorial for creating an enemy in Unity, but they didn't teach how to flip the enemy in case the Player goes to the other side of the map, oppose to where the enemy is.
So I tried to increase the raycast area, so when the Player collides with it from behind, the enemy will know that it has to flip. But something isn't working, cause it goes fine to the Player when it's facing the left side of the map, but once it flips, it totally stops working, and I can't figure it out why.
Anyone have any idea what should I do?
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Skeleton : MonoBehaviour
{
#region Public Variables
public Transform rayCast;
public LayerMask raycastMask;
public GameObject target;
public float rayCastLength;
public float attackDistance; //Mininum distance to attack
public float moveSpeed;
public float timer; // Cooldown b/w attacks
public bool inRange; //check if the player is near
#endregion
#region Private Variables
private RaycastHit2D hit;
private Animator anim;
private float distance; //Distance b/w enemy and player
public bool attackMode;
private float intTimer;
#endregion
void Awake() {
intTimer = timer;
anim = GetComponent<Animator>();
}
void Update() {
if (inRange)
{
hit = Physics2D.Raycast(rayCast.position, Vector2.left, rayCastLength, raycastMask);
}
//When the player is detected
if(hit.collider != null)
{
EnemyLogic();
}
// If it's not inside the raycast
else if(hit.collider == null)
{
inRange = false;
}
// If the player leaves the range
if (inRange == false)
{
anim.SetBool("canWalk", false);
StopAttack();
anim.SetInteger("Idle", 0);
}
}
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Player")
{
target = col.gameObject;
inRange = true;
Flip();
}
}
void EnemyLogic()
{
distance = Vector2.Distance(transform.position, target.transform.position);
if(distance > attackDistance)
{
Move();
StopAttack();
}
else if(attackDistance >= distance)
{
Attack();
}
}
void Move()
{
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", true);
if (!anim.GetCurrentAnimatorStateInfo(0).IsName("attack"))
{
Vector2 targetPosition = new Vector2(target.transform.position.x, transform.position.y);
transform.position = Vector2.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
}
void Attack()
{
timer = intTimer; //reset timer
attackMode = true;
anim.SetInteger("Idle", 1);
anim.SetBool("canWalk", false);
anim.SetBool("Attack", true);
}
void StopAttack()
{
attackMode = false;
anim.SetBool("Attack", false);
}
// Detects if the player is on the other side
void Flip()
{
Vector3 rotation = transform.eulerAngles;
if(target.transform.position.x < transform.position.x)
{
rotation.y = 180f;
}
else
{
rotation.y = 0f;
}
transform.eulerAngles = rotation;
}
}
You can flip the enemy using localScale. Do this:
if (Player.transform.position.x < this.transform.position.x)
{
transform.localScale = new Vector3(-1, 1, 1);
}else
{
transform.localScale = new Vector3(1, 1, 1);
}
This detects whenever the player's x position is greater or lower than the enemy and flips the whole object.

Why does OnCollisionEnter2D not working? Unity

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);
}
}
}

Enemy Shoot Closest Object Within Shooting Range

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)
{
...
}
...
}
}

Enemy Projectile Script Won't Shoot Closest Object

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?

Destroy gameObject from another script

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.

Categories

Resources