I denne artikkelen vil vi undersøke bruken av fysikk for å simulere prosjektil effekter i spill som Angry Birds. Vi ser på grunnleggende om å bruke 2D fysikk i spillverdenen, for eksempel å skape kropper og bruke impulser og krefter.
Hvorfor bruke en fysikkmotor? Hva gjør det egentlig?
En fysikkmotor hjelper oss med å gjøre to svært viktige ting for spillet vårt:
Kollisjonsdeteksjon: Spill ville ikke vært så mye moro hvis karakteren din falt gjennom gulvet før du kunne hoppe, eller hvis du slår en fiende med foten din, falt du rett gjennom. Kollisjonsdeteksjon ved hjelp av en fysikkmotor tillater veldig nøyaktig kontaktlytting, og tillater samhandling mellom objekter som skal simuleres ved hjelp av krefter.
Force simulering:Etter en kollisjon, hva skal skje? Spilllogikken kan bli kalt, du kan hoppe, det andre spillobjektet kan hoppe, eller du kan bare ikke flytte lenger. Alt dette håndteres bak kulissene, ved hjelp av motorens beregnede krefter. Men styrker er ikke begrenset til kontakt; Andre krefter, som tyngdekraften og impulser, kan oppstå, uten at gjenstander faktisk rører. Forsvar påvirker handlinger i spillet og bevegelsen av objekter, tegn og til og med verdensrommet selv.
Vi ser på hvordan fysikk motorer jobber kort, men først kan vi se på hva motorer du kanskje vil bruke, og Hvorfor Du kan bestemme deg for å bruke dem, basert på dine spesielle behov.
Når du først begynner å tenke på å bruke fysikk i spillet ditt, må du bestemme hvordan du vil nærme seg problemet, og hva spillet ditt vil kreve når det gjelder simulering. Du har to muligheter for å bruke fysikk:
Flere gode alternativer finnes for forhåndsdefinerte og ferdige fysikkmotorer. Et av de mest populære valgene for 2D-spill er Box2D; Det er en innfødt C ++-skriftlig motor, men har wrappers, porter og utvidelser som gjør at den kan brukes i nesten hvilken som helst 2D-plattform. Et annet populært valg er Chipmunk 2D, som brukes i flere vanlige spillmotorer, som Cocos2D.
I noen spill er det ikke nødvendigvis det optimale valget å bruke en forhåndsdefinert motor. Ved å bruke en fysikkmotor kan det oppstå litt unødvendig overhead når det ikke er nødvendig med full funksjon. I tilfeller som enkle plattformspillere eller brick-breaker type spill hvor du ikke trenger pixel-perfekt kollisjonsdeteksjon eller noen av de andre egenskapene til en motor, kan det unødvendig bruke ressurser som kan brukes bedre andre steder.
Å bygge egen motor kan gi deg mer fleksibilitet enn sluttproduktet, men det kan også gjøre ting mer komplisert hvis du har å gjøre med mer enn noen få tilfeller av tegn og objekter.
Før vi diskuterer egenskapene og detaljene i en fysikk simulering, la oss se på hvordan det kalles i løpet av spillscenen.
Den typiske spillsløyfen løper gjennom følgende for hver ramme, i rekkefølge:
Dette betyr at beregning av den resulterende fysikken er den siste oppgaven som utføres i løkken før skjermen oppdateres. Dette gir mening fordi simuleringspunktet er å reagere på det som har skjedd innenfor spillets verdensrom.
Legg merke til at dette bildet viser at fysikk simuleres i hver ramme av spillsløyfen din. Dette kan resultere i noen store overhead hvis simuleringen din blir for stor eller komplisert. Av denne grunn er det best å holde spillstyring og samtaler til simuleringen og dets lyttere begrenset.
Det er fornuftig nå å diskutere to forskjellige metoder for avstemning av fysikk simulering: fast vs. rammeavhengige priser. Vurder (Void) oppdatering:
metode konsistent innenfor de fleste spillsløyfer. Denne løkken kalles en gang per ramme av spillscenen. Hvis din "simulere fysikk" -metode kalles fra (Void) oppdatering:
, Din spillverden fysikk kommer til å stole på rammen din, og dette kan føre til noen hakkete og urealistiske simuleringer. I IOS reduseres denne effekten ved bruk av usesPreciseCollisionDetection
Boolsk eiendom, men hva med andre motorer?
Vurder følgende kodesegment:
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval; self.lastUpdateTimeInterval = currentTime; hvis (timeSinceLast> 1) timeSinceLast = 1.0 / 60.0;
Denne koden er utformet for å kompensere for problemer med deltaverdien for tiden. Tenk på en situasjon hvor du spilte spillet på telefonen din og ringte: det ville hjelpe spillet ditt for å tilbakestille deltaet tilbake til forventet 1/60 (for et 60 fps spill).
Dette er faktisk det første trinnet i en diskusjon om avkobling av fysikkimuleringen fra tidstrinnet til (Void) oppdatering:
metode. Mens et modifisert tidsintervall sikkert vil hjelpe til i en mer stabil fysikk simulering samtale, er det ikke riktig for alle situasjoner. For å gjøre dette, ville vi faktisk måtte fjerne fysikk simuleringen anrop fra spill rendering loop, og opprette en fast syklus der den kan kjøre. For eksempel; hvis spillet ditt er ment å kjøre med 60 fps, setter du fysikken til å simulere 60 ganger per sekund. Denne avkoblingen fjerner eventuelle bekymringer for gjengivelsesproblemer som forårsaker hakkete tilbakemelding i fysikk simuleringen.
Kort sagt, vær samvittighetsfull i din implementering av fysikk. Hvis du finner deg selv ved å bruke en motor i et miljø der du beskatter systemressurser, bør du vurdere et fast fysikk simulering for å opprettholde rettferdighet og troskap.
EN sprite er et bilde gjengitt til skjermen av spillet ditt. En sprite har ingen egenskaper som standard i en fysikk simulering. Du kan "forfalske" noen av oppføringene i en fysisk verden ved å bruke egenskaper av en sprite som en avgrensingsboks og et skjæringsanrop, men da må du skrive all den logikken du selv skriver. Ville det ikke vært bedre hvis spillet kunne håndtere alt dette for oss?
I disse utdragene lager vi en sprite:
SKSpriteNode * sprite = [SKSpriteNode spriteNodeWithImageNamed: @ "image"]; sprite.position = sted; [self addChild: sprite];
... og kaller en kollisjon mellom to sprites:
-(ugyldig) oppdatering: (CFTimeInterval) currentTime / * Kalt før hver ramme gjengis * / hvis (CGRectIntersectsRect (sprite1.frame, sprite2.frame)) // gjør noe
fysikk organer er "enkle" former som definerer grov størrelse og form av sprite, eller kanskje definere et aktivt område av sprite. Vurder følgende:
En fysikk kropp er ikke forhåndsdefinert av bildet av sprite, og er vanligvis usynlig i spillet. Du lager formen dynamisk, ofte ved å kalle en metode for å enten tegne formen som vil gjøre opp i kroppen, eller ved hjelp av et program som hjelper deg å tegne og definere kroppen. Deretter legger du kroppen til sprite, og får tilgang til de simulerte effekter og egenskaper som er tildelt den kroppen.
Du kan ha flere fysikkorganer knyttet til en enkelt sprite. Ta for eksempel et sprit av en helt som bærer et sverd. Det ville være fornuftig å skape en kropp for helten karakter, og en annen for sverdet han bærer. Dette vil tillate deg å lage spilllogikk basert på kollisjoner mellom ulike organer.
I pseudokode ville logikken se slik ut:
// fysikk logikk - (void) physicsCollisionDidOccur bryter (kollisjon bitmask) case (Player || Sword): // gjør ingenting; gå i stykker; saken (Player || Enemy): // ouch !!; gå i stykker; saken (Sword || Enemy): // gjør skade !!; gå i stykker; standard: // gjør ingenting; gå i stykker;
Tenk situasjonen til et romspill hvor du har et helt-skip og et fiendtlig skip:
Du vil sannsynligvis ønske å gjøre fysikklegemet til spilleren litt mindre enn base-spritbildet av to grunner:
Forbedret visuell kollisjon: Når en spiller kolliderer med en gjenstand i spillet ditt, ved å lage denne mindre fysiske kroppen, vil spritbildene overlappe midlertidig ved kontaktpunktet, som ser bra ut visuelt. (Videre til dette punktet: når du tegner z-verdier, behold spillerens karakter foran på scenehierarkiet.)
Brukeroppfattet rettferdighet: For å forsøke å få spillet til å føle seg "rettferdig" til spilleren, må du holde den kolliderbare kroppen begrenset til hoveddelen av objektet, og vekk fra fremmede fremspring som bakfinen til bildet ovenfor. På denne måten vil det ikke være noen "billige treff" for å irritere spillerne av spillet ditt. Omvendt vil du vanligvis at fiendens fysikk skal være minst størrelsen på basisbildet; hvis vi gir vår romhelt en laser for å skyte fienden hans, gjør en litt fiendtlig fiende kropp det mer fornuftig for vår spiller å få en hit. Vurder også denne samme tilnærmingen til fliser i et plattformspill eller et puslespill som krever at spilleren din hopper fra plattform til plattform. Spillere er vant til en liten "nåde" i disse typer spill; å utvide fysikklegemet en tad vil bidra til å holde spillet rimelig "rettferdig".
Det er to hovedtyper av fysikkorganer:
En kantbasert kropp er en statisk, ugjennomtrengelig linje som skaper en grense for andre organer å kollidere med. Den har en negativ plass innenfor det som ikke har noen effekt på noen kropper. En god applikasjon av dette ville være å skape en grense rundt skjermen for å inneholde noen organer innenfor.
En volumbasert kropp har volum og masse, og kan enten være dynamisk eller statisk. Fordi disse kroppene har masse, teller objekter av dem og de kan bli påvirket av kraftkontakter. Volumbaserte organer kan være av fire hovedformer:
Det er noen begrensninger for å bruke kropper i din typiske 2D fysikkmotor. Her er de to hovedbegrensningene:
Hvis en form er konveks, det betyr at ingen innvendig vinkel er mindre enn 180 grader.
For å være klar kan det være mulig å kjøre fysiksimulasjoner på konkavformer, men prosesskostnaden er så høy at den ikke er realistisk for 2D, spesielt når den kjører på en håndholdt eller mindre kraftig enhet. konkav-som former kan bygges ved å knytte sammen to konvekse former ved å bruke noe som heter a Statisk felles. Ledd er en annen flott funksjon tilgjengelig med 2D-motorer, men er utenfor rammen av denne diskusjonen.
Når en ball treffer en vegg, vil det i den "virkelige" verden oppstå noe som dette:
Din karakter er sprite kan gjennomgå denne typen transformasjon, men dens fysikk kropp kan ikke. Du kan kontrollere visse egenskaper av kroppen for å påvirke dens "bounciness", men det kan egentlig ikke ha en mutable form. Dette kalles en Stiv kropp, noe som betyr at selve kroppen ikke kan deformeres eller knuses.
La oss få en rask titt på hva noen av de mest nyttige egenskapene som er tilgjengelige på en typisk fysikk kropp er:
De fleste motorer har flere egenskaper tilgjengelig enn dette, men i denne diskusjonen vil disse være tilstrekkelige for å komme i gang.
I en simulert fysikkverden beveges kroppene ved bruk av krefter og impulser.
Krefter: Generelle krefter påvirker vanligvis organer mer gradvis enn impulser. De er en konstant kraft som påføres over en enhetstid (som tyngdekraften eller en motor).
Impulser (impulsstyrker): Impulser er umiddelbart anvendte justeringer av kroppens momentum. Impulser brukes vanligvis på en simulering basert på brukerinngang.
Nå som du forstår teorien, er den beste måten å sementere forståelsen av prosjektil fysikk motorer, å bygge en selv. Deretter bryter jeg koden for et enkelt fysikkbasert spill som jeg har skrevet, slik at du kan se nøyaktig hvordan det fungerer!