jak zrobić grę jak Fruit Ninja z Box2D i Cocos2D-Część 1
to jest post Przez IOS samouczek członek zespołu Allen Tan, iOS developer i współzałożyciel w White Widget. Można go również znaleźć na Google+ i Twitterze.
w tym samouczku dowiesz się, jak stworzyć grę do cięcia sprite 'ów na iPhone’ a podobną do Fruit Ninja firmy Halfbrick Studios przy użyciu potężnych bibliotek Cocos2d i Box2D wraz z gotowymi narzędziami.
w większości gier krojenia, gdy rysujesz linię cięcia przez sprite 'a, gra zazwyczaj konwertuje obraz sprite’ a na dwa wstępnie narysowane obrazy sprite ’ a z plasterkiem zawsze pośrodku, niezależnie od tego, gdzie faktycznie wyciąłeś.
ale ten tutorial zademonstruje jeszcze fajniejszą technikę. Nasze owoce będą mogły być cięte wielokrotnie, a ich dynamiczny podział będzie zależał od dokładnych linii cięcia!
jak można sobie wyobrazić, jest to zaawansowana technika, więc ten poradnik jest dla zaawansowanych programistów Cocos2d i Box2D. Jeśli jesteś nowy w Cocos2D lub Box2D, powinieneś najpierw przejść (przynajmniej) wprowadzenie do cocos2d i wprowadzenie do samouczków Box2D, zanim przejdziesz do tego samouczka.
ta seria poradników jest podzielona na trzy części:
- w pierwszej części serii położysz podwaliny pod grę i nauczysz się tworzyć teksturowane wielokąty.
- druga część pokaże Ci, jak pokroić & dzielenie tych teksturowanych wielokątów.
- trzecia część pokaże Ci, jak przekształcić to w kompletną grę, dodając rozgrywkę i efekty.
chciałbym szczególnie podziękować Rickowi Smorawskiemu za położenie fundamentów pod projekt, na którym opiera się ten poradnik. Był odpowiedzialny za przeportowanie tego opartego na flashu demo do cocos2d, a także za portowanie CCBlade i PRKit do Cocos2D 2.0.
Czytaj Dalej, aby sprawdzić film z tego, co zrobisz i zacząć uczyć się nowych, fajnych technik!
Demo gry
oto film demonstracyjny pokazujący, co zrobisz w tej serii samouczków:
jak wspomniałem, zobaczysz, że efekt cięcia owoców jest naprawdę dynamiczny. Owoce są cięte dynamicznie w zależności od miejsca, w którym kroisz, a ponieważ możesz kroić przedmioty wiele razy,możesz naprawdę kroić rzeczy!
możesz zobaczyć, że zaimplementujesz również fajny efekt cięcia ścieżek, niektóre systemy cząsteczek, logikę rozgrywki i dźwięki, aby urozmaicić rzeczy.
jest wiele do omówienia – więc zaczynajmy!
pierwsze kroki: konfiguracja projektu
będziesz używać Cocos2D 2.X w tym projekcie, więc śmiało i pobierz go, jeśli jeszcze go nie masz. Pamiętaj, że możesz swobodnie korzystać z Cocos2D 1.X zamiast 2.X. Z 1.X, możesz pominąć części dotyczące konwersji PRKit i CCBlade do Cocos2D 2.X, ale pamiętaj, aby zwrócić uwagę na inne małe zmiany, które wprowadzasz do tych klas.
po pobraniu kliknij dwukrotnie tar, aby go usunąć, a następnie zainstaluj szablony za pomocą następujących poleceń w Terminalu:
cd ~/Downloads/cocos2d-iphone-2.0-beta./install-templates.sh -f -u
Uruchom Xcode i utwórz nowy projekt za pomocą iOS\cocos2d v2.x \ cocos2d iOS z szablonem Box2d i nazwij go CutCutCut.
Twój nowy projekt powinien wyglądać mniej więcej tak:
po pierwsze – powinieneś trochę wyczyścić szablon, aby dostać się do dobrego punktu wyjścia.
Otwórz HelloWorldLayer.h i usuń następujący wiersz:
CCTexture2D *spriteTexture_;// weak ref
Przełącz na HelloWorldLayer.mm i wprowadź następujące zmiany
// 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;
w tym momencie usunąłeś wszystkie odniesienia do PhysicsSprite z HelloWorldLayer, ale nie usuwaj jeszcze plików z projektu. Później musisz skopiować metodę, która PhysicsSprite.mm zawiera gdzieś indziej, więc zostaw to na razie.
naciśnij Command + R, aby skompilować i uruchomić projekt, a powinieneś zobaczyć pusty ekran z zieloną ramką wokół niego:
pozostały kod szablonu skonfigurował rysowanie debugowania Box2D, które rysuje obramowania wokół ciał Box2D na ekranie. Widzisz cienkie zielone linie narysowane wokół ekranu? Są to ściany generowane przez domyślną metodę initPhysics dostarczoną z szablonem.
spójrz na pozostały kod szablonu, aby upewnić się, że rozumiesz, co się dzieje do tej pory – inicjalizuje świat Box2D, ustawia podłoże (zielone ramki), ustawia rysunek debugowania itp. Jest to całkiem dobry” prawie pusty ” punkt wyjścia z Box2D, na którym możemy budować.
Resource Kit
następnie Pobierz zasoby dla tego projektu i rozpakuj plik.
nie dodawaj jeszcze wszystkiego do projektu; niektóre pliki są rzeczywiście opcjonalne. Zachowaj folder pod ręką – gdy przejdziesz przez samouczek, od czasu do czasu poproszę Cię o dodanie niektórych z tych plików do projektu.
oto co znajdziesz w środku:
- obrazek w tle i garść owoców wykonanych przez Vicki oraz inne różne obrazy w folderze Images
- mix dźwięków w tle wykonany przy użyciu gomixa.w folderze Sounds
- efekty dźwiękowe wykonane za pomocą bfxr lub pobrane z freesound w folderze Sounds
- wszystkie systemy cząstek utworzone za pomocą Particle Designer w folderze Particles
- plik PLIST wygenerowany przez PhysicsEditor zawierający informacje o wierzchołkach dla owoców & klas Bomb w folderze Misc
- owoców & klas Bomb w folderze Classes
- wersje prkit i ccblade, których będziesz używać w samouczku w folderze klasy
- lista atrybucji zasobów, które są objęte licencją atrybucji w Misc folder
rysowanie teksturowanych wielokątów za pomocą PRKit
naszym celem jest cięcie spritów na wiele kawałków. Typowy CCSprite zawiera teksturę i obwiednię bez względu na kształt obrazu. To nie jest odpowiednie dla naszej gry, ponieważ znajomość rzeczywistych kształtów w obrazach jest kluczowym krokiem do tworzenia sprite ’ ów, które można ciąć, krojone, i podzielić.
musisz utworzyć teksturowane wielokąty, które:
- Utwórz korespondencję między wielokątem / kształtem a obrazem (mapowanie tekstur)
- Pokaż tylko te części obrazu, które znajdują się w granicach wielokąta (wypełnianie tekstur)
ani Cocos2d, ani Box2D nie mają wbudowanej klasy, która obsługuje niestandardowe funkcje, które chcesz, i normalnie zajęłoby to trochę triangulacji w połączeniu z niestandardowym kodem rysowania OpenGL.
brzmi ciężko, prawda?
na szczęście wszystkie skomplikowane obliczenia i Kod rysunkowy potrzebny do osiągnięcia tego celu zostały już napisane przez dobrych ludzi z Prekognitive Research. Stworzyli dodatek do biblioteki Cocos2d o nazwie PRKit, który Obsługuje mapowanie tekstur i wypełnianie.
aby rozpocząć pracę z teksturowanymi wielokątami, Pobierz PRKit, rozpakuj go i przeciągnij folder PRKit do swojego projektu. Upewnij się, że zaznaczono opcję „Kopiuj elementy do folderu grupy docelowej” i wybrano opcję „Utwórz grupy dla dodanych folderów”.
zauważ, że PRKit jest utrzymywany przez badania Prekognitywne, więc może zostać zaktualizowany na czas. Aby uniknąć nieporozumień, nasz zestaw zasobów zawiera również dokładną wersję PRKit użyłem w tworzeniu tego samouczka.
Twój projekt powinien teraz zawierać te pliki:
Skompiluj i uruchom, a napotkasz kilka błędów:
pojawiają się błędy, ponieważ PRKit został wykonany dla Cocos2D 1.X, który używa OpenGL ES 1.1, podczas gdy ty używasz Cocos2D 2.X, który używa OpenGL ES 2.0, i istnieją znaczne różnice między nimi.
aby to naprawić, otwórz PRFilledPolygon.m i wprowadzić te zmiany:
// 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);}
omówmy te zmiany krok po kroku.
po pierwsze, w Cocos2D każdy CCNode ma dołączony do niego program shader OpenGL ES 2.0. Aby narysować PRFilledPolygon, musisz pozwać wbudowany moduł cieniujący „Position / Texture”, który przypisujesz w metodzie init.
następnie musisz ustawić poprawne współrzędne tekstury dla każdego punktu wielokąta. Aby to zrobić, musisz wprowadzić dwie zmiany w metodzie calculateTextureCoordinates:
- Skala: ponieważ ta klasa wykonuje własne obliczenia na współrzędnych swojej tekstury, nie obsługuje automatycznie wyświetlacza siatkówki. Aby to naprawić, wystarczy pomnożyć teksturę.pixelsWide z CC_CONTENT_SCALE_FACTOR-wygodna wartość mnożnika dostarczana przez Cocos2D do konwersji wartości między równoważnikami regularnymi i retina.
- Flip Y: Z jakiegoś powodu PRFIlledPolygon rysuje tekstury do góry nogami, więc po prostu odwracasz tutaj wartość y.
ostatni, kod rysunku jest aktualizowany do OpenGL ES 2.0, w podobny sposób jak zmienił się rysunek CCSprite z Cocos2D 1.X do Cocos2D 2.X:
- zacznij od wywołania CC_NODE_DRAW_SETUP (), aby przygotować węzeł do rysowania.
- wywołania do glDisableClientState () i glEnableClientState () są przestarzałe i są odrzucane.
- polecenia glVertexPointer() i glTexCoordPointer() są zastępowane przez glvertexattribointer(), która teraz przyjmuje pozycję wierzchołka lub współrzędną tekstury jako pierwszą opcję.
- konfiguracja gltexenvf(), która była odpowiedzialna za powtarzanie sprite ’ a w przypadku, gdy wielokąt był większy niż tekstura, jest zastępowana przez wywołania gltexparameteri().
jeśli coś Cię myli, możesz sprawdzić nasz OpenGL ES 2.0 Dla iPhone ’ a i niestandardowego Cocos2D 2.Samouczki X Shaders, aby uzyskać więcej informacji na temat tła. Ale nie musisz się tym zbytnio martwić, ponieważ w tym momencie wszystko, co robimy, to przenoszenie klasy do pracy w Cocos2D 2.X :]
Skompiluj i uruchom, a wszystkie błędy PRKit powinny zniknąć!
czas uruchomić PRKit. Będziesz podklasować klasę Prkit PRFilledPolygon, aby utworzyć podstawową klasę PolygonSprite, która narysuje nasze owoce.
PolygonSprite opiera się na PRFilledPolygon, dołączając ciało Box2D do sprite ’ a, a także będzie zawierać inne niestandardowe zmienne i metody dla fruits w naszej implementacji gry.
przejdźmy do rzeczy. Naciśnij Command + N i utwórz nowy plik za pomocą iOS \ cocos2d v2.szablon klasy X \ CCNode. Niech będzie podklasą PRFilledPolygon i nazwij ją PolygonSprite.m.
Przełącz na PolygonSprite.h i wprowadzić następujące zmiany:
// 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;
powyższy kod deklaruje zmienne podstawowe i Metody potrzebne do utworzenia PolygonSprite. Są to:
- ciało: jest to ciało Box2D, które jest dołączone do naszego sprite ’ a. Jest on potrzebny do symulacji fizyki.
- original: Complete i plastry Sprite będą używać tej samej klasy PolygonSprite, jako takiej, rozróżnienie między tymi dwoma będzie ważne. Jeśli tak, oznacza to, że jest to niecięty lub oryginalny obiekt, który stworzyłeś, w przeciwnym razie jest to tylko kawałek całości.
- centroid: Środek wielokąta w obrazie nie zawsze będzie taki sam jak środek obrazu, dlatego warto przechowywać tę wartość.
- właściwości: wyeksponuj wszystkie zmienne za pomocą właściwości, aby inne klasy mogły mieć do nich swobodny dostęp.
- init/spriteWith*: nasze główne metody init zgodnie z tą samą konwencją nazewnictwa co Cocos2D.
- inne metody: są to metody tworzące & zajmujące się dołączonym ciałem Box2D i jego właściwościami.
- PTM_RATIO: stosunek pikseli do Metrów. Box2D potrzebuje tej wartości konwersji, ponieważ zajmuje się miernikami zamiast pikselami.
szybko przełącz się na PolygonSprite.m I zmienić jego nazwę PolygonSprite.mm. wszystkie klasy, które mieszają Objective-C (Cocos2d) i C++ (Box2D) muszą mieć rozszerzenie”. mm”, aby powiadomić kompilator o mieszanej składni.
następnie wprowadź następujące zmiany do 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;}
podobnie jak w Cocos2D, wszystkie metody spriteWith* są tylko automatycznymi odpowiednikami metod initWith*, podczas gdy initWithWorld nie ma jeszcze rzeczywistego zastosowania dla tej klasy, ale zamiast tego będzie ona używana przez podklasy PolygonSprite ’ a później.
większość zmian można znaleźć w metodach initWithFile i initwithtexture. Aby uzyskać przepływ rzeczy, tworzenie owoców będzie wywoływane w tej sekwencji:
- initWithWorld: jest to przeznaczone dla podklas PolygonSprite, więc nie robisz nic poza zwróceniem nil i zajęciem się tym później.
- initWithFile: dodaje teksturę z naszego pliku i przekazuje wszystko do initWithTexture.
- initWithTexture: nasza główna inicjalizacja. PRFilledPolygon potrzebuje tekstury i wszystkich wierzchołków wielokąta, który wypełnia. Ponieważ poprzedni krok zajmował się już częścią tekstury, ten krok obsługuje wierzchołki, zbierając je z ciała Box2D sprite ’ a. Po przekazaniu ich do PRFilledPolygon, następuje inicjalizacja wcześniej zadeklarowanych zmiennych.
- initWithPoints: wszystko, co to robi, jest zawarte w PRKit, a dobrą rzeczą jest to, że tak naprawdę nie musisz już dotykać PRKit po zaktualizowaniu jego kodu.
jeszcze w środku PolygonSprite.mm, dodaj następujące metody:
-(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);}
w powyższym kodzie najpierw przeciążasz metodę setPosition CCNode tak, że podczas aktualizacji pozycji sprite ’ a, powiązana pozycja ciała Box2D również zostanie zaktualizowana.
następnie tworzysz wygodną metodę tworzenia i definiowania ciała Box2D. Aby utworzyć ciało, musisz zdefiniować definicję ciała, obiekt ciała, kształt i definicję urządzenia. Nie są tu jeszcze przypisywane żadne prawdziwe twarde wartości, ponieważ ta metoda będzie później używana przez podklasy PolygonSprite.
jedyną rzeczą, na którą warto zwrócić uwagę, jest kategoria i maskbity. Te dwa są używane do filtrowania kolizji między obiektami w taki sposób, że jeśli bit kategorii obiektu pasuje do bitu maski innego obiektu i odwrotnie, dojdzie do kolizji między tymi dwoma obiektami. Najpierw ustawiasz je na 0, ponieważ nie chcesz, aby doszło do kolizji podczas pierwszej inicjalizacji obiektów.
na koniec definiujesz dwie metody, które po prostu zastępują categoryBits i maskBits, dzięki czemu możesz aktywować i dezaktywować kolizje naszych wielokątów.
jest jeszcze jedna rzecz do dodania 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_;}
pamiętasz, jak wspomniałem, że potrzebujesz czegoś od Physicsprite? To jest to. Wszystko to sprawia, że nasz kształt Box2D i nasz sprite są w tej samej pozycji podczas ruchu. Jest przygotowany dla nas przez Cocos2D i to czyni go jeszcze bardziej niesamowitym.
po skopiowaniu powyższego kodu możesz teraz usunąć oba Physicsprite.h i PhysicsSprite.mm z projektu, jak masz całkowicie wyeliminowane ich przydatność.
Skompiluj i uruchom, i wszystko powinno być w porządku. Na razie skończyłeś z PolygonSprite.
planowanie naszych owoców
przed utworzeniem klas dla naszych owoców, musisz być jasny na zasadach, że obrazy i ich kształty muszą przestrzegać. Ponieważ będziesz mapować nasze tekstury na pojedyncze wielokąty Box2D, musisz również przestrzegać ograniczeń wielokątów Box2D. Musisz pamiętać o dwóch rzeczach:
- wielokąty muszą być wypukłe, co oznacza, że żaden kąt wewnętrzny nie jest większy niż 180.
- wielokąty nie mogą przekraczać 8 wierzchołków.
możesz obejść to ograniczenie, jeśli pozwolisz, aby każde ciało zawierało wiele kształtów. Box2D może obsługiwać wklęsłe kształty, jeśli używasz metody triangulacji i tworzysz wklęsłe kształty z kilku trójkątów, ale to wykracza poza zakres samouczka.
aby wszystko było proste, w tym samouczku będziesz miał regułę 1 Body is to 1 Shape.
Uwaga: PhysicsEditor, narzędzie, które omówimy w dalszej części tego samouczka, zawiera kod do automatycznego triangulacji wielokątów narysowanych w zestaw wypukłych kształtów. Jednak, jak już powiedziałem, staramy się tutaj zachować prostotę, więc upewnimy się, że narysujemy nasze kształty wypukłe, więc mamy tylko jeden kształt na ciało.
spójrz na te dwa owoce:
używanie Banana nie jest dobrym pomysłem, ponieważ jest naturalnie wklęsły. Arbuz z drugiej strony jest bardzo dobry, ponieważ można zdefiniować wielokąt wypukły, który bardzo przypomina jego kształt.
gdybyś zdefiniował wielokąty zgodne z regułami Box2D dla dwóch owoców, mniej więcej skończyłbyś z tymi:
wielokąt arbuza idealnie pasuje do obrazu, podczas gdy wielokąt bananowy ma dużą pustą przestrzeń, w której obraz zakrzywia się do wewnątrz. Box2D potraktuje tę przestrzeń jako część naszego obiektu i może sprawić, że banan poczuje się nienaturalnie, gdy zderzy się z innymi obiektami lub zostanie przecięty.
nie oznacza to, że nie można używać Banana, ale raczej, że nie zaleca się używania Banana. W rzeczywistości gra, którą będziesz tworzyć w tym samouczku, użyje tego samego Banana.
Tworzenie pierwszego owocu
nadszedł czas, aby stworzyć pierwszy owoc: arbuz (przynajmniej jego kawałek).
Wracając do przebiegu procesu inicjalizacji PolygonSprite, wiesz, że initWithTexture oczekuje ciała Box2D, ale poprzedni krok, initWithFile, tego nie zapewnia.
powodem tego jest to, że musisz tworzyć i definiować ciało indywidualnie dla każdego owocu, więc będzie to pierwszy krok, initWithWorld, który tworzy ciało i ustawia wszelkie inne wartości specyficzne dla każdego owocu.
aby utworzyć nasze ciało Box2D, musisz najpierw poznać wierzchołki kształtu wielokąta, który chcesz utworzyć. Istnieją różne sposoby, aby to zrobić, ale w tym samouczku użyjesz sprytnego narzędzia o nazwie PhysicsEditor. To narzędzie jest pełne funkcji, ale będziesz go używać tylko do prowadzenia nas w uzyskiwaniu współrzędnych wierzchołków naszego wielokąta.
jeśli go nie masz, pobierz PhysicsEditor, zainstaluj go i odpal. Otrzymasz pusty projekt z 3 panelami / kolumnami.
praca z PhysicsEditor jest dość prosta. Po lewej stronie umieszczasz wszystkie obrazy, z którymi chcesz pracować. Na środku wizualnie definiujesz wielokąt dla swojego obrazu. Po prawej stronie masz parametry dla ciała.
chwyć arbuza.png z folderu Obrazy zestawu zasobów i przeciągnij go do lewego panelu. Powinieneś teraz zobaczyć arbuza na środkowym panelu.
zwiększ powiększenie znajdujące się na dole tego panelu do wygodnego poziomu, a następnie dotknij przycisku Pentagon w górnej części tego panelu, aby utworzyć trójstronny kształt wielokąta.
kliknij prawym przyciskiem myszy wielokąt i wybierz „Dodaj wierzchołek”, aż będziesz miał 5-8 wierzchołków we wszystkich. Przesuń wierzchołki wokół krawędzi arbuza, jednocześnie upewniając się, że dwie rzeczy:
- wielokąt, który tworzysz, jest wypukły.
- Wszystkie piksele arbuza znajdują się wewnątrz wielokąta.
Uwaga: Innym skrótem do rysowania kształtów jest użycie narzędzia Magiczna Różdżka PhysicsEditor. Wystarczy ustawić wysoką tolerancję (5-8), aby uzyskać około 5-8 punktów i dostosować punkty stamtąd.
Dodaj wszystkie inne owoce i obraz bomby z folderu Obrazy zestawu zasobów i zrób to samo dla nich.
powinieneś definiować kształty dla następujących obrazów:
- banan.png
- bomba.png
- png
- png
- truskawka.png
- arbuz.png
kiedy skończysz, w prawym górnym rogu zmień wartość eksportera na „Box2D generic (PLIST)” i powinieneś skończyć z czymś takim:
naciśnij „Publikuj” lub „publikuj jako”, Aby wyeksportować plik PLIST zawierający informacje o wierzchołkach. Zapisz plik jako owoce.plist.
jako przykład, owoce.plist, którego użyłeś w tym samouczku, znajduje się w folderze różne zestawu zasobów.
chcesz tylko spojrzeć na informacje zawarte w pliku PLIST, więc nie dodawaj tego pliku do swojego projektu, a raczej po prostu otwórz owoce.plist za pomocą Xcode, aby wyświetlić jego zawartość w zorganizowany sposób.
kliknij ikonę trójkąta obok „ciała”, aby rozwinąć tę sekcję, a zobaczysz listę obrazów, dla których zdefiniowałeś kształty. Musisz przewiercić się do najgłębszego poziomu, aby uzyskać wierzchołki wielokątów arbuza w ten sposób:
rozwiń arbuz/fixtures / Item 0 / polygons i powinieneś teraz zobaczyć inny element 0 tablicy typu pod polygons. Ta ostatnia tablica jest Twoim kształtem. Jeśli prawidłowo zdefiniowałeś wypukły kształt z 8 lub mniej wierzchołkami, powinieneś zobaczyć tylko jedną tablicę pod wielokątami.
jeśli widzisz więcej niż jeden, ja.e pozycja 0 tablica, Pozycja 1 tablica, itd, to znaczy, że fizyczny edytor zrobił złożony kształt, ponieważ albo zdefiniowałeś zbyt wiele wierzchołków, albo utworzyłeś wielokąt wklęsły. Jeśli tak się stanie, wróć do PhysicsEditor i popraw swój kształt.
następnie rozwiń pozycję 0 typu Array, aby zobaczyć ostateczną listę pozycji. To są Twoje wierzchołki, a wartość, którą widzisz po prawej stronie w tym formacie { liczba, liczba}, to twoje współrzędne x & y dla każdego wierzchołka.
teraz, gdy masz dokładne wartości dla wierzchołków wielokąta, możesz kontynuować tworzenie klasy arbuz.
w Xcode utwórz nowy plik za pomocą iOS \ cocos2d v2.szablon klasy X \ CCNode. Niech to będzie podklasa PolygonSprite i nazwij to arbuzem. Otwórz Arbuza.h i wprowadzić następujące zmiany:
// Add to top of file#import "PolygonSprite.h"
Przełącz na arbuza.m, Zmień nazwę na Watermelon.mm i dodać następującą metodę 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;}
w powyższym kodzie najpierw definiujesz ile wierzchołków jest, co w tym przypadku wynosi 7. Następnie tworzysz tablicę wierzchołków zawierającą wszystkie współrzędne, które właśnie widziałeś w PLIŚCIE. Te informacje są wykorzystywane do tworzenia treści przy użyciu metody wygody zdefiniowanej w PolygonSprite.
nakładasz trochę tarcia, aby kształty nie ślizgały się bez końca, a także nakładasz trochę restytucji, aby kształty nie zatrzymywały się, gdy odbijają się od siebie.
na koniec tworzysz obiekt przez wywołanie inicjalizacji superklasy i przekazujesz nazwę pliku obrazu, ciało Box2D i stwierdzasz, że jest to Oryginalny Owoc.
potrzebujesz obrazów arbuza z zestawu zasobów, więc teraz byłby dobry czas, aby po prostu dodać wszystkie zasoby graficzne potrzebne do dalszej części samouczka.
w Panelu nawigatora projektu kliknij prawym przyciskiem myszy zasoby i wybierz „Dodaj pliki do CutCutCut”. Dodaj folder Obrazy z zestawu zasobów do projektu. Upewnij się, że zaznaczono opcję „Kopiuj elementy do folderu grupy docelowej” i wybrano opcję „Utwórz grupy dla dodanych folderów”.
wykonaj te same kroki, aby stworzyć Banana, Winogrona, ananasa, truskawkę i bombę.
zajmujesz się tylko tym, jak krok po kroku stworzyć pierwszy owoc, ponieważ jest to w zasadzie proces płukania &dla każdego owocu. Zestaw zasobów zawiera gotowe klasy fruit i bomb w folderze Classes, które możesz przejrzeć, jeśli nadal potrzebujesz wskazówek, lub możesz dodać je wszystkie do swojego projektu, jeśli chcesz pominąć ten krok.
Skompiluj i uruchom, i upewnij się, że wszystko jest w porządku.
dodawanie owocu do sceny
do tej pory nic nie działo się na ekranie, a ty oczywiście swędzisz, aby zobaczyć owoce swojej pracy-kalambur! :]
Przełącz na HelloWorldLayer.h i wprowadzić następujące zmiany:
// Add to top of file#import "PolygonSprite.h"// Add inside the @interfaceCCArray *_cache;// Add after the @interface@property(nonatomic,retain)CCArray *cache;
Przełącz z powrotem do HelloWorldLayer.mm i wprowadzić te zmiany:
// 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]; ; ; ;}
deklarujesz tablicę pamięci podręcznej, która pomieści wszystkie owoce i bomby, które stworzysz w przyszłości. Następnie tworzysz 1 arbuza i dodajesz go do sceny. Wywołujesz aktywnekoleje, aby arbuz nie przechodził przez ściany.
Skompiluj i uruchom, a powinieneś zobaczyć arbuza spadającego ze środkowego obszaru ekranu i lądującego na dole, jak pokazano poniżej.
możesz zauważyć, że arbuz nie jest dokładnie w centrum. Powodem tego jest to, że obiekt został umieszczony w oparciu o jego ciało Box2D, a pochodzenie naszego ciała Box2D znajduje się w lewym dolnym rogu obiektu. Cienki kontur wokół arbuza jest widoczny, ponieważ tryb rysowania debugowania jest nadal włączony.
Dokąd Się Udać?
oto przykładowy projekt z całym kodem z powyższego samouczka.
to tyle w pierwszej części serii. Do tej pory masz teksturowany wielokąt arbuza, który po prostu spada na dół ekranu.
ale zamiast rysowania prostokątnego sprite ’ a z przezroczystą spacją, jak zwykle widzisz w samouczkach Box2D, używa To PRKit do rysowania tylko części tekstury, które odpowiadają wierzchołkom ciała Box2D. To się wkrótce przyda!
teraz jesteś gotowy na drugą część samouczka, w której dodajesz możliwość krojenia owoców!
w międzyczasie, jeśli masz jakieś pytania lub uwagi dotyczące tej części, dołącz do dyskusji na forum poniżej!
to jest post Przez IOS samouczek członek zespołu Allen Tan, iOS developer i współzałożyciel w White Widget. Można go również znaleźć na Google+ i Twitterze.
raywenderlich.com tygodniowe
raywenderlich.com newsletter to najprostszy sposób, aby być na bieżąco ze wszystkim, co musisz wiedzieć jako programista mobilny.
Otrzymuj cotygodniowy przegląd naszych samouczków i kursów, a otrzymasz darmowy pogłębiony kurs e-mail jako bonus!