Sztuczna inteligencja od lat odgrywa kluczową rolę w grach wideo, to mózg każdego przeciwnika i postaci niezależnej (NPC, non-player character). To, jak sprytnie zachowują się NPC, często decyduje o tym, czy rozgrywka jest wciągająca. Dobrze zaprogramowana AI sprawia, że wrogowie reagują na działania gracza w naturalny i realistyczny sposób, stanowiąc wyzwanie i budując klimat gry. Z kolei słaba AI bywa od razu zauważona i potrafi popsuć całą zabawę.
Na szczęście, dzięki silnikowi Unity i językowi C#, nawet niewielki zespół lub samodzielny programista może tworzyć całkiem inteligentne NPC bez potrzeby pisania wszystkiego od zera. Unity oferuje gotowe narzędzia (np. system nawigacji NavMesh), a C# pozwala na elastyczne skryptowanie logiki postaci. W tym artykule przyjrzymy się, jak praktycznie wykorzystać te technologie do zbudowania sprytnego NPC w grze.
Tworzenie inteligentnych NPC w Unity (C#)
W praktyce implementacja AI w grach sprowadza się do połączenia ruchu postaci po świecie oraz logiki podejmowania decyzji. Oto kluczowe elementy, które warto znać, tworząc inteligentne zachowania NPC:
• Nawigacja (Pathfinding): NPC musi umieć poruszać się po świecie gry, omijając przeszkody. W Unity służy do tego NavMesh, czyli wbudowany system wyznaczania ścieżek. Wystarczy oznaczyć powierzchnie jako możliwe do chodzenia i dodać komponent NavMeshAgent do postaci, a silnik zadba o znajdowanie optymalnych dróg. Przykładowo, żeby wysłać NPC w określone miejsce, ustawiamy agent.SetDestination(cel), postać automatycznie podąży wyliczoną ścieżką.
• Logika decyzyjna (stany i zachowania): Sama nawigacja to nie wszystko, postać musi wiedzieć, co robić (atakować, patrolować, uciekać itp.). Często wykorzystuje się do tego skończone maszyny stanów (FSM) lub drzewa zachowań. FSM dzielą zachowanie NPC na stany (np. PATROL, POŚCIG) i definiują, kiedy następuje przełączenie między nimi. Dzięki temu NPC może np. patrolować obszar, a gdy zobaczy gracza - przejść w stan pościgu. Drzewa zachowań to alternatywa hierarchiczna, definiują decyzje w formie drzewa warunków. Obie techniki pomagają symulować inteligencję w sposób czytelny i łatwy do rozbudowy.
• Zmysły i interakcja: Aby NPC reagował na gracza, potrzebuje pewnych zmysłów. Najprościej zaimplementować pole widzenia, np. wykonując raycast (promień) od NPC do gracza lub korzystając z koliderów w kształcie stożka reprezentujących wzrok. Gdy gracz wejdzie w pole widzenia lub zasięg słuchu NPC, możemy zmienić stan AI (np. z trybu spokojnego patrolu na alarm i pościg). Takie wykrywanie otoczenia czyni zachowanie postaci bardziej wiarygodnym.
• Uczenie maszynowe: Coraz częściej w grach eksperymentuje się też z AI uczoną maszynowo. Unity udostępnia pakiet ML-Agents, który pozwala trenować model uczący się zachowania na podstawie nagród i kar (uczenie ze wzmocnieniem). W ten sposób można stworzyć NPC, które same uczą się optymalnych strategii – np. przeciwników adaptujących się do stylu gry gracza. To zaawansowane podejście wykraczające poza tradycyjne skryptowanie, ale niezwykle obiecujące, jeśli chodzi o tworzenie bardzo złożonych i nieprzewidywalnych przeciwników.
Poniżej prosty przykład wykorzystania FSM w C# dla wroga, który patroluje i goni gracza, gdy go zobaczy:
public enum EnemyState { Patrol, Chase }
public class EnemyAI : MonoBehaviour
{
public Transform[] patrolPoints;
public Transform player;
private NavMeshAgent agent;
private EnemyState state = EnemyState.Patrol;
private int currentPatrol = 0;
void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.SetDestination(patrolPoints[currentPatrol].position);
}
void Update()
{
switch(state)
{
case EnemyState.Patrol:
/* Jeśli dotarł do punktu patrolowego, wybierz następny */
if (!agent.pathPending && agent.remainingDistance < 0.5f)
{
currentPatrol = (currentPatrol + 1) % patrolPoints.Length;
agent.SetDestination(patrolPoints[currentPatrol].position);
}
/* Czy gracz znalazł się w zasięgu wzroku? */
if (CanSeePlayer())
{
state = EnemyState.Chase;
agent.SetDestination(player.position);
}
break;
case EnemyState.Chase:
/* Goni gracza */
agent.SetDestination(player.position);
/* Jeśli zgubił gracza, wraca do patrolu */
if (!CanSeePlayer())
{
state = EnemyState.Patrol;
agent.SetDestination(patrolPoints[currentPatrol].position);
}
break;
}
}
bool CanSeePlayer()
{
/* Przykładowa logika wykrywania gracza (np. na podstawie odległości) */
return Vector3.Distance(player.position, transform.position) < 10f;
}
}W powyższym kodzie NPC ma dwa stany: Patrol (chodzenie między wyznaczonymi punktami) i Chase (pościg za graczem). Gdy gracz pojawi się w zasięgu (tutaj dla uproszczenia sprawdzamy dystans), NPC przełącza się na pościg. Gdy gracza "zgubi", wraca do patrolowania. Oczywiście funkcja CanSeePlayer() mogłaby być rozbudowana o dokładniejsze sprawdzanie pola widzenia czy przeszkód terenowych, ale nawet tak prosty schemat znacznie zwiększa realizm zachowania wroga.
Podsumowanie
Sztuczna inteligencja w grach to temat rzeka, od prostych algorytmów po uczenie maszynowe - ale nawet podstawowe techniki pozwalają stworzyć znacznie mądrzejszych NPC, którzy uprzyjemnią rozgrywkę. Unity i C# dają nam solidne podstawy: gotowy system nawigacji oraz możliwość pisania własnej logiki, co w połączeniu wystarczy do zrealizowania większości klasycznych zachowań przeciwników. Kluczem jest zaczynać od prostych rozwiązań (np. patrol + pościg), a następnie iteracyjnie je ulepszać, dodawać nowe stany, ulepszać "zmysły" NPC lub sięgnąć po bardziej zaawansowane metody AI, jeśli zajdzie taka potrzeba.
Jeżeli temat sztucznej inteligencji Cię zaciekawił i chcesz zgłębić go bardziej od strony praktycznej w ekosystemie .NET, sprawdź moje szkolenie online "Szkoła AI w C#/.NET". Uczymy tam, jak tworzyć aplikacje z wykorzystaniem AI i uczenia maszynowego krok po kroku, również w kontekście gier i nie tylko. To świetny sposób, by podnieść swoje umiejętności i stworzyć jeszcze bardziej imponujące projekty.