cum sa faci un joc ca Fruit Ninja cu Box2D și Cocos2D – Partea 1

acesta este un post de iOS Tutorial membru al echipei Allen Tan, un dezvoltator iOS și co-fondator la White Widget. Îl puteți găsi și pe Google+ și Twitter.

în acest tutorial, veți învăța cum să faceți un joc de tăiere sprite pentru iPhone similar cu Fruit Ninja de Halfbrick Studios folosind puternicele biblioteci Cocos2D și Box2D împreună cu unele instrumente pre-făcute.

în majoritatea jocurilor de feliere, atunci când trageți o linie tăiată printr-un sprite, jocul convertește de obicei imaginea sprite în două imagini sprite pre-desenate, cu felia întotdeauna pe mijloc, indiferent de locul în care tăiați de fapt.

dar acest tutorial va demonstra o tehnică și mai rece. Fructele noastre vor putea fi tăiate de mai multe ori și vor fi împărțite dinamic pe baza liniilor de tăiere exacte!

după cum vă puteți imagina, aceasta este o tehnică avansată, deci acest tutorial este pentru dezvoltatorii avansați Cocos2D și Box2D. Dacă sunteți nou la Cocos2D sau Box2D, ar trebui să parcurgeți (cel puțin) introducerea la tutorialele Cocos2D și introducerea la tutorialele Box2D înainte de a continua cu acest tutorial.

această serie tutorial este împărțit în trei părți:

  • în această primă parte a seriei, veți pune bazele jocului și veți învăța cum să creați poligoane texturate.
  • a doua parte vă va arăta cum să tăiați & împărțiți aceste poligoane texturate.
  • a treia parte vă va arăta cum să transformați acest lucru într-un joc complet adăugând gameplay și efecte.

aș dori să mulțumesc special lui Rick Smorawski pentru că a pus bazele proiectului pe care se bazează acest tutorial. El a fost responsabil pentru portarea acestui demo de feliere bazat pe flash în Cocos2D și, de asemenea, pentru portarea CCBlade și PRKit la Cocos2D 2.0.

continuați să citiți pentru a vedea videoclipul a ceea ce veți face și pentru a începe să învățați câteva tehnici noi și interesante!

Game Demo

Iată un videoclip demo care vă arată ce veți face în această serie de tutoriale:

după cum am menționat, veți vedea că efectul de tăiere a fructelor este cu adevărat dinamic. Fructul este tăiat dinamic în funcție de locul în care feliați și, din moment ce puteți tăia obiecte de mai multe ori, puteți tăia cu adevărat lucrurile!

puteți vedea că veți implementa, de asemenea, un efect de traseu de feliere rece, unele sisteme de particule, logica jocului și sunete pentru a condimenta lucrurile.

sunt multe de acoperit – deci să începem!

Noțiuni de bază: configurarea proiectului

veți utiliza Cocos2D 2.X în acest proiect, deci mergeți mai departe și descărcați-l dacă nu îl aveți deja. Rețineți că sunteți liber să utilizați Cocos2D 1.X în loc de 2.X. Cu 1.X, puteți sări peste părțile despre conversia PRKit și CCBlade la Cocos2D 2.X, dar asigurați-vă că acordați atenție celorlalte mici modificări pe care le faceți acelor clase.

după descărcare, faceți dublu clic pe gudron pentru a-l dezarhiva, apoi instalați șabloanele cu următoarele comenzi în Terminal:

cd ~/Downloads/cocos2d-iphone-2.0-beta./install-templates.sh -f -u

porniți Xcode și creați un nou proiect cu iOS\cocos2d v2.x \ cocos2d iOS cu șablon Box2d și denumiți-l CutCutCut.

noul tău proiect ar trebui să arate cam așa:

start proiect

primele lucruri în primul rând – ar trebui să curețe șablonul un pic pentru a ajunge la un bun punct de plecare.

Deschide HelloWorldLayer.h și eliminați următoarea linie:

CCTexture2D *spriteTexture_;// weak ref

comută la HelloWorldLayer.mm și efectuați următoarele modificări

// Remove this line from the top#import "PhysicsSprite.h"// Replace the init method with this-(id) init{ if( (self=)) { // enable events self.isTouchEnabled = YES; self.isAccelerometerEnabled = YES; CGSize s = .winSize; // init physics ; ; } return self;}// Remove these two methods-(void) createMenu { //all content}-(void) addNewSpriteAtPosition:(CGPoint)p methods { //all content}// Remove this line from ccTouchesEnded;

