Come Fare Un Gioco Come Fruit Ninja Con Box2D e Cocos2D – Parte 1

Questo è un post di iOS Tutorial Membro del Team di Allen Tan, uno sviluppatore di iOS e co-fondatore di White Widget. Lo si può anche trovare su Google + e Twitter.

In questo tutorial, imparerai come creare un gioco di taglio sprite per iPhone simile a Fruit Ninja di Halfbrick Studios utilizzando le potenti librerie Cocos2D e Box2D insieme ad alcuni strumenti pre-fatti.

Nella maggior parte dei giochi di affettatura, quando si disegna una linea di taglio attraverso uno sprite, il gioco in genere converte l’immagine sprite in due immagini sprite pre-disegnate con la fetta sempre al centro, indipendentemente da dove si taglia effettivamente.

Ma questo tutorial dimostrerà una tecnica ancora più interessante. I nostri frutti saranno in grado di essere tagliati più volte e saranno divisi dinamicamente in base alle linee di taglio esatte!

Come si può immaginare, questa è una tecnica avanzata, quindi questo tutorial è per gli sviluppatori avanzati Cocos2D e Box2D. Se siete nuovi a Cocos2D o Box2D, si dovrebbe passare attraverso (almeno) l’introduzione a Cocos2D e intro a Box2D tutorial prima di procedere con questo tutorial.

Questa serie di tutorial è divisa in tre parti:

  • In questa prima parte della serie, si porre le basi per il gioco, e imparare a creare poligoni strutturati.
  • La seconda parte ti mostrerà come tagliare & dividere questi poligoni strutturati.
  • La terza parte vi mostrerà come trasformare questo in un gioco completo con l’aggiunta di gameplay ed effetti.

Vorrei dare un ringraziamento speciale a Rick Smorawski per aver gettato le basi per il progetto su cui si basa questo tutorial. È stato responsabile del porting di questa demo di slicing basata su flash in Cocos2D e anche del porting di CCBlade e PRKit in Cocos2D 2.0.

Continua a leggere per controllare il video di quello che farai e per iniziare ad imparare alcune nuove tecniche fresche!

Demo del gioco

Ecco un video demo che mostra quello che farai in questa serie di tutorial:

Come ho detto, vedrai che l’effetto di taglio della frutta è davvero dinamico. Il frutto viene tagliato dinamicamente in base a dove si taglia, e dal momento che è possibile tagliare gli oggetti più volte, si può davvero tagliare le cose!

Puoi vedere che implementerai anche un effetto di traccia di affettatura, alcuni sistemi di particelle, logica di gioco e suoni per rendere le cose più interessanti.

C’è molto da coprire – quindi iniziamo!

Guida introduttiva: Configurazione del progetto

Si sta andando a utilizzare Cocos2D 2.X in questo progetto, quindi vai avanti e scaricalo se non lo hai già. Si noti che si è liberi di utilizzare Cocos2D 1.X invece di 2.X. Con 1.X, puoi saltare le parti sulla conversione di PRKit e CCBlade in Cocos2D 2.X, ma assicurati di prestare attenzione alle altre piccole modifiche apportate a quelle classi.

Dopo il download, fare doppio clic sul tar per annullarlo, quindi installare i modelli con i seguenti comandi nel Terminale:

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

Avviare Xcode e creare un nuovo progetto con iOS \ cocos2d v2.x \ cocos2d iOS con il modello Box2d e chiamalo CutCutCut.

Il tuo nuovo progetto dovrebbe essere simile a questo:

Inizio progetto

Per prima cosa – dovresti ripulire un po ‘ il modello per arrivare a un buon punto di partenza.

Apri HelloWorldLayer.h e rimuovere la seguente riga:

CCTexture2D *spriteTexture_;// weak ref

Passa a HelloWorldLayer.mm e apporta le seguenti modifiche

// 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;

