hur man gör ett spel som Fruit Ninja med Box2D och Cocos2D – Del 1

Detta är ett inlägg av iOS Tutorial teammedlem Allen Tan, en iOS-utvecklare och medgrundare på White Widget. Du kan också hitta honom på Google+ och Twitter.

i den här handledningen lär du dig att göra ett sprite-skärspel för iPhone som liknar Fruit Ninja av Halfbrick Studios med hjälp av de kraftfulla Cocos2D-och Box2D-biblioteken tillsammans med några färdiga verktyg.

i de flesta skivspel, när du ritar en snittlinje genom en sprite, konverterar spelet vanligtvis sprite-bilden till två fördragen sprite-bilder med skivan alltid i mitten, oavsett var du faktiskt skär.

men denna handledning kommer att visa en ännu kallare teknik. Våra frukter kommer att kunna skäras flera gånger, och de kommer att delas dynamiskt baserat på de exakta snittlinjerna!

som du kan föreställa dig är detta en avancerad teknik, så den här handledningen är för avancerade Cocos2D-och Box2D-Utvecklare. Om du är ny på Cocos2D eller Box2D, bör du gå igenom (åtminstone) intro till Cocos2D och intro till Box2D tutorials först innan du fortsätter med denna handledning.

denna handledning serien är uppdelad i tre delar:

  • i den här första delen av serien lägger du grunden för spelet och lär dig att skapa texturerade polygoner.
  • den andra delen visar hur du skär & dela dessa texturerade polygoner.
  • den tredje delen visar hur du gör detta till ett komplett spel genom att lägga till spel och effekter.

Jag vill ge ett särskilt tack till Rick Smorawski för att lägga grunden för projektet denna handledning bygger på. Han var ansvarig för att portera denna flash-baserade skivning demo till Cocos2D, och även för portning CCBlade och PRKit till Cocos2D 2.0.

Fortsätt läsa för att kolla in videon om vad du ska göra och för att komma igång med att lära dig några coola nya tekniker!

Game Demo

här är en demo video som visar dig vad du ska göra i denna handledning serie:

som jag nämnde ser du att fruktskärningseffekten är verkligen dynamisk. Frukten skärs dynamiskt baserat på var du skär, och eftersom du kan skära föremål flera gånger kan du verkligen hugga upp saker!

du kan se att du också kommer att implementera en cool skivspårseffekt, vissa partikelsystem, spellogik och ljud för att krydda saker.

det finns mycket att täcka – så låt oss komma igång!

komma igång: Projektinställning

du kommer att använda Cocos2D 2.X i det här projektet, så fortsätt och ladda ner det om du inte redan har det. Observera att du är fri att använda Cocos2D 1.X istället för 2.X. Med 1.X, Du kan hoppa över delarna om att konvertera PRKit och CCBlade till Cocos2D 2.X, Men var noga med att vara uppmärksam på de andra små förändringarna du gör i dessa klasser.

efter nedladdning dubbelklickar du på tar för att avarkivera den och installerar sedan mallarna med följande kommandon i terminalen:

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

starta Xcode och skapa ett nytt projekt med iOS\cocos2d v2.x \ cocos2d iOS med Box2d Mall och namnge det CutCutCut.

ditt nya projekt ska se ut så här:

projektstart

första saker först – du bör städa upp mallen lite för att komma till en bra utgångspunkt.

Öppna HelloWorldLayer.h och ta bort följande rad:

CCTexture2D *spriteTexture_;// weak ref

Byt till HelloWorldLayer.mm och gör följande ändringar

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

vid denna tidpunkt har du tagit bort alla referenser till Physicsprite från HelloWorldLayer, men ta inte bort filerna från projektet ännu. Senare måste du kopiera en metod som PhysicsSprite.mm innehåller någon annanstans, så lämna det för nu.

Hit Command + R för att kompilera och köra ditt projekt, och du bör se en tom skärm med en grön kant runt den:

ren skiffer

den återstående mallkoden har satt upp Box2D debug-ritning, som drar gränser runt Box2D-kropparna på skärmen. Se de tunna gröna linjerna ritade runt skärmen? Det är väggarna som genereras av standard initPhysics-metoden som följde med mallen.

