20
2012
Cocos2D: Facciamo saltare uno sprite
Vediamo come far saltare e atterrare uno sprite utilizzando Cocos2D senza la gravità che potrebbe mettere a disposizione Box2D e con un controllo di salto variabile.
Per questo tutorial utilizziamo delle free art realizzate da Vika Wenderlich.
Obbiettivo
Realizzare un personaggio che corre con animazione e che al tocco effettua un salta con cambio di immagine e atterra sullo stesso asse.
Iniziamo con le texture
Primo passo è quello di creare una texture, per fare questo possiamo utilizzare l’ottimo strumento Texture Packer, che farà gran parte del lavoro per noi in automatico, oppure Zwoptex che è gratuito e un po’ più spartano.

LA soluzione più semplice in questo caso se si è un po’ pigri è quella di scaricare la texture già preparata per voi.
Download monkey texture
Loggati per scaricare il fileImportiamo la nostra texture e il file .plist, che avete generato (oppure scaricato), all’interno della cartella resource del nostro progetto.
Creiamo il codice
Apriamo il file HelloWorldLayer.h e all’interno dell’interfaccia (@interface) aggiungiamo quanto segue:
@interface HelloWorldLayer : CCLayer { CGSize winSize; CCSpriteBatchNode *batchNode; CCSprite *monkey; CCAction *runAction; CGPoint monkeyRunningPosition; CGPoint jumpVelocity; NSMutableArray *runAnimFrames; BOOL isJumping; }
CCSpriteBatchNode viene utilizzato quando si ha a che fare con le texture. *batchNode, che è la variabile può far riferimento solo ad una Texture
monkeyRunningPosition determinerà la posizione del nostro sprite.
JumpVelocity determinerà il punto del posizionamento del nostro sprite.
runAction la utilizziamo per creare le nostre azioni.
runAnimFrames è un array che conterrà l’animazione
isJumping controllerà se è in corso o meno un salto.
ora aggiungiamo le property, senza queste non potremmo passare i valori in self, che vedremo più avanti
@property (nonatomic, retain) CCSprite *monkey; @property (nonatomic, retain) CCAction *runAction; @property CGPoint monkeyRunningPosition; @property CGPoint jumpVelocity; @property BOOL isJumping;
Le property vanno aggiunte subito prima della fine del codice @end
Spostiamoci ora sul file HelloWorldLayer.m
La prima cosa da fare è quella di sintetizzare tutte le property, in un unica riga divisi da una virgola subito sotto @implement come vediamo
// HelloWorldLayer implementation @implementation HelloWorldLayer @synthesize monkey, runAction, monkeyRunningPosition, jumpVelocity, isJumping;
Ora divertiamoci con nuove cose.
Aggiungiamo delle costanti con la parola chiave #define
#define kJumpHigh 33 #define kJumpShort 13 #define kGravityFactor -1
Definiamo in questo modo:
l’altezza massima del salto 33
l’altezza minima del salto 13
e la gravità -1
iniziamo ad aggiungere i metodi
Partiamo dal touch
-(void) registerWithTouchDispatcher { [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; } - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { if (isJumping == NO) { isJumping = YES; jumpVelocity = ccp(0, kJumpHigh); [self schedule:@selector(jump:) interval:(1.0 / 60.0)]; } return YES; } - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { if (jumpVelocity.y > kJumpShort) { jumpVelocity = ccp(0, kJumpShort); } }
registerWithTouchDispatcher è una funzione pubblica della classe CCLayer
Se isTouchEnabled è attivo questo metodo viene chiamato ed esegue un ovveraide in modo da cambiare la ricezione degli eventi di CCLayer.
Quando premeremo lo schermo per far saltare la nostra scimmia entreremo all’interno del metodo (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event.
Began in inglese significa inizio, è quindi il primo metodo che viene cercato nel codice quando premiamo lo schermo, se questo non ci fosse andrebbe a cercare il successivo. ma concentriamo su Began dato che lo abbiamo.
Controlla se Jumping è uguale a NO e quindi se lo è entra all’interno del blocco.
Questo controllo serve per non aver salti continui, omettendolo potremmo fare altri salti in volo.
Quindi una volta entrati nel blocco cambia la variabile in YES, e la terrà per tutta la durata del salto.
Posiziona lo sprite tenendolo fermo al punto di partenza nell’asse X mentre nell’asse Y lo porta in alto usando come valore la costante predefinita in precedenza.
l’ultima riga richiama il metodo jump che non l’abbiamo ancora scritto, e gli chiede di aggiornarsi continuamente ad un intervallo di un secondo diviso per 60.
l’ultimo metodo di questa parte: – (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
controlla se al rilascio dello schermo la posizione del salto è inferiore alla costante del salto corto, se lo è e quindi risulta vera gli farà fare un salto più corto ma non meno di quello definito in precedenza.
Creiamo lo sprite
-(void)createMonkey{ batchNode = [CCSpriteBatchNode batchNodeWithFile:@"monkey.png"]; [self addChild:batchNode]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"monkey.plist"]; //gather list of frames runAnimFrames = [NSMutableArray array]; for(int i = 1; i <= 2; ++i) { [runAnimFrames addObject: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: [NSString stringWithFormat:@"monkey_walk_right_%d.png", i]]]; } //create sprite and run the hero self.monkey = [CCSprite spriteWithSpriteFrameName:@"monkey_walk_right_2.png"]; // monkey.anchorPoint = CGPointZero; monkey.position = self.monkeyRunningPosition; //create the animation object CCAnimation *runAnim = [CCAnimation animationWithFrames:runAnimFrames delay:0.1f]; self.runAction = [CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:runAnim restoreOriginalFrame:YES]]; [monkey runAction:runAction]; [batchNode addChild:monkey z:1]; }
Gran parte di questo codice lo abbiamo già affrontato in altri tutorial dove parlavamo di texture e di animazioni quindi c’è poco da dire se non che qualcosa di diverso e strano lo abbiamo:
self.monkey = [CCSprite spriteWithSpriteFrameName:@"monkey_walk_right_2.png"]; monkey.position = self.monkeyRunningPosition; self.runAction = [CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:runAnim restoreOriginalFrame:YES]];
Sono tutti self perché?
Questo perché ci sono dei passaggi di valori tra un metodo e l’altro, per questo motivo abbiamo creato le @property in precedenza.
la prima riga crea uno sprite iniziale che poi verra preso il posto dall’animazione, ma più avanti quando faremo saltare lo sprite cambieremo nuovamente immagine andando aggiungere alla cache la nuova immagine e
la seconda riga invece non da una posizione, questo perché la prenderà nel metodo init e anche qui abbiamo una posizione che cambierà quando salterà il nostro personaggio.
ultima è l’action, questa dovrà fermarsi e poi ripartire.
insomma sono tutte cose che si devono fermare nel momento del salto e cambiare valori per poi riprendere e dato che non è un metodo che continuerà ad andare perché non ha un deltaTime e non fa parte di un update questa è la soluzione con grande risparmio di energia da parte del device.
Finalmente il salto
-(void)changeImageDuringJump { [monkey setTextureRect:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"monkey_jump_right.png"].rect]; } -(void)jump:(ccTime)delta { if (isJumping == YES) { if (jumpVelocity.y < 0 && monkey.position.y > monkeyRunningPosition.y && monkey.position.y < monkeyRunningPosition.y + monkey.textureRect.size.height) { monkey.position = monkeyRunningPosition; [self unschedule:@selector(jump:)]; isJumping = NO; //NSLog(@"run action."); if (monkey.position.y <= monkeyRunningPosition.y) [monkey runAction:runAction]; } else { jumpVelocity = ccpAdd(jumpVelocity, ccp(0,kGravityFactor)); monkey.position = ccpAdd(monkey.position, jumpVelocity); //cambia l'immagine del salto [monkey stopAllActions]; [self changeImageDuringJump]; } } }
Il primo metodo cambia l’immagine durante il salto, ma concentriamoci di più sul metodo Jump.
è un metodo deltaTime questo perché come abbiamo visto in precedenza nel metodo CCTouchBegan se lo schermo è toccato chiamerà il metodo più volte nel corso di un solo secondo.
Controlla per prima cosa se isJumping il nostro valore BOOLEANO è ancora vero e se lo è entra. (durante tutto il salto rimarrà vero )
Poi controlla se il jumpVelocity è minore di zero e la posizione nuova con quella vecchia, quindi se non siamo più in fase di decollo resetta tutto come l’inizio, riportando l’immagine alla posizione di partenza (monkeyRunningPosition) togliendo la schedulazione di Jump e riattivando le action, se invece il controllo di flusso risultasse falso allo andremmo a saltare cambiando il posizionamento del nostro sprite, fermando tutte le azioni presenti nel codice e richiamando il metodo per cambiare l’immagine.
Per quanto riguarda ccpAdd invece preferisco creare un nuovo articolo in appunti di programmazione per spiegare meglio il concetto.
Il metodo init
-(id) init { // always call "super" init // Apple recommends to re-assign "self" with the "super" return value if( (self=[super init])) { self.isTouchEnabled = YES; isJumping = NO; winSize = [CCDirector sharedDirector].winSize; monkeyRunningPosition = ccp(winSize.width / 2, 150); [self createMonkey]; } return self; }
Attivato il touch impostato il valore BOOLEANO isJump su NO, in quanto non deve saltare, diamo la posizione al nostro sprite quando non è in fase di salto, in questa variabile monkeyRunningPosition che è globale e infine chiamiamo il metodo che crea il nostro sprite.
dealloc
- (void) dealloc { // in case you have something to dealloc, do it in this method // in this particular example nothing needs to be released. // cocos2d will automatically release all the children (Label) // don't forget to call "super dealloc" self.monkey = nil; self.runAction = nil; [self.monkey release]; [self.runAction release]; [super dealloc]; }
ultima parte di codice la utilizziamo per liberare la memoria.
Ultimi passi
Dato che abbiamo utilizzato delle immagini di grandi dimensioni prese dal blog di Vika Wenderlich senza modificarle utilizziamo come simulatore l’iPad, quindi andate su target e modificate il device da iPhone ad iPad.
Nota: Se volete rimpicciolire le immagini per testare questo tutorial su un iPhone stai ben attento di modificare la costante del salto alto perché 33 risulterebbe troppo.
Puoi ora provare la tua applicazione.
Continuo del tutorial
Nel prossimo tutorial implementeremo uno sfondo scorrevole in modo da dare alla nostra scimmia un effetto di salto in lungo e non statico come può risultare ora.
Download Scarica il progetto completo
Loggati per scaricare il fileArticoli correlati
13 Commenti + Aggiungi commento
Log In
Articoli In Evidenza
Commenti recenti
- Zaen su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Gabriele Carbonai su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Gabriele Carbonai su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Zaen su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Zaen su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Zaen su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Gabriele Carbonai su Cocos2D: Creare un menu con effetti di animazione e di transizione
- Zaen su Cocos2D: Creare un menu con effetti di animazione e di transizione
Categorie
- Applicazioni utenti (5)
- Appunti di programmazione (9)
- box2D (21)
- cocos2D (44)
- Contest (3)
- Corona SDK (3)
- Developer Software (4)
- news (18)
- objective-c (2)
- open source (6)
- Problemi da sviluppatore (3)
- Video tutorial (19)




Articolo scritto da Gabriele Carbonai


























Innanzitutto complimenti per il tutorial :)
Ma volevo chiarire una cosa, lo sprite una volta che ha saltato, se lo tieni premuto un po, torna giù normalmente, se premi appena salta giustamente di meno ma non torna giù regolarmente.
vorrei chiarire questa cosa perché mi è indispensabile per il progetto che sto attuando.
Grazie Mille.
rivedi bene il tutto perché io l’ho testato e non ho notato questo difetto..
hai provato a scaricare il file del progetto?
fa difetto anche li?
riprovato e nessun difetto…
Io ho scaricato il progetto e mi fa questo bug…
dove lo testi? usi il simulatore? se si quale?
.Apro il progetto
.Faccio partire il simulatore iPad 5.0 Simulator
.Provo a fare il salto premendo appena e lo sprite salta in alto al minimo che è settato a 13
ma quando torna giù, sembra una cosa innaturale come posso spiegarti.. va troppo veloce.
ho capito e notato questo difetto.
succede perché il salto è breve e la caduta non è veloce… lo fa anche se fai il salto alto, solo che l’occhio non riesce a percepirlo, è un difetto di animazione, ma se ci inserisci uno sfondo parallelo in movimento questa sbavatura non si dovrebbe notare.
se non sbaglio lo spiegherai nel prossimo tutorial lo sfondo parallelo giusto?
non sbagli
ma se invece di scrivere articoli facessi un video? perchè per chi è alle prime armi è parecchio complicato seguire le indicazioni scritte mentre in un video è molto più facile :D comunque complimenti per tutti i tutorial svolti :D
bè per chi è agli inizi magari parte dai primi tutorial che sono più semplici :)
oppure se vuole i video tutorial può andare nella sezione dei video tutorial che trovi in alto nel menu…
i videotutorial li ho seguiti tutti senza problemi… è per quello che ti ho chiesto se potevi fare dei video :D comunque seguirò il tuo consiglio e partirò dai primi tutorial ;)
Ciao, potresti gentilmente spiegarmi meglio cosa sono le property? Grazie mille! :)