Detalles del tutorial
- Tecnología: iOS
- Dificultad: Nivel medio
- Tiempo de realización: 45 - 60 minutos
Comenzamos con la 3ª y última parte del tutorial. Ya tenemos todas las clases necesarias creadas y lo que necesitamos es ir picando un poco de código dentro de ellas para rematar la cuestión. En la 2ª parte habiamos creado la vista SaberOnView que será controlada por SaberOnViewController. SaberOnView ya no necesita más código por lo que nos vamos a meter de lleno con SaberOnViewController.
SaberOnViewController
Vamos a utilizar un patrón de delegación para poder devolver el control a ViewController cuando desaparezca la vista modal SaberOnView mediante un toque del usuario en la pantalla. Presuponemos unos conocimientos básicos de creación de protocolos para este tutorial. Crearemos el protocolo SaberOnViewControllerDelegate y su delegado estará en ViewController. Aquí vamos a tener toda la lógica del desplazamiento del láser y de disparar sonidos y vibración. Los valores de las constantes se pueden variar a gusto, yo les he dado esos valores después de testear bastante.
Cuando apretemos el botón de lanzar el sable ocurrirán las siguientes cosas:
- Lanzamos la vista modal SaberOnView y se activará de inicio, un sonido constante (pulse) y una vibración será disparada
- Se activará el acelerómetro y dependiendo de nuestros movimientos en el espacio y la brusquedad de estos, serán lanzados determinados sonidos y vibración algunos de forma aleatoria y otros fija. Además el sable se moverá por el eje X
- Cuando toquemos la pantalla será disparado un sonido de final y la vista SaberOnView se ocultará y volveremos a la vista inicial
Os dejo el código completo de la clase:
#import <uikit /UIKit.h> #import <avfoundation /AVFoundation.h> #import "SaberOnView.h" @protocol SaberOnViewControllerDelegate; @interface SaberOnViewController : UIViewController <uiaccelerometerdelegate , AVAudioPlayerDelegate>{ AVAudioPlayer *pulse; AVAudioPlayer *startLaser; AVAudioPlayer *stopLaser; AVAudioPlayer *pasada1; AVAudioPlayer *pasada2; AVAudioPlayer *pasada3; AVAudioPlayer *pasada4; NSMutableArray *saberSoundsArray; UIAccelerometer *acelerometro; //SaberOnView *saberOnView; double min; double max; double negMin; } @property (nonatomic, assign) id <saberonviewcontrollerdelegate> delegate; @property (nonatomic, strong) SaberOnView *saberOnView; @property (nonatomic, strong) NSMutableArray *saberSoundsArray; - (void) done; - (void) createSounds; @end @protocol SaberOnViewControllerDelegate - (void)flipsideViewControllerDidFinish:(SaberOnViewController *)controller; @end
#import "SaberOnViewController.h" #import <audiotoolbox /AudioToolbox.h> @implementation SaberOnViewController @synthesize delegate=_delegate; @synthesize saberOnView; @synthesize saberSoundsArray = _saberSoundsArray; double const kminimum = 0.8; double const knegativeMinimum = -0.8; double const kmaximum = 1.3; double const knegativeMaximum = -1.3; - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } #pragma mark - View lifecycle - (void)viewDidUnload { [super viewDidUnload]; self.saberOnView=nil; acelerometro=nil; self.saberSoundsArray=nil; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation == UIInterfaceOrientationPortrait); } - (void)loadView { UIApplication *thisApp = [UIApplication sharedApplication]; thisApp.idleTimerDisabled = YES; saberOnView = [[SaberOnView alloc] initWithFrame:CGRectZero]; [saberOnView canBecomeFirstResponder]; [saberOnView becomeFirstResponder]; [self createSounds]; acelerometro = [UIAccelerometer sharedAccelerometer]; [acelerometro setUpdateInterval:0.0416]; [acelerometro setDelegate:self]; //variables del acelerometro min=kminimum; max=kmaximum; negMin=knegativeMinimum; NSLog(@"monitoring accelerometer"); self.view = saberOnView; [startLaser play]; [pulse play]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@"stopLaser!!"); [self done]; } - (void)done { [acelerometro setDelegate:nil]; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); [pulse stop]; [stopLaser play]; UIApplication *thisApp = [UIApplication sharedApplication]; thisApp.idleTimerDisabled = NO; NSLog(@"not monitoring accelerometer"); [self.delegate flipsideViewControllerDidFinish:self]; } - (void)accelerometer:(UIAccelerometer *)meter didAccelerate:(UIAcceleration *)accel { saberOnView.xShift = saberOnView.xShift * 0.8 + [accel x] * 20.0; NSLog(@"monitoring accelerometer2"); // Redraw the view [self.view setNeedsDisplay]; if ( accel.x > min && accel.x < kmaximum) { [pasada1 play]; min=accel.x; negMin=knegativeMinimum; } if ( accel.x < negMin && accel.x > knegativeMaximum) { [pasada2 play]; negMin=accel.x; min=kminimum; } if ( accel.y > min && accel.y < kmaximum) { [pasada3 play]; min=accel.y; negMin=knegativeMinimum; max=kmaximum; } if ( accel.y < negMin && accel.y > knegativeMaximum) { [pasada4 play]; negMin=accel.y; min=kminimum; } if ( accel.y > max) { int randomHit = 7 + arc4random() % 7; //NSLog(@"randomHit:%i",randomHit); [(AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:randomHit] play] ; max=accel.y; AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); } //NSLog(@"accel.x:%f",accel.x); //NSLog(@"accel.y:%f",accel.y); //NSLog(@"accel.z:%f",accel.z); } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } -(void) createSounds { //sonido constante************************* pulse = (AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:0]; pulse.numberOfLoops=-1; pulse.delegate=self; //sonido entrada************************* startLaser=(AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:1]; //sonido salida************************* stopLaser = (AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:2]; //sonido pasada1************************* pasada1 = (AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:3]; //sonido pasada2************************* pasada2 = (AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:4]; //sonido pasada3************************* pasada3 = (AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:5]; //sonido pasada4************************* pasada4 = (AVAudioPlayer *)[self.saberSoundsArray objectAtIndex:6]; } -(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player { //NSLog(@"audioPlayerBeginInterruption"); [pulse stop]; } -(void)audioPlayerEndInterruption:(AVAudioPlayer *)player { //NSLog(@"audioPlayerEndInterruption"); [pulse play]; } @end
ViewController
Para concluir vamos a añadir la delegación a esta clase con lo cual añadiremos el protocolo SaberOnViewControllerDelegate a ViewController, asignaremos como delegado de SaberOnViewController a ViewController e implementaremos el método flipsideViewControllerDidFinish.
@interface ViewController : UIViewController <saberonviewcontrollerdelegate>{
ViewController.m quedará de la siguiente forma:
#import "ViewController.h" @implementation ViewController @synthesize saberSoundsArray=_saberSoundsArray; - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)viewDidUnload { [super viewDidUnload]; self.saberSoundsArray = nil; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); } - (IBAction)startLaser:(id)sender { //vibración AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); SaberOnViewController *controller = [[SaberOnViewController alloc] init]; [controller setDelegate:self]; [controller setSaberSoundsArray: _saberSoundsArray]; [self presentModalViewController:controller animated:YES]; } - (void)flipsideViewControllerDidFinish:(SaberOnViewController *)controller { [self dismissModalViewControllerAnimated:YES]; } @end
Conclusión
Supongo que a estas alturas ya habeis compilado en vuestro dispositivo y vereis que cumple dignamente, pero hay muchas otras cosas que se pueden hacer… Tampoco creo que ésta sea la única o mejor forma de hacerlo ni nada parecido, es simplemente una forma más que espero os pueda servir de base para otros proyectos.
Espero os haya gustado, podeis descargar el proyecto completo de Xcode:
Deja una respuesta