Search code examples
c#unity-game-engineraycasting

How do you make raycasts that shoot at the player in C#?


I have been trying to do an fps game and got stuck at the part where the enemies can shoot the player, and I'm not quite sure what I can do. The enemy keeps on roaming instead of actually attacking the player. Even worse, they sometimes walk away from the player. Could anyone help?

using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
public NavMeshAgent NavAgent;
public Transform Player;
public LayerMask GroundCheck, PlayerCheck;
public Transform EnemyPrototype;
public float range;
public float Damage;

public Vector3 WalkPoint; // Code for patrolling Around
bool WalkPointSet;
public float WalkPointRange;

public float SightRange, AttackRange;   // Code for checking when to engage in a firefight with the player
public bool PlayerInSight, AttackPlayer;

public float AttackCooldown; // Code for firefights with the player
bool AlreadyAttacked;

private void AIActive()
{
    Player = GameObject.Find("Player").transform;
    NavAgent = GetComponent<NavMeshAgent>();
}

private void Update()
{
    PlayerInSight = Physics.CheckSphere(transform.position, SightRange, PlayerCheck);
    AttackPlayer = Physics.CheckSphere(transform.position, AttackRange, PlayerCheck);

    if (!PlayerInSight && !AttackPlayer)
    {
        Patrol();
    }
    if (PlayerInSight && !AttackPlayer)
    {
        Engage();
    }
    if (PlayerInSight && AttackPlayer)
    {
        FireAtPlayer();
    }
}

private void Patrol() // The enemy will move in order to try and find the player
{
    if (!WalkPointSet)
    {
        SearchWalkPoint();
    }

    if (WalkPointSet)
    {
        NavAgent.SetDestination(WalkPoint);
    }

    Vector3 WalkPointDistance = transform.position - WalkPoint;

    if (WalkPointDistance.magnitude < 1f)
    {
        WalkPointSet = false;
    }
}

private void SearchWalkPoint()  // Makes a random point where the enemy would patrol
{
    float WalkZ = Random.Range(-WalkPointRange, WalkPointRange);
    float WalkX = Random.Range(-WalkPointRange, WalkPointRange);
    WalkPoint = new Vector3(transform.position.x + WalkX, transform.position.y, transform.position.z + WalkZ);
    if (Physics.Raycast(WalkPoint, -transform.up, 2f, GroundCheck))
    {
        WalkPointSet = true;
    }
}

private void Engage() // The enemy has found the player and will move towards them to get a better shot
{
    NavAgent.SetDestination(Player.position);
}

private void FireAtPlayer() // The enemy will now try to get a shot on the player
{
    NavAgent.SetDestination(transform.position);
    transform.LookAt(Player);
    if (!AlreadyAttacked)
    {
        RaycastHit Hit;
        if (Physics.Raycast(EnemyPrototype.transform.position, EnemyPrototype.transform.forward, out Hit, range, PlayerCheck))
        {
            Debug.Log(Hit.collider.name);

            Target target = Hit.transform.GetComponent<Target>();
            if (target != null)
            {
                target.TakeDamage(Damage);
            }
        }
        AlreadyAttacked = true;
        Invoke(nameof(AttackReset), AttackCooldown);
    }
}

private void AttackReset()
{
    AlreadyAttacked = false;
}
}

I don't know if the problem is the patrolling or the actual code for shooting, as I am quite new to C# and mostly use tutorials available on the internet to help me, but this time I don't know where to go


Solution

  • There are a number of things to check. Does PlayerInSight or AttackPlayer ever evaluate to true? If not, it could mean that the layer associated with your Player is not in the PlayerCheck LayerMask.

    You can assign the layer for your Player GameObject in the inspector:

    img: assigning layer to Player GameObject

    And you can assign the layers for you LayerMask in the inspector:

    img: assigning layers in a LayerMask field