Nelle due precedenti lezioni del nostro corso di programmazione videogame con cocos2d abbiamo analizzato le principali classi che compongono un videogioco realizzato con questo framework, in questa lezione proseguiremo il discorso iniziato creando il primo esempio pratico: realizzeremo la prima bozza di un videogioco.
E’ chiaro che per questo primo esempio non avremo molte pretese, il nostro gioco sarà infatti ridotto all’osso: sarà composto da una singola scena e avrà un unico (e solo sigh) personaggio che andrà in giro su è giù per il nostro schermo, comandato dal nostro fantastico primo joystick. Ok ok, vita piuttosto monotona per il nostro personaggio, ma da qualche parte dobbiamo pur iniziare, no? Eh allora bando alle ciance. Avviamo XCode, creiamo un nuovo progetto di tipo cocos2s e chiamiamolo “Stickman”.
Salviamo il progetto in una cartella di nostro gradimento e fermiamoci ad esaminare il codice generato.
Come abbiamo già visto si tratta di un progetto completo, avviabile e già dotato di una scena e un layer. Non vogliamo però continuare ad utilizzare il nome “helloworldLayer” nel nostro progetto, abbiamo quindi due possibilità:
- possiamo cancellare completamente la classe (ricordandoci di eliminare anche la riga
#import "HelloWorldLayer.h"
nel file AppDelegate.m - oppure possiamo ricorrere ad una comoda scorciatoia chiamata “refactoring”.
Il refactoring (wikipedia) è una operazione in cui si modifica il codice sorgente per migliorarlo senza modificarne il comportamento finale (altrimenti si chiamerebbe debugging!). In questo caso possiamo quindi cambiare il nome di questa classe e tutti i riferimenti cliccando semplicemente con il tasto destro del mouse (o se preferite tramite la combinazione “ctrl + click”) sulla parola “HelloWorldLayer” della riga @interface HelloWorldLayer : CCLayer
all’interno del file HelloWorldLayer.h e scegliendo la voce “refactor->renane”.
Diamogli quindi un nome più significativo come “BackgroundLayer”. Assicuriamoci di aver messo il segno di spunta su “rename related files” e clicchiamo su “preview”. Tutto corretto? Allora clicchiamo su “Save”.
Un approfondimento per i curiosi
Non paragoniamo quello che abbiamo appena fatto con una forma evoluta di un semplice “trova e sostituisci”. Il refactoring è quasi una scienza ed entra spesso in campo nelle strategie di sviluppo del software, esistono interi libri (qui un esempio) sull’argomento e XCode fornisce un eccellente supporto alle tecniche di refactoring più comuni, come il rename che abbiamo appena visto e altre come extract (avete mai avuto voglia di mettere quelle 30 righe di codice in un metodo separato? provate extract e poi commentate sul forum il risultato!). Per avere una lista più o meno completa delle tecniche di refactoring potete consultare il sito del guru Martin Fowler.
Una volta effettuato il refactoring della classe dobbiamo modificarne il metodo init, perché questo livello servirà solo per visualizzare l’immagine di sfondo. Modifichiamo quindi il metodo con questo codice:
-(id)init {
self = [super init];
if (self != nil) {
CCSprite *backgroundImage;
backgroundImage = [CCSprite spriteWithFile:@"background.png"];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
[backgroundImage setPosition: CGPointMake(screenSize.width/2, screenSize.height/2)];
[self addChild:backgroundImage z:0 tag:0];
}
return self;
}
Il codice che ho riportato dovrebbe esservi familiare, abbiamo creato una sprite usando l’immagine background.png e l’abbiamo posizionata al centro dello schermo, successivamente l’abbiamo aggiunta al layer.
Potete scaricare le due immagini per il background da qui: [background.png] e [background-hd.png]. Sono due perché così come avviene per le immagini @2x dell’UIKit possiamo aggiungere il suffisso -hd alle immagini per far sì che vengano utilizzate automaticamente sui device dotati di retina display.
Il livello dei personaggi
Una volta creato il livello dello sfondo passiamo al livello dove si muoverà il nostro personaggio. Va fatta una precisazione: la suddivisione in layer è arbitraria e del tutto non obbligatoria, avremmo potuto infatti tenere tutto nello stesso livello, ma un pizzico di buon senso ci suggerisce di mantenere un’ordinata separazione dei ruoli.
Aggiungiamo quindi un nuovo file, selezioniamo il tipo cocos2d – CCNode Class, subclass di CCLayer e chiamiamolo “StickLayer”.
Aggiungiamo una variabile di istanza modificando l’header (.h) della classe in questo modo:
#import
#import "cocos2d.h"
@interface StickLayer : CCLayer {
CCSprite *stickMan;
}
@end
Aggiungiamo ora il metodo -(id)init nel file di implementazione (.m)
Potete scaricare le due immagini da qui:
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize; // 1
stickMan = [CCSprite spriteWithFile:@"sprite_run0.png"];// 2
[stickMan setPosition: CGPointMake(screenSize.width/2, 72.5)]; //3
[self addChild:stickMan]; // 4
}
return self;
}
Anche questo codice non presenta particolari novità se non alla riga //3, dove posizioniamo la nostra sprite. ho inserito 72.5 come parametro dell’altezza perché la sprite è alta 55 pixel, la barra che simula il pavimento è alta 45 quindi (45 + (55 / 2) = 72.5. In questo modo la prite sembrerà appoggiata sul pavimento.
Un altro approfondimento per i curiosi
Più che per i curiosi questo approfondimento è per chi vuole migliorare il proprio stile di programmazione. Il valore 72.5 che abbiamo inserito nel codice sarebbe stato definito da Kernighan “a magic number” (vedi: book). Magico in quanto non c’è nel codice spiegazione del perché si sia scelto quel valore e non un altro, sappiamo solo che quel 72.5 “magicamente” funziona.
Chiaramente tutto questo non fa bene alla leggibiltià del codice! Se un’altro programmatore dovesse vedere quella riga di codice non potrebbe comprendere il ragionamento che ci sta dietro.
Esistono diverse possibiltià per rendere il tutto più chiaro: la prima (e più semplice) è quella di aggiungere un commento a quella riga di codice, in modo da spiegare come si è ottenuto il valore 72.5, questo però significa che dobbiamo assicurarci di tenere aggiornato anche il commento, perché se dovessimo cambiare l’immagine di sfondo o la sprite dovremmo sia cambiare il valore 72.5 che il commento stesso. Come si dice in gergo “Se il codice è in disaccordo con il commento, uno dei due è sbagliato”.
Il secondo metodo è quello di rendrere più esplicito il calcolo utilizzando delle variabili che rendano tutto più chiaro, ad esempio avremmo potuto scrivere:
float floorHeight = 45;
float spriteCenter = [stickMan boundingBox].size.height / 2;
[stickMan setPosition: CGPointMake(screenSize.width/2, floorHeight + spriteCenter)];
Anche se abbiamo aggiunto due variabili abbiamo reso il codice molto più comprensibile ed anche questa è una qualità da ricercare nei nostri programmi.
Se compilassimo in questo momento non noteremmo alcun cambiamento. Questo perché il layer StickLayer non viene mai usato, ci servirà visualizzarlo insieme al livello background.
Facciamo un passo indietro: quando abbiamo deciso di effettuare il refactoring della classe HelloWorldLayer non avevamo messo in conto che quella classe era anche responsabile di fornire una scena (CCScene) standard che veniva creata all’interno del metodo di classe +(CCScene *)scene. (ne abbiamo parlato nella precedente lezione)
Questo poteva andar bene per un gioco in cui c’è un solo layer, ma se ci sono più layer chi dovrebbe prendersi la responsabilità di creare la scena? Il primo? ll secondo?
È più corretto creare una specifica subclass di CCScene liberando così i layer da questo ingrato compito.
Aggiungiamo quindi un nuovo file ti dipo cocos2d -> CCnode Class e selezioniamo il tipo di subclass “CCNode”, perché non è presente la voce CCScene.
Possiamo modificare il contenuto dell’intestazione della classe appena generata in modo che appaia in questo modo:
#import
#import "cocos2d.h"
@interface Game0Scene : CCScene {
}
@end
e così l’implementazione:
#import "Game0Scene.h"
#import"BackgroundLayer.h"
#import"StickLayer.h"
@implementation Game0Scene
-(id)init {
self = [super init];
if (self != nil) {
BackgroundLayer *backgroundLayer = [BackgroundLayer node]; // 1
[self addChild:backgroundLayer z:0];
StickLayer *sticklayer = [StickLayer node];
[self addChild:sticklayer z:5];
}
return self;
}
@end
Che cosa facciamo in questa classe? Niente che non abbiate già visto: semplicemente allochiamo due layer (BackgroundLayer e StickLayer) e li aggiungiamo alla scena corrente.
Dobbiamo modificare adesso il file AppDelegate.h in modo da far caricare questa scena e non più quella generata dal layer, aggiungiamo quindi un:
#import "Game0Scene.h"
e sostituiamo la riga:
[[CCDirector sharedDirector] runWithScene: [BackgroundLayer scene]];
con questa:
[[CCDirector sharedDirector] runWithScene: [Game0Scene node]];
Se tutto è andato secondo i piani dovreste poter compilare e vedere l’interfaccia di questo nostro “gioco”:
Carino, no?
Certo sarebbe più bello se magari tutto fosse corredato da un pizzico di interattività! Perché allora non aggiungere un bel joystick da utilizzare per muovere il personaggio? Bella idea, facciamolo!
Possiamo, a tal fine, sfruttare il progetto SneakyJoystick che troviamo a questo indirizzo: https://github.com/cjhanson/SneakyJoystick. Per comodità eccovi un file zip con tutte le classi che dovete copiare all’interno del vostro progetto. [FILE ZIP]
Per semplicità aggiungeremo il joystick nello stesso livello del personaggio, così sarà più facile gestirne i movimenti.
Selezioniamo quindi il file StickLayer.h e modifichiamolo in questo modo:
#import
#import "cocos2d.h"
#import "SneakyJoystick.h" //1
#import "SneakyJoystickSkinnedBase.h" //2
@interface StickLayer : CCLayer {
CCSprite *stickMan;
SneakyJoystick *leftJoystick; //3
}
@end
Abbiamo aggiunto le righe //1 //2 e //3 con cui importiamo le classi che ci servono e per dichiarare una variabile di istanza di tipo SneakyJoystick.
Nel file StickLayer.m aggiungiamo ora un metodo che ci servirà per configurare il joystick:
-(void)initJoystick{
SneakyJoystickSkinnedBase *joystickBase = [[[SneakyJoystickSkinnedBase alloc] init] autorelease]; //1
joystickBase.position = ccp(50,50); //2
joystickBase.backgroundSprite = [CCSprite spriteWithFile:@"dpadDown.png"]; //3
joystickBase.thumbSprite = [CCSprite spriteWithFile:@"joystickCenter.png"]; //4
joystickBase.joystick = [[SneakyJoystick alloc] initWithRect:CGRectMake(0, 0, 128.0f, 128.0f)]; //5
leftJoystick = joystickBase.joystick; //6
[self addChild:joystickBase]; //7
}
Analizziamo il codice:
#1 Allochiamo e inizializziamo un oggetto di tipo SneakyJoystickSkinnedBase
#2 ne impostiamo la posizione nell’angolo in basso a sinistra
#3 ne impostiamo l’immagine di sfondo
#4 impostiamo l’immagine della parte centrale del joystick
#5 Allochiamo e inizializziamo un oggetto di tipo SneakyJoystik di 128 pixel per 128 pixel.
#6 Impostiamo la variabile di istanza all’oggetto appena creato
#7 Aggiungiamo al layer corrente il joystick
Modifichiamo il metodo init di questa stessa classe per richiamare il metodo che abbiamo appena scritto e per aggiungere una nuova istruzione:
-(id)init {
self = [super init];
if (self != nil) {
CGSize screenSize = [CCDirector sharedDirector].winSize;
stickMan = [CCSprite spriteWithFile:@"sprite_run0.png"];
[stickMan setPosition: CGPointMake(screenSize.width/2, 72.5 )];
[self addChild:stickMan];
[self initJoystick]; //1
[self scheduleUpdate]; //2
}
return self;
}
Le righe aggiunte sono la //1 e la //2. Vediamole nel dettaglio.
La //1 richiama il metodo per la configurazione del joystick, la //2, invece, fa una cosa un pò più complessa. In pratica dichiarando quel metodo ad ogni iterazione (in questo caso 60 volte al sec) verrà invocato sulla nostra classe un metodo con questa signature:
-(void) update:(ccTime)deltaTime
Noi useremo questo metodo per esaminare il valore del joystick e spostare il nostro personaggio di conseguenza. Aggiungiamo qiundi questo metodo:
-(void) update:(ccTime)deltaTime
{
[self applyJoystick:leftJoystick toNode:stickMan forTimeDelta:deltaTime];
}
Xcode segnalerà un errore perché il metodo applyJoystick:toNode:forTimeDelta non è stato dichiarato, diamogli quindi retta ed aggiungiamolo subito:
-(void)applyJoystick:(SneakyJoystick *)aJoystick toNode:(CCNode*)tempNode forTimeDelta:(float)deltaTime
{
CGPoint scaledVelocity = ccpMult(aJoystick.velocity, 350.0f);
CGPoint newPosition = ccp(tempNode.position.x + scaledVelocity.x * deltaTime,tempNode.position.y + scaledVelocity.y * deltaTime);
[tempNode setPosition:newPosition];
}
In questo modo modifichiamo la posizione del nostro personaggino in funzione della posizione del joystick e del tempo intercorso dall’ultimo aggiornamento.
Nota: scaledVelocity serve per aumentare o diminuire la velocità con cui si sposta il personaggio, provate ad inserire valori diversi e analizzate quello che succede.
Ok, ci siamo! Proviamo a compilare il programma e, se avete seguito tutto per bene fino a qui, potrete anche voi godervi finalmente il vostro bellissimo “omino nero volante”.
Conclusioni
La lezione di oggi è stata veramente lunga e impegnativa, abbiamo affrontato gli argomenti principali di cocos2d come le scene e i layer e abbiamo imparato ad usare la classe SneakyJoystick per fornire un joystick ai nostri videogame. Nella prossima lezione vedremo come gestire al meglio le sprite.
26 Responses to “03. Realizziamo il nostro primo videogioco: muoviamo un personaggio con il joystick”
16 Luglio 2012
riccardoComplimenti grande guida….
16 Luglio 2012
CarloBella guida, ma le immagini delle sprite non ci sono!
16 Luglio 2012
03. Creiamo il primo videogioco | Corso gratuito di programmazione videogame per iPhone e iPad | Vivi Capena[…] pronto dunque? Allora non vi resta che seguire il seguente indirizzo e iniziare a sperimentare con la nuova […]
16 Luglio 2012
03. Creiamo il primo videogioco | Corso gratuito di programmazione videogame per iPhone e iPad | Tutto App[…] pronto dunque? Allora non vi resta che seguire il seguente indirizzo e iniziare a sperimentare con la nuova […]
16 Luglio 2012
AndyOttima guida
1) Manca l’immagine dello sprite
2) Nel mio file AppDelegate.h non c’è questa riga di codice: [[CCDirector sharedDirector] runWithScene: [BackgroundLayer scene]];
16 Luglio 2012
MattiaMolto interessante il vostro corso ma mancano i link alle immagini (sprite_run0.png) ed il file zip con le classi per il joystick .
Continuate così il corso è ben fatto e molto chiao
16 Luglio 2012
ignaziocmi dispiace per i file, li ho inviati in questo momento per essere caricati sul sito.
Intanto ho messo il progetto su github!
https://github.com/ignazioc/-Cocos2d.Lesson03-ExampleWithJoystick
17 Luglio 2012
RedazioneFile aggiunti, scusate il piccolo inconveniente..
17 Luglio 2012
FrancescoQuando aggiungo il metodo -(id)init nel file di implementazione (.m) mi da 9 errori, dove sbaglio?
17 Luglio 2012
andreaciao..bellissima guida..l’unica cosa che a me da in fase di build and run 3 errori nel metodo -(void) initJoystick.
in particolar modo:
Undefined symbols for architecture armv7:
“_OBJC_CLASS_$_SneakyJoystick”, referenced from:
objc-class-ref in stickManLayer.o
“_OBJC_CLASS_$_SneakyJoystickSkinnedBase”, referenced from:
objc-class-ref in stickManLayer.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
grazie mille per l’attenzione, spero possiate aiutarmi.
18 Luglio 2012
jackPer chi non trova la riga
[[CCDirector sharedDirector] runWithScene: [BackgroundLayer scene]];
La guida utilizza la versione 1.0.1 di cocos2d, non la 2.0 che non ha più quel metodo 🙂
Anch’io riscontro invece lo stesso errore del clinker riguardo al Joystick
18 Luglio 2012
Ignaziocal momento in cui è stato scritto l’articolo la 2.0 non era ancora stata rilasciata, vedremo di fare un aggiornamento.
Per il problema del joystick vi invito a scaricare il progetto completo che trovate su github, ho messo i link in un commento precedente.
18 Luglio 2012
LorenzoAnche io ho lo stesso errore/gli stessi errori di andrea, nessuna idea su come risolverlo/i??? (a parte scaricare tutto da github intendo).
19 Luglio 2012
Ignaziocassicuratevi di aver copiato all’interno del progetto le classi presenti in questo file zip http://www.devapp.it/wordpress/wp-content/uploads/2012/07/JoystickClasses.zip
oppure scaricate il progetto da github
19 Luglio 2012
LorenzoSono riuscito a risolvere spostando semplicemente i file (passandoli dalla cartella stickman dove sono AppDelegate e BackgroundLayer a quella superiore che è la cartella base del progetto dove c’è stickman.xcodeproj).
Però ho notato che le “proporzioni” della mia App sono diverse da quelle nelle immagini qui sopra (in pratica l’omino è molto più grande rispetto all’ambiente e l’indicatore del framerate è fuori schermo)! Per ora non è un gran problema, ma sarei curioso di capire il motivo di questa differenza.
26 Luglio 2012
MarcoCiao,
ho seguito il tutorial fino alla fine ma:
– anche a me, come a Lorenzo, da problemi di “proporzioni” (bkgr e pg troppo grandi e decentrati) utilizzando Game0Layer node al posto di BackgroundLayer scene (con il quale invece il backgroud lo vedo correttamente)
– inserendo le lib per il joystick da anche a me i 3 errori citati da Andrea
– provando invece ad aprire il prj scaricato da github non va proprio niente 😐 perché mi da una marea di problemi 🙁
28 Luglio 2012
Waltera me il codice nel file di implementazione StickLayer da 2 avvisi:
uno su [self initJoystick];
e il secondo nel metodo di update
questi due avvisi fanno si che a un movimento del joystick la sprite sparisca.
c’e qualcuno che può aiutarmi? grazie in anticipo.
2 Agosto 2012
MarcelloProprio così Walter,
anche io ho il tuo stesso errore. A me il joystick non appare proprio, in quanto appaiono due warning nei punti che hai detto tu: “stickLayer may not respond to initJoystick”.
Quando faccio partire il tutto il joystick come ho detto non appare e se con il mouse clicco su di un punto qualunque dello schermo, lo stickman scompare.
Ci perderò un pò di tempo su, sperando di risolvere, e nel caso ti faccio sapere!
2 Agosto 2012
MarcelloOk,
sono riuscito a farlo partire ed il tutto funziona correttamente. Poichè sono sicuro che tutti qui siano per imparare e non solo copia/incollare il codice di queste guide senza capire nulla, posterò le mie supposizioni:
– WARNING: STICKLAYER MAY NOT RESPOND TO -INITJOYSTICK
Cercando su siti come StackOverflow ho capito che questo warning appare quando un metodo non è stato dichiarato correttamente o nel punto giusto (nel nostro caso il metodo è initjoystick). Quindi cosa ho fatto, ho dichiarato initJoystick prima di init all’interno del file StickLayer.m, in questo modo:
-(void)initJoystick {
SneakyJoystickSkinnedBase *joystickBase = [[[SneakyJoystickSkinnedBase alloc] init] autorelease];
joystickBase.position = ccp(50,50);
joystickBase.thumbSprite = [CCSprite spriteWithFile:@"DPad_BG.png"];
joystickBase.joystick = [[SneakyJoystick alloc] initWithRect:CGRectMake(0, 0, 128.0f, 128.0f)];
leftJoystick = joystickBase.joystick;
[self addChild:joystickBase];
}
-(id)init {
self = [super init];
if (self != nil) {
float floorHeight = 95;
float spriteCenter = [stickMan boundingBox].size.height / 2;
CGSize screenSize = [CCDirector sharedDirector].winSize;
stickMan = [CCSprite spriteWithFile:@"sprite_run0.png"];
[stickMan setPosition:CGPointMake(screenSize.width/2, floorHeight+spriteCenter)];
[self addChild:stickMan];
[self initJoystick];
[self scheduleUpdate];
}
return self;
}
Subito dopo questo pezzo di codice ne segue un altro. Anche in questo caso ho messo prima applyJoystick di update per evitare un simile warning.
-(void)applyJoystick:(SneakyJoystick *)aJoystick toNode:(CCNode*)tempNode forTimeDelta:(float)deltaTime {
CGPoint scaledVelocity = ccpMult(aJoystick.velocity, 350.0f);
CGPoint newPosition = ccp(tempNode.position.x + scaledVelocity.x * deltaTime,tempNode.position.y + scaledVelocity.y * deltaTime);
[tempNode setPosition:newPosition];
}
-(void) update:(ccTime)deltaTime {
[self applyJoystick:leftJoystick toNode:stickMan forTimeDelta:deltaTime];
}
Questo dovrebbe risolvere il problema dello stickman che scompare al primo click del mouse dopo aver avviato il Simulator. L’unico problema è che purtroppo l’autore del post non ci ha postato le immagini del pad che apparirà in basso a sinistra! Spulciando sul github di SneakyJoystick tuttavia ho trovato un immagine decente. L’ho rimpicciolita perchè era troppo grande e l’ho caricata su questo sito. Scaricatela e mettetela nella cartella Resources del vostro progetto.
Mi raccomando a me l’immagine si chiamava DPad_BG.png ed è per questo che nel codice che ho postato più sopra risulta:
joystickBase.thumbSprite = [CCSprite spriteWithFile:@"DPad_BG.png"];
Come ultima cosa vorrei anche farvi notare che io nel codice, proprio prima di quest’ultima riga che vi ho appena postato, ho completamente rimosso la riga:
joystickBase.backgroundSprite = [CCSprite spriteWithFile:@"dpadDown.png"]; //3
che l’autore aveva scritto perchè da quello che ho capito non fa altro che far apparire una immagine sotto al joystick quando lo trasciniamo e lo spostiamo per far muovere il nostro Stickman. Non la ritenevo fortemente necessaria! 🙂
Spero di esservi stati d’aiuto e di aver detto cose sufficientemente sensate per poter risolvere i vostri problemi… 🙂
2 Agosto 2012
waltergrazie mille
6 Settembre 2012
RaFCiao,
utilizzando la versione 2.0 di cocos2d non è possibile effettuare la sostituzione della riga:
[[CCDirector sharedDirector] runWithScene: [BackgroundLayer scene]];
con
[[CCDirector sharedDirector] runWithScene: [Game0Scene node]];
È invece necessario effettuare questa modifica nel file IntroLayer.m:
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[BackgroundLayer scene] withColor:ccWHITE]];
va sostituita con:
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[Game0Scene node] withColor:ccWHITE]];
Per quanto riguarda invece il funzionamento del Joystick è necessario effettuare le seguenti modifiche nella funzione Draw in entrambi i file ColoredCircleSprite.m e ColoredSquareSprite.m:
Sostituire le seguenti 5 righe:
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisable(GL_TEXTURE_2D);
glVertexPointer(2, GL_FLOAT, 0, circleVertices_);
glColor4f(color_.r/255.0f, color_.g/255.0f, color_.b/255.0f, opacity_/255.0f);
con:
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_Color );
ed eliminare le 3 righe:
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
Io facendo queste modifiche sono riuscito a far funzionare tutto… 🙂
12 Ottobre 2012
MPowAnche io sto usando la 2.0 sono riuscito a far tutto ma non capisco se è normale che l’ omino esca dallo schermo se tengo il joistick spostato ! Io vorrei che sbattesse contro la fine dello schermo!
29 Novembre 2012
Alexqualcuno potrebbe inviarmi il progetto?
Io l’ho rifatto più e più volte ma mi da 3 errori.
Io xcode 4.5 e cocos2d 2.0
Grazie.
Mail: alexsitieregistrazioni@gmail.com
29 Novembre 2012
AlexEcco gli errori:
Undefined symbols for architecture i386:
“_OBJC_CLASS_$_SneakyJoystick”, referenced from:
objc-class-ref in StickLayer.o
“_OBJC_CLASS_$_SneakyJoystickSkinnedBase”, referenced from:
objc-class-ref in StickLayer.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
7 Gennaio 2013
MAXScusate, anche io ho riportato gli stessi errori di Alex, possibile che nessuno abbia trovato soluzione? Cmq la guida è buona anche per me.
Grazie.
Ah gli errori sono:
Undefined symbols for architecture i386:
“_OBJC_CLASS_$_SneakyJoystick”, referenced from:
objc-class-ref in StickLayer.o
“_OBJC_CLASS_$_SneakyJoystickSkinnedBase”, referenced from:
objc-class-ref in StickLayer.o
ld: symbol(s) not found for architecture i386
collect2: ld returned 1 exit status
1 Settembre 2013
GiuseppeGrandi ragazzi, vi ringrazio tantissimo per il vostro lavoro. Purtroppo sono riuscito a seguire fino a prima dell’inserimento del joystick, poi nada, non ne sono venuto a capo, mi dà gli stessi errori che qualcun altro ha già riportato 🙁
Ho Xcode aggiornato all’ultima versione (6.qualcosa) e cocos2d come da tutorial, ovvero 1.0.1