în acest moment, ați eliminat toate referințele la PhysicsSprite din HelloWorldLayer, dar nu eliminați fișierele din proiect încă. Mai târziu, va trebui să copiați o metodă care PhysicsSprite.mm conține în altă parte, așa că lăsați-l pus pentru moment.

apăsați Command + R pentru a compila și rula proiectul dvs. și ar trebui să vedeți un ecran gol cu o margine verde în jurul acestuia:

Clean Slate

codul șablonului rămas a configurat desenul de depanare Box2D, care desenează margini în jurul corpurilor Box2D de pe ecran. Vedeți liniile verzi subțiri desenate în jurul ecranului? Acestea sunt pereții generați de metoda initPhysics implicită care a venit cu șablonul.

aruncați o privire la codul șablonului rămas pentru a vă asigura că înțelegeți ce se întâmplă până acum – inițializează o lume Box2D, configurează terenul (marginile verzi), configurează desenul de depanare etc. Acesta este un punct de plecare destul de bun „aproape gol” cu Box2D pe care îl putem construi de aici.

Kit de resurse

apoi descărcați resursele pentru acest proiect și dezarhivați fișierul.

nu adăugați totul în proiect încă; unele dintre fișiere sunt de fapt opționale. Păstrați dosarul la îndemână – pe măsură ce parcurgeți tutorialul, din când în când vă voi cere să adăugați unele dintre aceste fișiere în proiect.

Iată ce veți găsi în interior:

  • o imagine de fundal și o grămadă de artă de fructe realizate de Vicki și alte imagini diverse din folderul Imagini
  • mixul de sunet de fundal realizat folosind gomix.în folderul sunete
  • efecte sonore realizate folosind bfxr sau descărcate de la freesound în folderul sunete
  • toate sistemele de particule create cu designer de particule în folderul particule
  • un fișier PLIST generat de PhysicsEditor care conține informații vertex pentru fructe & clase bombă în folderul Misc
  • fructe & clase bombă în folderul clase
  • versiunile de prkit și Ccblade veți folosi în tutorialul din folderul clase
  • o listă de atribuire pentru resursele care se află sub licența de atribuire în diverse folder

desen poligoane texturate cu PRKit

scopul nostru este de a reduce sprite în mai multe bucăți. Un CCSprite tipic conține o textură și o cutie de încadrare indiferent de forma imaginii. Acest lucru nu este potrivit pentru jocul nostru, deoarece cunoașterea formelor reale din imagini este un pas crucial pentru crearea spritelor care pot fi tăiate, tăiate și împărțite.

trebuie să creați poligoane texturate, care:

  • creați o corespondență între un poligon / formă și o imagine (maparea texturii)
  • afișați numai părțile imaginii care se află în limitele poligonului (umplerea texturii)

nici Cocos2D, nici Box2D nu vine cu o clasă încorporată care gestionează caracteristicile personalizate pe care le doriți și, în mod normal, acest lucru ar necesita o triangulare cuplată cu codul de desen OpenGL personalizat.

sună greu, nu?

din fericire, toate calculele complicate și Codul de desen necesare pentru a realiza acest lucru au fost deja scrise de oamenii buni la cercetarea precognitivă. Au creat o completare la Biblioteca Cocos2D numită PRKit, care se ocupă de cartografierea și umplerea texturilor.

pentru a începe poligoanele texturate, descărcați PRKit, extrageți-l și trageți folderul PRKit în proiectul dvs. Asigurați-vă că” Copiați elementele în folderul grupului de destinație „este bifată și este selectată” Creați grupuri pentru orice foldere adăugate”.

rețineți că PRKit este menținut prin cercetări Precognitive, deci poate fi actualizat în timp. Pentru a evita confuzia, Kitul nostru de resurse conține și versiunea exactă a PRKit pe care am folosit-o la realizarea acestui tutorial.

proiectul dvs. ar trebui să includă acum aceste fișiere:

PRKit Yey!

compila și a alerga, și veți întâlni câteva erori:

PRKit trebuie să fie convertit

Erorile pop-up, deoarece PRKit a fost făcută pentru Cocos2D 1.X, care utilizează OpenGL ES 1.1, în timp ce utilizați Cocos2D 2.X, care utilizează OpenGL ES 2.0, și există diferențe semnificative între cele două.

pentru a remedia această problemă, deschideți PRFilledPolygon.m și să facă aceste modificări:

