Grunnleggende 2D Platformer Fysikk, Del 5 Objekt vs Objekt Kollisjonsdeteksjon

I denne delen av serien begynner vi å gjøre det mulig for objekter å ikke bare samhandle fysisk med tilkilden alene, men også med noe annet objekt ved å implementere en kollisjonsdeteksjonsmekanisme mellom spillobjektene.

Demo

Demoen viser sluttresultatet av denne opplæringen. Bruk WASD til å flytte tegnet. Den midtre museknappen gir en enveisplattform, den høyre museknappen gir en solid flis, og mellomromstasten gir en tegnklon. Skyvekontrollene endrer størrelsen på spillerens karakter. Objektene som oppdager en kollisjon, blir gjort halvtransparent. 

Demoen har blitt publisert under Unity 5.4.0f3, og kildekoden er også kompatibel med denne versjonen av Unity.

Kollisjonsdeteksjon

Før vi snakker om noen form for kollisionsrespons, for eksempel å gjøre det umulig for objektene å gå gjennom hverandre, må vi først vite om disse bestemte objektene overlapper. 

Dette kan være en svært kostbar operasjon hvis vi bare sjekket hvert objekt mot hvert annet objekt i spillet, avhengig av hvor mange aktive objekter spillet trenger å håndtere. For å lindre spillernes stakkars prosessor litt, bruker vi ...

Romlig partisjonering!

Dette er i utgangspunktet splittelse av spillets plass i mindre områder, noe som gjør at vi kan kontrollere sammenstøtene mellom objekter som tilhører kun det samme området. Denne optimaliseringen er svært nødvendig i spill som Terraria, hvor verden og antall mulige kolliderende objekter er store og gjenstandene er sparsomt plassert. I enkeltskjermspill hvor antall objekter er sterkt begrenset av størrelsen på skjermen, er det ofte ikke nødvendig, men fortsatt nyttig.

Metoden

Den mest populære romlige partisjoneringsmetoden for 2D-plass er quad-tre; Du finner beskrivelsen i denne opplæringen. For mine spill bruker jeg en flat struktur, som i utgangspunktet betyr at spillplassen er delt i rektangler av en viss størrelse, og jeg ser etter kollisjoner med gjenstander som ligger i samme rektangulære rom.

Det er en nyanse til dette: Et objekt kan være mer enn ett underrom ad gangen. Det er helt fint - det betyr bare at vi må oppdage gjenstander som tilhører noen av partisjonene som vårt tidligere objekt overlapper med.

Data for partisjonering

Basen er enkel. Vi trenger å vite hvor stor hver celle skal være, og et todimensjonalt array, hvorav hvert element er en liste over objekter som er bosatt i et bestemt område. Vi må plassere disse dataene i kartklassen.

offentlig int mGridAreaWidth = 16; offentlig int mGridAreaHeight = 16; offentlig liste[,] mObjectsInArea;

I vårt tilfelle bestemte jeg meg for å uttrykke størrelsen på partisjonen i fliser, og så er hver partisjon 16 med 16 fliser stor. 

For våre objekter vil vi ha en liste over områder som objektet for øyeblikket overlapper med, så vel som indeksen i hver partisjon. La oss legge til disse i MovingObject klasse.

offentlig liste mAreas = ny liste(); offentlig liste mIdsInAreas = ny liste();

I stedet for to lister kan vi bruke en enkelt ordliste, men dessverre går ytelsen til å bruke komplekse containere i den nåværende iterasjonen av enhet, mye å være ønsket, så vi holder fast med lister for demoen.

Initialiser partisjoner

La oss fortsette å beregne hvor mange partisjoner vi trenger for å dekke hele området på kartet. Forutsetningen her er at ingen gjenstand kan flyte utenfor kartgrensene. 

mHorizontalAreasCount = Mathf.CeilToInt ((float) mWidth / (float) mGridAreaWidth); mVerticalAreasCount = Mathf.CeilToInt ((float) mHeight / (float) mGridAreaHeight);

Selvfølgelig, avhengig av kartstørrelsen, må partisjonene ikke nøyaktig matche kartgrensene. Derfor bruker vi et tak på beregnet verdi for å sikre at vi har minst nok til å dekke hele kartet.

La oss starte partisjonene nå.