A questo punto, hai rimosso tutti i riferimenti a PhysicsSprite da HelloWorldLayer, ma non rimuovere ancora i file dal progetto. In seguito, dovrai copiare un metodo che PhysicsSprite.mm contiene da qualche altra parte, in modo da lasciare mettere per ora.

Premi Command + R per compilare ed eseguire il tuo progetto e dovresti vedere una schermata vuota con un bordo verde attorno ad essa:

Clean Slate

Il codice modello rimanente ha impostato il disegno di debug di Box2D, che disegna i bordi attorno ai corpi di Box2D sullo schermo. Vedi le sottili linee verdi disegnate intorno allo schermo? Questi sono i muri generati dal metodo initPhysics predefinito fornito con il modello.

Dai un’occhiata al codice del modello rimanente per assicurarti di capire cosa sta succedendo finora: inizializza un mondo Box2D, imposta il terreno (bordi verdi), imposta il disegno di debug, ecc. Questo è un buon punto di partenza “quasi vuoto” con Box2D su cui possiamo costruire da qui.

Resource Kit

Quindi scaricare le risorse per questo progetto e decomprimere il file.

Non aggiungere ancora tutto nel progetto; alcuni dei file sono in realtà opzionali. Mantenere la cartella a portata di mano però-come si passa attraverso il tutorial, di tanto in tanto vi chiederò di aggiungere alcuni di questi file nel progetto.

Ecco cosa troverai all’interno:

  • Un’immagine di sfondo e un mazzo di frutta arte fatta da Vicki, e altre immagini varie nella cartella Immagini
  • Il mix suono di sottofondo realizzato con gomix.nella cartella dei Suoni
  • effetti Sonori realizzati utilizzando bfxr o scaricato da freesound nella cartella dei Suoni
  • Tutti i sistemi di particelle creato con Particelle di Designer nelle Particelle cartella
  • UN file PLIST generato da PhysicsEditor contenente vertice di informazioni per i Frutti & Bomba classi nella cartella Misc
  • Frutta & Bomba classi nelle Classi cartella
  • Le versioni di PRKit e CCBlade verrà utilizzato nel tutorial nella cartella Classes
  • attribuzione di Un elenco di risorse che sono sotto la Licenza Attribuzione in Misc cartella

Disegno di poligoni testurizzati con PRKit

Il nostro obiettivo è tagliare gli sprite in più pezzi. Un tipico CCSprite contiene una texture e un riquadro di delimitazione indipendentemente dalla forma dell’immagine. Questo non è adatto per il nostro gioco poiché conoscere le forme reali all’interno delle immagini è un passo cruciale per la creazione di sprite che possono essere tagliati, affettati e divisi.

È necessario creare Poligoni strutturati, che:

  • Crea una corrispondenza tra un poligono / forma e un’immagine (Mappatura texture)
  • Mostra solo le parti dell’immagine che si trovano entro i limiti del poligono (Riempimento texture)

Né Cocos2D né Box2D sono dotati di una classe integrata che gestisce le funzionalità personalizzate desiderate e, normalmente, ciò richiederebbe una triangolazione accoppiata a codice di disegno OpenGL personalizzato.

Suona duro giusto?

Fortunatamente, tutti i complicati calcoli e il codice di disegno necessari per raggiungere questo obiettivo sono già stati scritti dai bravi ragazzi di Precognitive Research. Hanno creato un’aggiunta alla libreria Cocos2D denominata PRKit, che gestisce la mappatura e il riempimento delle texture.

Per iniziare con i poligoni testurizzati, scarica PRKit, estrailo e trascina la cartella PRKit nel tuo progetto. Assicurati che” Copia elementi nella cartella del gruppo di destinazione “sia selezionata e che” Crea gruppi per tutte le cartelle aggiunte ” sia selezionata.

Si noti che PRKit è mantenuto dalla ricerca precognitiva, quindi potrebbe essere aggiornato in tempo. Per evitare confusione, il nostro kit di risorse contiene anche la versione esatta di PRKit che ho usato per fare questo tutorial.

