Comment Créer un Jeu Comme Fruit Ninja Avec Box2D et Cocos2D – Partie 1
Ceci est un article de Allen Tan, membre de l’équipe de Didacticiels iOS, développeur iOS et co-fondateur de White Widget. Vous pouvez également le trouver sur Google+ et Twitter.
Dans ce tutoriel, vous apprendrez à créer un jeu de découpe de sprites pour iPhone similaire à Fruit Ninja de Halfbrick Studios en utilisant les puissantes bibliothèques Cocos2D et Box2D ainsi que des outils prédéfinis.
Dans la plupart des jeux de tranchage, lorsque vous tracez une ligne de coupe à travers un sprite, le jeu convertit généralement l’image de sprite en deux images de sprite pré-dessinées avec la tranche toujours au milieu, quel que soit l’endroit où vous coupez réellement.
Mais ce tutoriel démontrera une technique encore plus cool. Nos fruits pourront être coupés plusieurs fois, et ils seront divisés dynamiquement en fonction des lignes de coupe exactes!
Comme vous pouvez l’imaginer, il s’agit d’une technique avancée, ce tutoriel est donc destiné aux développeurs avancés de Cocos2D et Box2D. Si vous êtes nouveau sur Cocos2D ou Box2D, vous devez passer (au moins) par les tutoriels d’introduction à Cocos2D et d’introduction à Box2D avant de procéder à ce tutoriel.
Cette série de tutoriels est divisée en trois parties:
- Dans cette première partie de la série, vous allez jeter les bases du jeu, et apprendre à créer des polygones texturés.
- La deuxième partie vous montrera comment couper & diviser ces polygones texturés.
- La troisième partie vous montrera comment transformer cela en un jeu complet en ajoutant du gameplay et des effets.
Je voudrais remercier tout particulièrement Rick Smorawski d’avoir jeté les bases du projet sur lequel ce tutoriel est basé. Il était responsable du portage de cette démo de tranchage basée sur flash dans Cocos2D, ainsi que du portage de CCBlade et PRKit sur Cocos2D 2.0.
Continuez à lire pour voir la vidéo de ce que vous allez faire et pour commencer à apprendre de nouvelles techniques sympas!
Démo du jeu
Voici une vidéo de démonstration vous montrant ce que vous allez faire dans cette série de tutoriels:
Comme je l’ai mentionné, vous verrez que l’effet de coupe des fruits est vraiment dynamique. Le fruit est coupé dynamiquement en fonction de l’endroit où vous coupez, et comme vous pouvez couper des objets plusieurs fois, vous pouvez vraiment couper les choses!
Vous pouvez voir que vous implémenterez également un effet de traînée de tranchage cool, des systèmes de particules, une logique de jeu et des sons pour pimenter les choses.
Il y a beaucoup à couvrir – alors commençons!
Mise en route: Configuration du projet
Vous allez utiliser Cocos2D 2.X dans ce projet, alors allez-y et téléchargez-le si vous ne l’avez pas déjà. Notez que vous êtes libre d’utiliser Cocos2D 1.X au lieu de 2.X. Avec 1.X, vous pouvez ignorer les parties sur la conversion de PRKit et CCBlade en Cocos2D 2.X, mais assurez-vous de faire attention aux autres petits changements que vous apportez à ces classes.
Après le téléchargement, double-cliquez sur le tar pour le désarchiver, puis installez les modèles avec les commandes suivantes dans le Terminal:
cd ~/Downloads/cocos2d-iphone-2.0-beta./install-templates.sh -f -u
Démarrez Xcode et créez un nouveau projet avec iOS\cocos2d v2.x\cocos2d iOS avec le modèle Box2d et nommez-le CutCutCut.
Votre nouveau projet devrait ressembler à ceci:
Tout d’abord – vous devez nettoyer un peu le modèle pour obtenir un bon point de départ.
Ouvrez HelloWorldLayer.h et supprimez la ligne suivante:
CCTexture2D *spriteTexture_;// weak ref
Passer à HelloWorldLayer.mm et apportez les modifications suivantes
// 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;
À ce stade, vous avez supprimé toutes les références à PhysicsSprite de HelloWorldLayer, mais ne supprimez pas encore les fichiers du projet. Plus tard, vous devrez copier une méthode qui PhysicsSprite.mm contient ailleurs, alors laissez-le pour l’instant.
Appuyez sur Command + R pour compiler et exécuter votre projet, et vous devriez voir un écran vide avec une bordure verte autour de celui-ci:
Le code de modèle restant a configuré le dessin de débogage Box2D, qui dessine des bordures autour des corps Box2D à l’écran. Vous voyez les fines lignes vertes tracées autour de l’écran? Ce sont les murs générés par la méthode initPhysics par défaut fournie avec le modèle.
Jetez un œil au code de modèle restant pour vous assurer de comprendre ce qui se passe jusqu’à présent – il initialise un monde Box2D, définit le sol (bordures vertes), définit le dessin de débogage, etc. C’est un très bon point de départ « presque vide » avec Box2D sur lequel nous pouvons nous appuyer à partir d’ici.
Kit de ressources
Téléchargez ensuite les ressources de ce projet et décompressez le fichier.
N’ajoutez pas tout dans le projet pour l’instant; certains fichiers sont en fait facultatifs. Gardez le dossier à portée de main – au fur et à mesure du tutoriel, je vous demanderai de temps en temps d’ajouter certains de ces fichiers dans le projet.
Voici ce que vous trouverez à l’intérieur:
- Une image d’arrière-plan et un bouquet d’art fruitier réalisé par Vicki, et d’autres images diverses dans le dossier Images
- Le mélange de son d’arrière-plan réalisé à l’aide de gomix.dans le dossier Sons
- Effets sonores réalisés à l’aide de bfxr ou téléchargés depuis freesound dans le dossier Sons
- Tous les systèmes de particules créés avec Particle Designer dans le dossier Particules
- Un fichier PLIST généré par PhysicsEditor contenant des informations de sommet pour les Fruits & classes de bombes dans le dossier Divers
- Fruits & Classes de bombes dans le dossier Classes
- Les versions de PRKit et CCBlade que vous utiliserez dans le tutoriel dans le dossier Classes
- Une liste d’attribution pour les ressources qui sont sous la licence d’attribution dans le Misc dossier
Dessin de Polygones texturés avec PRKit
Notre objectif est de couper les sprites en plusieurs morceaux. Un CCSprite typique contient une texture et une boîte englobante, quelle que soit la forme de l’image. Cela ne convient pas à notre jeu car connaître les formes réelles dans les images est une étape cruciale pour créer des sprites qui peuvent être coupés, tranchés et divisés.
Vous devez créer des polygones texturés, qui:
- Créer une correspondance entre un polygone/forme et une image (Mappage de texture)
- Afficher uniquement les parties de l’image qui se trouvent dans les limites du polygone (Remplissage de texture)
Ni Cocos2D ni Box2D ne sont livrés avec une classe intégrée qui gère les fonctionnalités personnalisées que vous souhaitez, et normalement, cela prendrait une triangulation couplée à un code de dessin OpenGL personnalisé.
Cela semble difficile non?
Heureusement, tous les calculs compliqués et le code de dessin nécessaires pour y parvenir ont déjà été écrits par les bonnes personnes de la recherche Précognitive. Ils ont créé un ajout à la bibliothèque Cocos2D nommé PRKit, qui gère le mappage et le remplissage des textures.
Pour commencer sur les polygones texturés, téléchargez PRKit, extrayez-le et faites glisser le dossier PRKit dans votre projet. Assurez-vous que « Copier les éléments dans le dossier du groupe de destination » est coché et que « Créer des groupes pour tous les dossiers ajoutés » est sélectionné.
Notez que PRKit est maintenu par une recherche précognitive, il peut donc être mis à jour à temps. Pour éviter toute confusion, notre kit de ressources contient également la version exacte de PRKit que j’ai utilisée pour créer ce tutoriel.
Votre projet devrait maintenant inclure ces fichiers:
Compilez et exécutez, et vous rencontrerez quelques erreurs:
Les erreurs apparaissent car PRKit a été créé pour Cocos2D 1.X, qui utilise OpenGL ES 1.1, alors que vous utilisez Cocos2D 2.X, qui utilise OpenGL ES 2.0, et il existe des différences significatives entre les deux.
Pour résoudre ce problème, ouvrez PRFilledPolygon.m et apporter ces modifications:
// 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);}
Passons en revue ces changements petit à petit.
Tout d’abord, dans Cocos2D, chaque CCNode a un programme de shader OpenGL ES 2.0 qui lui est attaché. Pour dessiner le PRFilledPolygon, vous devez poursuivre le shader « Position / Texture » intégré, que vous affectez dans la méthode init.
Ensuite, vous devez définir les coordonnées de texture correctes pour chaque point du polygone. Pour ce faire, vous devez effectuer deux modifications de la méthode calculateTextureCoordinates:Échelle
- : Puisque cette classe effectue ses propres calculs sur les coordonnées de sa texture, elle ne gère pas automatiquement l’affichage de la rétine. Pour résoudre ce problème, il vous suffit de multiplier la texture.pixelsWide avec CC_CONTENT_SCALE_FACTOR – une valeur multiplicatrice pratique fournie par Cocos2D pour convertir les valeurs entre les équivalents réguliers et retina.
- Flip Y: Pour une raison quelconque, PRFIlledPolygon dessine des textures à l’envers, vous suffit donc de retourner la valeur y ici.
Enfin, le code de dessin est mis à jour en OpenGL ES 2.0, de la même manière que le dessin CCSprite a changé de Cocos2D 1.X à Cocos2D 2.X:
- Commencez par appeler CC_NODE_DRAW_SETUP() pour préparer le nœud pour le dessin.
- Les appels à glDisableClientState() et glEnableClientState() sont obsolètes et sont ignorés.
- Les commandes glVertexPointer() et glTexCoordPointer() sont toutes deux remplacées par glVertexAttribPointer(), qui accepte désormais la Position du Sommet ou la Coordonnée de texture comme première option.
- La configuration de glTexEnvf(), qui était responsable de la répétition du sprite au cas où le polygone serait plus grand que la texture, est remplacée par des appels à glTexParameteri().
Si vous êtes confus par tout cela, vous voudrez peut-être consulter notre OpenGL ES 2.0 pour iPhone et notre Cocos2D 2 personnalisé.Tutoriels X Shaders pour plus d’informations de fond. Mais vous n’avez pas à vous en soucier trop, car à ce stade, tout ce que nous faisons est de porter la classe pour qu’elle fonctionne dans Cocos2D 2.X:]
Compile et exécute, et toutes les erreurs PRKit devraient disparaître !
Il est temps de mettre PRKit en action. Vous allez sous-classer la classe PRFilledPolygon de PRKit pour créer une classe PolygonSprite de base qui dessinera nos fruits.
PolygonSprite s’appuie sur PRFilledPolygon en attachant un corps Box2D au sprite, et il contiendra également d’autres variables et méthodes personnalisées pour les fruits dans notre implémentation de jeu.
Allons-y. Appuyez sur Commande + N et créez un nouveau fichier avec iOS\cocos2d v2.modèle de classe x\CCNode. Faites-en une sous-classe de PRFilledPolygon et nommez-la PolygonSprite.m.
Basculez sur PolygonSprite.h et apporter les modifications suivantes:
// 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;
Le code ci-dessus déclare les variables et méthodes de base dont vous avez besoin pour créer un PolygonSprite. Ce sont:
- corps : C’est le corps Box2D qui est attaché à notre sprite. Il est nécessaire pour la simulation physique.
- original: Les sprites complets et tranchés utiliseront la même classe PolygonSprite, en tant que telle, la différenciation entre les deux sera importante. Si c’est OUI, cela signifie que c’est l’objet non coupé ou original que vous avez créé, sinon, ce n’est qu’un morceau du tout.
- centroïde: Le centre du polygone dans l’image ne sera pas toujours le même que le centre de l’image, il est donc utile de stocker cette valeur.propriétés
- : Expose toutes les variables à l’aide de propriétés afin que les autres classes puissent y accéder librement.
- init/spriteWith* : Nos principales méthodes d’initialisation suivent la même convention de nommage que Cocos2D.
- autres méthodes : Il s’agit de méthodes créant & traitant du corps Box2D attaché et de ses propriétés.
- PTM_RATIO : Rapport Pixels/mètres. Box2D a besoin de cette valeur de conversion car elle traite des mètres au lieu des Pixels.
Passez rapidement à PolygonSprite.m et renommez-le PolygonSprite.mm . Toutes les classes qui mélangent du code Objective-C (Cocos2D) et du code C++ (Box2D) doivent avoir une extension « .mm » pour notifier au compilateur la syntaxe mixte.
Ensuite, apportez les modifications suivantes à 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;}
Similaire à Cocos2D, toutes les méthodes spriteWith* ne sont que des homologues à libération automatique des méthodes initWith*, alors que initWithWorld n’a pas encore d’utilisation réelle pour cette classe, mais elle sera utilisée par les sous-classes de PolygonSprite plus tard.
La majeure partie des modifications se trouve dans les méthodes initWithFile et initWithTexture. Pour obtenir le flux des choses, la création d’un fruit sera appelée dans cette séquence:
- initWithWorld: Ceci est destiné aux sous-classes de PolygonSprite, vous ne faites donc rien d’autre que retourner nil, et traitez-le plus tard.
- initWithFile: Cela ajoute la texture de notre fichier et transmet tout à initWithTexture.
- initWithTexture: Notre initialisation principale. PRFilledPolygon a besoin d’une texture et de tous les sommets du polygone qu’il remplit. Puisque l’étape précédente gérait déjà la partie texture, cette étape gère les sommets en les collectant à partir du corps Box2D du sprite. Après les avoir transmis à PRFilledPolygon, il initialise les variables que vous avez précédemment déclarées.
- initWithPoints: Tout ce que cela fait est contenu dans PRKit et la bonne chose est que vous n’avez plus vraiment besoin de toucher PRKit maintenant que vous avez mis à jour son code.
Toujours à l’intérieur PolygonSprite.mm , ajoutez les méthodes suivantes:
-(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);}
Dans le code ci-dessus, vous surchargez d’abord la méthode setPosition de CCNode de sorte que lorsque vous mettez à jour la position du sprite, la position du corps Box2D associé est également mise à jour.
Vous créez ensuite une méthode pratique pour créer et définir un corps Box2D. Pour créer un corps, vous devez définir une définition de corps, un objet de corps, une forme et une définition de luminaire. Aucune valeur réelle n’est encore attribuée ici car cette méthode sera utilisée par les sous-classes de PolygonSprite plus tard.
La seule chose à noter est la catégoriebits et maskBits. Ces deux sont utilisés pour filtrer les collisions entre objets de sorte que si un bit de catégorie d’un objet correspond à un bit de masque d’un autre objet et vice versa, il y aura une collision entre ces deux objets. Vous les définissez d’abord sur 0 car vous ne souhaitez pas que des collisions se produisent lorsque les objets sont initialisés pour la première fois.
Enfin, vous définissez deux méthodes qui remplacent simplement les categoryBits et maskBits afin que vous puissiez activer et désactiver les collisions de nos PolygonSprites.
Il y a encore une chose à ajouter 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_;}
Rappelez-vous quand j’ai mentionné que vous aviez besoin de quelque chose de PhysicsSprite? Eh bien, c’est ça. Tout cela permet de s’assurer que notre forme Box2D et notre sprite sont dans la même position lors du déplacement. Il est préparé pour nous par Cocos2D et cela le rend d’autant plus génial.
Après avoir copié le code ci-dessus, vous pouvez maintenant supprimer les deux PhysicsSprite.h et PhysicsSprite.mm du projet que vous avez complètement éliminé leur utilité.
Compile et exécute, et tout devrait bien se passer. Vous avez terminé avec PolygonSprite pour l’instant.
Planifier nos fruits
Avant de créer des classes pour nos fruits, vous devez être clair sur les règles que les images et leurs formes doivent suivre. Puisque vous allez mapper nos textures sur des polygones Box2D uniques, vous devez également respecter les limitations des polygones de Box2D. Vous devez garder deux choses à l’esprit:
- Les polygones doivent être convexes, ce qui signifie qu’aucun angle intérieur n’est supérieur à 180.
- Les polygones ne doivent pas dépasser 8 sommets.
Vous pouvez réellement contourner cette limitation si vous autorisez chaque corps à contenir plusieurs formes. Box2D peut gérer des formes concaves si vous utilisez une méthode de triangulation et créez des formes concaves à partir de plusieurs triangles, mais cela dépasse le cadre du tutoriel.
Pour garder les choses simples, dans ce tutoriel, vous aurez une règle de 1 Corps à 1 forme.
Remarque: PhysicsEditor, l’outil que nous couvrirons plus tard dans ce tutoriel, contient en fait du code pour trianguler automatiquement les polygones que vous dessinez dans un ensemble de formes convexes. Cependant, comme je l’ai dit, nous essayons de garder les choses simples ici, nous veillerons donc à dessiner nos formes convexes afin que nous n’ayons qu’une seule forme par corps.
Regardez ces deux fruits:
Utiliser la banane n’est pas une bonne idée car elle est naturellement concave. La pastèque en revanche est très bonne car vous pouvez définir un polygone convexe qui ressemble étroitement à sa forme.
Si vous deviez définir des formes de polygones qui suivent les règles de Box2D pour les deux fruits, vous vous retrouveriez plus ou moins avec celles-ci:
Le polygone de pastèque s’adapte parfaitement à l’image, tandis que le polygone de banane a un grand espace vide où l’image se courbe vers l’intérieur. Box2D traitera cet espace comme faisant partie de notre objet, et cela pourrait rendre la banane anormale lorsqu’elle entre en collision avec d’autres objets ou lorsqu’elle est coupée.
Cela ne signifie pas que vous ne pouvez pas utiliser la Banane, mais plutôt qu’il n’est tout simplement pas recommandé d’utiliser la banane. En fait, le jeu que vous allez créer dans ce tutoriel utilisera cette même banane.
Création du Premier Fruit
Il est temps de créer le premier fruit : la Pastèque (une tranche au moins).
En repensant au flux du processus d’initialisation de notre PolygonSprite, vous savez que initWithTexture attend un corps Box2D, mais l’étape précédente, initWithFile, ne le fournit pas.
La raison en est que vous devez créer et définir le corps individuellement par fruit, donc ce sera la toute première étape, initWithWorld, qui crée le corps et définit toutes les autres valeurs spécifiques à chaque fruit.
Pour créer notre corps Box2D, vous devez d’abord connaître les sommets de la forme du polygone que vous souhaitez créer. Il existe différentes façons de le faire, mais pour ce tutoriel, vous utiliserez un outil astucieux appelé PhysicsEditor. Cet outil est rempli de fonctionnalités, mais vous ne l’utiliserez que pour nous guider dans l’obtention des coordonnées des sommets de notre polygone.
Si vous ne l’avez pas, téléchargez PhysicsEditor, installez-le et lancez-le. Vous obtiendrez un projet vierge avec 3 panneaux / colonnes.
Travailler avec PhysicsEditor est assez simple. Sur la gauche, vous mettez toutes les images avec lesquelles vous souhaitez travailler. Au milieu, vous définissez visuellement un polygone pour votre image. Sur la droite, vous avez les paramètres pour le corps.
Prenez la pastèque.png à partir du dossier Images du kit de ressources et faites-le glisser vers le panneau de gauche. Vous devriez maintenant voir la pastèque sur le panneau central.
Augmentez le grossissement, situé en bas de ce panneau, à un niveau confortable, puis appuyez sur le bouton Pentagone situé dans la partie supérieure de ce panneau pour créer une forme de polygone à 3 côtés.
Faites un clic droit sur le polygone et choisissez « Ajouter un sommet » jusqu’à ce que vous ayez 5 à 8 sommets en tout. Déplacez les sommets autour des bords de la pastèque, tout en vous assurant de deux choses:
- Le polygone que vous créez est convexe.
- Tous les pixels de la pastèque sont à l’intérieur du polygone.
Remarque: Un autre raccourci pour dessiner les formes consiste à utiliser l’outil baguette magique de PhysicsEditor. Réglez simplement la tolérance élevée (5-8) de sorte que vous vous retrouviez avec environ 5-8 points, et ajustez les points à partir de là.
Ajoutez tous les autres fruits et l’image bombe du dossier Images du kit de ressources et faites la même chose pour eux.
Vous devez définir des formes pour les images suivantes:
- banane.png
- bombe.png
- raisins.png
- ananas.png
- fraise.png
- pastèque.png
Lorsque vous avez terminé, dans le coin supérieur droit, changez la valeur de l’exportateur en « Box2D generic (PLIST) », et vous devriez vous retrouver avec quelque chose comme ceci:
Cliquez sur « Publier » ou « Publier sous » pour exporter le fichier PLIST contenant les informations de sommet. Enregistrez le fichier en tant que fruits.plist.
À titre d’exemple, les fruits.la liste que vous avez utilisée pour ce tutoriel se trouve dans le dossier Divers du kit de ressources.
Vous voulez seulement regarder les informations contenues dans le fichier PLIST, alors n’ajoutez pas ce fichier à votre projet, mais ouvrez simplement fruits.utilisez Xcode pour afficher son contenu de manière organisée.
Cliquez sur l’icône du triangle à côté de « corps » pour développer cette section et vous verrez la liste des images pour lesquelles vous avez défini des formes. Vous devez forer jusqu’au niveau le plus profond pour obtenir les sommets du polygone de la pastèque comme ceci:
Développe watermelon/fixtures/Item 0/polygons et vous devriez maintenant voir un autre Item 0 du tableau de type sous polygones. Ce dernier tableau est votre forme. Si vous aviez correctement défini une forme convexe avec 8 sommets ou moins, vous ne devriez voir qu’un seul tableau sous les polygones.
Si vous en voyez plus d’un, je.e Tableau de l’élément 0, Tableau de l’élément 1, etc., cela signifie que PhysicsEditor a créé une forme complexe parce que vous avez défini trop de sommets ou que vous avez formé un polygone concave. Si cela se produit, retournez à PhysicsEditor et corrigez votre forme.
Ensuite, développez l’élément 0 du tableau de type pour voir la liste finale des éléments. Ce sont vos sommets, et la valeur que vous voyez sur le côté droit avec ce format {number, number} sont vos coordonnées x & y pour chaque sommet.
Maintenant que vous avez les valeurs exactes pour les sommets de votre polygone, vous pouvez procéder à la création de la classe Watermelon.
Dans Xcode, créez un nouveau fichier avec iOS\cocos2d v2.modèle de classe x\CCNode. Faites-en une sous-classe de PolygonSprite et nommez-la Pastèque. Ouvrez la pastèque.h et apporter les modifications suivantes:
// Add to top of file#import "PolygonSprite.h"
Passez à la pastèque.m, renommez-le en Watermelon.mm , et ajoutez la méthode d’initialisation suivante:
// 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;}
Dans le code ci-dessus, vous définissez d’abord le nombre de sommets, qui dans ce cas est de 7. Ensuite, vous créez un tableau de sommets contenant toutes les coordonnées que vous venez de voir dans la liste. Vous utilisez ces informations pour créer un corps en utilisant la méthode de commodité que vous avez définie dans PolygonSprite.
Vous mettez un peu de frottement pour que les formes ne glissent pas sans fin, et vous mettez également un peu de restitution pour que les formes ne s’arrêtent pas lorsqu’elles rebondissent l’une contre l’autre.
Enfin, vous créez l’objet en appelant l’initialisation de la superclasse et passez le nom du fichier image, le corps Box2D, et déclarez qu’il s’agit d’un fruit original.
Vous avez besoin des images de pastèque du kit de ressources, alors ce serait le bon moment d’ajouter simplement toutes les ressources graphiques dont vous avez besoin pour le reste du tutoriel.
Dans le panneau de navigation de votre projet, cliquez avec le bouton droit sur Ressources et sélectionnez « Ajouter des fichiers à CutCutCut ». Ajoutez le dossier Images du kit de ressources au projet. Assurez-vous que « Copier les éléments dans le dossier du groupe de destination » est coché et que « Créer des groupes pour tous les dossiers ajoutés » est sélectionné.
Suivez les mêmes étapes pour créer des Bananes, des Raisins, des Ananas, des Fraises et des Bombes.
Vous avez seulement abordé la façon de créer le premier fruit étape par étape car il s’agit essentiellement d’un processus de rinçage & répété pour chaque fruit. Le kit de ressources contient des classes de fruits et de bombes prêtes à l’emploi dans le dossier Classes que vous pouvez consulter au cas où vous auriez encore besoin de conseils, ou vous pouvez toutes les ajouter à votre projet si vous souhaitez ignorer cette étape.
Compilez et exécutez, et assurez-vous que tout va bien.
Ajout d’un Fruit à la scène
Jusqu’à présent, rien ne s’est encore passé à l’écran, et vous avez évidemment envie de voir les fruits de votre jeu de mots prévu! :]
Passez à HelloWorldLayer.h et apporter les modifications suivantes:
// Add to top of file#import "PolygonSprite.h"// Add inside the @interfaceCCArray *_cache;// Add after the @interface@property(nonatomic,retain)CCArray *cache;
Revenir à HelloWorldLayer.mm et faire ces changements:
// 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]; ; ; ;}
Vous déclarez un tableau de cache, qui contiendra tous les fruits et bombes que vous créerez à l’avenir. Ensuite, vous créez 1 pastèque et l’ajoutez à la scène. Vous appelez Activecollisions pour que la pastèque ne traverse pas les murs.
Compilez et exécutez, et vous devriez voir une pastèque tomber de la zone centrale de l’écran et atterrir en bas comme indiqué ci-dessous.
Vous remarquerez peut-être que la pastèque n’est pas exactement au centre. La raison en est que vous avez positionné l’objet en fonction de son corps Box2D, et l’origine de notre corps Box2D se trouve dans le coin inférieur gauche de l’objet. Le contour mince autour de la pastèque est visible car le mode de dessin de débogage est toujours activé.
Où Aller D’Ici ?
Voici un exemple de projet avec tout le code du tutoriel ci-dessus.
C’est tout pour la partie 1 de la série. Jusqu’à présent, vous avez un polygone texturé de pastèque qui tombe juste au bas de l’écran.
Mais au lieu de dessiner un sprite rectangulaire avec un espace transparent comme vous le voyez habituellement dans les tutoriels Box2D, cela utilise PRKit pour dessiner uniquement les parties de la texture qui correspondent aux sommets du corps Box2D. Cela vous sera bientôt utile!
Maintenant, vous êtes prêt pour la partie 2 du tutoriel, où vous ajoutez la possibilité de couper les fruits!
En attendant, si vous avez des questions ou des commentaires sur cette partie, veuillez rejoindre la discussion du forum ci-dessous!
Ceci est un article de Allen Tan, membre de l’équipe de didacticiels iOS, développeur iOS et co-fondateur de White Widget. Vous pouvez également le trouver sur Google+ et Twitter.
raywenderlich.com Hebdomadaire
Le raywenderlich.com la newsletter est le moyen le plus simple de rester à jour sur tout ce que vous devez savoir en tant que développeur mobile.
Obtenez un résumé hebdomadaire de nos tutoriels et cours, et recevez un cours par e-mail gratuit en bonus!