// Add inside the initWithPoints: andTexture: usingTriangulator: methodself.shaderProgram = programForKey:kCCShader_PositionTexture];// Replace the calculateTextureCoordinates method with this-(void) calculateTextureCoordinates { for (int j = 0; j < areaTrianglePointCount; j++) { textureCoordinates = ccpMult(areaTrianglePoints,1.0f/texture.pixelsWide*CC_CONTENT_SCALE_FACTOR()); textureCoordinates.y = 1 - textureCoordinates.y; }}// Replace the draw method with this-(void) draw{ CC_NODE_DRAW_SETUP(); ccGLBindTexture2D( self.texture.name ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); ccGLBlendFunc( blendFunc.src, blendFunc.dst); ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords ); glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, areaTrianglePoints); glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); glDrawArrays(GL_TRIANGLES, 0, areaTrianglePointCount);}

să trecem peste aceste schimbări puțin câte puțin.

în primul rând, în Cocos2D fiecare CCNode are un program de shader OpenGL ES 2.0 atașat la acesta. Pentru a desena PRFilledPolygon, trebuie să dați în judecată shader-ul încorporat „Position/Texture”, pe care îl atribuiți în metoda init.

apoi, trebuie să configurați coordonatele texturii corecte pentru fiecare punct din poligon. Pentru a face acest lucru, va trebui să facă două modificări metoda calculateTextureCoordinates:

  • scară: deoarece această clasă își face propriile calcule pe coordonatele texturii sale, nu gestionează automat afișajul retina. Pentru a remedia acest lucru, pur și simplu multiplicați textura.pixelsWide cu CC_CONTENT_SCALE_FACTOR – o valoare de multiplicare convenabilă furnizată de Cocos2D pentru conversia valorilor între echivalentele regulate și retina.
  • Flip Y: din anumite motive, PRFIlledPolygon atrage texturi cu susul în jos, astfel încât să flip pur și simplu valoarea y aici.

ultima, codul de desen este actualizat la OpenGL ES 2.0, într-un mod similar cu modul în care CCSprite desen schimbat de la Cocos2D 1.X la Cocos2D 2.X:

  • începeți prin a apela CC_NODE_DRAW_SETUP () pentru a pregăti nodul pentru desen.
  • apelurile către glDisableClientState() și glEnableClientState() sunt învechite și sunt eliminate.
  • comenzile glVertexPointer() și glTexCoordPointer() sunt ambele înlocuite de glVertexAttribPointer(), care acceptă acum poziția vârfului sau coordonata texturii ca primă opțiune.
  • setarea glTexEnvf(), care a fost responsabil pentru repetarea sprite în cazul în care poligonul a fost mai mare decât textura, este înlocuit cu apeluri către glTexParameteri().

dacă sunteți confuz de oricare dintre acestea, vă recomandăm să consultați OpenGL ES 2.0 Pentru iPhone și Cocos2D personalizat 2.X Shaders tutoriale pentru mai multe informații de fond. Dar nu trebuie să vă faceți griji prea mult, pentru că în acest moment tot ce facem este să portăm clasa pentru a lucra în Cocos2D 2.X:]

compilați și rulați și toate erorile PRKit ar trebui să dispară!

este timpul să punem PRKit în acțiune. Veți subclasa clasa PRFilledPolygon a PRKit pentru a face o clasă de bază PolygonSprite care va atrage fructele noastre.

PolygonSprite se bazează pe PRFilledPolygon prin atașarea unui corp Box2D la sprite și va conține și alte variabile și metode personalizate pentru fructele din implementarea jocului nostru.

să trecem la subiect. Apăsați Command + N și creați un fișier nou cu iOS\cocos2d v2.x \ șablon de clasă CCNode. Faceți-o o subclasă de PRFilledPolygon și denumiți-o PolygonSprite.m.

treceți la PolygonSprite.h și efectuați următoarele modificări:

// Add to top of file#import "Box2D.h"#import "PRFilledPolygon.h"#define PTM_RATIO 32// Add inside @interfaceb2Body *_body;BOOL _original;b2Vec2 _centroid;// Add after the @interface@property(nonatomic,assign)b2Body *body;@property(nonatomic,readwrite)BOOL original;@property(nonatomic,readwrite)b2Vec2 centroid;// Add before the @end-(id)initWithTexture:(CCTexture2D*)texture body:(b2Body*)body original:(BOOL)original;-(id)initWithFile:(NSString*)filename body:(b2Body*)body original:(BOOL)original;+(id)spriteWithFile:(NSString*)filename body:(b2Body*)body original:(BOOL)original;+(id)spriteWithTexture:(CCTexture2D*)texture body:(b2Body*)body original:(BOOL)original;-(id)initWithWorld:(b2World*)world;+(id)spriteWithWorld:(b2World*)world;-(b2Body*)createBodyForWorld:(b2World*)world position:(b2Vec2)position rotation:(float)rotation vertices:(b2Vec2*)vertices vertexCount:(int32)count density:(float)density friction:(float)friction restitution:(float)restitution;-(void)activateCollisions;-(void)deactivateCollisions;