Il tuo progetto dovrebbe ora includere questi file:

PRKit Yey!

Compila ed esegui e incontrerai alcuni errori:

PRKit deve essere convertito

Gli errori compaiono perché PRKit è stato creato per Cocos2D 1.X, che usa OpenGL ES 1.1, mentre stai usando Cocos2D 2.X, che utilizza OpenGL ES 2.0, e ci sono differenze significative tra i due.

Per risolvere questo problema, apri PRFilledPolygon.m e apportare queste modifiche:

// 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);}

Esaminiamo questi cambiamenti un po ‘ alla volta.

Innanzitutto, in Cocos2D ogni CCNode ha un programma shader OpenGL ES 2.0 collegato ad esso. Per disegnare il PRFilledPolygon, è necessario citare in giudizio lo shader “Position/Texture” incorporato, che si assegna nel metodo init.

Successivamente, è necessario impostare le coordinate di trama corrette per ogni punto del poligono. Per fare ciò, è necessario apportare due modifiche al metodo calculateTextureCoordinates:

  • Scala: Poiché questa classe esegue i propri calcoli sulle coordinate della sua texture, non gestisce automaticamente il display retina. Per risolvere questo problema, basta moltiplicare la trama.pixelsWide con CC_CONTENT_SCALE_FACTOR – un comodo valore moltiplicatore fornito da Cocos2D per la conversione di valori tra equivalenti regolari e retina.
  • Capovolgi Y: Per qualche motivo, PRFIlledPolygon disegna le trame a testa in giù, quindi semplicemente capovolgi il valore y qui.

Infine, il codice di disegno viene aggiornato a OpenGL ES 2.0, in modo simile a come il disegno CCSprite è cambiato da Cocos2D 1.X a Cocos2D 2.X:

  • Inizia chiamando CC_NODE_DRAW_SETUP () per preparare il nodo per il disegno.
  • Le chiamate a glDisableClientState () e glEnableClientState () sono obsolete e vengono scartate.
  • I comandi glVertexPointer() e glTexCoordPointer() sono entrambi sostituiti da glVertexAttribPointer(), che ora accetta la posizione del vertice o la coordinata della trama come prima opzione.
  • La configurazione di glTexEnvf(), che era responsabile della ripetizione dello sprite nel caso in cui il poligono fosse più grande della texture, viene sostituita dalle chiamate a glTexParameteri().

Se sei confuso da tutto questo, potresti voler controllare il nostro OpenGL ES 2.0 per iPhone e Custom Cocos2D 2.X Shader tutorial per ulteriori informazioni di base. Ma non devi preoccuparti troppo, perché a questo punto tutto ciò che stiamo facendo è il porting della classe per funzionare in Cocos2D 2.X :]

Compila ed esegui e tutti gli errori PRKit dovrebbero scomparire!

È il momento di mettere PRKit in azione. Sarai sottoclasse della classe PRFilledPolygon di PRKit per creare una classe PolygonSprite di base che attirerà i nostri frutti.

Il PolygonSprite si basa su PRFilledPolygon collegando un corpo Box2D allo sprite, e conterrà anche altre variabili e metodi personalizzati per i frutti nella nostra implementazione del gioco.

Andiamo ad esso. Premi Comando + N e crea un nuovo file con iOS \ cocos2d v2.modello di classe x \ CCNode. Rendilo una sottoclasse di PRFilledPolygon e chiamalo PolygonSprite.m.

Passa a PolygonSprite.h e apportare le seguenti modifiche:

// 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;