mObjectsInArea = ny liste[mHorizontalAreasCount, mVerticalAreasCount]; for (var y = 0; y < mVerticalAreasCount; ++y)  for (var x = 0; x < mHorizontalAreasCount; ++x) mObjectsInArea[x, y] = new List(); 

Ikke noe fancy skjer her - vi sørger bare for at hver celle har en liste over objekter som er klare for at vi skal operere på.

Tilordne Objektpartisjoner

Nå er det på tide å lage en funksjon som vil oppdatere områdene en bestemt gjenstand overlapper.

offentlig ugyldig UpdateAreas (MovingObject obj) 

Først av, må vi vite hvilke kartfliser objektet overlapper med. Siden vi bare bruker AABB, er alt vi trenger å sjekke hvilken flis hvert hjørne av AABB lander på.

var topLeft = GetMapTileAtPoint (obj.mAABB.center + ny Vector2 (-obj.mAABB.HalfSize.x, obj.mAABB.HalfSizeY)); var topRight = GetMapTileAtPoint (obj.mAABB.center + obj.mAABB.HalfSize); var bottomLeft = GetMapTileAtPoint (obj.mAABB.center - obj.mAABB.HalfSize); var bottomRight = ny Vector2i ();

Nå for å få koordinaten i partisjonert rom, er alt vi trenger å gjøre, å dele flisposisjonen med partisjonens størrelse. Vi trenger ikke å beregne nederste høyre hjørne partisjon akkurat nå, fordi x-koordinatet vil være lik topp høyre hjørne, og y-koordinatet vil være lik nederst til venstre.

topLeft.x / = mGridAreaWidth; topLeft.y / = mGridAreaHeight; topRight.x / = mGridAreaWidth; topRight.y / = mGridAreaHeight; bottomLeft.x / = mGridAreaWidth; bottomLeft.y / = mGridAreaHeight; bottomRight.x = topRight.x; bottomRight.y = bottomLeft.y;

Alt dette skal fungere basert på antagelsen om at ingen gjenstand skal flyttes utenfor kartgrensene. Ellers må vi ha en ekstra sjekk her for å ignorere objekter som ikke er begrenset. 

Nå er det mulig at objektet ligger helt i en enkelt partisjon, det kan ligge i to, eller det kan oppta plasset der fire partisjoner møtes. Dette er under antagelsen om at ingen gjenstand er større enn partisjonsstørrelsen, i så fall kan den okkupert hele kartet og alle partisjonene dersom det var stort nok! Jeg har operert under denne antagelsen, så det er hvordan vi skal håndtere dette i opplæringen. Modifikasjonene for å tillate større objekter er ganske trivielle, skjønt, så jeg skal forklare dem også.

La oss begynne med å sjekke hvilke områder karakteren overlapper med. Hvis alle hjørnens partisjonskoordinater er de samme, opptar objektet bare et enkelt område.

hvis (topLeft.x == topRight.x && topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft); 

Hvis ikke, og koordinatene er de samme på x-aksen, overlapper objektet seg med to forskjellige partisjoner vertikalt.

hvis (topLeft.x == topRight.x && topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft);  annet hvis (topLeft.x == topRight.x) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (bottomLeft); 

Hvis vi støttet objekter som er større enn partisjoner, ville det være nok hvis vi bare lagde alle partisjoner fra øverste venstre hjørne til bunnen til venstre med en loop.

Den samme logikken gjelder hvis bare de vertikale koordinatene er de samme.