codul de mai sus declară variabilele de bază și metodele de care aveți nevoie pentru a crea un Poligonsprite. Acestea sunt:

  • corp: acesta este Corpul Box2D care este atașat sprite-ului nostru. Este necesar pentru simulare fizica.
  • original: spritele Complete și feliate vor folosi aceeași clasă PolygonSprite, ca atare, diferențierea dintre cele două va fi importantă. Dacă acest lucru este da, înseamnă că este obiectul netăiat sau original pe care l-ați creat, altfel, este doar o bucată din întreg.
  • centroid: Centrul poligonului din imagine nu va fi întotdeauna același cu centrul imaginii, deci este util să stocați această valoare.
  • proprietăți: expuneți toate variabilele folosind proprietăți, astfel încât alte clase să le poată accesa liber.
  • init/spriteWith*: principalele noastre metode init urmând aceeași convenție de denumire ca Cocos2D.
  • alte metode: acestea sunt metode care creează & care se ocupă de corpul Box2D atașat și de proprietățile sale.
  • PTM_RATIO: raportul pixeli-metri. Box2D are nevoie de această valoare de conversie, deoarece se ocupă cu metri în loc de pixeli.

treceți rapid la PolygonSprite.m și redenumiți-l PolygonSprite.mm. toate clasele care amestecă Codul Objective-C (Cocos2D) și C++ (Box2D) trebuie să aibă o extensie „.mm” pentru a notifica compilatorul sintaxei mixte.

apoi, efectuați următoarele modificări la PolygonSprite.mm:

// Add inside the @implementation@synthesize body = _body;@synthesize original = _original;@synthesize centroid = _centroid;+(id)spriteWithFile:(NSString *)filename body:(b2Body *)body original:(BOOL)original{ return initWithFile:filename body:body original:original] autorelease];}+(id)spriteWithTexture:(CCTexture2D *)texture body:(b2Body *)body original:(BOOL)original{ return initWithTexture:texture body:body original:original] autorelease];}+(id)spriteWithWorld:(b2World *)world{ return initWithWorld:world] autorelease];}-(id)initWithFile:(NSString*)filename body:(b2Body*)body original:(BOOL)original{ NSAssert(filename != nil, @"Invalid filename for sprite"); CCTexture2D *texture = addImage: filename]; return ;}-(id)initWithTexture:(CCTexture2D*)texture body:(b2Body*)body original:(BOOL)original{ // gather all the vertices from our Box2D shape b2Fixture *originalFixture = body->GetFixtureList(); b2PolygonShape *shape = (b2PolygonShape*)originalFixture->GetShape(); int vertexCount = shape->GetVertexCount(); NSMutableArray *points = ; for(int i = 0; i < vertexCount; i++) { CGPoint p = ccp(shape->GetVertex(i).x * PTM_RATIO, shape->GetVertex(i).y * PTM_RATIO); ]; } if ((self = )) { _body = body; _body->SetUserData(self); _original = original; // gets the center of the polygon _centroid = self.body->GetLocalCenter(); // assign an anchor point based on the center self.anchorPoint = ccp(_centroid.x * PTM_RATIO / texture.contentSize.width, _centroid.y * PTM_RATIO / texture.contentSize.height); // more init stuff here later when you expand PolygonSprite } return self;}-(id)initWithWorld:(b2World *)world{ //nothing to do here return nil;}

Similar cu Cocos2D, toate metodele spriteWith* sunt doar omologi autorelease ai metodelor initWith*, în timp ce initWithWorld nu are încă o utilizare reală pentru această clasă, dar în schimb va fi folosit de subclasele PolygonSprite mai târziu.

cea mai mare parte a modificărilor pot fi găsite în initWithFile și initWithTexture metode. Pentru a obține fluxul de lucruri, crearea unui fruct va fi numit în această secvență:

