Найти тему
Suludadza

Raycast 2D в Unity. Просто и наглядно.

Во время создания своей прекрасной и непревзойдённой игры мне потребовались лучи Raycast-a, так как работаю над top - down танковым шутером с механикой обнаружения противника .В интернете мало чего дельного есть, кроме документации, поэтому в этой статье разложу всё по полочкам.

Будем рассматривать работу Raycast - а в 2D пространстве на примере моего же кода. Всё работает на актуальной версии Unity, не судите код, я - любитель.

Рассматриваем куски кода, который идут по порядку:

Итак, здесь я ввожу булевые переменные для проверки данным скриптом, попал ли луч в нужный нам объект.

IsEyeContact - попадает ли луч в цель?

AimYet - может ли бот уже стрелять, довернулось ли орудие до игрока?

Также вводятся переменные объектов.

Массив target - это список объектов: точки, куда мы пускаем лучи, и объект с коллизией игрока под индексом target[0]. Все остальные точки массива расположены по периметру танка.

SpotPoint, AimPoint - точки, ИЗ которых пускаются лучи. Они находятся у противника на башне.

Далее в FixedUpdate я задаю маску этим лучам, т.е. слои объектов, которые они проходят насквозь.

-----------------------------------------------------------------------

int ignoreWeaponMask = 1 << 12;

int ignoreWeaponMask2 = 1 << 11;

int ignoreRaycastMask = 1 << 9;

int ignoreRaycastMask2 = 1 << 2;

int layerMask = ignoreWeaponMask | ignoreRaycastMask | ignoreWeaponMask2 | ignoreRaycastMask2;

layerMask = ~layerMask;

------------------------------------------------------------------------------------

Числа 12; 11; 9; 2 - номера тех слоёв, которые луч игнорирует.

Хотите добавить слой в игнор, добавляете новую переменную. Названия ignoreWeaponMask, gnoreWeaponMask2 и др. просто названия новоявленных переменных, поэтому вы можете вместо них использовать, какие вам взбредёт в голову, например:

int UselessLayer = 1 << номер слоя;

Потом мы их совмещаем их в одну переменную последними двумя строчками. Там вписываются название ранее объявленных переменных через данный символ | .

Итак, дальше можно пускать лучи.

-2

RaycastHit2D hit0 = Physics2D.Raycast(SpotPoint.transform.position, target[0].transform.position - SpotPoint.transform.position, Mathf.Infinity, layerMask);

Я могу и пускаю сразу несколько лучей одновременно в направлении точек из массива.

-3

---------------------------------------------------------

RaycastHit2D aiming = Physics2D.Raycast(AimPoint.transform.position, transform.TransformDirection(Vector2.up), Mathf.Infinity, layerMask);

---------------------------------------------------------------

Здесь луч пускается чётко вверх от объекта и зависит от его поворота в пространстве.

Заключительный этап. Проверка попадания

Код может и неоптимизированный, но зато рабочий (не бейте)
Код может и неоптимизированный, но зато рабочий (не бейте)

if (hit0.collider != null) //В этой строке проверяется, попал ли луч вообще в какой - либо коллайдер.

{

if (hit0.collider.gameObject == target[0]) //А в этой, является ли этим коллайдером коллайдер именно нужного нам объекта.

{

IsEyeContact = true;

}

else

{

IsEyeContact = false;

}

}

else

{

IsEyeContact = false;

}

Ну вот и всё, о чём стоит поговорить на тему рэйкаста в 2D пространстве. Надеюсь, всё было понятно и доходчиво, мне бы данная статья точно помогла) Оценивайте, пишите комментарии, в последствии постараюсь выложить ещё что - нибудь.

Ниже прикреплю полный код:

Пофантазируйте, модернизируйте и упрощайте наздоровье!

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Raycast : MonoBehaviour

{

public GameObject[] target;

public bool IsEyeContact = false;

public bool AimYet = false;

public GameObject SpotPoint;

public GameObject AimPoint;

void FixedUpdate()

{

int ignoreWeaponMask = 1 << 12;

int ignoreWeaponMask2 = 1 << 11;

int ignoreRaycastMask = 1 << 9;

int ignoreRaycastMask2 = 1 << 2;

int layerMask = ignoreWeaponMask | ignoreRaycastMask | ignoreWeaponMask2 | ignoreRaycastMask2;

layerMask = ~layerMask;//инвертируем маску, теперь выбранные слои будут игнорироваться

// Cast a ray straight down.

RaycastHit2D hit0 = Physics2D.Raycast(SpotPoint.transform.position, target[0].transform.position - SpotPoint.transform.position, Mathf.Infinity, layerMask);

RaycastHit2D hit1 = Physics2D.Raycast(SpotPoint.transform.position, target[1].transform.position - SpotPoint.transform.position, Mathf.Infinity, layerMask);

RaycastHit2D hit2 = Physics2D.Raycast(SpotPoint.transform.position, target[2].transform.position - SpotPoint.transform.position, Mathf.Infinity, layerMask);

RaycastHit2D hit3 = Physics2D.Raycast(SpotPoint.transform.position, target[3].transform.position - SpotPoint.transform.position, Mathf.Infinity, layerMask);

RaycastHit2D hit4 = Physics2D.Raycast(SpotPoint.transform.position, target[4].transform.position - SpotPoint.transform.position, Mathf.Infinity, layerMask);

RaycastHit2D aiming = Physics2D.Raycast(AimPoint.transform.position, transform.TransformDirection(Vector2.up), Mathf.Infinity, layerMask);

// If it hits something...

if (hit0.collider != null || hit1.collider != null || hit2.collider != null || hit3.collider != null || hit4.collider != null)

{

if (hit0.collider.gameObject == target[0] || hit1.collider.gameObject == target[0] || hit2.collider.gameObject == target[0] || hit3.collider.gameObject == target[0] || hit4.collider.gameObject == target[0])

{

IsEyeContact = true;

}

else

{

IsEyeContact = false;

}

}

else

{

IsEyeContact = false;

}

if (aiming.collider != null)

{

if (aiming.collider.gameObject == target[0])

{

AimYet = true;

}

else

{

AimYet = false;

}

}

else

{

AimYet = false;

}

}

}