hvis (topLeft.x == topRight.x && topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft);  annet hvis (topLeft.x == topRight.x) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (bottomLeft);  annet hvis (topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (topRight); 

Til slutt, hvis alle koordinatene er forskjellige, må vi legge til alle fire områdene.

hvis (topLeft.x == topRight.x && topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft);  annet hvis (topLeft.x == topRight.x) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (bottomLeft);  annet hvis (topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (topRight);  ellers mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (bottomLeft); mOverlappingAreas.Add (topRight); mOverlappingAreas.Add (bottomRight); 

Før vi går videre med denne funksjonen, må vi kunne legge til og fjerne objektet fra en bestemt partisjon. La oss lage disse funksjonene, begynner med å legge til.

offentlig tomrom AddObjectToArea (Vector2i areaIndex, MovingObject obj) var area = mObjectsInArea [areaIndex.x, areaIndex.y]; // lagre indeksen for objektet i området obj.mAreas.Add (areaIndex); obj.mIdsInAreas.Add (area.Count); // legge objektet til områdeområdet. Legg til (obj); 

Som du kan se, er prosedyren veldig enkel - vi legger til indeksen til området til objektets overlappende områdesliste, vi legger til den tilsvarende indeksen til objektets ids-liste, og til slutt legger objektet til partisjonen.

La oss nå lage fjerningsfunksjonen.

offentlig ugyldig RemoveObjectFromArea (Vector2i areaIndex, int objIndexInArea, MovingObject obj) 

Som du kan se, bruker vi koordinatene til området som tegnet ikke lenger overlapper med, indeksen i objektlisten i det området og referansen til objektet vi må fjerne.

For å fjerne objektet, bytter vi det med det siste objektet i listen. Dette vil kreve at vi også sørger for at objektets indeks for dette området blir oppdatert til det vi fjernet objektet hadde. Hvis vi ikke bytte objektet, må vi oppdatere indeksene for alle objektene som går etter det vi må fjerne. I stedet må vi bare oppdatere den vi byttet med. 

Å ha en ordbok her vil spare mye problemer, men å fjerne objektet fra et område er en operasjon som trengs langt mindre enn iterating gjennom ordboken, som må gjøres hver ramme for hvert objekt når vi oppdaterer objektets overlapping områder.

// bytte det siste elementet med det vi fjerner var tmp = område [area.Count - 1]; område [area.Count - 1] = obj; område [objIndexInArea] = tmp;

Nå må vi finne området vi er opptatt av i områdets liste over det bytteobjektet, og endre indeksen i ids-listen til indeksen for det fjernede objektet.

var tmpIds = tmp.mIdsInAreas; var tmpAreas = tmp.mAreas; for (int i = 0; i < tmpAreas.Count; ++i)  if (tmpAreas[i] == areaIndex)  tmpIds[i] = objIndexInArea; break;  

Til slutt kan vi fjerne det siste objektet fra partisjonen, som nå er en referanse til objektet vi trengte å fjerne.

area.RemoveAt (area.Count - 1);

Hele funksjonen skal se slik ut:

offentlig ugyldig RemoveObjectFromArea (Vector2i areaIndex, int objIndexInArea, MovingObject obj) var area = mObjectsInArea [areaIndex.x, areaIndex.y]; // bytte det siste elementet med det vi fjerner var tmp = område [area.Count - 1]; område [area.Count - 1] = obj; område [objIndexInArea] = tmp; var tmpIds = tmp.mIdsInAreas; var tmpAreas = tmp.mAreas; for (int i = 0; i < tmpAreas.Count; ++i)  if (tmpAreas[i] == areaIndex)  tmpIds[i] = objIndexInArea; break;   //remove the last item area.RemoveAt(area.Count - 1); 

La oss flytte tilbake til UpdateAreas-funksjonen.

Vi vet hvilke områder karakteren overlapper denne rammen, men siste ramme kunne objektet allerede blitt tildelt til samme eller forskjellige områder. La oss først løpe gjennom de gamle områdene, og hvis objektet ikke lenger overlapper dem, så la vi fjerne objektet fra disse.

var områder = obj.mAreas; var ids = obj.mIdsInAreas; for (int i = 0; i < areas.Count; ++i)  if (!mOverlappingAreas.Contains(areas[i]))  RemoveObjectFromArea(areas[i], ids[i], obj); //object no longer has an index in the area areas.RemoveAt(i); ids.RemoveAt(i); --i;  

La oss nå løpe gjennom de nye områdene, og hvis objektet ikke tidligere er tildelt dem, la oss legge dem til nå.

for (var i = 0; i < mOverlappingAreas.Count; ++i)  var area = mOverlappingAreas[i]; if (!areas.Contains(area)) AddObjectToArea(area, obj); 

Til slutt fjerner du listen over overlappende områder slik at den er klar til å behandle neste objekt.

mOverlappingAreas.Clear ();

Det er det! Den endelige funksjonen skal se slik ut:

offentlig ugyldig UpdateAreas (MovingObject obj) // få områdene på aabbs hjørner var topLeft = GetMapTileAtPoint (obj.mAABB.center + ny Vector2 (-obj.mAABB.HalfSize.x, obj.mAABB.HalfSizeY)); var topRight = GetMapTileAtPoint (obj.mAABB.center + obj.mAABB.HalfSize); var bottomLeft = GetMapTileAtPoint (obj.mAABB.center - obj.mAABB.HalfSize); var bottomRight = ny Vector2i (); topLeft.x / = mGridAreaWidth; topLeft.y / = mGridAreaHeight; topRight.x / = mGridAreaWidth; topRight.y / = mGridAreaHeight; bottomLeft.x / = mGridAreaWidth; bottomLeft.y / = mGridAreaHeight; bottomRight.x = topRight.x; bottomRight.y = bottomLeft.y; // se hvor mange forskjellige områder vi har om (topLeft.x == topRight.x && topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft);  annet hvis (topLeft.x == topRight.x) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (bottomLeft);  annet hvis (topLeft.y == bottomLeft.y) mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (topRight);  ellers mOverlappingAreas.Add (topLeft); mOverlappingAreas.Add (bottomLeft); mOverlappingAreas.Add (topRight); mOverlappingAreas.Add (bottomRight);  var områder = obj.mAreas; var ids = obj.mIdsInAreas; for (int i = 0; i < areas.Count; ++i)  if (!mOverlappingAreas.Contains(areas[i]))  RemoveObjectFromArea(areas[i], ids[i], obj); //object no longer has an index in the area areas.RemoveAt(i); ids.RemoveAt(i); --i;   for (var i = 0; i < mOverlappingAreas.Count; ++i)  var area = mOverlappingAreas[i]; if (!areas.Contains(area)) AddObjectToArea(area, obj);  mOverlappingAreas.Clear(); 

Oppdag kollisjon mellom objekter

Først av alt må vi sørge for å ringe UpdateAreas på alle spillobjektene. Vi kan gjøre det i hovedoppdateringssløyfen, etter hvert enkelt gjenstands oppdateringsanrop.

void FixedUpdate () for (int i = 0; i < mObjects.Count; ++i)  switch (mObjects[i].mType)  case ObjectType.Player: case ObjectType.NPC: ((Character)mObjects[i]).CustomUpdate(); mMap.UpdateAreas(mObjects[i]); break;   

Før vi lager en funksjon der vi kontrollerer alle kollisjoner, la oss lage en struktur som vil holde dataene for kollisjonen. 

Dette vil være svært nyttig, fordi vi vil kunne bevare dataene som det var på tidspunktet for kollisjonen, mens hvis vi bare lagret referansen til et objekt vi kolliderte med, ville vi ikke bare ha for lite til å jobbe med, men også posisjonen og andre variabler kunne ha endret seg for objektet før tiden vi faktisk får til å behandle kollisjonen i objektets oppdateringssløyfe.

offentlig struktur CollisionData offentlig CollisionData (MovingObject andre, Vector2 overlapping = standard2), Vector2 speed1 = standard2, Vector2 speed2 = standard (Vector2), Vector2 oldPos1 = standard (Vector2), Vector2 oldPos2 = default (Vector2) Vector2 pos1 = standard (Vector2), Vector2 pos2 = standard (Vector2)) this.other = other; this.overlap = overlapping; this.speed1 = speed1; this.speed2 = speed2; this.oldPos1 = oldPos1; this.oldPos2 = oldPos2; this.pos1 = pos1; this.pos2 = pos2;  offentlig MovingObject andre; offentlig Vector2 overlapping; offentlig Vector2 speed1, speed2; offentlig Vector2 oldPos1, oldPos2, pos1, pos2; 

Dataene vi lagrer er referansen til objektet vi kolliderte med, overlappingen, hastigheten til begge objektene på tidspunktet for kollisjonen, deres posisjoner og også deres posisjoner like før kollisjonstidspunktet.

La oss flytte til MovingObject klasse og opprett en beholder for de nyopprettede kollisjonsdataene som vi må oppdage.

offentlig liste mAllCollidingObjects = ny liste();

La oss nå gå tilbake til Kart klasse og opprett en CheckCollisions funksjon. Dette blir vår heavy duty-funksjon der vi oppdager sammenstøtene mellom alle spillobjektene.

offentlig ugyldig CheckCollisions () 

For å oppdage kollisjonene blir det iterating gjennom alle partisjonene.

for (int y = 0; y < mVerticalAreasCount; ++y)  for (int x = 0; x < mHorizontalAreasCount; ++x)  var objectsInArea = mObjectsInArea[x, y];  

For hver partisjon blir det iterating gjennom hvert objekt i den.

for (int y = 0; y < mVerticalAreasCount; ++y)  for (int x = 0; x < mHorizontalAreasCount; ++x)  var objectsInArea = mObjectsInArea[x, y]; for (int i = 0; i < objectsInArea.Count - 1; ++i)  var obj1 = objectsInArea[i];   

For hver gjenstand kontrollerer vi hvert annet objekt som ligger lenger ned i listen i partisjonen. På den måten kontrollerer vi bare hver eneste kollisjon.

for (int y = 0; y < mVerticalAreasCount; ++y)  for (int x = 0; x < mHorizontalAreasCount; ++x)  var objectsInArea = mObjectsInArea[x, y]; for (int i = 0; i < objectsInArea.Count - 1; ++i)  var obj1 = objectsInArea[i]; for (int j = i + 1; j < objectsInArea.Count; ++j)  var obj2 = objectsInArea[j];    

Nå kan vi sjekke om AABBene til objektene overlapper hverandre.

Vector2 overlapper; for (int y = 0; y < mVerticalAreasCount; ++y)  for (int x = 0; x < mHorizontalAreasCount; ++x)  var objectsInArea = mObjectsInArea[x, y]; for (int i = 0; i < objectsInArea.Count - 1; ++i)  var obj1 = objectsInArea[i]; for (int j = i + 1; j < objectsInArea.Count; ++j)  var obj2 = objectsInArea[j]; if (obj1.mAABB.OverlapsSigned(obj2.mAABB, out overlap))      

Her er hva som skjer i AABB OverlapsSigned funksjon.

offentlig bool OverlapsSigned (AABB andre, ut Vector2 overlapping) overlap = Vector2.zero; hvis (HalfSizeX == 0.0f || HalfSizeY == 0.0f || other.HalfSizeX == 0.0f || other.HalfSizeY == 0.0f || Mathf.Abs (center.x - other.center.x)> HalfSizeX + other.HalfSizeX || Mathf.Abs (center.y - other.center.y)> HalfSizeY + other.HalfSizeY) returnere false; overlap = ny Vector2 (Mathf.Sign (center.x - other.center.x) * ((other.HalfSizeX + HalfSizeX) - Mathf.Abs (center.x - other.center.x)), Mathf.Sign .y - other.center.y) * ((other.HalfSizeY + HalfSizeY) - Mathf.Abs (center.y - other.center.y))); returnere sant; 