init secvență

  • initWithWorld: acest lucru este destinat pentru subclase de PolygonSprite astfel încât să nu faci nimic, cu excepția reveni zero, și să se ocupe de ea mai târziu.
  • initWithFile: aceasta adaugă textura din fișierul nostru și trece totul la initWithTexture.
  • initWithTexture: inițializarea noastră principală. PRFilledPolygon are nevoie de o textură și toate vârfurile poligonului se umple. Deoarece pasul anterior a gestionat deja partea de textură, acest pas gestionează vârfurile colectându-le din corpul Box2D al sprite-ului. După trecerea lor la PRFilledPolygon, continuă să inițializeze variabilele pe care le-ați declarat anterior.
  • initWithPoints: tot ceea ce face acest lucru este conținut în PRKit și lucrul bun este că nu mai trebuie să atingeți PRKit acum că i-ați actualizat codul.

încă înăuntru PolygonSprite.mm, adăugați următoarele metode:

-(void)setPosition:(CGPoint)position{ ; _body->SetTransform(b2Vec2(position.x/PTM_RATIO,position.y/PTM_RATIO), _body->GetAngle());}-(b2Body*)createBodyForWorld:(b2World *)world position:(b2Vec2)position rotation:(float)rotation vertices:(b2Vec2*)vertices vertexCount:(int32)count density:(float)density friction:(float)friction restitution:(float)restitution{ b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position = position; bodyDef.angle = rotation; b2Body *body = world->CreateBody(&bodyDef); b2FixtureDef fixtureDef; fixtureDef.density = density; fixtureDef.friction = friction; fixtureDef.restitution = restitution; fixtureDef.filter.categoryBits = 0; fixtureDef.filter.maskBits = 0; b2PolygonShape shape; shape.Set(vertices, count); fixtureDef.shape = &shape; body->CreateFixture(&fixtureDef); return body;}-(void)activateCollisions{ b2Fixture *fixture = _body->GetFixtureList(); b2Filter filter = fixture->GetFilterData(); filter.categoryBits = 0x0001; filter.maskBits = 0x0001; fixture->SetFilterData(filter);}-(void)deactivateCollisions{ b2Fixture *fixture = _body->GetFixtureList(); b2Filter filter = fixture->GetFilterData(); filter.categoryBits = 0; filter.maskBits = 0; fixture->SetFilterData(filter);}

în codul de mai sus, mai întâi supraîncărcați metoda setPosition a CCNode, astfel încât atunci când actualizați poziția sprite, poziția asociată a corpului Box2D să fie actualizată.

apoi faceți o metodă de comoditate pentru crearea și definirea unui corp Box2D. Pentru a crea un corp, trebuie să definiți o definiție a corpului, un obiect al corpului, o formă și o definiție a corpului. Nu există valori reale greu sunt atribuite aici încă, deoarece această metodă va fi utilizată de subclase de PolygonSprite mai târziu.

singurul lucru de remarcat este categoriabits și maskBits. Aceste două sunt utilizate pentru filtrarea coliziunilor între obiecte, astfel încât, dacă un bit de categorie al unui obiect se potrivește cu un bit de mască al unui alt obiect și invers, va exista o coliziune între aceste două obiecte. Setați acestea la 0 Mai întâi pentru că nu doriți să se întâmple coliziuni atunci când obiectele sunt inițializate pentru prima dată.

în cele din urmă, definiți două metode care înlocuiesc pur și simplu categoryBits și maskBits, astfel încât să puteți activa și dezactiva coliziunile poligoanelor noastre.

mai este un lucru de adăugat PolygonSprite.mm:

