{"id":8146,"date":"2011-12-15T15:06:15","date_gmt":"2011-12-15T14:06:15","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=8146"},"modified":"2011-12-15T15:26:36","modified_gmt":"2011-12-15T14:26:36","slug":"t104-caemitterlayer-creiamo-un-simpatico-generatore-di-fiocchi-di-neve-con-il-nostro-iphone","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/t104-caemitterlayer-creiamo-un-simpatico-generatore-di-fiocchi-di-neve-con-il-nostro-iphone\/","title":{"rendered":"T#104 &#8211; CAEmitterLayer: Creiamo un simpatico generatore di fiocchi di neve con il nostro iPhone"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/tutorial-advanced-devAPP.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/10\/tutorial-advanced-devAPP.jpg\" alt=\"tutorial-iOS-dev-advanced-devAPP\" title=\"tutorial-advanced-devAPP\" width=\"200\" height=\"100\" class=\"alignleft size-full wp-image-7860\" \/><\/a> In questo periodo di grandi incertezze in cui lo spread altalenante sembra essere l&#8217;unico vero problema con cui confrontarsi, c&#8217;\u00e8 ancora qualcosa con cui divertirsi quando si \u00e8 stanchi la sera. No! &#8230;non \u00e8 la TV e neanche la PS3&#8230; \u00e8 la programmazione. Da sempre il periodo di Natale \u00e8 uno dei miei pi\u00f9 proficui momenti per programmare. Ricordo ancora il clima di festa e l&#8217;odore del pino, rigorosamente naturale, che si respirava a casa da giorno 8 Dicembre in poi quando ero piccolo. Ogni anno era un&#8217;attesa senza fine&#8230; ogni anno c&#8217;era un nuovo pezzo di tecnologia informatica da aggiungere alla mia collezione. Purtroppo, per\u00f2, la sete di conoscenza andava sempre pi\u00f9 veloce dei naturali periodi di rotazione della terra e cos\u00ec capitava spesso che gi\u00e0 alla met\u00e0 dell&#8217;anno appena entrato, avevo voglia\/bisogno di qualcosa di nuovo con cui giocare. Erano bei tempi.<\/p>\n<p>Da un p\u00f2 di tempo questa cosa non capita pi\u00f9, forse \u00e8 colpa dell&#8217;et\u00e0 che avanza. A voler essere sinceri, la reale motivazione sono sicuro coincide con l&#8217;essermi imbattuto in Cocoa ed Objective-C (con relativo hardware, si intende). Cos\u00ec, il periodo delle feste natalizie \u00e8 diventato una piacevole occasione per sedermi davanti al fuoco caldo del camino, giocando con qualche nuovo oggetto del framework che sino ad ora mi era passato sfuggente sotto gli occhi a causa della mancanza di tempo.<\/p>\n<p>Rilasattevi e fatevi un buon the caldo. E&#8217; il momento di scaldare il nostro MacBook. Tra qualche minuto faremo quello che qualunque buon programmatore vorrebbe edovrebbe fare in questo periodo: creare un bel generatore di fiocchi di neve. Meglio se accellerato in <strong>OpenGL<\/strong>. D&#8217;altrocanto, visto che siamo aspiranti programmatori iOS, ottempereremo al nostro dovere sfruttando il nostro dispositivo preferito. Buonalettura.<!--more--><\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre.jpg\" alt=\"banner-allertasoglie-push-tre\" title=\"banner-allertasoglie-push-tre\" width=\"550\" height=\"293\" class=\"aligncenter size-full wp-image-8150\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre.jpg 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre-300x159.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<h4>Preparazione del progetto<\/h4>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-01.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-01.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-01\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-01\" width=\"80\" height=\"120\" class=\"alignright size-full wp-image-8162\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-01.jpg 250w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-01-200x300.jpg 200w\" sizes=\"auto, (max-width: 80px) 100vw, 80px\" \/><\/a> Quello che vogliamo realizzare sar\u00e0 qualcosa di questo tipo: al tocco dello schermo, cercheremo di creare una caduta di fiocchi di neve.<\/p>\n<p>Sar\u00e0 un p\u00f2 come avere la nostra neve personale sempre a portata di mano, con cui fare divertire i nostri amici durante le feste di natale.<\/p>\n<p>Creiamo un nuovo progetto, scegliendo un template il pi\u00f9 generale possibile (Empty Application):<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-02.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-02.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-02\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-02\" width=\"550\" height=\"370\" class=\"aligncenter size-full wp-image-8154\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-02.jpg 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-02-300x201.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Chiamiamo il nostro progetto: SnowFlakes.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-03.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-03.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-03\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-03\" width=\"550\" height=\"370\" class=\"aligncenter size-full wp-image-8155\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-03.jpg 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-03-300x201.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Abbiate cura di deselezionare l&#8217;opzione ARC (Automatic Reference Counting). Il motivo per cui \u00e8 meglio deselezionarlo lo raccontiamo un&#8217;altra volta.<\/p>\n<p>Se vorrete installare l&#8217;applicativo realizzato su dispositivi o regalarlo ad amici con una IPA, date un company identifier valido al vostro applicativo. Altrimenti, potrete ignorarlo.<\/p>\n<p>Aggiungiamo un p\u00f2 di frameworks a quelli forniti in dotazione standard. Ci serviranno durante il corso del nostro applicativo. Se non sapete a che servono, non vi preoccupate. Ogni qualvolta ne useremo uno, verr\u00e0 indicato.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-04.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-04.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-04\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-04\" width=\"550\" height=\"301\" class=\"aligncenter size-full wp-image-8156\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-04.jpg 1000w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-04-300x164.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>I frameworks da aggiungere sono:<\/p>\n<ul>\n<li>AVFoundation.framework (necessario per dialogare con le API audio\/video)<\/li>\n<li>QuartzCore.framework (necessario per dialogare con CALayer)<\/li>\n<\/ul>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-05.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-05.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-05\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-05\" width=\"492\" height=\"151\" class=\"aligncenter size-full wp-image-8157\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-05.jpg 492w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-05-300x92.jpg 300w\" sizes=\"auto, (max-width: 492px) 100vw, 492px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Modifichiamo opportunamente il file di <strong>*-Prefix.pch<\/strong>. In questo modo, ci eviteremo noiosi warning ed errori da parte del compilatore ed eviteremo di dover includere gli headers necessari in ogni classe che ne necessita l&#8217;uso.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-06.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-06.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-06\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-06\" width=\"550\" height=\"204\" class=\"aligncenter size-full wp-image-8158\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-06.jpg 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-06-300x111.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<h4>La classe CAEmitterLayer<\/h4>\n<p>La classe <strong>CAEmitterLayer<\/strong> crea un emettitore di particelle <strong>CAEmitterCell<\/strong>. Queste particelle, sono disegnate attraverso il framework Quartz \/ Core Animation direttamente sul layer della UIView che ci ospita. Questo significa che qualunque oggetto che eredita da UIView, potr\u00e0 ereditare i favolosi effetti grafici che potremo creare. Molto bene, mettiamoci al lavoro.<\/p>\n<p>L&#8217;idea generale sar\u00e0 quella di creare un &#8220;contenitore&#8221; CAEmitterLayer, aggiungendogli un numero variabile di &#8220;particelle&#8221; CAEmitterCell. Ogni cella produrr\u00e0 particelle secondo la configurazione fornita. Come potete immaginare gli usi e gli scopi sono infiniti, tra cui quello dei fiocchi di neve.<\/p>\n<p>Prima di tutto dobbiamo procurarci un&#8217;istanza valida di CAEmitterLayer. Se guardiamo la documentazione Apple, ci accorgeremo che la classe CAEmitterLayer eredita direttamente da CALayer. Questo significa che qualunque oggetto che dialoga con un CALayer, potr\u00e0 essere utile per il nostro scopo. E&#8217; proprio quello che cercavamo.<\/p>\n<p>Creiamo una nuova classe che chiameremo SnowflakeParticleView e che eredita da UIView.<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-07.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-07.jpg\" alt=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-07\" title=\"CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-07\" width=\"550\" height=\"382\" class=\"aligncenter size-full wp-image-8159\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-07.jpg 743w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/CAEmitterLayer-creare-un-generatore-di-neve-per-iphone-opengl-07-300x208.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n<p>Modifichiamo l\u2019header della classe, aggiungendo una variabile d&#8217;istanza che chiameremo snowflakeEmitter ed un&#8217;altra che far\u00e0 riferimento all&#8217;istanza (singletone) del nostro AppDelegate.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import <UIKit\/UIKit.h>\r\n\r\n@class AppDelegate;\r\n\r\n@interface SnowflakeParticleView : UIView\r\n{\r\n    AppDelegate *appDelegate;\r\n    CAEmitterLayer* snowflakeEmitter;\r\n}\r\n<\/pre>\n<p>Nel metodo di init, provvederemo ad inizializzare le variabili dichiarate nell&#8217;interfaccia, cos\u00ec come indicato sotto.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (id)initWithFrame:(CGRect)frame {\r\n    if(self = [super initWithFrame:frame]) {\r\n        \/\/Create the emitter layer and retain it\r\n        snowflakeEmitter = [[CAEmitterLayer layer] retain];\r\n        appDelegate = (AppDelegate *)\\\r\n                      [[UIApplication sharedApplication] delegate];\r\n    }\r\n    return self;\r\n}\r\n<\/pre>\n<p>In questo modo, tutta la classe SnowflakeParticleView condivider\u00e0 la stessa istanza di snowflakeEmitter (il nostro emettitore di neve). Alla variabile appDelegate, invece, assegneremo il riferimento di memoria della classe singletone AppDelegate. Quest\u2019ultima \u00e8 importante perch\u00e8 sar\u00e0 al suo interno che dichiareremo il nostro player di musica\u2026abbiamo detto che \u00e8 Natale, giusto? Ricordiamoci di dichiarare ed implementare un metodo di dealloc per il nostro oggetto.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void)dealloc\r\n{\r\n    [snowflakeEmitter release];\r\n    [super dealloc];\r\n}\r\n<\/pre>\n<h4>Gestione del tocco ed interazione con UIView<\/h4>\n<p>Ogni oggetto che eredita da UIView, pu\u00f2 implementare tre metodi magici che gli permettono di prendere il controllo del tocco dell&#8217;utente (esistono anche altri modi per farlo ma in questa sede e per semplicit\u00e0 useremo questa tecnica). Ci baster\u00e0 implementare la logica corrispondente ad ogni azione (inizio tocco, movimento, fine tocco) per fare in modo che tutto vada come desideriamo.<\/p>\n<p>Partiamo dall\u2019evento di inizio tocco (touchesBegan:withEvent). Quando toccate un oggetto che eredita da UIView, il suo UIResponder lancia un messaggio che, se correttamente implementato all&#8217;interno della nostra subclasse, permette di monitorare<br \/>\ne reagire al tocco.<\/p>\n<p>Nel nostro caso, quello che dovremo fare sar\u00e0 fare partire il nostro audioPlayer ed iniziare a sparare fiocchi di neve.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event\r\n{\r\n    if(![appDelegate.audioPlayer isPlaying])\r\n        [appDelegate.audioPlayer play];\r\n...\r\n<\/pre>\n<p>Il parametro touches, passato al metodo dall\u2019evento di tocco, ci permette di ottenere informazioni importanti, quali ad esempio la posizione relativa del tocco sullo schermo. Da questo punto faremo partire il nostro generatore di neve.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n...\r\nCGPoint pt = [[touches anyObject] locationInView:self];\r\n...\r\n<\/pre>\n<p>Infine, modifichiamo la posizione dell&#8217;emettitore snowflakeEmitter, facendola corrispondere con il punto di tocco sullo schermo. Variamo anche la sua modalit\u00e0 di emissione (emitterMode), lo shape usato per generare particelle (emitterShape) e la modalit\u00e0 di rendering usata dal motore Quartz (renderMode). Per i dettagli, vi invito a dare un occhiata alla documentazione Apple fornita di seria. Risulta molto precisa ed esaustiva.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n...\r\n    snowflakeEmitter.emitterPosition = pt;\r\n    snowflakeEmitter.emitterMode = kCAEmitterLayerOutline;\r\n    snowflakeEmitter.emitterShape = kCAEmitterLayerCircle;\r\n    snowflakeEmitter.renderMode = kCAEmitterLayerAdditive;\r\n    snowflakeEmitter.emitterSize = CGSizeMake(100 * multiplier, 0);\r\n...\r\n<\/pre>\n<p>E\u2019 la volta delle nostre particelle di neve. Creiamo una cella emettitrice di particelle e configuriamola secondo le nostre preferenze. Tra i parametri che possiamo modificare spiccano: birthRate per il numero di particelle generate in un range di tempo, lifeTime che indica il tempo di vita di ogni particella e velocity per la velocit\u00e0.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n...\r\n    \/\/Create the emitter cell\r\n    CAEmitterCell* aSnowflake = [CAEmitterCell emitterCell];\r\n    aSnowflake.birthRate = 200;\r\n    aSnowflake.lifetime = 3.0;\r\n    aSnowflake.lifetimeRange = 0.5;\r\n    aSnowflake.velocity = 0.5*pt.x;\r\n    aSnowflake.velocityRange = 0.5*pt.x;\r\n    aSnowflake.emissionRange = 1.5*pt.x;\r\n    aSnowflake.scaleSpeed = 0.1;\r\n    aSnowflake.spin = 0.3;\r\n    aSnowflake.emissionLatitude = 100.0;\r\n    aSnowflake.yAcceleration = 150.0;\r\n    aSnowflake.xAcceleration = 0.0;\r\n    aSnowflake.emissionLongitude = 0.0;\r\n    aSnowflake.color = [[UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:0.1] CGColor];\r\n    aSnowflake.contents = (id)[[UIImage imageNamed:@\"snow.png\"] CGImage];\r\n    [aSnowflake setName:@\"snowflake\"];\r\n...\r\n<\/pre>\n<p>Possiamo creare quante celle vogliamo. L&#8217;importante \u00e8 passare al nostro emettitore un oggetto NSArray, contentente tutte le celle create. Nel nostro caso, popoleremo l&#8217;array con un solo elemento. Vi invito a non abbondare con il numero di celle create.<br \/>\nSpesso \u00e8 possibile ottenere lo stesso effetto che state cercando giocando con i parametri sopra e non con il numero di particelle create. La documentazione Apple, ancora una volta, sar\u00e0 nostra amica.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n...\r\n    snowflakeEmitter.emitterCells = [NSArray arrayWithObject:aSnowflake];\r\n    [self.layer addSublayer:snowflakeEmitter];\r\n...\r\n<\/pre>\n<p>Ad ogni movimento del nostro dito, supponendo di non averlo tolto dallo schermo, viene invocato un&#8217;altro metodo. Anche questo, se implementato, ci fornisce di interagire con il movimento del nostro utente. Tutto quello che faremo sar\u00e0 aggiornare la posizione del nostro emettitore (che, vi ricordo, contiene tutte le celle generatrici di particelle).<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event\r\n{\r\n    CGPoint pt = [[touches anyObject] locationInView:self];\r\n    snowflakeEmitter.emitterPosition = pt;\r\n}\r\n<\/pre>\n<p>Analogamente, al rilascio del tocco, implementando il metodo sotto potremo effettuare le operazioni di blocco del nostro player musicale e della neve.<\/p>\n<p>E&#8217; interessante notare &#8220;come&#8221; blocchiamo la neve. Anzich\u00e8 rilasciare l&#8217;oggetto snowflakeEmitter (che vi ricordo essere condiviso per tutta la durata di vita della nostra classe SnowFlakeParticleView), semplicemente ne configuriamo la grandezza dell&#8217;emettitore (immaginatevelo come la grandezza del tubo da cui esce la neve) a zero. Simultaneamente, ci adoperiamo per interrompere il flusso di emissione delle particelle, settando a zero la propriet\u00e0 birthRate di ogni cella.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event\r\n{\r\n    if([appDelegate.audioPlayer isPlaying])\r\n           [appDelegate.audioPlayer pause];\r\n\r\n    for(CAEmitterCell *aSnowFlake in\r\n        snowflakeEmitter.emitterCells) {\r\n        aSnowFlake.birthRate = 0;\r\n    }\r\n\r\n    snowflakeEmitter.emitterSize = CGSizeZero;\r\n}\r\n<\/pre>\n<h4>Modifiche finali ed AppDelegate<\/h4>\n<p>Spostiamoci nel file AppDelegate.h e modifichiamolo come segue:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@interface AppDelegate : UIResponder <UIApplicationDelegate> {\r\n    AVAudioPlayer *audioPlayer;\r\n}\r\n\r\n@property (strong, nonatomic) UIWindow *window;\r\n@property (nonatomic, retain) AVAudioPlayer *audioPlayer;\r\n@end\r\n<\/pre>\n<p>La variabile di istanza audioPlayer, ci servir\u00e0 per poter &#8220;rispescare&#8221; ed interagire con l&#8217;oggetto audioPlayer dall&#8217;interno della classe generatrice dei fiocchi di cui sopra.<\/p>\n<pre>\r\n<strong>Esercizio:<\/strong> Al posto dell\u2019uso di una shared instance di AppDelegate, per indicizzare un\u2019oggetto globale quale il lettore musicale, si potrebbe pensare di costruire una nuova classe singletone.\r\n<\/pre>\n<p>Spostiamoci nel file di implementazione AppDelegate.m e sintetizziamo la nuova variabile:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n@synthesize audioPlayer;\r\n<\/pre>\n<p>ricordiamoci di aggiungere nella sezione di header la dichiarazione di import per la classe generatrice di neve creata sopra.<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n#import \"SnowflakeParticleView.h\"\r\n<\/pre>\n<p>Modifichiamo il metodo di didFinishLaunchingWithOptions come segue:<\/p>\n<pre lang=\"objc\" line=\"1\" escaped=\"true\">\r\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary\r\n*)launchOptions\r\n{\r\n    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];\r\n    self.window.backgroundColor = [UIColor colorWithRed:0.0\/255.0\r\n                                                  green:5.0\/255.0\r\n                                                   blue:113.0\/255.0\r\n                                                  alpha:1.0];\r\n\r\n    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"jingleBells\"\r\n                                                                        ofType:@\"mp3\"]];\r\n    NSError *error;\r\n    audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error] autorelease];\r\n    audioPlayer.numberOfLoops = -1;\r\n  \r\n    if (audioPlayer == nil) NSLog(@\"%@\", [error description]);\r\n\r\n    SnowflakeParticleView *contentView = [[SnowflakeParticleView alloc] init];\r\n\r\n    [self.window addSubview:contentView];\r\n    [contentView release];\r\n\r\n    [self.window makeKeyAndVisible];\r\n    return YES;\r\n}\r\n<\/pre>\n<p>Se avete seguito tutti i passi, potete compilare e godervi il frutto della vostra fatica. Se non ci siete riusciti o siete stati impegnati nella lettura, potete scaricare lo zip con tutto il progetto compresso a questo indirizzo.<\/p>\n<p>Grazie tante per l&#8217;attenzione dedicatami. Vi auguro un felice periodo di Natale ed uno straordinario anno nuovo, ricco di applicazioni ed idee entusiasmanti.<\/p>\n<p>Costantino aka (valv`0)<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/t104-devapp-SnowFlakes.zip\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/05\/download_icon.png\" alt=\"\" width=\"33\" height=\"40\" align=\"middle\" \/><\/a> Se avete problemi con il progetto presentato, <a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/t104-devapp-SnowFlakes.zip\" target=\"_blank\">questo \u00e8 il link per scaricare il nostro esempio.<\/a><\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre.jpg\" alt=\"banner-allertasoglie-push-tre\" title=\"banner-allertasoglie-push-tre\" width=\"550\" height=\"293\" class=\"aligncenter size-full wp-image-8150\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre.jpg 550w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/12\/banner-allertasoglie-push-tre-300x159.jpg 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/a><br \/>\n<\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In questo periodo di grandi incertezze in cui lo spread altalenante sembra essere l&#8217;unico vero problema con&#8230;<\/p>\n","protected":false},"author":476,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[998,997,999,996,188],"class_list":["post-8146","post","type-post","status-publish","format-standard","hentry","category-tutorial-pratici","tag-caemittercell","tag-caemitterlayer","tag-core-animation","tag-opengl-ios","tag-quartz-core"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/8146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/476"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=8146"}],"version-history":[{"count":22,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/8146\/revisions"}],"predecessor-version":[{"id":8176,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/8146\/revisions\/8176"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=8146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=8146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=8146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}