I'm making a 2D game with Unity. I have a patrol enemy that has to shoot bullets. The problem is that the bullets are being spawned from a random point at the middle of the scene, instead of bulletSpawnPos
(an empty game object which is a child of the pistol). I also want the enemy to shoot whenever the player is near. But it seems like all the code does is to shoot towards it, no matter if it's near or not. In general I want to solve these two problems that are pretty much related to each other:
- Bullets should be spawn from
bulletSpawnPos
. - Enemy should start shooting whenever the player is near (maybe by triggering something).
Pistol script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pistol : MonoBehaviour
{
[SerializeField] GameObject bullet;
[SerializeField] Transform bulletSpawnPos;
private bool isShooting;
[SerializeField] private float shootDistance = 5f;
[SerializeField] private float shootDelay = .5f;
private Enemy enemy;
void Start()
{
enemy = transform.parent.GetComponent<Enemy>();
InvokeRepeating("Shoot", 1f, shootDelay);
Rigidbody2D rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
//Detecting hits to the right
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.right, shootDistance);
//making sure we hit something and it is the player
if (hit.collider != null && hit.collider.tag.Equals("Player"))
{
//We only want to start repeated shooting in case we do not shoot yet
if (!isShooting) InvokeRepeating("Shoot", 0f, shootDelay);
isShooting = true;
}
else
{
//Stopping ongoing shooting
if (isShooting) CancelInvoke("Shoot");
isShooting = false;
}
}
void Shoot()
{
GameObject b = Instantiate(bullet);
b.GetComponent<Bullet>().StartShoot(enemy.IsFacingLeft());
b.transform.position = bulletSpawnPos.transform.position;
}
}
Bullet script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
[SerializeField] float speed;
[SerializeField] int damage;
[SerializeField] GameObject bullet;
GameObject Enemy;
float timeToDestroy = 3;
NewPlayer target;
Vector2 moveDirection;
void Start()
{
Rigidbody2D rb = GetComponent<Rigidbody2D>();
target = GameObject.FindObjectOfType<NewPlayer>();
moveDirection = (target.transform.position - transform.position).normalized * speed;
rb.velocity = new Vector2(moveDirection.x, moveDirection.y);
Destroy(gameObject, 3f);
}
public void StartShoot(bool isFacingLeft)
{
Rigidbody2D rb = GetComponent<Rigidbody2D>();
if (isFacingLeft)
{
rb.velocity = new Vector2(-speed, 0);
}
else
{
rb.velocity = new Vector2(speed, 0);
}
Destroy(gameObject, timeToDestroy);
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name.Equals ("Player"))
{
Destroy(gameObject);
}
}
}
Enemy script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : PhysicsObject
{
[Header("Attributes")]
[SerializeField] private int attackPower = 10;
private int direction = 1;
public int health = 100;
private int maxHealth = 100;
[SerializeField] private float maxSpeed;
[SerializeField] private LayerMask rayCastLayerMask; //Which layer do we want the raycast to interact with?
[SerializeField] private Vector2 rayCastOffset; //Offset from the center of the raycast origin
[SerializeField] private float rayCastLength = 2;
bool isFacingLeft;
public bool IsFacingLeft()
{
return isFacingLeft;
}
[Header("References")]
private RaycastHit2D rightLedgeRaycastHit;
private RaycastHit2D leftLedgeRaycastHit;
private RaycastHit2D rightWallRaycastHit;
private RaycastHit2D leftWallRaycastHit;
// Update is called once per frame
void Update()
{
targetVelocity = new Vector2(maxSpeed * direction, 0);
if (targetVelocity.x < -.01)
{
transform.localScale = new Vector2(-1, 1);
isFacingLeft = true;
}
else if (targetVelocity.x > .01)
{
transform.localScale = new Vector2(1, 1);
isFacingLeft = false;
}
//Check for right ledge!
rightLedgeRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x + rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down, rayCastLength);
Debug.DrawRay(new Vector2(transform.position.x + rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down * rayCastLength, Color.blue);
if (rightLedgeRaycastHit.collider == null) direction = -1;
//Check for left ledge!
leftLedgeRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x - rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down, rayCastLength);
Debug.DrawRay(new Vector2(transform.position.x - rayCastOffset.x, transform.position.y + rayCastOffset.y), Vector2.down * rayCastLength, Color.green);
if (leftLedgeRaycastHit.collider == null) direction = 1;
//Check for right wall!
rightWallRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.right, rayCastLength, rayCastLayerMask);
Debug.DrawRay(new Vector2(transform.position.x, transform.position.y), Vector2.right * rayCastLength, Color.red);
if (rightWallRaycastHit.collider != null) direction = -1;
//Check for left wall!
leftWallRaycastHit = Physics2D.Raycast(new Vector2(transform.position.x, transform.position.y), Vector2.left, rayCastLength, rayCastLayerMask);
Debug.DrawRay(new Vector2(transform.position.x, transform.position.y), Vector2.left * rayCastLength, Color.magenta);
if (leftWallRaycastHit.collider != null) direction = 1;
//If health < 0, destroy me
if (health <= 0)
{
Destroy(gameObject);
}
}
//If I collide with the player, hurt the player (health is going to decrease, update the UI)
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject == NewPlayer.Instance.gameObject)
{
//Hurt the player, then update the UI!
NewPlayer.Instance.health -= attackPower;
NewPlayer.Instance.UpdateUI();
}
}
}
This is the pistol inspector window.

Enemy object structure
b.GetComponent<Bullet ().StartShoot(enemy.IsFacingLeft());
line in pistol script. \$\endgroup\$enemy
variable, then ask here if you're still having trouble. \$\endgroup\$enemy
variable? \$\endgroup\$private Enemy enemy;
that you have never assigned a value into (this should generate a compiler warning to alert you of this). You need to assign a value to this variable before you can use it. \$\endgroup\$