Il codice di cui sopra dichiara le variabili di base e i metodi necessari per creare un PolygonSprite. Questi sono:

  • corpo: Questo è il corpo Box2D che è attaccato al nostro sprite. È necessario per la simulazione fisica.
  • originale: gli sprite completi e affettati useranno la stessa classe PolygonSprite, in quanto tale, la differenziazione tra i due sarà importante. Se questo è SÌ, significa che è l’oggetto non tagliato o originale che hai creato, altrimenti è solo un pezzo del tutto.
  • centroide: Il centro del poligono all’interno dell’immagine non sarà sempre lo stesso del centro dell’immagine, quindi è utile memorizzare questo valore.
  • proprietà: Esporre tutte le variabili utilizzando le proprietà in modo che altre classi possano accedervi liberamente.
  • init/spriteWith*: I nostri principali metodi di init che seguono la stessa convenzione di denominazione di Cocos2D.
  • altri metodi: Questi sono metodi che creano & che si occupano del corpo Box2D allegato e delle sue proprietà.
  • PTM_RATIO: rapporto pixel / metri. Box2D ha bisogno di questo valore di conversione perché si occupa di Metri invece di Pixel.

Passa rapidamente a PolygonSprite.m e rinominarlo PolygonSprite.mm. Tutte le classi che mescolano il codice Objective-C (Cocos2D) e C++ (Box2D) devono avere un’estensione “.mm” per notificare al compilatore la sintassi mista.

Quindi, apportare le seguenti modifiche a 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;}

Simile a Cocos2D, tutti i metodi spriteWith * sono solo controparti autorelease dei metodi initWith*, mentre initWithWorld non ha ancora alcun uso effettivo per questa classe, ma verrà utilizzato dalle sottoclassi di PolygonSprite in seguito.

La maggior parte delle modifiche può essere trovata nei metodi initWithFile e initWithTexture. Per ottenere il flusso delle cose, la creazione di un frutto verrà chiamata in questa sequenza:

Sequenza di avvio

  • initWithWorld: Questo è destinato alle sottoclassi di PolygonSprite in modo da non fare nulla se non restituire nil e affrontarlo in un secondo momento.
  • initWithFile: questo aggiunge la texture dal nostro file e passa tutto a initWithTexture.
  • initWithTexture: la nostra inizializzazione principale. PRFilledPolygon ha bisogno di una texture e di tutti i vertici del poligono che riempie. Poiché il passaggio precedente gestiva già la parte texture, questo passaggio gestisce i vertici raccogliendoli dal corpo Box2D dello sprite. Dopo averli passati a PRFilledPolygon, procede all’inizializzazione delle variabili precedentemente dichiarate.
  • initWithPoints: Tutto ciò che fa è contenuto in PRKit e la cosa buona è che non è più necessario toccare PRKit ora che hai aggiornato il suo codice.

Ancora all’interno PolygonSprite.mm, aggiunga i metodi seguenti:

-(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);}

Nel codice precedente, si sovraccarica prima il metodo setPosition di CCNode in modo che quando si aggiorna la posizione dello sprite, anche la posizione del corpo Box2D associata viene aggiornata.

Si crea quindi un metodo di convenienza per la creazione e la definizione di un corpo Box2D. Per creare un corpo, è necessario definire una definizione di corpo, un oggetto corpo, una forma e una definizione di fixture. Non vengono ancora assegnati valori reali poiché questo metodo verrà utilizzato in seguito dalle sottoclassi di PolygonSprite.

L’unica cosa da notare è la categoryBits e maskBits. Questi due sono usati per filtrare le collisioni tra oggetti in modo tale che se un bit di categoria di un oggetto corrisponde a un bit di maschera di un altro oggetto e viceversa, ci sarà una collisione tra questi due oggetti. Si impostano prima su 0 perché non si desidera che si verifichino collisioni quando gli oggetti vengono inizializzati per la prima volta.

Infine, definisci due metodi che sostituiscono semplicemente categoryBits e maskBits in modo da poter attivare e disattivare le collisioni dei nostri PolygonSprites.

C’è un’altra cosa da aggiungere 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_;}

Ricorda quando ho detto che avevi bisogno di qualcosa da PhysicsSprite? Beh, ci siamo. Tutto questo fa è quello di assicurarsi che la nostra forma Box2D e il nostro sprite sono nella stessa posizione quando si muove. È preparato per noi da Cocos2D e questo lo rende ancora più fantastico.

