Как проверить тег Unity C#
При стрельбе запускается луч, при попадании в любой объект с колайдером он спавнит эффект попадания в моем случае, след от пули, мне нужно сделать так, чтобы при попадании в объект с тегом Person у меня спавнился эффект крови и потом пропадал, не понимаю как это сделать, надеюсь на вашу помощь.
Вот сама реализация кода стрельбы для игры на движке Unity.
using System.Collections;
using UnityEngine;
public class Weapon : MonoBehaviour
{
public float damage = 21f;
public float fireRate = 1f;
public float force = 155f;
public float range = 15f;
public ParticleSystem hitFlash;
public ParticleSystem muzzleFlash;
public Transform bulletSpawn;
public AudioClip shotSFX;
public AudioSource _audioSource;
public GameObject hitEffect;
public GameObject Gilza;
public float GilzaForce = 5f;
public Camera _cam;
private float nextFire = 0f;
public GameObject BloodEffect;
void Update()
{
if (Input.GetButton("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + 1f / fireRate;
Shoot();
GilzaF();
}
}
void Shoot()
{
_audioSource.PlayOneShot(shotSFX);
muzzleFlash.Play();
RaycastHit hit;
if (Physics.Raycast(_cam.transform.position,_cam.transform.forward,out hit,range))
{
Debug.Log("Попадание в обьект "+ hit.collider);
GameObject impact = Instantiate(hitEffect, hit.point, Quaternion.LookRotation(hit.normal));
if(hit.rigidbody !=null)
{
hit.rigidbody.AddForce(-hit.normal * force);
}
}
}
void GilzaF()
{
Instantiate(Gilza,bulletSpawn.position, bulletSpawn.rotation);
{
Gilza.GetComponent<Rigidbody>().AddForce(bulletSpawn.forward * GilzaForce, ForceMode.Impulse);
}
}
Ответы (1 шт):
Суп нужно отделять от мух. Бизнес логика поведения, визуал и управление это должны быть разные классы.
Класс Weapon
должен отвечать ТОЛЬКО за стрельбу и ни за что больше. Тут стоит использовать корутину.
public class Weapon : MonoBehaviour
{
public event Action Shot;
public event Action<RaycastHit> OnHit;
[SerializeField] private float _damage = 21f;
[SerializeField] private float _fireRate = 1f;
[SerializeField] private float _distance = 15f;
[SerializeField] private float _pushPower = 15f;
[Space]
[SerializeField] private Transform _firePoint;
private IEnumerator _shootProcess;
private bool _attack;
public void StartShoot ()
{
_attack = true;
if (_shootProcess != null)
return;
_shootProcess = ShootProcess();
StartCoroutine(_shootProcess);
}
public void StopShoot ()
{
_attack = false;
}
private IEnumerator ShootProcess ()
{
while (_attack)
{
Fire();
yield return new WaitForSeconds(_fireRate);
}
_shootProcess = null;
}
private void Fire ()
{
if (Physics.Raycast(_firePoint.position, _firePoint.forward, out RaycastHit hit, _distance))
{
GameObject target = hit.collider.gameObject;
if (target.TryGetComponent(out IDamagable dTarget))
dTarget.ApplyDamage(_damage);
if (_pushPower > 0 && target.TryGetComponent(out Rigidbody body))
body.AddForce(-hit.normal * _pushPower);
OnHit?.Invoke(hit);
}
Shot?.Invoke();
}
}
Визуал может получать калбеки через события. Теги не используются вообще из-за того что это строковый литерал в котором можно ошибиться, тяжело искать баги и ОЧЕНЬ трудно что-то поменять.
С геометрией уровня всё просто, декали с частами. Что касается реакции других объектов на попадание, то это не дело оружия, кровоточит не пуля! Цели могут пускать кровь, брызки, лужи и тд, но причиной может быть всё что угодно, пули, шипы, удар тяжёлым и тупым, а цвета могут быть от красного до серобуромалонового или не пускать ничего, потому что это какой-нибудь скелет, который не кровь пускает а осколки костей. В связи с чем за реакцией на ранение должна отвечать сама цель, один из её компонентов, желательно под каким-нибудь интерфейсом, поскольку их может быть много разных и не только у юнитов, но и декораций.
[RequireComponent(typeof(Weapon))]
public class WeaponView : MonoBehaviour
{
[SerializeField] private ParticleSystem _muzzleFlash;
[SerializeField] private AudioSource _audio;
[Space]
[SerializeField] private Transform _sleevePoint;
[SerializeField] private GameObject _sleeveTemplate;
[SerializeField] private float _sleeveForce = 5;
[Space]
[SerializeField] private GameObject _decalTemplate;
private Weapon _weapon;
private void OnEnable ()
{
_weapon = GetComponent<Weapon>();
_weapon.Shot += OnShot;
_weapon.OnHit += OnHit;
}
private void OnDisable ()
{
_weapon.Shot -= OnShot;
_weapon.OnHit -= OnHit;
}
private void OnShot ()
{
_muzzleFlash?.Play();
_audio?.PlayOneShot(_audio.clip);
SpawnSleeve();
}
private void OnHit (RaycastHit hit)
{
if (hit.collider.gameObject.GetComponent<Rigidbody>() == false)
OnHitGeometry(hit);
if (hit.collider.gameObject.TryGetComponent(out IHitReaction target))
target.Hit(hit.point, -hit.normal);
}
private void SpawnSleeve ()
{
var sleeve = Instantiate(_sleeveTemplate, _sleevePoint.position, _sleevePoint.rotation);
if (sleeve.TryGetComponent(out Rigidbody body))
body.AddForce(sleeve.transform.forward * _sleeveForce);
}
private void OnHitGeometry (RaycastHit hit)
{
Instantiate(_decalTemplate, hit.point, Quaternion.LookRotation(hit.normal));
}
}