Som du kan se, hvis en AABBs størrelse på en hvilken som helst akse er null, kan den ikke kollideres med. Den andre tingen du kan legge merke til er at selv om overlappingen er lik null, vil funksjonen returnere sann, da den vil avvise de tilfellene der gapet mellom AABBene er større enn null. Det er hovedsakelig fordi hvis objektene berører hverandre og ikke overlapper, vil vi fortsatt ha informasjonen om at dette er tilfelle, så vi trenger dette for å gå gjennom. 

Som det siste, når kollisjonen oppdages, beregner vi hvor mye AABB overlapper med den andre AABB. Overlappingen er signert, så i dette tilfellet hvis overlappende AABB er på denne AABBs høyre side, vil overlappingen på x-aksen være negativ, og hvis den andre AABB er på denne AABBs venstre side, vil overlappingen på x-aksen være positive. Dette vil gjøre det enkelt senere å komme ut av overlappende posisjon, som vi vet i hvilken retning vi vil at objektet skal bevege seg.

Flytter tilbake til vår CheckCollisions funksjon, hvis det ikke var noen overlapping, det er det, vi kan flytte til neste objekt, men hvis en overlapping oppstår, må vi legge til kollisionsdataene til begge objektene.

hvis (obj1.mAABB.OverlapsSigned (obj2.mAABB, overlapping)) obj1.mAllCollidingObjects.Add (ny CollisionData (obj2, overlapping, obj1.mSpeed, obj2.mSpeed, obj1.mOldPosition, obj2.mOldPosition, obj1.mPosition, obj1.mPosition, obj2.mPosition)); obj2.mAllCollidingObjects.Add (ny CollisionData (obj1, -overlapping, obj2.mSpeed, obj1.mSpeed, obj2.mOldPosition, obj1.mOldPosition, obj2.mPosition, obj1.mPosition)); 

