Realizati o scena in unity in care sa existe urmatoarele elemente:
Inregistrare pe Teams
Pentru navigarea automata a personajelor pana la un punct pe harta, indiferent ca e vorba de un personaj controlat sau un agent inteligent, avem nevoie in primul rand de generarea unor zone in care acestea sa se poata misca. Aceste zone poarta numele de Navigation Mesh sau NavMesh, prescurtat. In Unity se pot genera automat acest NavMesh folosind utilitarul de Navigation Bake: Window > AI > Navigation > Bake.
De mentionat este ca un navmesh se genereaza folosind elementele statice ale scenei. Pentru a marca un obiect ca fiind static, trebuie bifat in inspector casuta de Static.
Mai mult, meniul de Navigation, permite detalierea fiecarui obiect cu privire la navigatie, astfel incat se poate specifica daca un obiect e static sau daca e Walkable sau nu.
Crearea (Bake) NavMesh-ului este statica, in sensul ca odata creata ea nu se mai modifica la runtime. Astfel, daca avem obiecte mobile, care influienteaza NavMesh-ul, nu le putem declara statice si nu le putem include in procesul de Bake. Pentru acestea exista o componenta Nav Mesh Obstacle
care altereaza dinamic NavMesh-ul.
Rezultatul este o zona in care agentii sau jucatorii pot naviga folosind functii puse la dispozitie de unity pentru deplasare.
Pentru a programa o miscare automata pe harta se poate folosi aceasta functionalitate de navigare automata (NavMesh) si componenta de tip NavMeshAgent.
Pentru ca un inamic sa se miste spre player, atunci cand player-ul intra in raza de actiune putem folosi componenta de NavMeshAgent
void Update() { //calculam distanta intre player si inamic float distance = Vector3.Distance(target.position, transform.position); if(distance <= radius) { //misca agentul pana la player agent.SetDestination(target.position); //in momentul in care intra in raza de atac, ataca } else { // agentul se misca in treaba lui / patruleaza etc. }
Mai departe, se poate folosi o alta distanta, pentru a determina raza de atac. Un inamic poate avea atac melee (de aproape) sau de la o anumita distanta.
public float attackRadius = 1; void Update() { //calculam distanta intre player si inamic float distance = Vector3.Distance(target.position, transform.position); if(distance <= radius) { //misca agentul pana la player agent.SetDestination(hit.point); //in momentul in care intra in raza de atac, ataca if(distance <= attack) { //ataca } }
Pentru a misca efectivul jucatorul, trebuie sa folosim sistemul de navigare al Unity. Pentru asta se poate folosi pachetul UnityEngine.AI, vom adauga o componenta de tip Nav Mesh Agent
si vom initializa un agent.
using UnityEngine.AI; void Start() { agent = GetComponent<NavMeshAgent>(); }
Pentru a controla jucatorul cu mouse-ul, avem nevoie de destinatia la care trebuie personajul sa navigheze. Acest lucru putem sa il aflam cu un RayCast.
if(Input.GetMouseButtonDown(0)) //la apasarea click stanga { Ray mouseClickRay = camera.ScreenPointToRay(Input.mousePosition); //creaza o raza printr-un punct de pe ecran RaycastHit hit; if(Physics.Raycast(mouseClickRay, out hit)) { //misca player-ul pana la destinatie agent.SetDestination(hit.point); } }
In multe cazuri avem actiuni mai complexe la mouse click dreapta: cum ar fi atacarea unui inamic, sau preluarea unui obiect etc, caz un care obiectele se pot misca in scena. Pentru asta, trebuie implementata o functie astfel incat sa se poata actualiza pozitia targetului curent.
Transform target = null; if(Input.GetMouseButtonDown(1)) //la apasarea click dreapta { Ray mouseClickRay = camera.ScreenPointToRay(Input.mousePosition); //creaza o raza printr-un punct de pe ecran RaycastHit hit; if(Physics.Raycast(mouseClickRay, out hit)) { target = hit.transform; StartCoroutine(FollowTarget()); //follow target pana la destinatie } } if(Input.GetMouseButtonDown(0)) //la apasarea click stanga { target=null; //dezactiveaza target-ul } IEnumerator FollowTarget() { while(target!=null) { agent.SetDestination(target); yield return null; } yield return 0; }
Pentru a avea o miscare completa, camera trebuie sa urmareasca jucatorul. Astfel, putem plasa camera ca si child al player-ului, sau putem actualiza pozitia folosind un script ca in exemplul de mai jos.
public Transform target; public Vector3 offset; public float height = 2f; public float zoom=10f; void LateUpdate() //se apeleaza imediat dupa update { transform.position = target.position - offset * zoom; //actualizeaza pozitia transform.LookAt(target.position + Vector3.up * height); //seteaza directia camerei inspre player }