-(CGAffineTransform) nodeToParentTransform{ b2Vec2 pos = _body->GetPosition(); float x = pos.x * PTM_RATIO; float y = pos.y * PTM_RATIO; if ( !isRelativeAnchorPoint_ ) { x += anchorPointInPoints_.x; y += anchorPointInPoints_.y; } // Make matrix float radians = _body->GetAngle(); float c = cosf(radians); float s = sinf(radians); if( ! CGPointEqualToPoint(anchorPointInPoints_, CGPointZero) ){ x += c*-anchorPointInPoints_.x+ -s*-anchorPointInPoints_.y; y += s*-anchorPointInPoints_.x+ c*-anchorPointInPoints_.y; } // Rot, Translate Matrix transform_ = CGAffineTransformMake( c, s, -s,c, x,y ); return transform_;}

Îți Amintești Când am menționat că ai nevoie de ceva de la PhysicsSprite? Ei bine, asta este. Toate acestea nu este să vă asigurați că forma noastră Box2D și sprite noastre sunt în aceeași poziție atunci când se deplasează. Este pregătit pentru noi de Cocos2D și asta îl face cu atât mai minunat.

după copierea codului de mai sus, puteți șterge acum ambele PhysicsSprite.h și PhysicsSprite.mm din proiect, deoarece le-ați eliminat complet utilitatea.

compilați și rulați și totul ar trebui să fie bine. Ați terminat cu PolygonSprite pentru moment.

planificarea fructelor noastre

înainte de a crea clase pentru fructele noastre, trebuie să fiți clari cu privire la regulile pe care imaginile și formele lor trebuie să le urmeze. Din moment ce va fi maparea texturile noastre la poligoane Box2D unice, trebuie să adere, de asemenea, la limitările poligon Box2D lui. Trebuie să țineți cont de două lucruri:

  • poligoanele trebuie să fie convexe, ceea ce înseamnă că niciun unghi interior nu este mai mare de 180.
  • poligoanele nu trebuie să depășească 8 vârfuri.

puteți rezolva această limitare dacă permiteți fiecărui corp să conțină mai multe forme. Box2D poate gestiona forme concave dacă utilizați o metodă de triangulare și faceți formele concave din mai multe triunghiuri, dar acest lucru depășește domeniul de aplicare al tutorialului.

pentru a păstra lucrurile simple, în acest tutorial veți avea un corp 1 este de 1 regulă formă.

notă: PhysicsEditor, instrumentul pe care îl vom acoperi mai târziu în acest tutorial, conține de fapt cod pentru a triangula automat poligoanele pe care le desenați într-un set de forme convexe. Cu toate acestea, așa cum am spus, încercăm să păstrăm lucrurile simple aici, așa că ne vom asigura că ne desenăm formele convexe, astfel încât să avem o singură formă pe corp.

uitați-vă la aceste două fructe:

Concave vs Convex

utilizarea bananei nu este o idee bună, deoarece este în mod natural concavă. Pepenele verde, pe de altă parte, este foarte bun, deoarece puteți defini un poligon convex care seamănă foarte mult cu forma sa.

dacă ar fi să definiți forme de poligon care urmează regulile Box2D pentru cele două fructe, ați ajunge mai mult sau mai puțin cu acestea:

contur de formă Box2D

poligonul pepene verde se potrivește perfect imaginii, în timp ce poligonul banană are un spațiu gol mare în care imaginea se curbează spre interior. Box2D va trata acel spațiu ca parte a obiectului nostru și ar putea face Banana să se simtă nefiresc atunci când se ciocnește cu alte obiecte sau când este tăiată.

acest lucru nu înseamnă că nu puteți folosi Banana, ci mai degrabă că nu este recomandat să folosiți Banana. De fapt, jocul pe care îl veți crea în acest tutorial va folosi aceeași banană.

crearea primului fruct

este timpul pentru a crea primul fruct: pepene verde (o felie de ea cel puțin).

gândindu-ne la fluxul procesului de inițializare a poligoanelor noastre, știți că initWithTexture așteaptă un corp Box2D, dar pasul înainte, initWithFile, nu oferă acest lucru.

motivul pentru aceasta este că trebuie să creați și să definiți corpul individual pe fruct, deci va trebui să fie primul pas, initWithWorld, care creează corpul și stabilește orice alte valori specifice fiecărui fruct.

pentru a crea corpul nostru Box2D, trebuie să cunoașteți mai întâi vârfurile formei poligonului pe care doriți să le creați. Există diferite moduri de a face acest lucru, dar pentru acest tutorial, veți folosi un instrument puturos numit PhysicsEditor. Acest instrument este plin de caracteristici, dar îl veți folosi doar pentru a ne ghida în obținerea coordonatelor vârfurilor poligonului nostru.

dacă nu îl aveți, descărcați PhysicsEditor, instalați-l și porniți-l. Veți obține un proiect gol cu 3 panouri / coloane.

lucrul cu PhysicsEditor este destul de simplu. În stânga, puneți toate imaginile cu care doriți să lucrați. În mijloc, definiți vizual un poligon pentru imaginea dvs. În dreapta, aveți parametrii pentru corp.

 Editor De Fizică!

apuca pepene verde.png din folderul Imagini al kitului de resurse și trageți-l în panoul din stânga. Acum ar trebui să vedeți pepene verde pe panoul central.

măriți mărirea, Găsită în partea de jos a acestui panou, la un nivel confortabil, apoi atingeți butonul Pentagon din partea superioară a acestui panou pentru a crea o formă de poligon pe 3 fețe.

Faceți clic dreapta pe poligon și alegeți „Adăugați Vertex” până când aveți 5-8 vârfuri în toate. Mutați vârfurile în jurul marginilor pepenelui verde, asigurându-vă în același timp de două lucruri:

  • poligonul pe care îl creați este Convex.
  • toți pixelii pepenei sunt în interiorul poligonului.

Notă: O altă comandă rapidă pentru a desena formele este de a utiliza PhysicsEditor ‘ s magic wand tool. Doar setați toleranța ridicată (5-8), astfel încât să ajungeți la aproximativ 5-8 puncte și să modificați punctele de acolo.

adăugați toate celelalte fructe și imaginea bombei din folderul Imagini al kitului de resurse și faceți același lucru pentru ele.

ar trebui să definiți forme pentru următoarele imagini:

  • banana.png
  • bombă.png
  • struguri.png
  • ananas.png
  • căpșuni.png
  • pepene verde.png

când ați terminat, în colțul din dreapta sus, schimbați valoarea exportatorului în „Box2D generic (PLIST)” și ar trebui să ajungeți la ceva de genul acesta:

definiți forme cu ușurință cu PhysicsEditor!

apăsați „Publish”, sau „Publish As”, Pentru a exporta fișierul PLIST care conține informațiile vertex. Salvați fișierul ca fructe.plist.

ca exemplu, fructele.plistul pe care l-ați folosit pentru acest tutorial se află în folderul Misc al kitului de resurse.

doriți doar să vă uitați la informațiile conținute în fișierul PLIST, deci nu adăugați acest fișier la proiectul dvs., ci mai degrabă, doar fructe deschise.plist folosind Xcode pentru a vizualiza conținutul său într-un mod organizat.

Faceți clic pe pictograma triunghi de lângă „corpuri” pentru a extinde această secțiune și veți vedea lista de imagini pentru care ați definit forme. Aveți nevoie pentru a detalia până la cel mai adânc nivel pentru a obține vârfuri poligon pepene verde de genul asta:

PhysicsEditor PLIST

Expand pepene verde/corpuri/articol 0/poligoane și ar trebui să vedeți acum un alt element 0 de tip matrice sub poligoane. Această ultimă matrice este forma ta. Dacă ați definit corect o formă convexă cu 8 sau mai puține vârfuri, ar trebui să vedeți o singură matrice sub poligoane.

dacă vedeți mai mult de unul, eu.e element 0 matrice, element 1 matrice, etc, atunci înseamnă PhysicsEditor a făcut o formă complexă, deoarece fie definit prea multe noduri, sau ați format un poligon concav. Dacă se întâmplă acest lucru, reveniți la Fizicăditor și fixați-vă forma.

apoi, extindeți elementul 0 de matrice de tip pentru a vedea lista finală de elemente. Acestea sunt vârfurile dvs., iar valoarea pe care o vedeți în partea dreaptă cu acest format { Număr, Număr } sunt coordonatele x & y pentru fiecare vârf.

acum că aveți valorile exacte pentru vârfurile poligonului dvs., puteți continua cu crearea clasei pepene verde.

în Xcode, creați un fișier nou cu iOS\cocos2d v2.x \ șablon de clasă CCNode. Faceți-o o subclasă de Poligoniprit și numiți-l pepene verde. Deschide Pepene Verde.h și efectuați următoarele modificări:

// Add to top of file#import "PolygonSprite.h"

treceți la pepene verde.m, redenumiți-l la Watermelon.mm, și adăugați următoarea metodă de inițializare:

// Add inside the @implementation-(id)initWithWorld:(b2World *)world{ int32 count = 7; NSString *file = @"watermelon.png"; b2Vec2 vertices = { b2Vec2(5.0/PTM_RATIO,15.0/PTM_RATIO), b2Vec2(18.0/PTM_RATIO,7.0/PTM_RATIO), b2Vec2(32.0/PTM_RATIO,5.0/PTM_RATIO), b2Vec2(48.0/PTM_RATIO,7.0/PTM_RATIO), b2Vec2(60.0/PTM_RATIO,14.0/PTM_RATIO), b2Vec2(34.0/PTM_RATIO,59.0/PTM_RATIO), b2Vec2(28.0/PTM_RATIO,59.0/PTM_RATIO) }; CGSize screen = winSize]; b2Body *body = ; if ((self = )) { // We will initialize more values for the fruit here later } return self;}

în codul de mai sus, definiți mai întâi câte noduri există, care în acest caz este 7. Apoi, creați o serie de vârfuri care conțin toate coordonatele pe care tocmai le-ați văzut în PLIST. Utilizați aceste informații pentru a crea un corp folosind metoda de confort pe care ați definit-o în PolygonSprite.

pui puțină fricțiune pentru ca formele să nu alunece la nesfârșit și, de asemenea, pui puțină restituire pentru ca formele să nu se oprească atunci când se lovesc una de cealaltă.

în cele din urmă, creați obiectul apelând inițializarea superclasei și treceți numele fișierului imagine, corpul Box2D și declarați că acesta este un fruct original.

aveți nevoie de imaginile pepene verde din kitul de resurse, deci acum ar fi un moment bun pentru a adăuga doar toate resursele grafice de care aveți nevoie pentru restul tutorialului.

în panoul Project Navigator, faceți clic dreapta pe resurse și selectați „Adăugați fișiere la CutCutCut”. Adăugați folderul Imagini din kitul de resurse la proiect. Asigurați-vă că” Copiați elementele în folderul grupului de destinație „este bifată și este selectată” Creați grupuri pentru orice foldere adăugate”.

urmați aceiași pași pentru a crea banane, struguri, ananas, căpșuni și bombe.

ați abordat doar cum să creați primul fruct pas cu pas, deoarece este practic un proces de clătire & repetare pentru fiecare fruct. Kitul de resurse conține clase de fructe și bombe gata făcute în folderul clase pentru a vă uita în cazul în care mai aveți nevoie de îndrumare sau le puteți adăuga pe toate la proiectul dvs. dacă doriți să omiteți acest pas.

compilați și rulați și asigurați-vă că totul este bine.

adăugarea unui fruct la scena

până în prezent, nimic nu sa întâmplat pe ecran încă, și vă sunt în mod evident mâncărime pentru a vedea roadele muncii tale – joc de cuvinte destinate! :]