ta en titt på den återstående mallkoden för att se till att du förstår vad som händer hittills – det initierar en Box2D-värld, sätter upp marken (gröna gränser), ställer in felsökningsritning etc. Detta är en ganska bra ”nästan tom” utgångspunkt med Box2D som vi kan bygga vidare på härifrån.

Resource Kit

hämta sedan resurserna för det här projektet och packa upp filen.

lägg inte till allt i projektet ännu; några av filerna är faktiskt valfria. Håll mappen praktisk men-när du går igenom handledningen kommer jag då och då att be dig lägga till några av dessa filer i projektet.

här är vad du hittar inuti:

  • en bakgrundsbild och en massa fruktkonst gjord av Vicki och andra diverse bilder i mappen Bilder
  • bakgrundsljudmixen gjord med gomix.ljudmappen
  • ljudeffekter gjorda med bfxr eller nedladdade från freesound i mappen ljud
  • alla partikelsystem skapade med Partikeldesigner i mappen partiklar
  • en PLIST-fil genererad av PhysicsEditor som innehåller vertexinformation för frukterna & Bombklasser i mappen Misc
  • frukter & Bombklasser i mappen klasser
  • versionerna av prkit och Ccblade du kommer att använda i handledningen i mappen klasser
  • en Attribution lista för resurser som är under Attribution licens i Misc folder

Rita texturerade polygoner med PRKit

vårt mål är att skära sprites i flera bitar. En typisk CCSprite innehåller en textur och en avgränsningsruta oavsett vilken form bilden är. Detta är inte lämpligt för vårt spel eftersom att känna till de faktiska formerna i bilderna är ett viktigt steg för att skapa sprites som kan klippas, skivas och delas.

du måste skapa texturerade polygoner, som:

  • skapa en korrespondens mellan en polygon / form och en bild (texturmappning)
  • Visa endast de delar av bilden som ligger inom polygonens gränser (Texturfyllning)

varken Cocos2D eller Box2D kommer med en inbyggd klass som hanterar de anpassade funktionerna du vill ha, och normalt skulle det ta lite triangulering i kombination med anpassad OpenGL-ritningskod.

låter hårt rätt?

lyckligtvis har alla komplicerade beräkningar och ritningskod som behövs för att uppnå detta redan skrivits av de goda människorna vid Precognitiv forskning. De skapade ett tillägg till Cocos2D-biblioteket med namnet PRKit, som hanterar texturmappning och fyllning.

för att komma igång med texturerade polygoner, ladda ner PRKit, extrahera det och dra PRKit-mappen till ditt projekt. Se till att” kopiera objekt till destinationsgruppens mapp ”är markerad och” skapa grupper för alla tillagda mappar ” är markerat.

Observera att PRKit upprätthålls av Precognitiv forskning, så det kan uppdateras i tid. För att undvika förvirring innehåller vårt resurspaket också den exakta versionen av PRKit som jag använde för att göra denna handledning.

ditt projekt ska nu inkludera dessa filer:

PRKit Yey!

kompilera och kör, och du kommer att stöta på några fel:

PRKit måste konverteras

felen dyker upp eftersom PRKit gjordes för Cocos2D 1.X, som använder OpenGL ES 1.1, medan du använder Cocos2D 2.X, som använder OpenGL ES 2.0, och det finns betydande skillnader mellan de två.

för att åtgärda detta, öppna PRFilledPolygon.m och gör dessa förändringar:

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

Låt oss gå igenom dessa förändringar bit för bit.

först, i Cocos2D har varje CCNode ett OpenGL ES 2.0 shader-program kopplat till det. För att rita PRFilledPolygon måste du stämma den inbyggda” Position/Texture ” shader, som du tilldelar i init-metoden.

Därefter måste du ställa in rätt texturkoordinater för varje punkt i polygonen. För att göra detta måste du göra två ändringar metoden calculateTextureCoordinates:

  • skala: eftersom denna klass gör sina egna beräkningar på koordinaterna för dess struktur, hanterar den inte automatiskt retina-skärmen. För att åtgärda detta multiplicerar du bara textur.pixelsWide med CC_CONTENT_SCALE_FACTOR – ett bekvämt multiplikatorvärde som tillhandahålls av Cocos2D för att konvertera värden mellan vanliga och näthinneekvivalenter.
  • Flip Y: av någon anledning drar PRFIlledPolygon texturer upp och ner, så du vänder helt enkelt y-värdet här.

