Förstå styrningsbeteenden vandra

Styrbeteenden syftar till att hjälpa autonoma karaktärer att flytta på ett realistiskt sätt, med hjälp av enkla krafter som kombinerar för att producera livsliknande, improvisationsnavigering. I denna handledning täcker jag vandra beteende, vilket gör teckenet rörelse slumpmässigt.

Notera: Även om denna handledning skrivs med AS3 och Flash, borde du kunna använda samma tekniker och begrepp i nästan vilken spelutvecklingsmiljö som helst. Du måste ha en grundläggande förståelse för matematiska vektorer.


Går runt

Ofta måste karaktärerna i ett spel slumpmässigt röra sig om sin miljö. Vanligtvis väntar de karaktärerna på att något ska hända (som en kamp mot spelaren) eller de letar efter något. När spelaren kan se det beteendet måste karaktärens vandrande förmåga vara visuellt trevlig och realistisk nog.

Om spelaren kan identifiera starka definierade banlinjer eller orealistiskt rörelsebeteende, kommer det att generera frustration. I värsta fall kommer spelaren att räkna ut hur man förutse karaktärens rörelser, vilket resulterar i en tråkig spelupplevelse.

De vandra styrande beteende syftar till att skapa en realistisk "avslappnad" rörelse, vilket gör att spelaren tror att karaktären verkligen lever och går runt.


Sök och slumpmässighet

Det finns flera sätt att implementera vandringsmönstret med hjälp av styrningsbeteenden. Det enklaste använder det tidigare beskrivna sökbeteendet. När ett tecken utför sökande kommer det att röra sig mot ett mål.

Om positionen för det målet ändras några sekunder, kommer tecknet aldrig att nå målet (och även om det gör kommer målet att flytta igen). Att placera målet slumpmässigt i spelområdet gör att teckenet så småningom flyttar runt hela miljön som jagar målet. Demon nedan visar detta tillvägagångssätt i åtgärd:


Sökbeteendet och ett slumpmässigt mål. Klicka på demo för att visa kraftvektorer.

Koden för detta genomförande skulle vara:

 // Beräkna vandringskrappen privat funktion vandra (): Vector3D var nu: Number = (new Date ()). GetTime (); om (nu> = nextDecision) // Välj en slumpmässig position för "target" // returnera en styrkraft som trycker på tecknet // mot målet (sökningsbeteendet) retursökning (mål);  // I spelet loop, hantera styrkor och rörelse bara // som tidigare: allmän funktion uppdatering (): void styrning = vandra () styrning = stympa (styrning, max_force) styrning = styrning / masshastighet = trunkera (hastighet + styrning, max_speed) position = position + hastighet

Trots att detta är ett enkelt och bra tillvägagångssätt är det slutliga resultatet inte så övertygande. Ibland omvandlar karaktären helt sin väg eftersom målet ligger bakom det. Teckenets beteende verkar mycket mer som "Damn, jag glömde mina nycklar!" än "Okej, jag kommer att följa denna riktning nu".


wander

Ett annat genomförande av vandringsbeteendet föreslogs av Craig W. Reynolds när han uppfann dessa beteenden. Grundidén är att producera små slumpmässiga förskjutningar och tillämpa på teckenets nuvarande riktningsvektor (hastigheten, i vårt fall) varje spelram. Eftersom hastighetsvektorn definierar var karaktären är på väg och hur mycket den rör sig i varje ram ändras eventuell störning av den aktuella vägen.

Genom att använda små förskjutningar hindrar varje ram karaktären från att plötsligt ändra sin rutt. Om tecknet rör sig upp och vrider sig till höger, till exempel i nästa spelram kommer det fortfarande att röra sig upp och svänga till höger, men i en något annorlunda vinkel.

Det synsättet kan också genomföras på olika sätt. En av dem är att använda en cirkel framför karaktären med hjälp av det för att beräkna alla involverade krafter:

De förskjutningskraft  har sitt ursprung vid cirkelns centrum och begränsas av cirkelradien. Ju större radien och avståndet från karaktären till cirkeln, desto starkare kommer "push" karaktären att få varje spelram.

Denna förskjutningskraft kommer att användas för att störa karaktärens rutt. Det används för att beräkna vandra kraft.


Beräkning av cirkelns position

Den första komponenten som krävs för att beräkna vandringsstyrkan är cirkelns mittposition. Eftersom cirkeln ska placeras framför tecknet kan hastighetsvektorn användas som en guide:

 // CIRCLE_DISTANCE konstanten nedan är // ett nummer definierat någon annanstans. // Koden för att beräkna cirkelcentret: var circleCenter: Vector3D; circleCenter = hastighet.klon (); circleCenter.normalize (); circleCenter.scaleBy (CIRCLE_DISTANCE);

De circleCenter vektorn ovan är en klon (kopia) av hastighetsvektorn, vilket innebär att de pekar mot samma riktning. Det normaliseras och multipliceras med ett skalärvärde (CIRCLE_DISTANCE, i detta fall) som kommer att resultera i följande vektor:


Förskjutningskraft

Nästa komponent är förskjutningskraften, som är ansvarig för höger eller vänster sväng. Eftersom det här är en kraft som används för att producera störningar kan den peka överallt. Låt oss använda en vektor som är inriktad på Y-axeln:

 varförskjutning: Vector3D; förskjutning = ny vektor3D (0, -1); displacement.scaleBy (CIRCLE_RADIUS); // // Slumpvis ändra vektorriktningen // genom att göra den ändra sin nuvarande vinkel setAngle (displacement, wanderAngle); // // Ändra wanderAngle bara lite, så det // kommer inte att ha samma värde i // nästa spelram. wanderAngle + = (Math.random () * ANGLE_CHANGE) - (ANGLE_CHANGE * .5);

Förskjutningskraften skapas och skalas av cirkelradien. Som tidigare beskrivits, desto större är radie, desto starkare är det att vandra kraften. De wanderAngle är ett skalärvärde som definierar hur mycket förskjutningskraften ska "lutas" Efter det används används ett slumpmässigt värde för att göra det annorlunda för nästa spelram. Det ger den nödvändiga slumpen i rörelsen.

För förståelsens skull, låt oss anta att förskjutningskraften som beräknats ovan ligger i cirkelns centrum. Eftersom det var skalat av cirkelradiusvärdet, skulle det vara något så här:

Tips: Kom ihåg att matrisvektorer inte har en position i rymden, de har en riktning och en magnitud (längd). Som ett resultat kan de placeras var som helst.

Vandra kraften

Efter att cirkelcentralen och förskjutningsvektorn har beräknats, måste de kombineras för att producera vandra kraft. Den kraften beräknas genom att lägga till de två vektorerna:

 var wanderForce: Vector3D; wanderForce = circleCenter.add (förskjutning);

Vi kan visuellt representera dessa krafter som så:

Vandringsstyrkan kan föreställas som en vektor som går från karaktären till en punkt på cirkelns omkrets. Beroende på positionen för den punkten, kommer vandringsstyrkan att trycka tecken åt vänster eller till höger, starkt eller svagt:

Ju mer vandringskraften är i linje med hastighetsvektorn, desto mindre kommer tecknet att ändra sin nuvarande rutt. Vandringsstyrkan kommer att fungera exakt som sök- och flyktkrafterna: det kommer att driva karaktären mot en riktning.

På samma sätt som att söka och fly, där kraftriktningen beräknas baserat på ett mål, beräknas vandringsriktningen baserat på en slumpmässig punkt på cirkelns omkrets. Den sista koden för vandringsstyrkan är:

 Private Function Wander (): Vector3D // Beräkna cirkelcentralen var circleCenter: Vector3D; circleCenter = hastighet.klon (); circleCenter.normalize (); circleCenter.scaleBy (CIRCLE_DISTANCE); // // Beräkna förskjutningskraften varförskjutning: Vector3D; förskjutning = ny vektor3D (0, -1); displacement.scaleBy (CIRCLE_RADIUS); // // Slumpvis ändra vektorriktningen // genom att göra den ändra sin nuvarande vinkel setAngle (displacement, wanderAngle); // // Ändra wanderAngle bara lite, så det // kommer inte att ha samma värde i // nästa spelram. wanderAngle + = Math.random () * ANGLE_CHANGE - ANGLE_CHANGE * .5; // // Slutligen beräkna och returnera vandringsstyrkan var wanderForce: Vector3D; wanderForce = circleCenter.add (förskjutning); returnera wanderForce;  allmän funktion setAngle (vektor: Vector3D, värde: Number): void var len: Number = vector.length; vector.x = Math.cos (värde) * len; vector.y = Math.sin (värde) * len; 

Lägga till krafter

Efter att vandringsstyrkan har beräknats måste den läggas till karaktärens hastighet så att den kan påverka dess rörelse. Tillsatsen av den kraften utförs på samma sätt som tidigare:

 styrning = styrning () styrning = stympa (styrning, max_force) styrning = styrning / masshastighet = trunkera (hastighet + styrning, max_hastighet) position = läge + hastighet

Vandringsstyrkan påverkar karaktärens rutt på samma sätt som de tidigare beskrivna beteenden gjorde, med skillnaden att den skjuter karaktären i en slumpmässig riktning varje spelram:


Vandringsbeteendet. Klicka på demo för att visa kraftvektorer.

Demon ovan visar flera tecken som vandrar i miljön. Om de lämnar skärmen responeras de i mitten.


Slutsats

Vandringsbeteendet är ett utmärkt sätt att genomföra slumpmässiga rörelser. Det styrs av en imaginär cirkel placerad framför karaktären, som kan tweaked för att producera önskat rörelsemönster.

Denna handledning beskriver styrningsbeteenden och förklarar vandringsbeteendet. I nästa inlägg lär vi oss mer om beteende. Håll dig uppdaterad genom att följa oss på Twitter, Facebook eller Google+.