For å gjøre det enkelt for oss, antar vi at 1-ene (speed1, pos1, oldPos1) i CollisionData-strukturen alltid refererer til eieren av kollisionsdataene, og de to er dataene om den andre gjenstanden. 

Den andre tingen er at overlappingen beregnes ut fra obj1s perspektiv. Obj2s overlapping må bli negert, så hvis obj1 trenger å flytte til venstre for å bevege seg ut av kollisjonen, må obj2 bevege seg rett for å bevege seg ut av samme kollisjon.

Det er fortsatt en liten ting å ta vare på - fordi vi er iterating gjennom kartens partisjoner og ett objekt kan være i flere partisjoner på det samme, opptil fire i vårt tilfelle, er det mulig at vi vil oppdage en overlapping for det samme to gjenstander opptil fire ganger. 

For å fjerne denne muligheten, kontrollerer vi bare om vi allerede har oppdaget en kollisjon mellom to objekter. Hvis det er tilfelle, hopper vi over iterasjonen.

hvis (obj1.mAABB.OverlapsSigned (obj2.mAABB, overlapping) &&! obj1.HasCollisionDataFor (obj2)) obj1.mAllCollidingObjects.Add (ny CollisionData (obj2, overlapping, obj1.mSpeed, obj2.mSpeed, obj1.mOldPosition, obj2.mOldPosition, obj1.mPosition, obj2.mPosition)); obj2.mAllCollidingObjects.Add (ny CollisionData (obj1, -overlapping, obj2.mSpeed, obj1.mSpeed, obj2.mOldPosition, obj1.mOldPosition, obj2.mPosition, obj1.mPosition)); 