Dopo aver copiato il codice precedente, è ora possibile eliminare entrambi PhysicsSprite.h e PhysicsSprite.mm dal progetto come hai completamente eliminato la loro utilità.

Compila ed esegui, e tutto dovrebbe andare bene. Hai finito con PolygonSprite per ora.

Pianificare i nostri frutti

Prima di creare classi per i nostri frutti, è necessario essere chiari sulle regole che le immagini e le loro forme devono seguire. Poiché mapperai le nostre trame su singoli poligoni Box2D, devi anche rispettare le limitazioni del poligono di Box2D. Devi tenere a mente due cose:

  • I poligoni devono essere convessi, il che significa che nessun angolo interno è maggiore di 180.
  • I poligoni non devono superare 8 vertici.

È possibile aggirare questa limitazione se si consente a ciascun corpo di contenere più forme. Box2D può gestire forme concave se si utilizza un metodo di triangolazione e si creano forme concave da diversi triangoli, ma questo va oltre lo scopo del tutorial.

Per mantenere le cose semplici, in questo tutorial si avrà un 1 Corpo è quello di 1 regola di forma.

Nota: PhysicsEditor, lo strumento che tratteremo più avanti in questo tutorial, contiene in realtà il codice per triangolare automaticamente i poligoni disegnati in un insieme di forme convesse. Tuttavia, come ho detto, stiamo cercando di mantenere le cose semplici qui, quindi faremo in modo di disegnare le nostre forme convesse in modo da avere solo una forma per corpo.

Dai un’occhiata a questi due frutti:

Concavo vs Convesso

Usare la banana non è una buona idea perché è naturalmente concava. L’anguria d’altra parte è molto buona perché è possibile definire un poligono convesso che assomiglia molto alla sua forma.

Se dovessi definire forme poligonali che seguono le regole di Box2D per i due frutti, finiresti più o meno con questi:

Box2D Shape Outline

Il poligono di anguria si adatta perfettamente all’immagine, mentre il poligono di banana ha un grande spazio vuoto in cui l’immagine si curva verso l’interno. Box2D tratterà quello spazio come parte del nostro oggetto e potrebbe rendere la Banana innaturale quando si scontra con altri oggetti o quando viene tagliata.

Questo non significa che non puoi usare la Banana, ma piuttosto che non è consigliabile usare la Banana. In effetti, il gioco che creerai in questo tutorial utilizzerà questa stessa Banana.

Creazione del primo frutto

È tempo di creare il primo frutto: l’anguria (almeno una fetta di esso).

Ripensando al flusso del processo di inizializzazione di PolygonSprite, sai che initWithTexture si aspetta un corpo Box2D, ma il passaggio precedente, initWithFile, non lo fornisce.

La ragione di ciò è che è necessario creare e definire il corpo individualmente per frutto, quindi dovrà essere il primo passo, initWithWorld, che crea il corpo e imposta altri valori specifici per ciascun frutto.

Per creare il nostro corpo Box2D, devi prima conoscere i vertici della forma poligonale che vuoi creare. Ci sono diversi modi per farlo, ma per questo tutorial, si prevede di utilizzare uno strumento elegante chiamato PhysicsEditor. Questo strumento è pieno di funzionalità, ma lo userai solo per guidarci nell’ottenere le coordinate dei vertici del nostro poligono.

Se non ce l’hai, scarica PhysicsEditor, installalo e accendilo. Otterrai un progetto vuoto con 3 pannelli / colonne.

Lavorare con PhysicsEditor è piuttosto semplice. A sinistra, si mettono tutte le immagini che si desidera lavorare con. Al centro, definisci visivamente un poligono per la tua immagine. A destra, hai i parametri per il corpo.

 Editor di fisica!

