I denna artikel kommer vi att undersöka användningen av fysik för att simulera projektil effekter i spel som Angry Birds. Vi ska titta på grunderna för att använda 2D fysik i spelvärlden, till exempel skapa kroppar och tillämpa impulser och krafter.
Varför använda en fysikmotor? Vad gör det egentligen?
En fysikmotor hjälper oss att göra två mycket viktiga saker för vårt spel:
Kollisionsdetektering: Spel skulle inte mycket roligt om din karaktär föll igenom golvet innan du kunde hoppa, eller om du slog en fiende med din fot, föll du genast. Kollisionsdetektering med en fysikmotor möjliggör mycket exakt kontaktljud och tillåter interaktioner mellan objekt som ska simuleras med krafter.
Force simulering:Efter en kollision, vad ska hända? Spellogiken kunde ringas, du kan studsa, det andra spelobjektet kan studsa, eller du kan helt enkelt inte flytta längre. Allt hanteras bakom kulisserna, med hjälp av motorns beräknade krafter. Men styrkor är inte begränsade till kontakt; Andra krafter, såsom tyngdkraft och impulser, kan förekomma, utan föremål som faktiskt rör sig. Kraftar påverkar åtgärder i spelet och rörelse av objekt, tecken och till och med världens rymd.
Vi ska titta på på vilket sätt fysikmotorer fungerar inom kort, men först kan vi titta på Vad motorer du kanske vill använda, och Varför du kan bestämma att använda dem, baserat på dina specifika behov.
När du först börjar tänka på att använda fysik i ditt spel måste du bestämma hur du vill närma sig problemet och vad ditt spel kommer att kräva när det gäller simulering. Du har två alternativ för att använda fysik:
Flera utmärkta alternativ finns för fördefinierade och färdiga fysikmotorer. Ett av de mest populära valen för 2D-spel är Box2D; Det är en inbyggd C ++-skrivmaskin, men har wrappers, portar och tillägg som gör att den kan användas i nästan vilken 2D-plattform som helst. Ett annat populärt val är Chipmunk 2D, som används i flera vanliga spelmotorer, som Cocos2D.
I vissa spel är det inte nödvändigtvis det optimala valet att använda en fördefinierad motor. Att använda en fysikmotor kan orsaka lite onödigt överskott när full funktion inte behövs. I fall som enkla plattformar eller brick-breaker-typ spel där du inte behöver pixel-perfekt kollisionsdetektering eller några av de andra kapaciteterna hos en motor, kan det onödigt utnyttja resurser som bättre kan spenderas annorstädes.
Att bygga din egen motor kan ge dig större flexibilitet än slutprodukten, men det kan också göra saker mer komplicerade om du har att göra med mer än några få exempel på tecken och objekt.
Innan vi diskuterar egenskaperna och detaljerna i en fysiksimulering, låt oss se hur det kallas inom ramen för din spelscen.
Den typiska spelslingan går igenom följande för varje ram, i ordning:
Det innebär att beräkning av den resulterande fysiken är den sista uppgiften som utförts i slingan innan skärmen uppdateras. Det här är vettigt, eftersom simuleringspunkten är att reagera på vad som hänt inom spelets världsutrymme.
Observera att bilden visar att fysiken simuleras under varje ram i din spelslinga. Detta kan leda till några stora kostnader om din simulering blir alltför stor eller komplicerad. Av den anledningen är det bäst att hålla spelhanteringen och samtal till simuleringen och dess lyssnare begränsad.
Det är vettigt att nu diskutera två olika metoder för att stämma fysiksimuleringen: fasta vs ramberoende räntor. Överväga (Void) ändring:
Metoden är konsekvent inom de flesta spelloops. Denna slinga kallas en gång per ram av spelplatsen. Om din "simulera fysik" -metod heter från (Void) ändring:
, din spelvärld fysik kommer att bero på din ramhastighet, och detta kan leda till några häftiga och orealistiska simuleringar. IOS minskar denna effekt genom att använda usesPreciseCollisionDetection
Boolean egenskap, men vad sägs om i andra motorer?
Tänk på följande kodsegment:
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval; self.lastUpdateTimeInterval = currentTime; om (timeSinceLast> 1) timeSinceLast = 1.0 / 60.0;
Denna kod är utformad för att kompensera för problem med deltavärdet för tiden. Tänk på en situation där du spelade spelet på din telefon och ringde: det skulle hjälpa ditt spel att återställa ditt delta tillbaka till det förväntade 1/60 (för ett 60 fps-spel).
Detta är faktiskt det första steget i en diskussion om avkoppling av fysiksimuleringen från tidssteget av (Void) ändring:
metod. Medan ett modifierat tidsintervall säkert skulle hjälpa till i ett mer stabilt fysik simuleringssamtal, stämmer det inte för alla situationer. För att göra det, skulle vi faktiskt behöva ta bort fysik simuleringssamtalet från spelet rendering loop och skapa en fast cykel inom vilken den kan springa. Till exempel; Om ditt spel är tänkt att springa vid 60 bilder / sek, ställer du in fysiken för att simulera 60 gånger per sekund. Den här avkroppen tar bort eventuella problem med återgivningsproblem som orsakar choppy feedback i din fysik simulering.
Kort sagt, vara samvetsgranna i din implementering av fysiken. Om du befinner dig själv med en motor i en miljö där du beskattar systemresurser, överväga ett fast fysiksimulerings simulering för att upprätthålla rättvisa och trovärdighet.
en sprite är en bild som gjorts på skärmen i ditt spel. En sprite har inga egenskaper som standard inom en fysiksimulering. Du kan "förfalska" några av beteenden i en fysisk värld genom att använda egenskaper av en sprite som en avgränsningslåda och ett skärningssamtal, men då måste du själv skriva all den logiska logiken. Skulle det inte vara bättre om spelet kunde hantera allt detta för oss?
I dessa utdrag skapar vi en sprite:
SKSpriteNode * sprite = [SKSpriteNode spriteNodeWithImageNamed: @ "image"]; sprite.position = plats; [self addChild: sprite];
... och kalla en kollision mellan två sprites:
-(void) update: (CFTimeInterval) currentTime / * Kallas innan varje bild görs * / if (CGRectIntersectsRect (sprite1.frame, sprite2.frame)) // gör något
Fysik kroppar är "enkla" former som definierar grov storlek och form av din sprite, eller kanske definiera ett aktivt område i din sprite. Tänk på följande:
En fysik kropp är inte fördefinierad av bilden av din sprite, och är vanligtvis osynlig inom spelet. Du skapar formen dynamiskt, ofta genom att ringa en metod för att antingen dra den form som kommer att kompensera kroppen eller genom att använda ett program som hjälper dig att rita ut och definiera kroppen. Du bifogar sedan kroppen till sprite och får tillgång till de simulerade effekterna och egenskaperna som tilldelats den kroppen.
Du kan ha flera fysikorgan bundna till en enda sprite. Ta som ett exempel en sprit av en hjälte som bär ett svärd. Det vore bra att skapa en kropp för hjältekaraktären, och en annan för svärdet han bär. Det här låter dig skapa spellogik baserat på kollisioner mellan olika kroppar.
I pseudokod skulle logiken se ut så här:
// fysik logik - (void) physicsCollisionDidOccur switch (kollisionsbitmask) case (Player || Sword): // gör ingenting; ha sönder; fall (Player || Enemy): // ouch !!; ha sönder; fall (Sword || Enemy): // gör skada !!; ha sönder; standard: // gör ingenting; ha sönder;
Tänk på situationen för ett rymdspel där du har ett hjältefartyg och ett fiendefartyg:
Du skulle sannolikt vilja göra spelarens fysik kropp lite mindre än basen sprite bilden av två anledningar:
Förbättrad visuell kollision: När en spelare kolliderar med ett objekt i ditt spel, genom att skapa denna mindre fysik kropp, överlappar spritbilderna tillfälligt vid kontaktpunkten, vilket ser bra ut visuellt. (Vid sidan av denna punkt: behåll spelarens karaktär på framsidan av scenhierarkin när du ritar z-värden.)
Användarens upplevda rättvisa: För att försöka få ditt spel att känna sig "rättvist" för spelaren, behåll den kolliderbara kroppen begränsad till huvuddelen av objektet och bort från yttre utskjutningar som bakfinen på bilden ovan. På så sätt kommer det inte att finnas några "billiga träffar" för att irritera spelarna i ditt spel. Omvänt vill du vanligtvis att fiendens fysik kropp är minst storleken på basbilden; om vi ger vår rymdhjälte en laser för att skjuta sin fiende, gör en alltför stor fiendens kropp det mer rimligt för vår spelare att få en träff. Tänk också på samma sätt för plattor i en plattformsspelare eller ett pusselspel som kräver att din spelare hoppa från plattform till plattform. Spelare är vana vid lite "nåd" i dessa typer av spel; förlänger fysikkroppen en tad hjälper till att hålla ditt spel rimligt "rättvist".
Det finns två huvudtyper av fysikorgan:
En kantbaserad kropp är en statisk, ojämn linje som skapar en gräns för andra kroppar att kollidera med. Den har en negativt utrymme inom det som inte har någon effekt på några kroppar. En bra tillämpning av detta skulle vara att skapa en gräns runt din skärm för att innehålla några kroppar inom.
En volymbaserad kropp har volym och massa, och kan vara antingen dynamisk eller statisk. Eftersom dessa kroppar har massa, studsar objekt av dem och de kan påverkas av kraftkontakter. Volymbaserade kroppar kan vara av fyra huvudformer:
Det finns några begränsningar för att använda kroppar inom din typiska 2D-fysikmotor. Här är de två huvudbegränsningarna:
Om en form är konvex, det betyder att ingen inre vinkel är mindre än 180 grader.
För att vara tydlig kan det vara möjligt att köra fysiksimuleringar i konkava former, men bearbetningskostnaden är så hög att den inte helt enkelt är realistisk för 2D, speciellt när den körs på en handhållen eller mindre kraftfull enhet. Konkav-tycka om former kan konstrueras genom att länka samman två konvexa former med något som heter a Statisk gemensam. Ledningar är en annan bra funktion med 2D-motorer, men ligger utanför ramen för denna diskussion.
När en boll träffar en vägg, kommer i den "riktiga" världen något sådant att ske:
Din karaktär sprite kan genomgå denna typ av omvandling, men dess fysik kropp kan inte. Du kan kontrollera vissa egenskaper hos kroppen för att påverka dess "bounciness", men det kan inte egentligen ha en mutabel form. Detta är känt som a Styv kropp, vilket innebär att kroppen inte kan deformeras eller kläms.
Låt oss ta en snabb titt på vad några av de mest användbara egenskaperna som finns på en typisk fysik kropp är:
De flesta motorer har fler egenskaper tillgängliga än detta, men i den här diskussionen är dessa tillräckliga för att komma igång.
I en simulerad fysikvärld flyttas kroppar genom tillämpningen av krafter och impulser.
krafter: Allmänna krafter påverkar vanligen kroppar mer gradvis än impulser De är en konstant kraft som appliceras över en tidsenhet (som gravitation eller en motor).
Impulser (impulskrafter): Impulser är omedelbart tillämpade justeringar av kroppens momentum. Impulser appliceras vanligtvis på en simulering baserad på användarinmatning.
Nu när du förstår teorin är det bästa sättet att cementera din förståelse för projektilfysikmotorer att bygga en själv. Därefter bryter jag ner koden för ett enkelt fysikbaserat spel som jag har skrivit, så att du kan se exakt hur det fungerar!