Днешното обобщение ще обхване как играчът взаимодейства с околната среда с хвърляне на лъчи.
Завърших 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 контролера на персонажа. В следващата статия може да се потопя в началните и крайните сцени или да говоря за разрушими бариери.