Spel-AI, beteendemodellering, flocking
Denna labb syftar till att implementera flocking för en enkel 2D-animation. Att alls implementera flocking är ganska rättframt, men att balansera systemet så det beter sig trevligt är ett problem som inte syns i flocking-definitionen.
0. Labbpaketet. Kom igång.
Vi skall använda ett litet 2D-animationspaket, SpriteLight, som är en minimal spritemotor, riktigt stram för att göra labbmaterialet överskådligt och lättarbetat. Koden är såpass liten att du lätt kan sätta dig in i den själv. Dock, några ord om hur man kan arbeta:
Kompilera med medföljande makefil (så snart den är uppdaterad) eller direkt på kommandoraden (i stil med tidigare).
Labbmaterial:
lab4gui.zip (Ny testversion med SimpleGUI. Den kanske gör det lite lättare att justera parametrar?)
Gamla versioner:
lab4x.tar.xz (Experimentell C++-version.)
lab4x.tar.gz Experimentell version som använder VectorUtils för att få mer vektoroperationer. (OBS! Inte samma lab4x som ovan!)
En del bilder ingår i TGA-format. Den som vill byta mot snyggare får gärna göra det.
Utgå från lab4.c. Gör tillägg i Display eller Timer samt globalt för att modifiera objektens position och hastighet. När du behöver skilja på olika spritetyper, lägg till data i SpriteRec (SpriteLight.h) efter behov.
Världen är från början befolkad av ett antal varelser. De rör sig oberoende av varandra, rakt fram.
Provkör. Lägg till ett par extra varelser. Observera att du kan ladda fler bilder med GetFace. Notera också att alla sprites läggs i en och samma lista (gSpriteRoot) så om man vill ha olika beteenden på dem kan man inte blint gå igenom denna lista utan måste skilja olika typer av objekt åt. (En "riktig" spritemotor gör detta genom att ha olika hanterare för olika individer.)
Nu skall vi göra "boids" av dem, så de "bryr sig om" varandra.
Du kommer att vilja finjustera en del parametrar. Om du tycker det tar tid, tänk på att du inte behöver kompilera om för varje ändring! Se funktionen "Key" labbskalet. Där finns ett exempel på hur en parameter kan justeras med enkla tangentbordsinmatningar, med utdata på stdout.
Observera att pseudokoden jag visade på föreläsningen är en grov skiss som hoppar över flera saker. Mycket kan och bör göras annorlunda. Bör du ackumulera hastighetsskillnader eller hastigheter, och vad blir det då du vill påverka?
Varning: Se upp med vad som är absoluta och relativa positioner. Jag kommer att ta upp detta på föreläsningen.
1. Flocking steg 1: Cohesion
Sök alla varelser inom visst avstånd, beräkna tyngdpunkt, gå mot denna. Detta kommer att få alla varelser att samlas i en eller flera punkter. Justera din algoritm och startpositioner så att de samlas i minst två olika punkter.
Koden för att beräkna tyngdpunkt mm för alla får är central för laborationen. Utgå från spriteloopen i Display.
Fråga:
Hur gjorde du för att söka igenom alla boids?
2. Flocking steg 2: Separation
Skapa en bortstötande kraft från varelser inom visst avstånd. Detta skall sprida ut flockarna. Separationsfunktionen kan göras på flera sätt. Försök finna en som ge en mjuk bortstötning som inte ger kraftiga ryck i animationen.
Fråga: Vilken funktion valde du för den bortstötande kraften? Är din separation bra eller kan du tänka dig finjusteringar?
3. Flocking steg 3: Alignment
Låt alla varelser sträva efter att röra sig åt samma håll som sina grannar. Vikta ihop de tre delvillkoren så inget av dem dominerar över de andra.
Nu är alla tre grundläggande villkor implementerade. Din flock boids antagligen ett samlat men lite tråkigt beteende.
Fråga:
Vilken vikt lade du på alignment? Hur mycket rätar de upp sig efter varandra per iteration?
4. Tillför brus och personlighet.
Att lägga på brus, en slumpfunktion, kan tyckas vara ett väldigt fult sätt att ge liv åt beteenden men det är en grundläggande metod för att undvika "platthet" i såväl bild som rörelser. Om varje boid dessutom har en personlighet, dvs på vilket sätt brus påförs, så kan bruset bli en intressant och realistisk komponent.
Inför ett eller flera "busiga" boids, "svarta får", som har olika grader av brustillägg. Bruset kan modifiera position, hastighet, vinkel. Använd en spriteface med annan bild (färg) för att göra det lätt att följa den "busiga" boiden.
För att få brus kan du använda funktionen random(). Den returnerar ett slumpmässigt 32-bitars heltal. Seedning av denna (om du vill ha olika sekvenser) görs med srandom().
Frågor:
Hur håller du reda på ditt "svarta får”?
Är ditt svarta får en "ledare" eller en "busig flockmedlem". Hur skulle du ha gjort för att göra den andra av dessa två?
5. Bättre flocking
Minst en av följande uppgifter skall utföras.
5a. Attraktionspunkt: mat.
Låt "mat" dyka upp då och då som attraherar flocken. Det kan introduceras automatiskt eller med musklick. Det skall försvinna efter en viss tid eller när en boid kommer nära nog.
5b. Finjustering av flockbeteendet.
Det krävs normalt lite mer justeringar för att få flocken att bete sig som man önskar. Om det är en skock får vi modellerar (vilket grafiken antyder) så bör de inte glida fram för evigt utan bör bromsa in, och lugnt ströva omkring lokalt ("beta") när de inte har någon uttalad anledning att röra sig snabbt.
Observera att en flock som saktar in behöver någon möjlighet till yttre påverkan för att inte bli helt passiv. Du kan utnyttja ditt "svarta får" för detta.
5c. Objekt som kan påverka/skingra flocken.
Inför ett objekt som "skrämmer" dina boids. De skall bara påverkas inom ett visst avstånd. Det skall vara möjligt att med denna skingra flocken så den delas i en eller flera delflockar. Gör det styrbart med mus eller tangentbord.
5d. Vinkelberoende boids.
Ovan har vi inte krävt vinkelberoende i testen, vilket förenklar problemet, men det gör att våra boids har "ögon i nacken". Inför ett vinkelberoende så att du endast tar hänsyn till boids inom en viss vinkel. Gör det någon märkbar skillnad?
Slut! Redovisa för en labbassistent. Observera att alla frågor som ges ovan efter uppgifterna skall vara besvarade innan du redovisar!
Vi hoppas att labben var givande!