Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Raycast Drawing: Best method?

Discussion in 'Image Effects' started by LittleByrds, Apr 2, 2024.

  1. LittleByrds

    LittleByrds

    Joined:
    Aug 7, 2023
    Posts:
    28
    Hello, I am in the early stages of developing a 2D game, using the URP, and I have created a system where the enemy uses multiple ray casts and angles to create a FOV where the player can be detected. I would like to be able to draw these, but I have no documentation of how to do this online, so I am looking for help. I will provide the code:


    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. public class Enemy : MonoBehaviour
    6. {
    7.     public PlayerController playerScript;
    8.     public float speed = 2f;
    9.     public float pauseTime = 2f;
    10.     public Transform groundDetection;
    11.     public LayerMask whatIsGround;
    12.     public LayerMask playerLayer;
    13.     public GameObject projectile;
    14.     public float projectileSpeed = 5f;
    15.     public float detectionAngle = 45f;
    16.     public int rayCount = 5;
    17.     public float raycastDistance = 2f;
    18.     public float shootCooldown = 2f;
    19.     public Vector2 spawnPos;
    20.     public Slider healthBar;
    21.     public float enemyDamage;
    22.     public float MaxHealth = 10;
    23.     public float Health = 10;
    24.     private bool movingRight = true;
    25.     private bool isPaused = false;
    26.     private GameObject player;
    27.     private float lastShootTime;
    28.     private Rigidbody2D rb;
    29.  
    30.     void Start()
    31.     {
    32.  
    33.         spawnPos = gameObject.transform.position;
    34.         healthBar.maxValue = MaxHealth;
    35.         healthBar.minValue = 0;
    36.         Health = MaxHealth;
    37.         player = GameObject.FindGameObjectWithTag("Player");
    38.         playerScript = player.GetComponent<PlayerController>();
    39.         rb = GetComponent<Rigidbody2D>();
    40.     }
    41.  
    42.     void Update()
    43.     {
    44.         if (Health <= 0)
    45.         {
    46.             gameObject.transform.name = "Enemy(Killed)";
    47.             gameObject.transform.position = new Vector2(300, 0);
    48.         }
    49.         else
    50.         {
    51.             gameObject.transform.name = "Enemy(Alive)" + "(" + Health + ")";
    52.         }
    53.         if (Health >= MaxHealth)
    54.         {
    55.             Health = MaxHealth;
    56.         }
    57.         healthBar.value = Health;
    58.         if (!isPaused && !PlayerDetected())
    59.         {
    60.             transform.Translate(Vector2.right * speed * Time.deltaTime);
    61.         }
    62.  
    63.         RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, 2f, whatIsGround);
    64.         if (groundInfo.collider == false)
    65.         {
    66.             if (!isPaused)
    67.             {
    68.                 StartCoroutine(PauseAndTurn());
    69.             }
    70.         }
    71.  
    72.     }
    73.  
    74.     IEnumerator PauseAndTurn()
    75.     {
    76.         isPaused = true;
    77.         yield return new WaitForSeconds(pauseTime);
    78.         if (movingRight)
    79.         {
    80.             transform.eulerAngles = new Vector3(0, -180, 0);
    81.             healthBar.transform.localScale = new Vector3(-1, 1, 1);
    82.             movingRight = false;
    83.         }
    84.         else
    85.         {
    86.             transform.eulerAngles = new Vector3(0, 0, 0);
    87.             healthBar.transform.localScale = new Vector3(1, 1, 1);
    88.             movingRight = true;
    89.         }
    90.         isPaused = false;
    91.     }
    92.  
    93.     bool PlayerDetected()
    94.     {
    95.         float rayAngleStep = detectionAngle / (rayCount - 1);
    96.         Vector2 direction = player.transform.position - transform.position;
    97.         for (int i = 0; i < rayCount; i++)
    98.         {
    99.             float rayAngle = -detectionAngle / 2 + rayAngleStep * i;
    100.             Vector2 rayDirection = RotateVector(direction, rayAngle);
    101.             RaycastHit2D playerInfo = Physics2D.Raycast(transform.position, rayDirection, raycastDistance, playerLayer);
    102.             if (playerInfo.collider == true)
    103.             {
    104.                 if (Time.time > lastShootTime + shootCooldown)
    105.                 {
    106.                     ShootPlayer();
    107.                     lastShootTime = Time.time;
    108.                 }
    109.                 return true;
    110.             }
    111.         }
    112.         return false;
    113.     }
    114.  
    115.     void ShootPlayer()
    116.     {
    117.         GameObject proj = Instantiate(projectile, transform.position, Quaternion.identity);
    118.         Rigidbody2D rb = proj.GetComponent<Rigidbody2D>();
    119.         Vector2 direction = (player.transform.position - transform.position).normalized;
    120.         rb.velocity = direction * projectileSpeed;
    121.     }
    122.  
    123.     Vector2 RotateVector(Vector2 v, float degrees)
    124.     {
    125.         float radians = degrees * Mathf.Deg2Rad;
    126.         float sin = Mathf.Sin(radians);
    127.         float cos = Mathf.Cos(radians);
    128.         float tx = v.x;
    129.         float ty = v.y;
    130.         return new Vector2(cos * tx - sin * ty, sin * tx + cos * ty);
    131.     }
    132.  
    133.     private void OnCollisionEnter2D(Collision2D collision)
    134.     {
    135.         if (collision.collider.CompareTag("Bullet"))
    136.         {
    137.             Health -= playerScript.damage;
    138.         }
    139.     }
    140. }
    141.  
     
  2. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    1,084
    If you want the lines just for helping you to visualize the rays while testing then you can use Debug.DrawRay or Debug.DrawLine. But if you want the players to be able to see the rays when playing your game then you can use the LineRenderer.

    By the way, you can give your enemy a FOV by using Vector2.Dot to quickly test if the enemy is looking in the general direction of the player, and only then do you need to do a single ray cast from the enemy to the player to test if there's nothing blocking the enemy's view of the player.

    There are some occasions where a few ray casts can be better. For example the player may be peeking around a corner and so a single ray cast wouldn't reach the player's origin and yet the enemy should still be able to see the exposed side of the player. So in this situation you have to do three very specific ray casts - one to the player's origin, and one to the left and right sides of the player.
     
  3. LittleByrds

    LittleByrds

    Joined:
    Aug 7, 2023
    Posts:
    28
    Hello, thank for the reply, I am wondering on how to get this to actually work, I have tried but am still a little bit confused can you provide documentation or a code snippet? Thank you in advance!
     
  4. zulo3d

    zulo3d

    Joined:
    Feb 18, 2023
    Posts:
    1,084
    Code (CSharp):
    1. using UnityEngine;
    2. public class EnemyAI : MonoBehaviour
    3. {
    4.     public Transform player;
    5.  
    6.     void Update()
    7.     {
    8.         Vector2 playerDirection=(player.position-transform.position);
    9.         if (Vector2.Dot(playerDirection.normalized,transform.right)>0.5f)    // player within our field of view?
    10.             if (Physics2D.Linecast(transform.position,player.position).transform==player) // Do we have line of sight with the player? They could be hiding behind a wall..
    11.                 transform.right=Vector3.Lerp(transform.right,playerDirection,5*Time.deltaTime); // gradually look towards the player
    12.     }
    13. }
     
    Last edited: Apr 10, 2024
  5. LittleByrds

    LittleByrds

    Joined:
    Aug 7, 2023
    Posts:
    28
    Hello, my team has found an alternative for the enemy, and instead this code has been repurposed and reworked to be on the player as a ¨Fog of War¨ gimmick, the player is using a separate game object with the following components:
    -Mesh Renderer
    -Mesh Filter
    -The Script(Field Of View)

    I just need to work on the idea of creating a mask, so the player can see the level, but things like enemies are hidden, until the player can actually see the enemy, we want the player to have to make LOS of a enemy in order to see them, I have tried using sprite renderers and enabling and disabling them, but to no avail. Is there some other way to create a mask effect using a mesh renderer/filter to create a mask in the 2D URP? does somebody have some suggestions? I am really lost, Everything found is unable to work with the URP, and lighting is an important part of the project. Thanks for help in advanced!