senast uppdateras ritningskoden till OpenGL ES 2.0, på ett liknande sätt som hur CCSprite ritning ändras från Cocos2D 1.X till Cocos2D 2.X:

  • börja med att ringa CC_NODE_DRAW_SETUP () för att förbereda noden för ritning.
  • samtal till glDisableClientState () och glEnableClientState () är föråldrade och kasseras.
  • kommandona glVertexPointer() och glTexCoordPointer() ersätts båda av glVertexAttribPointer(), som nu accepterar vertexposition eller Texturkoordinat som sitt första alternativ.
  • installationen av glTexEnvf (), som var ansvarig för att upprepa sprite om polygonen var större än texturen, ersätts av samtal till glTexParameteri ().

om du är förvirrad av något av detta kanske du vill kolla in vår OpenGL ES 2.0 för iPhone och anpassad Cocos2D 2.X Shaders tutorials för mer bakgrundsinformation. Men du behöver inte oroa dig för det för mycket, för just nu är allt vi gör att porta klassen för att arbeta i Cocos2D 2.X:]

kompilera och kör, och alla PRKit-fel ska försvinna!

det är dags att sätta PRKit i aktion. Du kommer att underklassa Prkits PRFilledPolygon-klass för att skapa en Baspolygonprite-klass som kommer att dra våra frukter.

Polygonspriten bygger på PRFilledPolygon genom att fästa en Box2D-kropp till sprite, och den kommer också att innehålla andra anpassade variabler och metoder för frukterna i vårt spelimplementering.

Låt oss komma till det. Hit Command + N och skapa en ny fil med iOS\cocos2d v2.X\CCNode klass Mall. Gör det till en underklass av PRFilledPolygon och namnge det PolygonSprite.m.

växla över till PolygonSprite.h och gör följande ändringar:

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

ovanstående kod förklarar de basvariabler och metoder du behöver för att skapa en PolygonSprite. Dessa är:

  • kropp: Detta är Box2D-kroppen som är fäst vid vår sprite. Det behövs för fysik simulering.
  • original: Complete och skivade sprites kommer att använda samma PolygonSprite klass, som sådan, skilja mellan de två kommer att vara viktigt. Om detta är ja betyder det att det är det oklippta eller ursprungliga objektet som du skapade, annars är det bara en del av helheten.
  • centroid: Mitten av polygonen i bilden kommer inte alltid att vara densamma som mitten av bilden, så det är användbart att lagra detta värde.
  • egenskaper: exponera alla variabler med hjälp av egenskaper så att andra klasser kan komma åt dem fritt.
  • init / spriteWith*: våra huvudsakliga init-metoder följer samma namnkonvention som Cocos2D.
  • andra metoder: dessa är metoder som skapar & som hanterar den bifogade Box2D-kroppen och dess egenskaper.
  • PTM_RATIO: pixlar till meter förhållande. Box2D behöver detta konverteringsvärde eftersom det handlar om mätare istället för pixlar.

Byt snabbt till PolygonSprite.m och byt namn på det PolygonSprite.mm. alla klasser som blandar Objective-C (Cocos2D) och C++ (Box2D) – kod måste ha en ”.mm” – förlängning för att meddela kompilatorn för den blandade syntaxen.

gör sedan följande ändringar i 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;}

i likhet med Cocos2D är alla spriteWith* – metoder bara autorelease-motsvarigheter till initwith* – metoderna, medan initWithWorld inte har någon faktisk användning för den här klassen ännu, men istället kommer den att användas av Polygonsprites underklasser senare.

huvuddelen av ändringarna finns i metoderna initWithFile och initWithTexture. För att få flödet av saker kommer att skapa en frukt kallas i denna sekvens:

Init sekvens

  • initWithWorld: detta är avsett för underklasser av PolygonSprite så att du inte gör något annat än att returnera noll och hantera det senare.
  • initWithFile: detta lägger till texturen från vår fil och skickar allt till initWithTexture.
  • initWithTexture: vår huvudsakliga initiering. PRFilledPolygon behöver en struktur och alla hörn av polygonen den fyller. Eftersom det föregående steget redan hanterat texturdelen hanterar detta steg vertikalerna genom att samla dem från sprites Box2D-kropp. Efter att ha skickat dem till PRFilledPolygon fortsätter det att initiera de variabler som du tidigare har deklarerat.
  • initWithPoints: allt detta gör finns i PRKit och det bra är att du inte behöver röra PRKit längre nu när du har uppdaterat koden.

fortfarande inne PolygonSprite.mm, Lägg till följande metoder:

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

i ovanstående kod överbelastar du först setpositionsmetoden för CCNode så att när du uppdaterar sprites position uppdateras också den tillhörande Box2D-kroppens position.

du gör sedan en bekvämlighetsmetod för att skapa och definiera en Box2D-kropp. För att skapa en kropp måste du definiera en kroppsdefinition, ett kroppsobjekt, en form och en fixturdefinition. Inga riktiga hårda värden tilldelas här ännu eftersom denna metod kommer att användas av underklasser av PolygonSprite senare.

det enda att notera är kategoribits och maskBits. Dessa två används för att filtrera kollisioner mellan objekt så att om en kategoribit av ett objekt matchar en maskbit av ett annat objekt och vice versa, kommer det att bli en kollision mellan dessa två objekt. Du ställer in dessa till 0 först eftersom du inte vill att några kollisioner ska hända när objekten först initieras.

slutligen definierar du två metoder som helt enkelt ersätter kategoribits och maskBits så att du kan aktivera och inaktivera kollisionerna i våra PolygonSprites.

det finns ytterligare en sak att lägga till 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_;}

kom ihåg när jag nämnde att du behövde något från Physicsprite? Nu gäller det. Allt detta gör är att se till att vår Box2D-form och vår sprite är i samma position när de rör sig. Den är förberedd för oss av Cocos2D och det gör det allt mer fantastiskt.

efter att ha kopierat ovanstående kod kan du nu ta bort båda fysikerna.h och PhysicsSprite.mm från projektet som du helt har eliminerat deras användbarhet.

kompilera och kör, och allt ska vara bra. Du är klar med PolygonSprite för nu.

planera våra frukter

innan du skapar klasser för våra frukter måste du vara tydlig på de regler som bilderna och deras former måste följa. Eftersom du kommer att kartlägga våra texturer till enstaka Box2D-polygoner måste du också följa Box2ds polygonbegränsningar. Du måste ha två saker i åtanke:

  • polygoner måste vara konvexa, vilket innebär att ingen inre vinkel är större än 180.
  • polygoner får inte överstiga 8 hörn.

du kan faktiskt kringgå denna begränsning om du tillåter varje kropp att innehålla flera former. Box2D kan hantera konkava former Om du använder en trianguleringsmetod och gör de konkava formerna av flera trianglar, men detta ligger utanför handledningens omfattning.

för att hålla det enkelt, i den här guiden kommer du att ha en 1 kropp är att 1 Form regel.

Obs: PhysicsEditor, verktyget vi kommer att täcka senare i denna handledning, innehåller faktiskt kod för att automatiskt triangulera polygoner du ritar i en uppsättning konvexa former. Men som jag sa försöker vi hålla sakerna enkla här så kommer vi att se till att dra våra former konvexa så att vi bara har en form per kropp.

ta en titt på dessa två frukter:

konkav vs konvex

att använda banan är inte bra eftersom den är naturligt konkav. Vattenmelonen å andra sidan är mycket bra eftersom du kan definiera en konvex polygon som liknar dess form.

om du skulle definiera polygonformer som följer Box2ds regler för de två frukterna, skulle du mer eller mindre sluta med dessa:

Box2D form kontur

vattenmelon polygon passar bilden perfekt, medan banan polygon har ett stort tomt utrymme där bilden kurvor inåt. Box2D kommer att behandla det utrymmet som en del av vårt objekt, och det kan göra att bananen känns onaturlig när den kolliderar med andra föremål, eller när den skärs.

detta betyder inte att du inte kan använda banan, utan snarare att det bara inte rekommenderas att använda banan. Faktum är att spelet som du kommer att skapa i denna handledning kommer att använda samma banan.

skapa den första frukten

