Днешното обобщение ще обхване как играчът взаимодейства с околната среда с хвърляне на лъчи.

Завърших GLI Framework за курса GLI. Целта беше да се завършат някои основни механики в Sci-Fi Duck Hunt Game. Трябваше да внедря навигационната мрежа, AI, поведението на играча, HUD, звука на играта, условията за победа, условията за загуба, две бонус задачи, включително експлозивен варел и здраве на бариерата.

Целта на играта е да попречи на враговете да стигнат до горната врата, за да избягат. Следователно враговете трябва да пътуват от началната до крайната точка. В същото време играчът е в охранителната кула и стреля с пушката си, за да ги спре.

Днешното обобщение ще обхване как играчът взаимодейства с околната среда и Raycasting.

Поведение на играча

Играчът има две прости действия, движещи се и стрелящи. Също така към плейъра са прикачени три скрипта: един скрипт за FPS контролера, скрипт за изстрелване и скрипт за мениджър на играч.

  • Движението е ограничено до вътрешността на наблюдателната кула и се контролира от WASD
  • Стрелбата е обвързана с левия бутон на мишката и полустрелба. Което означава, че оръжието стреля само когато натиснете и се нулира при освобождаване. С леко охлаждане.

Скрипт за изстрелване

Скриптът за изстрелване изстрелва лъч в центъра на екрана, където е поставена мрежата.

_ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));

В момента използвам новата система за въвеждане и в този скрипт активирам картата на играча и извиквам извършеното събитие. Моят метод, прикрепен към събитието, проверява дали играчът може да стреля с оръжието си. Ако е така, хвърлете лъч от центъра, активирайте светкавицата на муцуната, пуснете аудио, забранете на плейъра да стреля отново до освобождаване и след това извикваме друг метод, който обработва действията на изстреляния лъч.

Бързо светкавицата на дулото е предимство от Filebase.com, а аудиото е безплатен източник, който намерих онлайн.

Всичко, което направих за дулната светкавица, беше да прикрепя системата за частици към цевта.

public class Fire : MonoBehaviour
{
    private Ray _ray;
    private ActionMaps _inputs;
    private AudioSource _gunFire;
    [SerializeField] private AudioClip _barrier;
    [SerializeField] private GameObject _muzzleFlash;
    private bool _canFire = true;
    [SerializeField] private Camera _camera;
    private PlayerManager _playerManager;
    [SerializeField] private LayerMask _mask;
    private float _timer = 0.5f;
    private IDamage _damagable;

    private void Awake()
    {
        _playerManager = GetComponent<PlayerManager>();
        _gunFire = GetComponent<AudioSource>();
        _inputs = new ActionMaps();
    }

    private void OnEnable()
    {
        _inputs.Player.Enable();
        _inputs.Player.Fire.performed += Fire_performed;
        _inputs.Player.Fire.canceled += Fire_canceled;
        _muzzleFlash.SetActive(false);
    }

    private void Fire_canceled(InputAction.CallbackContext obj)
    {
            _canFire = true;
    }

    private void Fire_performed(InputAction.CallbackContext obj)
    {
        if (_canFire) 
        {
            _ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
            _muzzleFlash.SetActive(true);
            _gunFire.Play();
            _canFire = false;
            _timer += Time.time;
            Firing();
        }
    }
}

Метод на изпичане

При този метод се изпълнява съпрограма за охлаждане, за да се деактивира ефектът на частиците за светкавицата на дулото.

 IEnumerator FiringCoolDownRoutine()
    {
        yield return new WaitForSeconds(0.2f);
        _muzzleFlash.SetActive(false);
    }

След това методът проверява дали raycast удря обект с правилната маска на слоя. (AI, бариери, експлозиви)

ако е така, имам три израза if-else, които сравняват маркера на обектите и определят резултата.

  • AI (Враг) Извикваме мениджъра на хайвера и намаляваме общото количество врагове, които се появяват в момента.
  • Обадете се на играча-мениджър и добавете 60 точки към резултата на играча.
  • След това уведомете скрипта на AI на изстрела да изпълни метода на смъртта.
  StartCoroutine(FiringCoolDownRoutine());
        if (Physics.Raycast(_ray, out RaycastHit _hit, Mathf.Infinity,_mask))
        {
            if (_hit.transform.CompareTag("Enemy"))
            {
                _hit.transform.gameObject.TryGetComponent<AI>(out AI ai);
                SpawnManager._instance._spawnCount--;
                _playerManager.PlayerScore(60);
                ai.Death();
            }
  • Компонентът на бариерата се съхранява в променлива и аз извиквам метода щети (интерфейс) и пускам аудио сигнал, когато рундът удари бариерата.
            else if (_hit.transform.CompareTag("Barriers"))
            {
                _damagable = _hit.transform.gameObject.GetComponent<Barrier>();
                _damagable.Damage(5);
                AudioSource.PlayClipAtPoint(_barrier, new Vector3(0, 11, 32), 500);
            }

  • И накрая, по отношение на експлозивните варели, когато лъчът удари варел, ние съхраняваме експлозивния компонент в променлива и уведомяваме скрипта да запали варела и да експлодира.

            else 
            {
                Explosive_Barrel barrel = _hit.transform.gameObject.GetComponentInParent<Explosive_Barrel>();
                barrel._isIgnited = true;
                Debug.Log("BOOM");
            }

Скрипт за мениджър на играчи

Скриптът обработва резултата на играча. Вероятно бих могъл да направя скрипт за един играч, който да управлява както стрелбата, така и резултата, но в крайна сметка тръгнах по този път.

public class PlayerManager : MonoBehaviour
{
    [SerializeField] public int Score { get; private set; }

    private void Awake()
    {
        Cursor.visible = false;
    }
    public void PlayerScore(int value) 
    {
        Score += value;
        UIManager._instance.PlayerScore(Score);
    }
}

В заключение, ето кратък преглед на това как настроих скриптовете на играча и използвах хвърляне на лъчи в проекта, за да копирам снайперска пушка. Отново движението на героя се контролира от FPS контролера на персонажа. В следващата статия може да се потопя в началните и крайните сцени или да говоря за разрушими бариери.