◉ VR-kurser
▶ Spela webbversionen

16. Monster, spawn och vägval

Målet

Förstå hur monster dyker upp utom synhåll, väljer en väg runt väggarna, skadar spelaren och försvinner efter tre träffar. Läs spawnMonster() och updateMonsters() i main.js, samt nextPathStep() i level.js.

Säkra spawnpunkter

Spelet har en lista med möjliga X–Z-positioner. spawnMonster() filtrerar bort punkter närmare spelaren än RULES.minimumSpawnDistance (6 meter) och punkter för nära ett annat levande monster. Det får vara högst fyra levande monster samtidigt. Den första Horror-fienden placeras bakom skydd, men på ett tillåtet avstånd. Senare spawnförsök sker med en timer.

Monsterarten väljs i monsterKindForSpawn() i rules.js. En spindel kan komma var tredje spawn när ingen annan spindel redan lever. Resten blir Horror Game Monster. På så sätt kan du ändra blandningen utan att blanda in 3D-modellernas inläsningskod.

En väg genom ett rutnät

En rak linje mot spelaren skulle gå genom väggar. nextPathStep() delar därför marken i celler på 0,7 meter, söker igenom grannceller med en kö och hoppar över celler där blocked() säger stopp. Den returnerar nästa punkt längs en funnen väg. Detta är en enkel bredden-först-sökning, inte ett avancerat navigationssystem.

Vägen räknas om ungefär var 0,65 sekund per monster. Vid varje bildruta rör sig monstret ett litet steg mot aktuell waypoint. Den slutliga rörelsen testas också med blocked(), så att en avrundning i rutnätet inte låter fienden gå igenom en vägg.

Attack och tydlig respons

Horror-monstret går långsammare än spindeln. Spindeln kan starta ett kodstyrt hopp när den är nära spelaren; dess höjd följer en sinuskurva. När ett monster når kontaktavståndet dras 12 hälsa, med cooldown så att spelaren inte förlorar all hälsa på en bildruta. Vid skott blinkar fienden röd. Efter tre träffar räknas en kill och fienden tas bort.

Varför zombien har en egen gånganimation

Zombiefilen innehåller egentligen klippen Idle, Walk och Run, men det konverterade skelettets bindning får fel skala i Three.js. Att spela klippet direkt gör modellen felaktig eller osynlig. loadModel() tar därför den synliga kroppen som en egen mesh. animateHorrorGait() utgår från vertexernas ursprungliga positioner och för vänster och höger ben åt motsatta håll. Armarna sänks från modellens T-pose och pendlar i motsatt fas. När monstret står still går rörelsen mjukt tillbaka mot vila.

En modell har också en lokal framåtriktning. Både zombiens och spindelns framsida pekar längs +Z i spelet. monsterFacingYaw() vrider därför båda modellerna med samma formel. Tidigare fick spindeln en extra halv rotation och såg ut att springa baklänges, trots att vägvalet var rätt. Om ett monster ser ut att gå baklänges, kontrollera modellens framåtriktning innan du ändrar vägvalet.

Följ ändringen i koden

  1. Öppna level.js och hitta loadModel(). För zombien kopieras HorrorBody till en vanlig mesh. Geometrin klonas för varje monster, och en kopia av vertexernas ursprungliga positioner sparas i object.userData.gait.rest. Om alla monster delar samma geometri skulle ett monsters steg ändra även de andras kroppar.
  2. Leta upp animateHorrorGait(model, phase, strength). phase är var i steget monstret befinner sig; strength går mjukt mellan 0 (stillastående) och 1 (gående). För varje vertex används dess ursprungliga X, Y och Z. X avgör vänster eller höger sida, Y avgör om punkten hör till ben eller arm. En sinuskurva för benen åt motsatta håll, sänker armarna från T-pose och ger dem en mindre pendelrörelse.
  3. I main.js ökar monster.gaitPhase bara när monstret faktiskt flyttade sig. animateHorrorGait() anropas sedan en gång per bildruta. Det är viktigt att varje ny position räknas från rest, inte från föregående bildruta; annars deformeras kroppen mer och mer.
  4. monsterFacingYaw() använder Math.atan2(direction.x, direction.z) för både zombien och spindeln. Båda modellernas framsida ska då peka åt det håll de rör sig. Ändra inte vägberäkningen när det bara är modellen som tittar åt fel håll.

Prova i din egen kopia: ändra bara gångfasens hastighet i monster.gaitPhase += dt * 5.4 till dt * 3. Zombien ska gå långsammare med benen men fortsätta förflytta sig lika fort på kartan. Återställ värdet efter testet. Om figuren står i T-pose, kontrollera att userData.gait finns på modellen och att position.needsUpdate = true körs efter vertexändringarna.

Prova en sak i taget

  1. Starta spelet flera gånger och skriv upp avståndet till första monstret. Det ska inte stå intill spelaren.
  2. Ställ en vägg mellan dig och ett monster. Se om det söker en väg runt.
  3. Öppna första dörren och se att både spelaren och monster kan använda passagen.
  4. Skjut en fiende tre gånger. Kontrollera röd träffrespons och kill-räknare.
  5. Höj maxantalet monster i din kopia och observera hur det påverkar spelbarhet och prestanda. Återställ sedan.

Klart när: du kan förklara skillnaden mellan spawnval, vägval, rörelse, attack och skadehantering. De är fem separata beslut.