treceți la HelloWorldLayer.h și efectuați următoarele modificări:

// Add to top of file#import "PolygonSprite.h"// Add inside the @interfaceCCArray *_cache;// Add after the @interface@property(nonatomic,retain)CCArray *cache;

comută înapoi la HelloWorldLayer.mm și să facă aceste schimbări:

// Add to top of file#import "Watermelon.h"// Add inside the @implementation@synthesize cache = _cache;// Add inside the init method, below ;// Add inside the dealloc method, before calling ;_cache = nil;// Add anywhere inside the @implementation and before the @end-(void)initSprites{ _cache = initWithCapacity:53]; // Just create one sprite for now. This whole method will be replaced later. PolygonSprite *sprite = initWithWorld:world]; ; ; ;}

declarați o matrice cache, care va deține toate fructele și bombele pe care le creați în viitor. Apoi, creați 1 pepene verde și adăugați-l la scenă. Apelezi activatastfel încât pepene verde să nu treacă prin pereți.

compilați și rulați și ar trebui să vedeți un pepene verde căzând din zona centrală a ecranului și aterizați în partea de jos, așa cum se arată mai jos.

fructul muncii tale

s-ar putea să observi că pepenele nu este exact în centru. Motivul pentru aceasta este că ați poziționat obiectul pe baza corpului său Box2D, iar originea corpului nostru Box2D se află în colțul din stânga jos al obiectului. Conturul subțire din jurul pepenelui verde este vizibil, deoarece modul de desenare a depanării este încă activat.