Afferra anguria.png dalla cartella Immagini del kit di risorse e trascinarlo sul pannello di sinistra. Ora dovresti vedere l’anguria sul pannello centrale.

Aumentare l’ingrandimento, che si trova nella parte inferiore di questo pannello, a un livello confortevole, quindi toccare il pulsante Pentagono sulla parte superiore di questo pannello per creare una forma poligonale a 3 lati.

Fai clic con il pulsante destro del mouse sul poligono e scegli “Aggiungi vertice” finché non hai 5-8 vertici in tutto. Spostare i vertici intorno ai bordi del cocomero, assicurandosi di due cose:

  • Il Poligono che stai creando è Convesso.
  • Tutti i pixel dell’Anguria sono all’interno del Poligono.

Nota: Un’altra scorciatoia per disegnare le forme è usare lo strumento bacchetta magica di PhysicsEditor. Basta impostare la tolleranza alta (5-8) in modo che si finisce con circa 5-8 punti, e modificare i punti da lì.

Aggiungi tutti gli altri frutti e l’immagine della bomba dalla cartella Immagini del kit di risorse e fai la stessa cosa per loro.

Dovresti definire le forme per le seguenti immagini:

  • banana.png
  • bomba.png
  • uva.png
  • ananas.png
  • fragola.png
  • anguria.png

Quando hai finito, nell’angolo in alto a destra, cambia il valore di Exporter in “Box2D generic (PLIST)”, e dovresti finire con qualcosa del genere:

Definire forme facilmente con PhysicsEditor!

Premere “Pubblica” o “Pubblica come” per esportare il file PLIST contenente le informazioni del vertice. Salvare il file come frutta.plist.

Ad esempio, i frutti.plist che hai usato per questo tutorial è all’interno della cartella Misc del resource kit.

Vuoi solo guardare le informazioni contenute nel file PLIST, quindi non aggiungere questo file al tuo progetto, ma piuttosto, apri semplicemente fruits.plist utilizzando Xcode per visualizzare il suo contenuto in modo organizzato.

Fai clic sull’icona del triangolo accanto a “corpi” per espandere questa sezione e vedrai l’elenco delle immagini per cui hai definito le forme. È necessario eseguire il drill down al livello più profondo per ottenere i vertici poligonali dell’anguria in questo modo:

Il PhysicsEditor PLIST

Espandi watermelon/fixtures/Item 0/polygons e ora dovresti vedere un altro elemento 0 di Type Array sotto polygons. Quest’ultimo array è la tua forma. Se hai definito correttamente una forma convessa con 8 o meno vertici, dovresti vedere solo una matrice sotto i poligoni.

Se ne vedi più di uno, io.e Elemento 0 Array, Elemento 1 Array, ecc., quindi significa che PhysicsEditor ha creato una forma complessa perché hai definito troppi vertici o hai formato un poligono concavo. Se ciò accade, torna a PhysicsEditor e aggiusta la tua forma.

Quindi, espandere l’elemento 0 di tipo Array per visualizzare l’elenco finale degli elementi. Questi sono i tuoi vertici e il valore che vedi sul lato destro con questo formato { number, number } sono le tue coordinate x & y per ogni vertice.

Ora che hai i valori esatti per i vertici del tuo poligono, puoi procedere con la creazione della classe Watermelon.

In Xcode, creare un nuovo file con iOS\cocos2d v2.modello di classe x \ CCNode. Rendilo una sottoclasse di PolygonSprite e chiamalo Anguria. Anguria aperta.h e apportare le seguenti modifiche:

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

Passa all’anguria.m, rinominarlo in Watermelon.mm, ed aggiunga il seguente metodo di init:

// 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;}

Nel codice sopra, per prima cosa definisci quanti vertici ci sono, che in questo caso è 7. Successivamente, si crea una matrice di vertici contenente tutte le coordinate che hai appena visto nel PLIST. Utilizzare queste informazioni per creare un corpo utilizzando il metodo di convenienza definito in PolygonSprite.

