Aceasta este cea de-a șasea tranșă a seriei noastre de tutorial Cocos2D privind clonarea Centipede pentru iOS. Asigurați-vă că ați finalizat piesele anterioare înainte de a începe.
În ultimul tutorial, v-am arătat cum să creați o serie de obiecte de rachete și să trageți un flux constant de ele. De asemenea, ați învățat despre interacțiunea cu jucătorii de bază în Cocos2D pentru a muta jucătorul.
În tutorialul de astăzi, vom explora cum să înființeze de bază coliziune în Cocos2D. Deși acest lucru nu este întotdeauna soluția optimă, este cu siguranță cel mai rapid și mai ușor de implementat.
Coliziunea cu rachete este la fel ca și coliziunea jucătorului cu mugurii. Pur și simplu verificăm limitele fiecărei rachete în joc împotriva limitelor fiecărui germinat în joc și determinăm dacă se ciocnesc. Când un vițel a fost lovit, noi îi decrementăm viața, modificăm opacitatea și îl înlăturăm dacă viața ajunge la 0.
Deschideți Missile.m, importați Sprout.h și adăugați următorul cod în partea de jos a metodei de actualizare:
CGRect missileRect = [auto getBounds]; [auto.gameLayer.sprouts enumerateObjectsUsingBlock: ^ (id id, NSUInteger idx, BOOL * oprire) Sprout * sprout = (Sprout *) obj; CGRect sproutRect = [sprout getBounds]; dacă (CGRectIntersectsRect (rachetăRect, sproutRect)) self.dirty = YES; sprout.lives--; ];
Pe masura ce fiecare racheta se actualizeaza, ea enumera toate varza in joc, verificand pentru a vedea daca rectul lor de intersectie se intersecteaza. Dacă există o coliziune, am stabilit racheta la "murdar" și diminuează viața germinei în consecință. Am scris deja codul pentru a modifica opacitatea sprouturilor pe baza vieții sale, deci, dacă executați jocul în acest moment, ar trebui să vedeți că mugurii se schimbă atunci când sunt loviți. Problema este că ei încă se află în joc. Trebuie să eliminăm mugurii cu 0 vieți.
Acest lucru se poate face în interiorul Actualizați:
în GameLayer.m. Deschideți GameLayer.m și adăugați următorul cod în partea de jos a Actualizați:
metodă:
// 1 __block Sprout * deadSprout = zero; [auto.sprouts enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * oprire) Sprout * sprout = (Sprout *) obj; dacă (sprout.lives == 0) deadSprout = sprout; * oprire = DA; ]; // 2 în cazul în care (deadSprout) [auto.spritesBatchNode removeChild: deadSprout.sprite cleanup: YES]; [auto.sprouts removeObject: deadSprout];
Acum, conduceți jocul și veți vedea că mugurii se estompează atunci când sunt loviți și în cele din urmă dispar.
Acum trebuie să adăugăm detectarea coliziunii între rachetă și omidă. Această interacțiune este ceea ce face cu adevărat aplicația dvs. un joc. Odată lovită, omida ar trebui să se împartă la segmentul de lovituri și fiecare nouă "omidă" ar trebui să călătorească în direcții separate. Segmentul care a fost lovit apoi devine transformat într-un sprout.
Începeți prin deschiderea Missile.m, importând Caterpillar.h și Segment.h și adăugați următorul cod în partea de jos a paginii Actualizați:
metodă:
__block Caterpillar * hitCaterpillar = zero; __block Segment * hitSegment = zero; // 1 [self.gameLayer.caterpillars enumerateObjectsUsingBlock: ^ (id id, NSUInteger idx, BOOL * stop) Caterpillar * caterpillar = (Caterpillar *) obj; [caterpillar.segments enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * oprire) Segment * segment = (Segment *) obj; Segmentul CGRectRect = [segment getBounds]; // 2 dacă (CGRectIntersectsRect (rachetăRect, segmentRect)) auto.dirty = DA; hitCaterpillar = [păstrează unitatea]; hitSegment = [reține segmentul]; * oprire = DA; ]; ]; // 3 dacă (hitCaterpillar && hitSegment) [self.gameLayer splitCaterpillar: hitCaterpillar atSegment: hitSegment]; [release release hit]; [lansarea hitCaterpillar];
Acum, când avem rachete care se ciocnesc cu omida, există câteva lucruri pe care trebuie să le facem. Primul este de a scrie logica pentru a împărți osoasa pe un anumit segment. Acest lucru se va face în GameLayer.m. Mai întâi, deschideți GameLayer.h și adăugați următoarele declarații de clasă înainte.
@ class Caterpillar; secțiunea @class;
Apoi, declarați următoarea metodă:
- (void) splitCaterpillar: (Caterpillar *) caterpillar atSegment: (Segment *) segment;
Înainte de a începe implementarea, trebuie să adăugăm două fișiere la proiect. Descărcați NSArray + Reverse, dezarhivează-l și trageți ambele fișiere în proiectul dvs. Este pur și simplu o categorie pe NSMutableArray care ne oferă o metodă inversă. Acum, deschideți GameLayer.m, importați Segment.h și NSArray + Reverse.h și implementați următoarea metodă:
- (void) splitCaterpillar: (Caterpillar *) caterpillar atSegment: (Segment *) segment // 1 dacă ([caterpillar.segments count] == 1) [auto.spritesBatchNode removeChild: segment.sprite cleanup: NO]; [auto.caterpillars removeObject: caterpillar]; [self createSproutAtPostion: segment.position]; întoarcere; // 2 [auto.spritesBatchNode removeChild: segment.sprite cleanup: NO]; // 3 [self createSproutAtPostion: segment.position]; // 4 NSInteger indexOfSegement = [caterpillar.segments indexOfObject: segment]; NSMutableArray * headSegments = [NSMutableArray matrice]; NSMutableArray * tailsSegments = [șir NSMutableArray]; // 5 [caterpillar.segments enumerateObjectsUsingBlock: ^ (id id, NSUInteger idx, BOOL * stop) if (idx < indexOfSegement) [headSegments addObject:obj]; else if(idx > indexOfSegement) [coziSegments addObject: obj]; ]; // 6 dacă ([tail Segments count]> 0) // 7 [tail Segments reverse]; // 8 Caterpillar * newCaterpillar = [[Caterpillar alloc] initWithGameLayer: segmente de segmente: coziSegmente de nivel: self.level] autorelease]; newCaterpillar.position = [[tailsSegments objectAtIndex: 0] poziție]; // 9 dacă (caterpillar.currentState == CSRight || caterpillar.previousState == CSRight) // A fost îndreptată spre dreapta dacă (caterpillar.currentState == CSDownLeft || caterpillar.currentState == CSDownRight) // Se îndreaptă în josul newCaterpillar .previousState = CSUpRight; altceva // Se îndreaptă spre newCaterpillar.previousState = CSDownRight; newCaterpillar.currentState = CSLeft; altceva // A fost îndreptată spre stânga dacă (caterpillar.currentState == CSDownLeft || caterpillar.currentState == CSDownRight) // Se îndreaptă în jos newCaterpillar.previousState = CSUpRight; altceva // Se îndreaptă spre newCaterpillar.previousState = CSDownRight; newCaterpillar.currentState = CSRight; [auto.caterpilluri addObject: newCaterpillar]; // 10 dacă ([numărul segmentelor segmente]> 0) caterpillar.segments = headSegments; altfel [self.caterpillars removeObject: caterpillar];
Wow, a fost o mulțime de luat. Mai ești cu mine? Există câteva metode pe care le-am folosit aici și în codul anterior, care trebuie încă implementate. Prima metodă de implementare este createSproutAtPosition:
. Adăugați următoarea declarație de metodă la interfața dvs. privată din partea de sus a GameLayer.m:
- (Void) createSproutAtPostion: poziția (CGPoint);
Acum, implementați următoarea metodă:
- (void) createSproutAtPostion: poziția (CGPoint) // 1 int x = (position.x - kGameAreaStartX) / kGridCellSize; int y = (kGameAreaStartY - kGridCellSize + kGameAreaHeight + kGridCellSize / 2 - poziția.y) / kGridCellSize; // 2 Sprout * sprout = [[Sprout alinia] initWithGameLayer: self]; sprout.position = poziție; [auto.sprouts addObject: sprout]; _locații [x] [y] = DA;
Ultima metodă pe care trebuie să o implementăm pentru a face acest lucru este de lucru initWithGameLayer: segmente: Nivel:
în clasa omidă. Această metodă va fi responsabilă pentru construirea unei noi oglinzi din segmentele care au fost transmise. Deschideți Caterpillar.h și adăugați următoarea declarație de metodă:
- (id) initWithGameLayer: (GameLayer *) segmente de strat: (NSMutableArray *) nivel de segmente: (NSInteger);
Acum, deschideți Caterpillar.m și implementați următoarea metodă:
- (id) = initWithGameLayer: (GameLayer *) segmente de strat: (NSMutableArray *) segmente nivel: (NSInteger) nivel if (auto = [super initWithGameLayer: layer]) self.segments = segmente; self.level = nivel; self.currentState = CSRight; auto.previousState = CSDownLeft; // setați poziția celorlalte segmente __block int x = 0; __block Segment * parentSegment = [auto.segmentul obiectAtIndex: 0]; parentSegment.parent = zero; [segmente de sine enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * oprire) Segment * segment = (Segment *) obj; dacă (x ++> 0) if (! [segmentul esteEqual: parentSegment]) segment.parent = părinteSegment; parentSegment = segment; ]; întoarce-te;
Această metodă este aproape identică cu cea anterioară initWithGameLayer: Nivel: Poziția:
metodă. Singura diferență este mai degrabă decât alocarea unei serii de segmente, setează matricea segmentelor la segmentele de intrare care sunt transmise.
Mergeți și conduceți jocul în acest stadiu. Ar trebui să fii capabil să omori pe deplin omida care se află în joc.
Ultimul lucru pe care avem nevoie pentru a finaliza cercul de detecție a coliziunii vieții este implementarea coliziunilor dintre omidă și player. Dacă o parte a oaselor lovește jucătorul, vrem să reducem numărul de vieți ale jucătorului. În plus, jucătorul va deveni invincibil pentru un moment scurt, astfel încât omida nu numai că se aprinde prin el.
Începeți prin a deschide GameConfig.h și adăugați următoarea opțiune:
#define kPlayerInvincibleTime 15
Acum, deschideți Caterpillar.m, introduceți Player.h și adăugați următorul cod în partea de jos a ferestrei Actualizați:
înainte de a seta poziția omisei:
player static intInvincibleCount = kPlayerInvincibleTime; static BOOL playerHit; CGRect playerRect = [auto.gameLayer.player getBounds]; // 1 [segmente de sine enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL * oprire) Segment * segment = (Segment *) obj; Segmentul CGRectRect = [segment getBounds]; dacă (CGRectIntersectsRect (segmentRect, playerRect) && playerInvincibleCount == kPlayerInvincibleTime) * stop = DA; playerHit = DA; // 2 self.gameLayer.player.lives--; [[NSNotificationCenter defaultCenter] postNotificationName: kNotificationPlayerObiectivul obiect: nil]; ]; // 3 dacă (playerHit) if (playerInvincibleCount> 0) playerInvincibleCount--; altfel playerHit = NU; playerInvincibleCount = kPlayerInvincibleTime;
Acum, conduceți jocul și lăsați-l pe omidă să vă lovească. Ar trebui să elimine una din viețile dvs. din partea de sus a ecranului.
Detectarea coliziunilor nu este niciodată o sarcină ușoară și am zgâriat doar suprafața. Dacă doriți să explorați mai profund detectarea coliziunilor, aruncați o privire la utilizarea Box2D cu Cocos2D.
În următorul tutorial al seriei, vom discuta despre jocul de lustruire. Aceasta va include condițiile câștigătoare, scorul, sunetele, jocul și scorul mare.
Codificare fericită!