Unde Să Mergem De Aici?

aici este un proiect eșantion cu tot codul din tutorialul de mai sus.

asta este pentru partea 1 a seriei. Până în prezent, aveți un poligon texturat pepene verde care cade doar în partea de jos a ecranului.

dar în loc să desenați un sprite dreptunghiular cu spațiu transparent, așa cum vedeți de obicei în tutorialele Box2D, acesta folosește PRKit pentru a desena doar părțile texturii care corespund vârfurilor corpului Box2D. Acest lucru va veni la îndemână în curând!

acum sunteți gata pentru partea 2 a tutorialului, unde adăugați capacitatea de a tăia fructele!

între timp, dacă aveți întrebări sau comentarii despre această parte, vă rugăm să vă alăturați discuției de pe forum de mai jos!


acesta este un post de iOS Tutorial membru al echipei Allen Tan, un dezvoltator iOS și co-fondator la White Widget. Îl puteți găsi și pe Google+ și Twitter.

raywenderlich.com săptămânal

raywenderlich.com buletinul informativ este cel mai simplu mod de a fi la curent cu tot ceea ce trebuie să știți ca dezvoltator mobil.

obțineți un rezumat săptămânal al tutorialelor și cursurilor noastre și primiți un curs gratuit de e-mail aprofundat ca bonus!

Leave a Reply

Adresa ta de email nu va fi publicată.