Metti un po ‘di attrito in modo che le forme non scivolino all’infinito, e metti anche un po’ di restituzione in modo che le forme non si fermino quando rimbalzano l’una contro l’altra.

Infine, si crea l’oggetto chiamando l’inizializzazione della superclasse e si passa il nome del file immagine, il corpo Box2D e si afferma che si tratta di un frutto originale.

Hai bisogno delle immagini di anguria dal kit di risorse, quindi ora sarebbe un buon momento per aggiungere solo tutte le risorse grafiche necessarie per il resto del tutorial.

Nel pannello di Navigazione del progetto, fare clic con il pulsante destro del mouse su Risorse e selezionare “Aggiungi file a CutCutCut”. Aggiungere la cartella Immagini dal resource kit al progetto. Assicurati che” Copia elementi nella cartella del gruppo di destinazione “sia selezionata e che” Crea gruppi per tutte le cartelle aggiunte ” sia selezionata.

Segui gli stessi passaggi per creare Banana, Uva, ananas, Fragola e Bomba.

Hai affrontato solo come creare il primo frutto passo dopo passo poiché è fondamentalmente un risciacquo & ripetere il processo per ogni frutto. Il kit di risorse contiene classi di frutta e bombe già pronte nella cartella Classi da esaminare nel caso in cui tu abbia ancora bisogno di una guida, oppure puoi aggiungerle tutte al tuo progetto se vuoi saltare questo passaggio.

Compila ed esegui e assicurati che tutto vada bene.

L’aggiunta di un frutto alla scena

Finora, nulla è accaduto sullo schermo ancora, e si sono ovviamente prurito di vedere i frutti del vostro lavoro – gioco di parole! :]

Passa a HelloWorldLayer.h e apportare le seguenti modifiche:

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

Torna a HelloWorldLayer.mm e apportare queste modifiche:

// 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]; ; ; ;}

Dichiari un array di cache, che conterrà tutti i frutti e le bombe che crei in futuro. Successivamente, si crea 1 Anguria e aggiungerlo alla scena. Chiami attivocollisioni in modo che l’anguria non passi attraverso le pareti.

Compila ed esegui, e dovresti vedere un cocomero che cade dall’area centrale dello schermo e atterrare in basso come mostrato di seguito.

Il frutto del tuo lavoro

Potresti notare che l’anguria non è esattamente al centro. La ragione di ciò è che hai posizionato l’oggetto in base al suo corpo Box2D e l’origine del nostro corpo Box2D si trova nell’angolo in basso a sinistra dell’oggetto. Il contorno sottile intorno al cocomero è visibile perché la modalità di disegno di debug è ancora attivata.

Dove andare da qui?

Ecco un progetto di esempio con tutto il codice del tutorial sopra.

Questo è tutto per la parte 1 della serie. Finora, si dispone di un poligono strutturato anguria che cade solo alla parte inferiore dello schermo.

Ma invece di disegnare uno sprite rettangolare con spazio trasparente come di solito si vede nelle esercitazioni Box2D, questo usa PRKit per disegnare solo le parti della trama che corrispondono ai vertici del corpo Box2D. Questo sarà utile presto!

Ora sei pronto per la Parte 2 del tutorial, dove aggiungi la possibilità di tagliare i frutti!

Nel frattempo, se avete domande o commenti su questa parte, si prega di partecipare alla discussione del forum qui sotto!


Questo è un post di iOS Tutorial Membro del team Allen Tan, uno sviluppatore iOS e co-fondatore di White Widget. Lo si può anche trovare su Google + e Twitter.

raywenderlich.com Settimanale

Il raywenderlich.com newsletter è il modo più semplice per rimanere up-to-date su tutto quello che c’è da sapere come uno sviluppatore mobile.

Ottieni un digest settimanale dei nostri tutorial e corsi e ricevi un corso e-mail di approfondimento gratuito come bonus!

Leave a Reply

Il tuo indirizzo email non sarà pubblicato.