Opdracht: | Schrijf een AI met die zowel tegen een speler als tegen een adere AI kan vechten |
Duur: | 2 maanden |
Team grootte: | Solo project |
Rol: | Development |
Vaardigheden: | ![]() ![]() |
Links: | ![]() |
Deze AI maakt gebruik van een modulair utility systeem. Hiermee kan het gedrag aangepast worden zonder dat er geprogrammeerd hoeft te worden. De AI maakt gebruik van een A* algoritme om zijn pad te bepalen. Dit was erg uitdagend om te implementeren. Ik had nog nooit met dit algoritme gewerkt. Wat het nog uitdagender maakte is dat het algoritme rekening moet houden met alle moves die uitgevoerd kunnen worden.
De base classes voor dit systeem is geïnspireerd op hoe de pawn en controller classes van Unreal werken. De pawn classes bevatten alle informatie over de moves die uitgevoerd kunnen worden. Op deze manier gebruiken de AI en de speler dezelfde regels. Het navigatie systeem van de AI bepaald welke input er gegeven moet worden om naar het volgende punt te gaan.
De AI moest de speler ook kunnen ontwijken. Hiervoor zijn alle tactische punten om de map gemarkeerd. Wanneer de speler te dichtbij komt maakt de AI een lijst van de dichtstbijzijnde punten. Vervolgens kiest hij hiervan het punt dat het verste weg is van de speler. In de meeste gevallen werkt dit behoorlijk goed en probeert de AI rond de speler te cirkelen. Wanneer de AI in de hoeken van de map terecht komt weet hij niet meer zo goed hoe hij de speler moet ontwijken.
Uiteindelijk bleek het heel lastig te zijn om de AI het pad goed te laten volgen. Doordat het pad continue veranderd komt het regelmatig voor dat de AI bepaalde sprongen net niet haalt. De AI is hierdoor zeker niet perfect maar ondanks dat is het wel een leuke AI om tegen te spelen. Door de kleine foutjes en het continue wisselen van pad voelt de AI wel heel levend aan. Het enige grote probleem is dat er een paar dingen zijn die de AI simpelweg niet kan. Wanneer je dit door hebt is de AI makkelijk te verslaan.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class Controller : MonoBehaviour {
protected Pawn pawn;
// Possess a pawn
public void Possess(Pawn newPawn) {
pawn = newPawn;
newPawn.SetController(this);
// parent this controller to the pawn
if (newPawn.transform != transform) {
transform.parent = newPawn.transform;
transform.localPosition = Vector3.zero;
}
}
// Return the current possessed pawn
public Pawn GetPawn () {
return pawn;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class AIController : Controller {
protected NavigationSystem navigation;
// Update is called every frame
protected virtual void Update () {
// Apply the navigation
if (navigation != null) {
pawn.SetVelocity(navigation.GetDirection());
}
}
// Get connected navigation system instace
public NavigationSystem GetNavigationSystem () {
return navigation;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlatformerAI : AIController {
public ProceduralTiles.Level level;
public Agent agent;
public Context context;
// Use this for initialization
protected void Start() {
SideScrollerPawn SSPawn = (SideScrollerPawn)pawn;
// Create new navigation system
if (SSPawn) {
navigation = new PlatformNavigator(SSPawn, level);
}
// Initialise agent
if (agent) {
agent.Initialise();
}
}
// Update is called once per frame
protected override void Update() {
// Update agent
if (agent && context) {
agent.UpdateStates(context);
}
}
}
![]() |
contact@rubenbimmel.nl | ![]() |
![]() |
Artstation | ![]() |
GitHub |