det är dags att skapa den första frukten: vattenmelonen (en bit av den åtminstone).

Tänk tillbaka till flödet av vår PolygonSprite initialiseringsprocess, du vet att initWithTexture förväntar sig en Box2D-kropp, men steget före, initWithFile, ger inte detta.

anledningen till detta är att du måste skapa och definiera kroppen individuellt per frukt, så det måste vara det allra första steget, initWithWorld, som skapar kroppen och sätter alla andra värden som är specifika för varje frukt.

för att skapa vår Box2D-kropp måste du först känna till topparna i polygonformen du vill skapa. Det finns olika sätt att göra detta, men för denna handledning kommer du att använda ett snyggt verktyg som heter PhysicsEditor. Detta verktyg är fyllt med funktioner, men du kommer bara att använda den för att vägleda oss att få koordinaterna för hörn av vår polygon.

om du inte har det, ladda ner PhysicsEditor, installera det och avfyra det. Du får ett tomt projekt med 3 paneler/kolumner.

att arbeta med PhysicsEditor är ganska enkelt. Till vänster lägger du alla bilder du vill arbeta med. I mitten definierar du visuellt en polygon för din bild. Till höger har du parametrarna för kroppen.

 Fysik Redaktör!

ta tag i vattenmelon.png från mappen bilder i resurssatsen och dra den till den vänstra panelen. Du bör nu se vattenmelonen på mittpanelen.

öka förstoringen, som finns längst ner på den här panelen, till en bekväm nivå och tryck sedan på Pentagon-knappen på den övre delen av den här panelen för att skapa en 3-sidig polygonform.

högerklicka på polygonen och välj ”Lägg till Vertex” tills du har 5-8 hörn i alla. Flytta hörnen runt Vattenmelonens kanter, samtidigt som du ser till två saker:

  • polygonen du skapar är konvex.
  • alla pixlar av vattenmelon är inuti polygonen.

en annan genväg för att rita formerna är att använda PhysicsEditor ’ s magic wand tool. Ställ bara in toleransen hög (5-8) så att du hamnar med cirka 5-8 poäng och justerar poängen därifrån.

Lägg till alla andra frukter och bombbilden från mappen bilder i resurssatsen och gör samma sak för dem.

du bör definiera former för följande bilder:

  • banan.PNG
  • bomb.PNG
  • druvor.PNG
  • ananas.PNG
  • jordgubbe.PNG
  • vattenmelon.png

när du är klar, i det övre högra hörnet, ändra värdet på exportören till ”Box2D generic (PLIST)”, och du bör sluta med något liknande:

definiera former enkelt med PhysicsEditor!

tryck på ”Publicera” eller ”Publicera som” för att exportera PLIST-filen som innehåller vertexinformationen. Spara filen som frukt.plist.

som ett exempel, frukterna.plist du använde för denna handledning finns i mappen Misc i resurssatsen.

du vill bara titta på informationen i PLIST-filen, så lägg inte till den här filen i ditt projekt, utan bara öppna frukter.plist använder Xcode för att visa innehållet på ett organiserat sätt.

klicka på triangelikonen bredvid ”bodies” för att expandera det här avsnittet och du kommer att se listan över bilder som du definierade former för. Du måste borra ner till den djupaste nivån för att få vattenmelons polygonhörn som så:

PhysicsEditor PLIST

expandera vattenmelon/fixturer/artikel 0/polygoner och du bör nu se en annan artikel 0 av typ Array under polygoner. Denna sista array är din form. Om du hade korrekt definierat en konvex form med 8 eller mindre hörn, bör du bara se en array under polygoner.

om du ser mer än en, jag.e Item 0 Array, Item 1 Array, etc, då betyder det att PhysicsEditor gjorde en komplex form eftersom du antingen definierade för många hörn, eller så bildade du en konkav polygon. Om detta händer, gå tillbaka till Fysiskredaktör och fixa din form.

nästa, expandera objektet 0 av typ Array för att se den slutliga listan över objekt. Det här är dina hörn, och värdet du ser på höger sida med detta format { nummer, nummer } är dina x & y-koordinater för varje toppunkt.

nu när du har exakta värden för din polygons hörn kan du fortsätta med att skapa Vattenmelonklassen.