De HasCollisionDataFor funksjonen er implementert som følger.

offentlig bool HasCollisionDataFor (MovingObject andre) for (int i = 0; i < mAllCollidingObjects.Count; ++i)  if (mAllCollidingObjects[i].other == other) return true;  return false; 

Det gjennomgår bare gjennom alle kollisionsdatastrukturene og ser opp om noen allerede tilhører objektet vi skal sjekke kollisjon for. 

Dette burde være fint i generell bruk, da vi ikke forventer et objekt å kollidere med mange andre objekter, så se gjennom listen vil bli rask. Men i et annet scenario kan det være bedre å erstatte listen over CollisionData med en ordbok, så i stedet for iterating kunne vi fortell med en gang om et element allerede er i eller ikke. 

Den andre tingen er at denne sjekken sparer oss fra å legge til flere kopier av samme kollisjon til samme liste, men hvis objektene ikke kolliderer, vil vi likevel sjekke overlapping flere ganger hvis begge objektene tilhører de samme partisjonene. 

Dette bør ikke være en stor bekymring, da kollisjonskontrollen er billig, og situasjonen er ikke så vanlig, men hvis det var et problem, kan løsningen være å bare ha en matrise av merkede kollisjoner eller en toveis ordbok, fyll ut det opp som kollisjonene blir sjekket, og tilbakestille det rett før vi kaller CheckCollisions funksjon.

La oss nå ringe funksjonen vi nettopp har avsluttet i hovedspillet.

void FixedUpdate () for (int i = 0; i < mObjects.Count; ++i)  switch (mObjects[i].mType)  case ObjectType.Player: case ObjectType.NPC: ((Character)mObjects[i]).CustomUpdate(); mMap.UpdateAreas(mObjects[i]); mObjects[i].mAllCollidingObjects.Clear(); break;   mMap.CheckCollisions(); 

Det er det! Nå skal alle våre objekter ha data om kollisjonene.

For å teste om alt fungerer som det skal, la oss gjøre det slik at hvis et tegn kolliderer med et objekt, vil karakterens sprite bli halvtransparent.

Som du ser, synes deteksjonen å fungere godt!

Sammendrag

Det er det for en annen del av den enkle 2D-plattformen fysikk-serien. Vi klarte å implementere en veldig enkel romlig partisjoneringsmekanisme og oppdage kollisjonene mellom hver gjenstand. 

Hvis du har et spørsmål, et tips om hvordan du gjør noe bedre, eller bare ha en mening på opplæringen, kan du gjerne bruke kommentarseksjonen til å gi meg beskjed!