Hello fellow developers,
How do I make an enemy shoot via Raycast? I tried for hours and I didn’t came to a solution, even using
allmighty Google I haven’t found anything.
I had some ideas, but I don’t know how to realise these.
The enemy should turn towards the player, then “shoot” a ray.
Has anyone a better approach on doing that, or any helpful documentation?
Thank you in advance, everyone!
-Cheatsrichter-
How convenient. I almost successfully programmed my enemy raycast was planning to ask people how to add an ability to shoot upwards. Alright, so how about this, copy my code and see if you can find a way to shoot upwards
using UnityEngine;
using System.Collections;
using UnityEngine.AI;
public class EnemyAiTutorial : MonoBehaviour
{
[SerializeField] Transform enemy;
[SerializeField] NavMeshAgent agent;
[SerializeField] Transform player;
[SerializeField] LayerMask whatIsGround, whatIsPlayer;
[Space]
//Patroling
[SerializeField] Vector3 walkPoint;
bool walkPointSet;
[SerializeField] float walkPointRange;
//Attacking
[SerializeField] float timeBetweenAttacks;
[SerializeField] bool isShooting;
bool alreadyAttacked;
[Space]
//States
[SerializeField] float sightRange, attackRange;
[SerializeField] bool playerInSightRange, playerInAttackRange;
[Space]
[SerializeField] float delaySeconds = 1.5f;
[SerializeField] bool fire;
[SerializeField] float range = 100f;
[SerializeField] float damage = 20f;
[SerializeField] Vector3 characterOffSet = new Vector3(0f, 0.3f, 0);
[SerializeField] Vector3 aimOffSet = new Vector3(0, 1, 0);
private LineRenderer laser;
bool fireLaser;
#region Awake & Update functions
private void Awake()
{
player = GameObject.Find("Player").transform;
}
public void Start()
{
laser = GetComponent<LineRenderer>();
}
private void Update()
{
//Check for sight and attack range
playerInSightRange = Physics.CheckSphere(transform.position, sightRange, whatIsPlayer);
playerInAttackRange = Physics.CheckSphere(transform.position, attackRange, whatIsPlayer);
if (!playerInSightRange && !playerInAttackRange) Patroling();
if (playerInSightRange && !playerInAttackRange) ChasePlayer();
if (playerInAttackRange && playerInSightRange) AttackPlayer();
laser.SetPosition(0, enemy.transform.position + characterOffSet);
if (!fireLaser)
{
laser.SetPosition(1, enemy.transform.position + characterOffSet);
}
}
#endregion
#region States
private void Patroling()
{
if (!walkPointSet) SearchWalkPoint();
if (walkPointSet)
agent.SetDestination(walkPoint);
Vector3 distanceToWalkPoint = transform.position - walkPoint;
//Walkpoint reached
if (distanceToWalkPoint.magnitude < 1f)
walkPointSet = false;
}
private void SearchWalkPoint()
{
//Calculate random point in range
float randomZ = Random.Range(-walkPointRange, walkPointRange);
float randomX = Random.Range(-walkPointRange, walkPointRange);
walkPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ);
if (Physics.Raycast(walkPoint, -transform.up, 2f, whatIsGround))
{
walkPointSet = true;
}
}
private void ChasePlayer()
{
agent.SetDestination(player.transform.position);
}
private void AttackPlayer()
{
//Make sure enemy doesn't move
agent.SetDestination(transform.position);
if (!isShooting)
{
Vector3 aimPlayer = player.transform.position + aimOffSet;
transform.LookAt(aimPlayer);
}
if (!alreadyAttacked)
{
StartCoroutine(Shoot());
}
}
private void ResetAttack()
{
alreadyAttacked = false;
}
#endregion
IEnumerator Shoot()
{
float totalTime = delaySeconds + timeBetweenAttacks;
isShooting = true;
yield return new WaitForSeconds(delaySeconds);
fireLaser = true;
RaycastHit Hit;
while (!alreadyAttacked)
{
Vector3 onward = transform.TransformDirection(Vector3.forward) * (range);
Debug.DrawRay(enemy.transform.position, onward, Color.red, 1f);
if (Physics.Raycast(enemy.transform.position, enemy.transform.forward, out Hit, range))
{
laser.SetPosition(1, Hit.point);
Debug.Log(Hit.collider.name);
if (Hit.collider.GetComponent<Damagable>() != null)
{
Hit.collider.GetComponent<Damagable>().TakeDamage(damage, Hit.point, Hit.normal);
}
else
{
Hit.collider.GetComponent<mapCollision>().TakeDamage(damage, Hit.point, Hit.normal);
}
} else
{
laser.SetPosition(1, onward);
}
alreadyAttacked = true;
}
isShooting = false;
yield return new WaitForSeconds(totalTime);
fireLaser = false;
alreadyAttacked = false;
}
}