i Xcode skapar du en ny fil med iOS\cocos2d v2.X\CCNode klass Mall. Gör det till en underklass av Polygonerpris och namnge det vattenmelon. Öppna Vattenmelon.h och gör följande ändringar:

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

Byt till vattenmelon.m, Byt namn på den till Watermelon.mm, och Lägg till följande init-metod:

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

i ovanstående kod definierar du först hur många hörn det finns, vilket i detta fall är 7. Därefter skapar du en rad hörn som innehåller alla koordinater du just såg i PLIST. Du använder den här informationen för att skapa en kropp med hjälp av bekvämlighetsmetoden som du definierade i PolygonSprite.

du lägger in lite friktion så att formerna inte glider oändligt, och du lägger också in en liten återbetalning så att Former inte slutar när de studsar mot varandra.

sist skapar du objektet genom att anropa superklassen’ initialisering och passera i namnet på bildfilen, Box2D-kroppen och ange att detta är en originalfrukt.

du behöver vattenmelonbilderna från resurssatsen, så nu skulle det vara en bra tid att bara lägga till alla grafiska resurser du behöver för resten av handledningen.

högerklicka på resurser i din Project Navigator-panel och välj ”Lägg till filer i CutCutCut”. Lägg till mappen Bilder från resurssatsen i projektet. Se till att” kopiera objekt till destinationsgruppens mapp ”är markerad och” skapa grupper för alla tillagda mappar ” är markerat.

följ samma steg för att skapa banan, druvor, ananas, jordgubbe och Bomb.

du tacklade bara hur man skapar den första frukten steg för steg eftersom det i grunden är en sköljning & upprepa processen för varje frukt. Resurssatsen innehåller färdiga frukt-och bombklasser i mappen klasser som du kan titta på om du fortfarande behöver vägledning, eller så kan du lägga till dem alla i ditt projekt om du vill hoppa över det här steget.

kompilera och kör, och se till att allt är bra.

lägga till en frukt till scenen

hittills har ingenting hänt på skärmen ännu, och du är uppenbarligen klåda för att se frukterna av ditt arbete – pun intended! :]

Byt till HelloWorldLayer.h och gör följande ändringar:

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

byt tillbaka till HelloWorldLayer.mm och gör dessa förändringar:

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

du förklarar en cache array, som kommer att hålla alla frukter och bomber du skapar i framtiden. Därefter skapar du 1 vattenmelon och lägger den till scenen. Du ringer aktiveratkollisioner så att vattenmelonen inte passerar genom väggarna.

kompilera och kör, och du bör se en vattenmelon falla från skärmens mittområde och landa längst ner som visas nedan.

frukten av ditt arbete

du kanske märker att vattenmelonen inte är exakt i mitten. Anledningen till detta är att du placerade objektet baserat på dess Box2D-kropp, och vår Box2D-kropp har sitt ursprung i objektets nedre vänstra hörn. Den tunna konturen runt vattenmelonen är synlig eftersom felsökningsritningsläget fortfarande är aktiverat.

Vart Ska Man Gå Härifrån?

här är ett exempelprojekt med all kod från ovanstående handledning.

det är det för del 1 i serien. Hittills har du en vattenmelon texturerad Polygon som bara faller till botten av skärmen.

men istället för att rita en rektangulär sprite med transparent utrymme som du brukar se i Box2D-tutorials, använder detta PRKit för att bara rita de delar av strukturen som motsvarar rutorna i Box2D-kroppen. Detta kommer snart att vara till nytta!

nu är du redo för del 2 i handledningen, där du lägger till möjligheten att skära frukterna!

under tiden, om du har några frågor eller kommentarer om den här delen, vänligen gå med i forumdiskussionen nedan!


Detta är ett inlägg av iOS Tutorial teammedlem Allen Tan, en iOS-utvecklare och medgrundare på White Widget. Du kan också hitta honom på Google+ och Twitter.

raywenderlich.com vecka

den raywenderlich.com nyhetsbrev är det enklaste sättet att hålla dig uppdaterad om allt du behöver veta som mobilutvecklare.

få en veckovis sammanfattning av våra handledning och kurser och få en gratis fördjupad e-postkurs som en bonus!

Leave a Reply

Din e-postadress kommer inte publiceras.