Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00265 005127 13083049 na godz. na dobę w sumie
Dotknij, przesuń, potrząśnij. Od pomysłu do gry na iPhone a i iPada - książka
Dotknij, przesuń, potrząśnij. Od pomysłu do gry na iPhone a i iPada - książka
Autor: Liczba stron: 208
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-3965-6 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie mobilne >> iphone
Porównaj ceny (książka, ebook (-25%), audiobook).

Zrealizuj swój pomysł na grę i odnieś sukces!

Nawet jeśli rynek gier i aplikacji mobilnych nie prześcignął jeszcze rynku tych produktów dla komputerów osobistych, to wkrótce to zrobi. Miliony użytkowników, przystępne ceny oraz powszechny dostęp do ekranów dotykowych, GPS i internetu - wszystko to sprawia, że gry na iPhone...a czy iPada są często o wiele bardziej atrakcyjne niż ich odpowiedniki przeznaczone na zwykłe komputery.

Najważniejszy jest pomysł na grę. Musi być nowatorski, atrakcyjny i wciągający. Jeśli już go masz, ten przewodnik pokaże Ci, w jaki sposób przejść do utworzenia prawdziwej i-aplikacji. Przedstawiony proces konstruowania rzeczywistej gry pozwoli Ci zdobyć podstawy dotyczące narzędzia Xcode i języka Objective-C. Jednocześnie nauczysz się, jak implementować logikę gry, przygotowywać grafikę i efekty dźwiękowe, a także opracować sztuczną inteligencję dla gracza-komputera. Już wkrótce możesz zdobyć sławę i czerpać z tego wymierne korzyści!

Z tą książką w ręku każdy programista zamieni pomysł na rzeczywisty produkt, gotowy do rozpowszechniania w sklepie iTunes App Store.

Zamień pomysł na produkt gotowy do rozpowszechniania w sklepie iTunes App Store!


Todd Moore założył firmę TMSOFT, by konstruować wyjątkowe aplikacje i gry przeznaczone dla smartfonów. Stworzona przez niego popularna gra Card Counter została wyróżniona przez Engadget, 'Los Angeles Times' oraz CNET TV. Najpopularniejsza aplikacja Todda - White Noise - zdobyła uznanie iTunes App Store, 'Health Magazine', 'Washington Post', 'PC Magazine' i Late Night with Jimmy Fallon.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Tap, Move, Shake: A Hands-on Guide to Creating Multi-touch Games with iPad and iPhone Tłumaczenie: Robert Górczyński ISBN: 978-83-246-3965-6 © 2012 Helion S.A. Authorized Polish translation of the English edition of Tap, Move, Shake, 1st Edition 9781449303457 © 2012 Todd Moore This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/dotkni.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/dotkni Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treļci O autorze ..........................................................................................................................7 Wstýp ................................................................................................................................9 Wprowadzenie ................................................................................................................11 12 13 14 15 Dla kogo przeznaczona jest ta ksiñĔka? Czego siö nauczysz? Konwencje zastosowane w ksiñĔce UĔycie przykäadowych kodów 1. Wprowadzenie do Xcode ....................................................................................16 17 17 19 33 36 39 Rejestracja konta programisty Instalacja Xcode Xcode Moduä Interface Builder Poäñczenia Logika gry 2. Hello Pong ........................................................................................................... 44 45 48 52 59 62 63 66 74 Utworzenie projektu Interfejs uĔytkownika gry WyĈwietlacz Multi-Touch Animacja Wykrywanie kolizji Punktacja Wykoþczenie gry DĒwiök 3. Grafika ................................................................................................................ 80 82 83 84 85 87 102 106 Wprowadzenie Grafika rastrowa i wektorowa Formaty obrazów WyĈwietlacz Retina Utworzenie obrazów dla gry Air Hockey Integracja aplikacji Kompilacja i uruchomienie gry 4. Fizyka .................................................................................................................108 109 120 Fizyka podczas ruchu paletek Fizyka podczas ruchu krñĔka 5. DŚwiýk ...............................................................................................................134 135 138 138 139 141 Czym jest dĒwiök? Tworzenie dĒwiöków Pobieranie dĒwiöków Nagrywanie dĒwiöku Edycja dĒwiöku 6. Sztuczna inteligencja.........................................................................................146 147 154 169 Przygotowanie menu gäównego Gracz-komputer Poziom trudnoĈci 7. App Store ........................................................................................................... 176 177 179 180 184 187 193 201 Zrzuty ekranu Przygotowanie opisu aplikacji i wybór säów kluczowych Podanie metadanych w iTunes Connect Archiwizacja i wysäanie aplikacji Recenzja aplikacji Marketing i sprzedaĔ Podsumowanie Skorowidz .................................................................................................................... 203 6 Spis treļci 2. Hello Pong 44 Rozdziaĥ 2. Hello Pong Moje uzaleĔnienie od gier wideo rozpoczöäo siö z chwilñ, gdy tata kupiä konsolö Atari Home Pong. Konsola byäa podäñczana do telewizora, posiadaäa dwa kontrolery i jedynie czarno-biaäñ grafikö. Po obu stronach ekranu byäy wyĈwietlane dwa prostokñty oznaczajñce paletki sterowane przez graczy. Kontroler byä wyposaĔony w obrotowñ tarczö pozwalajñcñ na poruszanie paletkñ w pionie. Na ekranie byäa wyĈwietlana takĔe piäeczka w ksztaäcie biaäego kwadratu, która odbijaäa siö od Ĉcian oraz paletek sterowanych przez graczy. KaĔde kolejne uderzenie piäki zwiökszaäo jej prödkoĈè, co jeszcze bardziej utrudniaäo jej ko- lejne odbicie paletkñ. JeĔeli graczowi nie udaäo siö odbiè piäeczki, przeciwnik otrzymy- waä punkt, nastöpowaäo zakoþczenie danej rundy i przywrócenie piäeczce jej prödkoĈci poczñtkowej. Wprawdzie gra Pong nie miaäa przyciñgajñcej uwagi grafiki i dĒwiöku, to jednak charakte- ryzowaäa siö wszystkimi typowymi elementami aktualnie wydawanych gier, takimi jak cel do zrealizowania, udziaä graczy, punkty wskazujñce na uzyskany postöp w grze oraz sposób ukoþczenia gry. InĔynier Atari, który zaprojektowaä i zbudowaä grö Pong, otrzymaä zadanie wykonania tego projektu jako èwiczenia majñcego mu pomóc w przygotowa- niach do tworzenia gier. UwaĔam, Ĕe takie èwiczenie nawet w obecnych czasach jest doskonaäym sposobem poznania metody tworzenia gier dla urzñdzeþ iPhone (zobacz rysunek 2.1). Podczas pracy nad tym projektem dowiesz siö, jak zaimplementowaè ob- säugö wyĈwietlacza Multi-Touch, animacji, wykrywania zderzeþ oraz punktacji. Rysunek 2.1. Gra Paddles uruchomiona w symulatorze iPhone Utworzenie projektu Pierwszym krokiem jest uruchomienie Xcode, utworzenie nowego projektu (File/New/New Project) i nadanie mu nazwy Paddles. Wybierz szablon iOS/Applications/Single View Application i kliknij przycisk Next. Podaj Paddles jako nazwö produktu i prefiks klas, podaj odpowiedni Utworzenie projektu 45 identyfikator firmy, jako urzñdzenie wybierz iPhone i usuþ zaznaczenie z trzech pól wybo- ru znajdujñcych siö na dole (zobacz rysunek 2.2). Kliknij przycisk Next, wybierz miejsce za- pisu projektu, a nastöpnie kliknij przycisk Create. Rysunek 2.2. Utworzenie nowego projektu: Paddles Po wygenerowaniu nowego projektu przez Xcode wyĈwietlana jest strona ustawieþ, na której trzeba bödzie wprowadziè kilka zmian. Wszystko zostaäo opisane poniĔej. Ustawienia aplikacji Ekran Summary dla aplikacji Paddles zawiera kilka waĔnych elementów, miödzy innymi obsäugiwane urzñdzenia oraz minimalnñ wymaganñ wersjö systemu iOS. Rozwijane menu Devices pozwala na wybór urzñdzenia docelowego: iPhone, iPad lub Universal (obsäuga obydwu wymienionych urzñdzeþ za pomocñ pojedynczej aplikacji). W tworzonym projek- cie pozostawiamy iPhone jako urzñdzenie docelowe, ale minimalnñ wymaganñ wersjö systemu iOS ustalamy na 3.0 (zobacz rysunek 2.3). Zawsze warto ustalaè jak najmniejszñ wymaganñ wersjö systemu iOS do uruchomienia aplikacji, aby nie eliminowaè potencjal- nych klientów, którzy nie posiadajñ najnowszych urzñdzeþ iOS. Budowana w tym roz- dziale gra nie wymaga funkcji znajdujñcych siö jedynie w najnowszych wydaniach sys- temu iOS. Aplikacje wykorzystujéce funkcje, które wymagajé nowszej wersji systemu iOS niŜ zdefiniowana w usta- wieniach, ulegné awarii po uruchomieniu ich w urzédzeniach dziaĥajécych ze starszé wersjé systemu niŜ wymagana. Bardzo waŜne jest wiýc sprawdzenie wersji systemu iOS podczas uruchamiania aplikacji lub wczeļniejsze zdefiniowanie minimalnej wymaganej przez funkcje uŜyte w danej aplikacji. W dokumentacji iOS zawsze naleŜy sprawdzaë wersjý systemu wymagané dla danej funkcji. 46 Rozdziaĥ 2. Hello Pong Rysunek 2.3. Ustawienia aplikacji oraz zdefiniowanie minimalnej wymaganej wersji systemu iOS Istnieje równieĔ moĔliwoĈè podania ukäadów ekranu obsäugiwanych przez aplikacjö — w sekcji Supported Devices Orientations dostöpne sñ opcje Portrait, Portrait Upside Down, Landscape Left oraz Landscape Right. Ma to szczególne znaczenie w przypadku aplikacji dla tabletu iPad, poniewaĔ mogñ byè one uruchamiane w dowolnym poäoĔeniu urzñdzenia (stñd koniecznoĈè zapewnienia odpowiedniego ekranu powitalnego dla poäoĔenia pozio- mego i pionowego). Jednak w przyszäoĈci moĔe to ulec zmianie w przypadku smartfona iPhone, wiöc najlepszym rozwiñzaniem jest poinformowanie systemu iOS, które ukäady sñ obsäugiwane przez aplikacjö. Gra Paddles obsäuguje jedynie ukäad pionowy, upewnij siö wiöc, Ĕe zaznaczony jest jedynie przycisk Portrait w sekcji Supported Devices Orientations. Kolejnym krokiem jest wprowadzenie kilku zmian w pliku typu App Info. Klasa kontrolera widoku takŜe okreļla obsĥugiwane ukĥady ekranu. Domyļlna implementacja zapewnia obsĥugý jedynie ukĥadu pionowego (Portrait), ale wygenerowany kod projektu moŜe zapewnië obsĥugý pozostaĥych ukĥa- dów. Otwórz plik PaddlesViewController.m i usuħ metodý shouldAutorotateToInterfaceOrientation, o ile taka istnieje. W ten sposób gwarantujesz, Ŝe kontroler widoku nie býdzie zmieniaĥ ukĥadu ekranu podczas gry. Plik typu App Info Gry w smartfonie iPhone najczöĈciej wykorzystujñ caäñ dostöpnñ powierzchniö ekranu, co oznacza ukrycie paska stanu. W pliku App Info znajduje siö wiele informacji opisujñ- cych aplikacjö iOS, miödzy innymi wersja, pliki ikon oraz wyĈwietlana nazwa. Wymienione informacje moĔna edytowaè poprzez rozwiniöcie grupy Supporting Files i otworzenie pliku Paddles-Info.plist albo poprzez klikniöcie karty Info na ekranie Paddles Target. Wiele ustawieþ nie jest domyĈlnie wyĈwietlanych, a moĔliwoĈè ukrycia paska stanu zalicza siö do jednej z nich. Musisz wiöc dodaè nowy element, klikajñc jeden z istniejñcych elementów, a nastöpnie ikonö plusa lub po prostu klikajñc prawym przyciskiem myszy i wybierajñc opcjö Add Row z menu kontekstowego. W polu Key nowo dodanego elementu z rozwi- janego menu wybierz opcjö Status bar is initially hidden i ustaw jej wartoĈè YES, jak pokazano na rysunku 2.4. Powodem dodania tej opcji w tym pliku zamiast w kodzie aplikacji jest to, Ĕe system powoli ukryje pasek stanu podczas wczytywania aplikacji. Animowane ukrycie paska stanu podczas wczytywania aplikacji wyglñda znacznie lepiej niĔ po prostu jego natychmiastowe ukrycie tuĔ po wczytaniu aplikacji. Utworzenie projektu 47 Rysunek 2.4. Ukrycie paska stanu w aplikacji iOS Interfejs uŜytkownika gry Pierwszñ grö dla smartfona iPhone utworzyäem bez uĔywania programu Interface Builder. Oznacza to, Ĕe musiaäem röcznie zaalokowaè wszystkie widoki, obrazy i etykiety poprzez odpowiednie dobranie ich wielkoĈci i poäoĔenia w taki sposób, aby wszystko przedstawiaäo siö dobrze. Wszystko, co mogäem szybko zrobiè w programie Interface Builder, tworzyäem powoli w kodzie Ēródäowym, co jest wyjñtkowo Ĕmudne i podatne na powstawanie bäö- dów. Gdybym miaä moĔliwoĈè cofniöcia siö w czasie i poĈwiöcenia póä godziny na poznanie sposobu uĔywania edytora WYSIWYG (ang. What You See Is What You Get, czyli otrzymasz to, co widzisz na ekranie) Interface Builder, grö ukoþczyäbym znacznie wczeĈniej. Moduĥ Interface Builder W panelu nawigacyjnym kliknij plik PaddlesViewController.xib, w obszarze edytora Xcode zostanie wyĈwietlony moduä Interface Builder pozwalajñcy na utworzenie bñdĒ zmody- fikowanie interfejsu uĔytkownika. Nastöpnie upewnij siö o wyĈwietleniu inspektora atrybutów w panelu narzödziowym (wybierz opcjö menu View/Utilities/Attributes In- spector). Panel narzödziowy jest wyĈwietlany po prawej stronie okna Xcode i pozwala na wybór jednego z kilku inspektorów za pomocñ paska narzödziowego znajdujñcego siö na górze panelu. Na rysunku 2.5 pokazano inspektora atrybutów (na górze) oraz bi- bliotekö obiektów (na dole). Kliknij jedyny widok wyĈwietlony na Ĉrodku ekranu moduäu Interface Builder. Teraz dowiesz siö, jak za pomocñ inspektora atrybutów zmodyfikowaè róĔne wäaĈciwoĈci tego widoku gäównego (ang. root view). To dobra chwila na poznanie pozostaĥych inspektorów dostýpnych w panelu narzýdziowym. Umieszczaj kursor myszy nad ikonami poszczególnych inspektorów, co spowoduje wyļwietlenie ich nazw. Zmieþ kolor täa (ang. Background) widoku z szarego na czarny (ang. Black). W rozwijanym menu Status Bar w sekcji Simulated Metrics wybierz opcjö None, poniewaĔ pasek stanu nie bödzie wyĈwietlany w grze. Pasek stanu zabiera na górze ekranu 20 pikseli z caäkowitej ich liczby 480. Tak wiöc przy wyĈwietlonym pasku stanu widok gäówny ma 460 pikseli wysokoĈci. PrzejdĒ do inspektora wielkoĈci (zobacz rysunek 2.6) i upewnij siö, Ĕe wyso- koĈè jest ustawiona na 480 pikseli, co odpowiada wysokoĈci ekranu bez paska stanu. 48 Rozdziaĥ 2. Hello Pong Rysunek 2.5. Panel narzýdziowy, inspektor atrybutów i biblioteka obiektów Rysunek 2.6. Inspektor wielkoļci i ustawienie punktu poczétkowego Biblioteka obiektów znajduje siö w dolnej czöĈci panelu narzödziowego, tuĔ pod inspekto- rami, i pozwala na przeciñganie nowych elementów interfejsu uĔytkownika do widoku. W bibliotece moĔna znaleĒè mnóstwo elementów, miödzy innymi przyciski, etykiety itd. Rozpoczniemy od uĔycia podstawowych elementów: widoku (ang. View) oraz obiektu, po którym dziedziczñ wszystkie elementy interfejsu uĔytkownika. Obiekt View posiada Interfejs uŜytkownika gry 49 wäaĈciwoĈci takie jak wymiary ramki i kolor täa. To wszystko, czego tak naprawdö w tym momencie potrzebujemy, poniewaĔ paletki i piäeczka bödñ w grze przedstawiane za pomocñ biaäych prostokñtów. Przewijaj listö elementów biblioteki, aĔ znajdziesz obiekt View, a nastöpnie przeciñgnij go do widoku gäównego, tworzñc w ten sposób podwidok dla istniejñcego widoku gäównego. Wymiary podwidoku to 64 piksele szerokoĈci i 16 pikseli wysokoĈci; ten widok bödzie przedstawiaä jednñ z paletek. Paletka ma zostaè umieszczona na górze, ale powinieneĈ po- zostawiè nieco miejsca na umieszczenie palca za paletkñ. Kliknij obszar Origin i zmieþ poäoĔenie punktu poczñtkowego na wyĈrodkowany na górze (zobacz strzaäkö po lewej stronie rysunku 2.6), co spowoduje dopasowanie poäoĔenia punktu poczñtkowego do poäoĔenia paletki wzglödem zawierajñcego jñ widoku. Pozycja X paletki powinna byè wyĈrodkowana w pozycji 160 pikseli od lewej strony ekranu, nato- miast pozycja Y paletki to 64 piksele od góry ekranu. Skopiuj i wklej tö paletkö, tworzñc w ten sposób drugñ o takich samych wymiarach. Druga paletka powinna znajdowaè siö w takiej samej odlegäoĈci od dolnej krawödzi ekranu jak pierwsza od górnej. Caäkowita wysokoĈè widoku wynosi 480 pikseli, wiöc trzeba wziñè pierwszy widoczny piksel (479) i odjñè od tej wartoĈci 64 (479 – 64 = 415). Punkt poczñtko- wy drugiej paletki powinien byè poäoĔony na Ĉrodku dolnej czöĈci ekranu, w poäoĔeniu 160, 415. Obydwie paletki powinny byè teraz wyĈrodkowane i znajdowaè siö w takiej samej odlegäoĈci od krawödzi ekranu. Kolejnym krokiem jest utworzenie piäeczki poprzez przeciñgniöcie nowego widoku i zmianö jego wielkoĈci na 16×16 pikseli. Nastöpnie kliknij rozwijane menu Arrange Position View i wybierz opcjö Center Horizontally In The Container. Teraz ponownie kliknij rozwijane menu Arrange Position View i wybierz opcjö Center Vertically In The Container. Po tych zabiegach piäeczka powinna znajdowaè siö dokäadnie na Ĉrodku widoku. Na Ĉrodku ekranu dodaäem poziomñ liniö dzielñcñ ekran na póä i pomagajñcñ w wizu- alnym oddzieleniu stron ekranu poszczególnych graczy. Przeciñgnij wiöc kolejny widok i zmieþ jego wymiary na 320×5 pikseli. Widok powinien zostaè wyĈrodkowany pionowo i poziomo, podobnie jak w przypadku piäeczki. PrzejdĒ do inspektora atrybutów i zmieþ kolor täa na szary (ang. Grey). Zwróè uwagö, Ĕe linia zostaäa poäoĔona na piäeczce, poniewaĔ przedstawiajñcy jñ widok zostaä dodany jako ostatni. KolejnoĈè obiektów moĔesz zmieniè, uĔywajñc panelu Outline View poäoĔonego przy lewej krawödzi edytora. JeĈli panel jest niewidoczny, kliknij jego ikonö wyĈwietlonñ w lewym dolnym rogu obszaru edytora. Panel Outline View wyĈwietla hierarchiczne drzewo od- zwierciedlajñce zwiñzki nadrzödny – potomny pomiödzy obiektami w pliku nib. Obiekty znajdujñce siö na dole drzewa sñ wyĈwietlane nad umieszczonymi w górnej czöĈci drzewa. Przeciñgnij widok linii dzielñcej ekran, aby staä siö pierwszym w hierarchii obiektów (zo- bacz rysunek 2.7). W ten sposób linia dzielñca ekran bödzie wyĈwietlana pod piäeczkñ. Tö samñ operacjö moĔna wykonaè, wybierajñc opcjö menu Editor/Arrangement/Send to Back. 50 Rozdziaĥ 2. Hello Pong Rysunek 2.7. Zmiana hierarchii widoków Poĥéczenia Podobnie jak w poprzednim rozdziale, takĔe tutaj trzeba wyĈwietliè panel drugiego edytora, aby plik PaddlesViewController.h zostaä wyĈwietlony obok panelu edytora Interface Builder. Przytrzymujñc wciĈniöty klawisz Control, przeciñgnij kursor myszy od górnej paletki do wiersza znajdujñcego siö pod definicjñ UIViewController. Podczas przeciñgania kursora zobaczysz wyĈwietlanñ na ekranie liniö (zobacz rysunek 2.8), jak równieĔ zaznaczone miejsce umieszczenia outletu. Rysunek 2.8. Bezpoļrednie poĥéczenie outletów z kodem Śródĥowym powoduje automatyczne utworzenie wĥaļciwoļci Po zwolnieniu przycisku myszy zobaczysz menu kontekstowe, które pozwala na okre- Ĉlenie typu poäñczenia, nazwy oraz typu obiektu. Tworzone tutaj poäñczenie powinno byè outletem, nazwa obiektu to viewPaddle1, natomiast jego typ to UIView. Powtórz ten Interfejs uŜytkownika gry 51 proces dla drugiej paletki i piäeczki. Po utworzeniu poäñczeþ plik nagäówkowy powinien mieè postaè: @interface PaddlesViewController : UIViewController @property (nonatomic, retain) IBOutlet UIView *viewPaddle1; @property (nonatomic, retain) IBOutlet UIView *viewPaddle2; @property (nonatomic, retain) IBOutlet UIView *viewPuck; @end PrzejdĒ do pliku implementacji PaddlesViewController.m i zwróè uwagö, Ĕe podobnie jak w poprzednim rozdziale, takĔe tutaj widoki zostaäy usuniöte z pamiöci w metodach dealloc i viewDidUnload: - (void)dealloc { [viewPaddle1 release]; [viewPaddle2 release]; [viewPuck release]; [super dealloc]; } - (void)viewDidUnload { [self setViewPaddle1:nil]; [self setViewPaddle2:nil]; [self setViewPuck:nil]; [super viewDidUnload]; } Poprzez poäñczenie obydwu paletek i piäeczki jako wäaĈciwoĈci kontrolera widoku uzy- skasz dostöp do ich poäoĔenia na ekranie i bödziesz mógä nimi manipulowaè, gdy zaj- dzie potrzeba. Kolejnym krokiem jest dodanie obsäugi paletek za pomocñ wyĈwietlacza Multi-Touch. Wyļwietlacz Multi-Touch Wprowadzenie przez firmö Apple na rynek jej pierwszego smartfona iPhone pokazaäo Ĉwiatu imponujñcñ listö innowacji zastosowanych w tak maäym urzñdzeniu. WyĈwie- tlacz Multi-Touch na pewno znajdowaä siö na poczñtku tej listy. Choè ekrany dotykowe byäy dostöpne juĔ od pewnego czasu, to firma Apple pokazaäa Ĉwiatu, jak tö technologiö moĔna efektywnie wykorzystaè w produkcie konsumenckim. Caäy interfejs uĔytkownika oraz system operacyjny zostaäy zbudowane wokóä koncepcji dotyku i wyĈwietlacza Multi- Touch. Interfejs zostaä zaprojektowany jako intuicyjny i äatwy w uĔyciu, co niewñtpliwie przyczyniäo siö do zyskania ogromnej popularnoĈci przez smartfona iPhone. WczeĈniej pró- bowano juĔ dodaè obsäugö dotyku do tradycyjnych biurkowych systemów operacyjnych, ale te próby najczöĈciej sprowadzaäy siö do mapowania punktu ekranu dotkniötego przez uĔytkownika na poäoĔenie kursora myszy. Takie rozwiñzanie nie dziaäa tak samo jak zastosowane w urzñdzeniach iOS, które od poczñtku zostaäy zaprojektowane z myĈlñ o ste- rowaniu nimi i kontrolowaniu ich za pomocñ dotyku. 52 Rozdziaĥ 2. Hello Pong W pierwszej chwili moĔesz porównaè dotyk do obsäugi zdarzeþ myszy, ale pomiödzy wy- mienionymi rozwiñzaniami istnieje wiele róĔnic. Pierwszñ i najbardziej oczywistñ jest wiele poäoĔeþ palców na ekranie w tym samym czasie. Pierwszy smartfon iPhone obsäugiwaä Ĉledzenie do piöciu poäoĔeþ w tym samym czasie. Druga róĔnica, która nie musi byè aĔ tak oczywista, to fakt, Ĕe czasami ekran w ogóle nie jest dotykany przez uĔytkownika. JeĔeli nie dotykasz ekranu, to nie ma poäoĔenia dotyku. Porównaj to do myszy, której kursor zawsze znajduje siö na ekranie. Nawet jeĈli nie dotykasz myszy, jej kursor pozostaje na ekranie, a system moĔe sprawdziè jego poäoĔenie. Z wymienionych powodów dziaäanie zdarzeþ dotyku zostanie tutaj dokäadnie omówione. Ponadto zapoznasz siö z najlepszymi prak- tykami stosowanymi podczas Ĉledzenia wielu dotkniöè ekranu. Cztery metody dotyku WyĈwietlacz Multi-Touch jest obsäugiwany poprzez dodanie czterech metod do obiektu kontrolera widoku. System bödzie wywoäywaä te metody za kaĔdym razem, gdy nastñpi zmiana stanu dotyku. Metoda touchesBegan jest wywoäywana po wykryciu pierwszego poäoĔenia palca na ekranie. Po przesuniöciu palca w nowe poäoĔenie nastñpi wywoäanie metody touchesMoved. Wreszcie po podniesieniu palca z ekranu wywoäana bödzie metoda to- uchesEnded. Istnieje moĔliwoĈè, Ĕe metoda touchesEnded nie zostanie wywoäana, jeĈli system zdecyduje o przerwaniu obsäugi dotkniöcia. W takim przypadku zamiast wywoäania wymienionej nastöpuje wywoäanie metody touchesCancelled. Przerwanie moĔe wystñpiè w przypadku zakäócenia dziaäania aplikacji poprzez innñ funkcjö urzñdzenia, na przykäad po otrzymaniu wiadomoĈci lub poäñczenia przychodzñcego. W kontrolerze widoku zaimplementujemy teraz kod powodujñcy wyĈwietlenie w oknie konsoli moduäu usuwania bäödów nazwy metody aktualnie obsäugujñcej dotyk. W pliku PaddlesViewController.m umieĈè przedstawiony poniĔej kod: - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@ touchesBegan ); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@ touchesMoved ); } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@ touchesEnded ); } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { NSLog(@ touchesCancelled ); } Upewnij siö o wyĈwietleniu okna konsoli w Xcode poprzez wäñczenie panelu moduäu usuwania bäödów za pomocñ paska narzödziowego lub wybór opcji menu View/Debug Area/Show Debug Area. Uruchom aplikacjö w symulatorze i szybko kliknij na ekranie. Dane wyjĈciowe w oknie konsoli powinny byè podobne do przedstawionych poniĔej: Wyļwietlacz Multi-Touch 53 2011-03-23 12:03:28.791 Paddles[6007:207] touchesBegan 2011-03-23 12:03:28.990 Paddles[6007:207] touchesEnded Zwróè uwagö, Ĕe nie wszystkie zdarzenia dotyku muszñ zostaè wygenerowane podczas ob- säugi dotyku. Jednak zawsze bödzie zdarzenie touchesBegan oraz touchesEnded lub touchesCan- celled. Teraz kliknij i przeciñgnij kursor myszy po ekranie symulatora iOS. Skutkiem bödzie wygenerowanie wielu zdarzeþ zmiany poäoĔenia palca na ekranie pomiödzy zdarzeniami touchesBegan i touchesEnded. 2011-03-23 12:04:09.025 Paddles[6007:207] touchesBegan 2011-03-23 12:04:10.884 Paddles[6007:207] touchesMoved 2011-03-23 12:04:10.933 Paddles[6007:207] touchesMoved 2011-03-23 12:04:11.066 Paddles[6007:207] touchesMoved 2011-03-23 12:04:11.766 Paddles[6007:207] touchesEnded Wĥéczenie obsĥugi wyļwietlacza Multi-Touch Na tym etapie uĔywamy symulatora iOS do monitorowania wszystkich zdarzeþ dotyku ekranu. Symulator ma moĔliwoĈè emulacji dwóch jednoczesnych dotkniöè poprzez przy- trzymanie klawisza Option podczas klikania. To jednak bardzo ograniczona moĔliwoĈè, najle- piej dopasowana do obsäugi gestu rozciñgania w celu zwiökszenia poziomu powiöksze- nia. Z tego powodu podczas implementacji obsäugi wyĈwietlacza Multi-Touch najlepiej korzystaè z rzeczywistego urzñdzenia iOS. Podäñcz urzñdzenie iOS, a nastöpnie schemat aktywnego projektu zmieþ na iOS Device. JeĔeli skompilujesz i uruchomisz aplikacjö w urzñdzeniu, a nastöpnie poäoĔysz dwa palce na ekranie, to zauwaĔysz, Ĕe drugie dotkniöcie zostaäo zignorowane. Wynika to z faktu do- myĈlnego ignorowania wielu dotkniöè przez widok. Tö moĔliwoĈè musisz wiöc röcznie wäñ- czyè dla kaĔdego wymagajñcego jej widoku. Odbywa siö to poprzez modyfikacjö wäaĈciwoĈci multipleTouchEnabled widoku gäównego lub uĔycie moduäu Interface Builder i wäñczenie Multiple Touch, jak pokazano na rysunku 2.9. Rysunek 2.9. UŜycie moduĥu Interface Builder do wĥéczenia obsĥugi wielu dotkniýë Metody obsäugi dotkniöè w kontrolerze widoku bödñ teraz wywoäywane dla kaĔdego dotkniöcia na ekranie. Trzeba koniecznie zapamiötaè, Ĕe kaĔdy obiekt UITouch ma gwarancjö pozostania tym samym egzemplarzem przez caäy cykl Ĕyciowy aplikacji, od poczñtku do koþca. W ten sposób kaĔde poszczególne dotkniöcie ekranu jest przedstawiane za pomocñ tego samego obiektu UITouch we wszystkich wywoäaniach. Aby siö o tym przekonaè, 54 Rozdziaĥ 2. Hello Pong dodaj poniĔszy fragment kodu do zaimplementowanych wczeĈniej wszystkich metod obsäugi dotyku: for (UITouch *touch in touches) { NSLog(@ - p , touch); } PowyĔszy kod powoduje wyĈwietlenie adresu w pamiöci kaĔdego obiektu UITouch w zbio- rze. Po uruchomieniu aplikacji w rzeczywistym urzñdzeniu iOS i umieszczeniu dwóch palców na ekranie wygenerowane dane wyjĈciowe w konsoli bödñ podobne do przed- stawionych poniĔej: 2011-03-23 14:48:05.015 Paddles[2962:307] touchesBegan 2011-03-23 14:48:05.019 Paddles[2962:307] - 0x12eed0 2011-03-23 14:48:05.021 Paddles[2962:307] - 0x12f3b0 2011-03-23 14:48:05.077 Paddles[2962:307] touchesMoved 2011-03-23 14:48:05.080 Paddles[2962:307] - 0x12eed0 2011-03-23 14:48:05.083 Paddles[2962:307] touchesEnded 2011-03-23 14:48:05.086 Paddles[2962:307] - 0x12f3b0 2011-03-23 14:48:05.093 Paddles[2962:307] touchesEnded 2011-03-23 14:48:05.096 Paddles[2962:307] - 0x12eed0 Zwróè uwagö, Ĕe obydwa przykäadowe dotkniöcia zostaäy zarejestrowane w tym samym czasie w metodzie touchesBegan i wskazujñ adresy 0x12eed0 i 0x12f3b0. Dotkniöcie obsäugiwa- ne przez obiekt 0x12eed0 zmienia poäoĔenie, podczas gdy drugie nie. Wiadomo, Ĕe dru- gie dotkniöcie nie zmieniäo poäoĔenia, poniewaĔ nie stanowi czöĈci zbioru. Dotkniöcie obsäugiwane przez obiekt znajdujñcy siö pod adresem 0x12f3b0 przechodzi do stanu za- koþczonego, podobnie jak obsäugiwane przez obiekt 0x12eed0 tuĔ po nim. Na tym etapie obydwa dotkniöcia zostaäy zakoþczone i adresy w pamiöci mogñ byè ponownie wykorzy- stane przez system. To jest jedynie prosty przykäad pokazujñcy jednoczesnñ obsäugö dwóch dotkniöè ekranu. Podczas przeprowadzania prób prawdopodobnie zobaczysz znacznie wiökszñ liczbö komunikatów wygenerowanych i wyĈwietlonych w oknie konsoli, a do- tkniöcia bödñ przechodziäy przez wszystkie dostöpne metody ich obsäugi. Poruszanie paletkami Teraz przeprowadzimy modyfikacjö procedur obsäugi dotkniöè, aby zapewniè moĔliwoĈè poruszania paletkami w poziomie wzdäuĔ osi X. W celu pobrania rzeczywistego poäoĔenia palca w widoku konieczne jest wywoäanie metody locationInView obiektu UITouch. WartoĈciñ zwrotnñ wymienionej metody jest miejsce dotkniöcia ekranu wzglödem wskazanego widoku. UĔyjemy widoku gäównego, którego wymiary odpowiadajñ wymiarom ekranu. WartoĈè zwrotna jest typu CGPoint; to struktura skäadajñca siö z poäoĔenia X i Y. Ekran ma wysokoĈè 480 pikseli, wiöc wartoĈè Y punktu bödzie uĔyta do okreĈlenia paletki, która powinna byè poruszona. JeĔeli bödzie dotyczyäa górnej czöĈci ekranu (wartoĈè mniejsza niĔ 240 pikseli), wówczas poruszona bödzie paletka paddle1. W przeciwnym razie poäoĔenie zmieni paletka paddle2. Paletka powinna poruszaè siö jedynie wzdäuĔ osi X, wiöc zadaniem ko- du jest ustalenie nowego centrum w punkcie okreĈlonym przez wartoĈè X dotkniöcia, podczas gdy wartoĈè Y powinna pozostaè bez zmian. MoĔesz wykorzystaè CGPointMake, co jest szybkim sposobem inicjalizacji nowej struktury CGPoint. WczeĈniejszñ implementacjö metody touchesBegan zastñp przedstawionym poniĔej kodem: Wyļwietlacz Multi-Touch 55 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // Iteracja przez elementy dotkniĊcia. for (UITouch *touch in touches) { // Pobranie miejsca dotkniĊcia palcem w widoku. CGPoint touchPoint = [touch locationInView:self.view]; // Poruszenie paletką na podstawie okreĞlenia poáowy ekranu, // w której nastąpiáo dotkniĊcie. if (touchPoint.y 240) { viewPaddle1.center = CGPointMake(touchPoint.x, viewPaddle1.center.y); } else { viewPaddle2.center = CGPointMake(touchPoint.x, viewPaddle2.center.y); } } } Kod przedstawiony powyĔej zajmuje siö obsäugñ poczñtku operacji dotkniöcia, ale nie obsäuguje sytuacji, w której palec uĔytkownika jest przesuwany po ekranie. Paletka jest obsäugiwana poprzez poäoĔenie palca na ekranie, a nastöpnie poruszanie nim w obydwie strony, co wymaga implementacji obsäugi zdarzenia touchesMoved. W omawianym przy- padku wystarczy po raz kolejny wywoäaè metodö touchesBegan, ponownie wykorzystujñc tö samñ logikö obsäugujñcñ ruch paletki. WczeĈniejszñ implementacjö metody touchesMoved zastñp przedstawionym poniĔej kodem: - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesBegan:touches withEvent:event]; } Uruchom aplikacjö w urzñdzeniu i przekonaj siö, Ĕe obiema paletkami moĔesz poruszaè w tym samym czasie poprzez jednoczesne dotykanie ekranu w róĔnych miejscach. NieĒle jak na jedynie kilka wierszy kodu! Pobaw siö przez chwilö paletkami i spróbuj znaleĒè bäödy w bieĔñcej implementacji. Implementacja zawiera dwa bäödy, które zostanñ popra- wione w kolejnej sekcji. Problemy z Multi-Touch: trzeci palec Gracz kontrolujñcy paletkö najczöĈciej umieĈci palec pomiödzy paletkñ i krawödziñ ekranu. Nastöpnie bödzie poruszaä palcem w górö i w dóä, nie podnoszñc palca z ekranu aĔ do koþca danej rundy gry. W bieĔñcej implementacji moĔna dostrzec dwa problemy. Pierwszy to Ĕe gracz moĔe przesunñè palec na poäowö drugiego gracza i tym samym przejmie kontrolö nad jego paletkñ. Jak pokazano na rysunku 2.10, drugi gracz przesuwa palec na poäowö pierwszego gracza, a nastöpnie w lewñ stronö. W ten sposób pierwszy gracz nie bödzie miaä peänej kontroli nad poruszaniem swojñ paletkñ, moĔe przepuĈciè piäeczkö, a gracz drugi zdobödzie nieuczciwie punkt. Drugi problem polega na tym, Ĕe kaĔde dodat- kowe (poza pierwszymi dwoma) dotkniöcie ekranu równieĔ wpäywa na poäoĔenie paletki gracza. Trzeci palec na ekranie (równieĔ pokazany na rysunku 2.10) spowoduje, Ĕe pierwszy gracz utraci peäniö kontroli nad swojñ paletkñ i drugi gracz moĔe zyskaè nieuczciwie 56 Rozdziaĥ 2. Hello Pong punkt. Obydwa wymienione problemy trzeba wyeliminowaè, aby gra nie cierpiaäa przez lata na skutek teorii spiskowych dotyczñcych tego, co tak naprawdö siö zdarzyäo podczas rozgrywki w aplikacji Paddles. Rysunek 2.10. Problemy wystýpujéce w bieŜécej implementacji gry Pod wzglödem sposobu kontroli paletek gra nie powinna siö róĔniè od rzeczywistej. W rzeczywistej grze osoba bierze paletkö do röki i trzyma jñ aĔ do zakoþczenia gry. W bu- dowanej przez nas grze oczekujemy takiego samego zachowania. Kiedy gracz zyskuje kon- trolö nad paletkñ, wówczas drugi gracz nie powinien mieè moĔliwoĈci zyskania kontroli nad tñ paletkñ, chyba Ĕe pierwszy gracz mu na to pozwoli. Dlatego teĔ paletka powinna ignorowaè wszelkie dodatkowe dotkniöcia wystöpujñce na jej poäowie ekranu. Poza tym jeĈli gracz ma przypisanñ paletkö, wtedy nie powinien uzyskaè moĔliwoĈci kontrolowania drugiej paletki po przeciñgniöciu palca na poäowö przeciwnika. W celu zaimplementowania takiej logiki trzeba wiedzieè, które dotkniöcia dotyczñ danej paletki. Jak juĔ wcze- Ĉniej wspomniano, obiekty UITouch zawsze bödñ miaäy te same egzemplarze w trakcie caäego cyklu Ĕyciowego zdarzeþ dotyku. Ten fakt moĔna wykorzystaè do powiñzania okreĈlonego dotkniöcia z danñ paletkñ. Wĥaļciwa obsĥuga dotkniýë Aby Ĉledziè dotkniöcia dotyczñce danej paletki, konieczne jest dodanie kilku zmiennych do interfejsu PaddlesViewController. Zmienna touch1 bödzie aktywnym dotkniöciem po- wiñzanym z paletkñ paddle1, natomiast touch2 — aktywnym dotkniöciem powiñzanym z paletkñ paddle2. JeĔeli paletka nie bödzie przypisana do danego dotkniöcia, wówczas war- toĈciñ bödzie nil. Przedstawione poniĔej zmienne dodaj do definicji interfejsu PaddlesView- Controller.h: @interface PaddlesViewController : UIViewController { UITouch *touch1; UITouch *touch2; } Trzeba zmodyfikowaè implementacjö metody touchesBegan w celu przypisania paletki do okreĈlonego dotkniöcia tylko wtedy, gdy pozostaje ono nieprzypisane. Nadal naleĔy wykorzystywaè logikö wymagajñcñ, aby dotkniöcie górnej czöĈci ekranu byäo przypisane do paletki paddle1, natomiast dolnej czöĈci ekranu — do paletki paddle2. JeĔeli wymie- nione warunki bödñ speänione, nastñpi przypisanie odpowiedniego obiektu dotkniöcia do paletki oraz przesuniöcie paletki z zapisanego wczeĈniej poäoĔenia. Poprzedniñ im- plementacjö metody touchesBegan zastñp poniĔszym kodem: Wyļwietlacz Multi-Touch 57 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // Iteracja przez elementy dotkniĊcia. for (UITouch *touch in touches) { // Pobranie miejsca dotkniĊcia palcem w widoku. CGPoint touchPoint = [touch locationInView:self.view]; // Sprawdzenie, która poáowa ekranu zostaáa dotkniĊta, i przypisanie // dotkniĊcia do okreĞlonej paletki, jeĞli nie zostaáo jeszcze przypisane. if (touch1 == nil touchPoint.y 240) { touch1 = touch; viewPaddle1.center = CGPointMake(touchPoint.x, viewPaddle1.center.y); } else if (touch2 == nil touchPoint.y = 240) { touch2 = touch; viewPaddle2.center = CGPointMake(touchPoint.x, viewPaddle2.center.y); } } } Po przypisaniu kaĔdej paletce odpowiednich dotkniöè trzeba zapewniè obsäugö poru- szania paletkami. Nie moĔemy juĔ däuĔej wywoäywaè metody touchesBegan, poniewaĔ paletki posiadajñce przypisane dotkniöcia zostanñ zignorowane. Zamiast tego trzeba sprawdziè, czy jakikolwiek dostarczony obiekt dotkniöcia odpowiada dowolnemu obiekto- wi dotkniöcia przypisanego paletce. W przypadku uaktualnienia dotkniöcia przypisanego paletce wiadomo, Ĕe moĔna zmieniè jej poäoĔenie. Wszelkie dotkniöcia nieprzypisane paletce moĔna bezpiecznie zignorowaè. Poprzedniñ implementacjö metody touchesMoved zastñp poniĔszym kodem: - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { // Iteracja przez elementy dotkniĊcia. for (UITouch *touch in touches) { // Pobranie miejsca dotkniĊcia palcem w widoku. CGPoint touchPoint = [touch locationInView:self.view]; // JeĪeli dotkniĊcie jest przypisane paletce, zmieniamy poáoĪenie paletki. if (touch == touch1) { viewPaddle1.center = CGPointMake(touchPoint.x, viewPaddle1.center.y); } else if (touch == touch2) { viewPaddle2.center = CGPointMake(touchPoint.x, viewPaddle2.center.y); } } } Trzeba jeszcze zapewniè obsäugö sytuacji, w której uĔytkownik podniósä palec znad ekranu, czyli znad paletki z przypisanym dotkniöciem. W tym celu naleĔy zaimplemen- towaè metodö touchesEnded. JeĔeli dowolne z dotkniöè w zbiorze odpowiada przypisanemu paletce, wówczas to przypisane powinno byè usuniöte poprzez ustawienie wartoĈci nil. 58 Rozdziaĥ 2. Hello Pong JeĈli tego nie zrobisz, to prawdopodobnie utracisz kontrolö nad paletkñ po podniesieniu palca z ekranu. To odpowiada odäñczeniu kontrolera od konsoli, co nie jest dobrym rozwiñzaniem! Poprzedniñ implementacjö metody touchesEnded zastñp przedstawionym poniĔej kodem: - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // Iteracja przez elementy dotkniĊcia. for (UITouch *touch in touches) { if (touch == touch1) touch1 = nil; else if (touch == touch2) touch2 = nil; } } Musisz siö takĔe upewniè o zapewnieniu obsäugi przerwania zdarzenia; w tym przy- padku moĔna uĔyè kodu utworzonego dla metody touchesEnded. Pamiötaj, Ĕe ta metoda bödzie wywoäana po przerwaniu operacji dotkniöcia. Tego rodzaju sytuacjö moĔesz przetestowaè, nawiñzujñc poäñczenie z urzñdzeniem (iPhone) lub wywoäujñc zdefinio- wany alarm (iPod touch). TuĔ przed wystñpieniem zakäócenia zdarzenia zauwaĔysz, Ĕe wszystkie operacje dotkniöcia zostaäy przerwane. JeĔeli nie zapewnisz obsäugi metody przerwania zdarzenia, gracze prawdopodobnie nie bödñ mogli uzyskaè kontroli nad paletkami po zakoþczeniu zdarzenia zakäócajñcego. Poprzedniñ implementacjö metody touchesCancelled zastñp przedstawionym poniĔej kodem: - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [self touchesEnded:touches withEvent:event]; } Uruchom aplikacjö w urzñdzeniu iOS i zwróè uwagö, Ĕe po przypisaniu dotkniöcia paletce dodatkowe dotkniöcie nie powoduje zmiany poäoĔenia paletki. Przekonaj siö równieĔ, Ĕe przeciñgniöcie palca na poäowö przeciwnika nie powoduje uzyskania kontroli nad jego paletkñ. Gra ma wiöc solidnñ implementacjö obsäugi wyĈwietlacza Multi-Touch. Animacja W tej chwili mamy paletki poruszajñce siö w zaleĔnoĈci od tego, który gracz dotyka ekranu. Nadeszäa wiöc pora na wprawienie piäeczki w ruch. Gra wymaga pötli animacji poruszajñcej piäeczkö w okreĈlonym kierunku z danñ prödkoĈciñ. W interfejsie PaddlesView- Controller dodaj poniĔsze zmienne odpowiedzialne za Ĉledzenie kierunku i prödkoĈci poruszania siö piäeczki: float dx; float dy; float speed; Zmienne dx i dy przedstawiajñ kierunek poruszania siö piäeczki, natomiast zmienna speed jej prödkoĈè. PrödkoĈè i kierunek wolö Ĉledziè za pomocñ oddzielnych zmiennych, po- niewaĔ to uäatwia zwiökszanie prödkoĈci piäeczki wraz z czasem trwania gry. Zmienna dx oznacza kierunek poruszania siö piäeczki wzdäuĔ osi X. WartoĈè -1 zmiennej dx oznacza ruch w lewñ stronö, 0 oznacza brak ruchu, natomiast 1 to ruch w prawñ stronö. Z kolei zmienna dy przedstawia poruszanie siö piäeczki w pionie: wartoĈè -1 oznacza ruch w górö, Animacja 59 wartoĈè 1 w dóä. Kierunek moĔe byè okreĈlony takĔe dowolnñ wartoĈciñ z zakresu od -1 do 1, w takim przypadku piäeczka bödzie poruszaäa siö po ekranie pod dowolnym kñtem. Informacje o kierunku i prödkoĈci poruszania siö piäeczki trzeba zerowaè na poczñtku kaĔdej rundy, co wymaga dodania metody odpowiedzialnej za inicjalizacjö wspomnianych wartoĈci. Na poczñtku gry i kaĔdej rundy zmienne okreĈlajñce poäoĔenie oraz kierunek poruszania siö piäeczki powinny otrzymaè losowo wygenerowane wartoĈci. Ponownie wykorzystamy funkcjö arc4random(), której uĔyliĈmy w poprzednim rozdziale podczas budowy gry matematycznej. Jednak tym razem wybierana bödzie wartoĈè -1 lub 1. W pliku implementacji naleĔy umieĈciè kod metody reset: - (void)reset { // OkreĞlenie kierunku poruszania siĊ piáeczki: w lewo lub w prawo. if ((arc4random() 2) == 0) dx = -1; else dx = 1; // Odwrócenie wartoĞci dy, jeĪeli nie wynosi 0, poniewaĪ to spowoduje ruch piáeczki // w kierunku gracza, który zdobyá punkt. W przeciwnym razie kierunek bĊdzie wybrany losowo. if (dy != 0) dy = -dy; else if ((arc4random() 2) == 0) dy = -1; else dy = 1; // PrzejĞcie do losowo wybranego poáoĪenia na Ğrodku ekranu. viewPuck.center = CGPointMake(15 + arc4random() (320-30), 240); // Wyzerowanie prĊdkoĞci. speed = 2; } W powyĔszym kodzie zmienna dx otrzymuje losowo wybranñ wartoĈè: -1 lub 1. Tak wiöc na poczñtku rundy piäeczka bödzie poruszaäa siö w lewo lub w prawo. Ponadto zmienna dy otrzyma wartoĈè -1 lub 1, jeĈli obecnie ma wartoĈè 0. Jednak gdy jej wartoĈè jest róĔna od zera, kierunek zostanie odwrócony. Przyjöto takie rozwiñzanie, poniewaĔ na poczñtku gry piäeczka powinna poruszaè siö w losowo wybranym kierunku. Jednak po zdobyciu punktu przez gracza 1 piäeczka powinna poruszaè siö w przeciwnym kie- runku, aby gracz, który zdobyä punkt, musiaä uderzyè piäeczkö jako pierwszy. Metoda zerujñca zmienia takĔe poäoĔenie piäeczki i umieszcza jñ w dowolnym punkcie na linii Ĉrodkowej. PrödkoĈè poczñtkowa wynosi 2; to liczba pikseli, o które piäeczka siö prze- suwa podczas pojedynczej klatki animacji. Dlaczego akurat 2? Poczñtkowo wybraäem wartoĈè 1, ale wówczas prödkoĈè wydawaäa siö zbyt maäa. Kolejnym krokiem jest dodanie prostej funkcji animacji odpowiedzialnej za przesuniöcie piäeczki z jej poäoĔenia bieĔñcego do nowego z uwzglödnieniem kierunku i szybkoĈci. Funkcja animacji bödzie nieustannie wywoäywana podczas gry. PoniĔszy kod umieĈè pod metodñ reset: - (void)animate { // PrzesuniĊcie piáeczki do nowego poáoĪenia, uwzglĊdniając jej kierunek i prĊdkoĞü. viewPuck.center = CGPointMake(viewPuck.center.x + dx*speed, viewPuck.center.y + dy*speed); } Do interfejsu PaddlesViewController dodaj zmiennñ NSTimer: NSTimer *timer; 60 Rozdziaĥ 2. Hello Pong Dodana zmienna bödzie säuĔyäa do wywoäywania funkcji animacji co 1/60 sekundy, czyli z szybkoĈciñ 60 klatek na sekundö. Kod gwarantuje takĔe, Ĕe piäeczka bödzie widoczna podczas rozpoczynania animacji i ukrywana po jej zatrzymaniu. W ten sposób uzyskuje- my efekt „zabrania” piäeczki z pola gry, co jest uĔyteczne w przypadku wstrzymania gry. Odpowiednia logika zostanie dodana w dalszej czöĈci rozdziaäu. W smartfonie iPhone ekran jest odļwieŜany z czýstotliwoļcié 60 Hz, czyli 60 razy na sekundý. UŜycie szyb- szej animacji niŜ czýstotliwoļë odļwieŜania ekranu moŜe spowodowaë „przeskoczenie” pewnych klatek ani- macji. W celu uzyskania pĥynnej animacji najlepszym rozwiézaniem jest okreļlenie jej szybkoļci na poziomie jak najbliŜszym czýstotliwoļci odļwieŜania ekranu. Przedstawiony poniĔej kod umieĈè tuĔ za metodñ reset. Dodany kod jest odpowiedzialny za uruchamianie i zatrzymywanie stopera animacji gry. - (void)start { if (timer == nil) { // Utworzenie stopera animacji. timer = [[NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(animate) userInfo:NULL repeats:YES] retain]; } // WyĞwietlenie piáeczki. viewPuck.hidden = NO; } - (void)stop { if (timer != nil) { [timer invalidate]; [timer release]; timer = nil; } // Ukrycie piáeczki. viewPuck.hidden = YES; } Kolejnym krokiem jest dodanie metody viewDidLoad poprzez usuniöcie znaków komentarzy wokóä kodu metody viewDidLoad znajdujñcego siö juĔ w pliku implementacji lub poprzez dodanie nowej na koþcu pliku implementacji. W wymienionej metodzie bödzie nastöpo- waäo wyzerowanie zmiennych gry i uruchomienie animacji. Metoda viewDidLoad to takĔe odpowiednie miejsce do przeprowadzenia operacji inicjalizacyjnych, takich jak wczytanie widoku oraz poäñczenie wäaĈciwoĈci widoku (paletki i piäeczka) w celu uzyskania moĔli- woĈci dostöpu do nich: - (void)viewDidLoad { [super viewDidLoad]; Animacja 61 [self reset]; [self start]; } Po uruchomieniu gry przekonasz siö, Ĕe piäeczka jest szybko animowana poza ekran i nigdy nie powraca. W kolejnej sekcji dodasz wiöc kod odpowiedzialny za odbijanie piäeczki od Ĉcian i paletek. Wykrywanie kolizji W grze konieczne jest wykrywanie kolizji piäeczki ze Ĉcianami i paletkami. Dobrñ wiado- moĈciñ jest istnienie äatwego sposobu okreĈlenia, czy dwa widoki przecinajñ siö ze sobñ. Klasa UIView zawiera zmiennñ frame bödñcñ strukturñ CGRect, która przedstawia poäoĔenie i wielkoĈè widoku. Dziöki uĔyciu funkcji CGRectIntersectsRect moĔna okreĈliè, czy ramka przecina siö z innymi widokami. Konieczne jest utworzenie funkcji sprawdzajñcej, czy dany prostokñt przecina siö z piäeczkñ. JeĔeli tak, kierunek piäeczki zostanie zmieniony. Nowy kierunek piäeczki bödzie opcjonalny; podanie wartoĈci 0 dla zmiennej dx lub dy nie spowoduje zmiany. Nad funkcjñ animate naleĔy umieĈciè poniĔszy kod: - (BOOL)checkPuckCollision:(CGRect)rect DirX:(float)x DirY:(float)y { // Sprawdzenie, czy piáeczka przecina siĊ z podanym prostokątem. if (CGRectIntersectsRect(viewPuck.frame, rect)) { // Zmiana kierunku poruszania siĊ piáeczki. if (x != 0) dx = x; if (y != 0) dy = y; return TRUE; } return FALSE; } W ten sposób utworzyliĈmy eleganckñ, ogólnñ funkcjö wykrywania kolizji. Pozostaäo juĔ tylko dodanie implementacji wykrywania kolizji w metodzie animate. W przypadku lewej Ĉciany naleĔy utworzyè prostokñt obejmujñcy lewñ stronö ekranu. Dlatego teĔ zde- finiowanie prostokñta za pomocñ polecenia CGRectMake(-10,0,20,480) powoduje utwo- rzenie pionowego paska wzdäuĔ lewej krawödzi ekranu. ćciana tak naprawdö zaczyna siö poza ekranem w punkcie –10 i ma gruboĈè 20 pikseli, co oznacza, Ĕe poäowa zdefiniowa- nego prostokñta znajduje siö na ekranie. Podobnñ Ĉcianö tworzymy po prawej stronie ekranu — CGRectMake(310,0,20,480). Do zmiany kierunku piäeczki moĔna uĔyè funkcji fabs() pobierajñcej wartoĈè bezwzglödnñ liczby zmiennoprzecinkowej. JeĔeli piäeczka uderzy w lewñ Ĉcianö, wówczas kierunek X zostania zmieniony na liczbö dodatniñ, nato- miast w przypadku uderzenia prawej Ĉciany kierunek X bödzie liczbñ ujemnñ. W ten sposób uzyskujemy efekt odbicia piäeczki od Ĉciany z takñ samñ prödkoĈciñ. W obydwu przypadkach kierunek Y piäeczki jest ignorowany poprzez przekazanie wartoĈci 0. Nie chcesz, aby piäeczka zostaäa odbita w kierunku gracza, od którego przybyäa. Dlatego teĔ na koþcu metody animate umieĈè przedstawiony poniĔej kod: 62 Rozdziaĥ 2. Hello Pong // Sprawdzenie wystąpienia kolizji piáeczki z lewą lub prawą Ğcianą. [self checkPuckCollision:CGRectMake(-10,0,20,480) DirX:fabs(dx) DirY:0]; [self checkPuckCollision:CGRectMake(310,0,20,480) DirX:-fabs(dx) DirY:0]; Do wykrywania kolizji z paletkñ moĔna wykorzystaè zmiennñ frame obiektów viewPaddle1 i viewPaddle2. Kierunek Y piäeczki moĔe byè dostosowany do odbicia jej od paletki. JeĔeli piäeczka uderzy górnñ krawödĒ paletki, wówczas kierunek Y bödzie zmieniony na 1, co oznacza kierunek w dóä ekranu. Natomiast uderzenie przez piäeczkö dolnej krawödzi paletki oznacza zmianö kierunku Y na -1, co oznacza kierunek w górö ekranu. Gra powinna dostosowaè takĔe kierunek X piäeczki na podstawie miejsca uderzenia paletki gracza. JeĔeli piäeczka uderzy lewñ stronö paletki, wówczas odbicie powinno nastñpiè w lewñ stronö. Natomiast uderzenie prawej strony paletki powinno spowodowaè odbicie piäeczki w prawñ stronö. Po obliczeniu róĔnicy pomiödzy dwoma Ĉrodkami obiektów wzdäuĔ osi X otrzyma siö liczbö dodatniñ lub ujemnñ — w zaleĔnoĈci od miejsca uderzenia. PoniewaĔ paletka ma szerokoĈè 64 pikseli, róĔnicö moĔna podzieliè przez 32 i znormalizowaè wartoĈè wynikowñ pomiödzy -1 i 1. Przykäadowo: jeĈli Ĉrodek piäeczki uderzy lewñ stronö paletki, wówczas róĔnica pomiödzy obydwoma Ĉrodkami wzdäuĔ osi X wyniesie –32. Po podziele- niu tej róĔnicy przez 32 wynikiem bödzie wartoĈè -1 przypisana zmiennej dx, co przekäada siö na odbicie piäeczki w lewñ stronö. PoniĔszy kod umieĈè na koþcu metody animate: // Wykrywanie kolizji piáeczki z paletkami graczy. [self checkPuckCollision:viewPaddle1.frame DirX:(viewPuck.center.x - viewPaddle1.center.x) / 32.0 DirY:1]; [self checkPuckCollision:viewPaddle2.frame DirX:(viewPuck.center.x - viewPaddle2.center.x) / 32.0 DirY:-1]; Po wprowadzeniu tych zmian uruchom grö i przekonaj siö, Ĕe piäeczka odbija siö od lewej i prawej Ĉciany oraz od górnej i dolnej paletki. Zwróè takĔe uwagö, Ĕe przejĈcie piäeczki obok paletki powoduje opuszczenie przez niñ pola gry, na które nigdy juĔ nie wraca. Trzeba wiöc zajñè siö obsäugñ i tej sytuacji oraz zapewniè moĔliwoĈè zdobywania punktów przez graczy. Punktacja W widoku trzeba umieĈciè kilka etykiet pozwalajñcych na wyĈwietlenie punktacji. PrzejdĒ do moduäu Iterface Builder i ponownie otwórz plik PaddlesViewController.xib. Przeciñgnij nowñ etykietö na widok, ustaw 0 jako jej tekst poczñtkowy, wyĈrodkuj go, a nastöpnie zwiöksz czcionkö do przynajmniej 24 punktów. Etykietö umieĈè przy prawej krawödzi ekranu. Nastöpnie przejdĒ do inspektora wielkoĈci i przenieĈ do centrum poäoĔenie punktu poczñtkowego (Origin). Ustaw 200 jako wartoĈè Y, co oznacza 40 pikseli nad li- niñ Ĉrodkowñ. Wynik powinien byè podobny do pokazanego na rysunku 2.11. Punktacja 63 Rysunek 2.11. Dodanie etykiet punktacji do widoku Skopiuj i wklej etykietö oraz umieĈè jñ poniĔej linii Ĉrodkowej, mniej wiöcej w takiej samej odlegäoĈci. Upewnij siö o dosuniöciu etykiety do prawej krawödzi widoku, a nastöpnie dla Y ustaw wartoĈè 280, czyli 40 pikseli poniĔej linii Ĉrodkowej. Podobnie jak wczeĈniej utwórz w kontrolerze widoku outlety dla nowych etykiet, co po- zwoli Ci na uzyskiwanie do nich dostöpu poprzez kod. Etykieta dla pierwszego gracza powinna nosiè nazwö viewScore1, natomiast dla drugiego — viewScore2. Po wprowadzeniu zmian plik interfejsu bödzie miaä nastöpujñcñ postaè: @interface PaddlesViewController : UIViewController { UITouch *touch1; UITouch *touch2; float dx; float dy; float speed; NSTimer *timer; } @property (nonatomic, retain) IBOutlet UIView *viewPaddle1; @property (nonatomic, retain) IBOutlet UIView *viewPaddle2; @property (nonatomic, retain) IBOutlet UIView *viewPuck; @property (nonatomic, retain) IBOutlet UILabel *viewScore1; @property (nonatomic, retain) IBOutlet UILabel *viewScore2; @end Konieczne jest dodanie funkcji sprawdzajñcej, czy którykolwiek z graczy wywalczyä punkt. JeĔeli piäeczka uderzy w górnñ krawödĒ ekranu, punkt wywalczyä gracz numer dwa. 64 Rozdziaĥ 2. Hello Pong Natomiast jeĈli piäeczka uderzy w dolnñ krawödĒ ekranu, punkt zyskuje gracz numer jeden. W celu dodania punktu wartoĈci obydwu etykiet punktacji muszñ zostaè skonwer- towane na liczby caäkowite. Klasa NSString posiada metodö o nazwie intValue, której wartoĈciñ zwrotnñ jest liczba caäkowita z podanego ciñgu tekstowego. Metoda intValue zawsze zwraca liczbý caĥkowité, niezaleŜnie od zawartoļci ciégu tekstowego. JeŜeli ciég tekstowy zawiera inne dane niŜ liczba, na przykĥad litery bédŚ symbole, wartoļcié zwrotné býdzie 0. Jeļli na po- czétku ciégu tekstowego znajdzie siý puste miejsce, zostanie pominiýte. Metoda ponadto zwraca wartoļë INT_MAX lub INT_MIN w przypadku przepeĥnienia. WartoĈci liczbowe obydwu etykiet bödñ przechowywane w zmiennych s1 i s2, a na- stöpnie zwiökszane o jeden po wywalczeniu punktu przez gracza. Ostatnim krokiem jest konwersja wartoĈci liczbowej z powrotem na ciñg tekstowy, uaktualnienie wartoĈci etykiet punktacji i wyzerowanie rundy. Funkcja checkGoal okreĈla takĔe, czy punkt zo- staä zaliczony, czy nie. PoniĔszy kod umieĈè przed funkcjñ animate: - (BOOL)checkGoal { // Sprawdzenie, czy piáeczka wykroczyáa poza ekran. JeĞli tak, zerujemy rundĊ. if (viewPuck.center.y 0 || viewPuck.center.y = 480) { // Pobranie wartoĞci liczbowej z etykiet punktacji. int s1 = [viewScore1.text intValue]; int s2 = [viewScore2.text intValue]; // Przydzielenie punktu odpowiedniemu graczowi. if (viewPuck.center.y 0) ++s2; else ++s1; // Uaktualnienie etykiet punktacji. viewScore1.text = [NSString stringWithFormat:@ u , s1]; viewScore2.text = [NSString stringWithFormat:@ u , s2]; // Wyzerowanie rundy. [self reset]; // Zwrócenie wartoĞci TRUE w przypadku zdobycia punktu. return TRUE; } // Brak punktu. return FALSE; } Nastöpnie wywoäanie funkcji checkGoal trzeba umieĈciè na koþcu metody animate: - (void)animate { // PrzesuniĊcie piáeczki do nowego poáoĪenia, uwzglĊdniając jej kierunek i prĊdkoĞü. viewPuck.center = CGPointMake(viewPuck.center.x + dx*speed, viewPuck.center.y + dy*speed); // Sprawdzenie wystąpienia kolizji piáeczki z lewą lub prawą Ğcianą. [self checkPuckCollision:CGRectMake(-10,0,20,480) DirX:fabs(dx) DirY:0]; Punktacja 65 [self checkPuckCollision:CGRectMake(310,0,20,480) DirX:-fabs(dx) DirY:0]; // Wykrywanie kolizji piáeczki z paletkami graczy. [self checkPuckCollision:viewPaddle1.frame DirX:(viewPuck.center.x - viewPaddle1.center.x) / 32.0 DirY:1]; [self checkPuckCollision:viewPaddle2.frame DirX:(viewPuck.center.x - viewPaddle2.center.x) / 32.0 DirY:-1]; // Sprawdzenie, czy zostaá zdobyty punkt. [self checkGoal]; } Uruchom grö i podziwiaj przyznawanie punktów oraz zerowanie rundy po przejĈciu piäeczki przez górnñ lub dolnñ krawödĒ ekranu. W ten sposób z powodzeniem zaimple- mentowaliĈmy dziaäajñcy system punktacji, ale obecnie gra nigdy siö nie koþczy. Kolej- nym krokiem bödzie dodanie warunku koþczñcego grö oraz ostateczne jej wykoþczenie. Wykoħczenie gry Grö trzeba jeszcze dopracowaè, miödzy innymi dodaè komunikat wyĈwietlany po wy- graniu rundy przez gracza, daè graczom moĔliwoĈè przygotowania siö przed rozpoczö- ciem gry, zwiökszaè trudnoĈè gry po kaĔdym uderzeniu piäeczki oraz dodaè moĔliwoĈè wstrzymywania i wznawiania gry. Wyļwietlanie komunikatów Najäatwiejszym sposobem wyĈwietlenia uĔytkownikowi komunikatu jest wykorzystanie okna komunikatu. Wspomniane okno powoduje wyĈwietlenie komunikatu i wymaga naci- Ĉniöcia przycisku zamykajñcego okno. UĔywana do wyĈwietlenia okna klasa UIAlertView ma bardzo prosty interfejs. W pliku interfejsu umieĈè poniĔszy wiersz kodu: UIAlertView *alert; Teraz naleĔy utworzyè funkcjö pobierajñcñ treĈè komunikatu i wyĈwietlajñcñ go uĔyt- kownikowi. Funkcja powinna równieĔ zatrzymaè animacjö, co efektywnie spowoduje wstrzymanie gry na czas wyĈwietlania komunikatu. Oprócz tego przed wyĈwietleniem komunikatu funkcja sprawdzi, czy w danej chwili jest wyĈwietlany jakikolwiek inny komunikat. Przedstawiony poniĔej kod umieĈè za funkcjñ stop: - (void)displayMessage:(NSString*) msg { // JednoczeĞnie moĪe byü wyĞwietlony tylko jeden komunikat. if (alert) return; // Wstrzymanie animacji. [self stop]; // Utworzenie i wyĞwietlenie okna komunikatu. 66 Rozdziaĥ 2. Hello Pong alert = [[UIAlertView alloc] initWithTitle:@ Gra message:msg delegate:self cancelButtonTitle:@ OK otherButtonTitles:nil]; [alert show]; [alert release]; } PowyĔszñ funkcjö moĔesz wykorzystaè po uruchomieniu gry w celu umoĔliwienia graczom przygotowania siö do rozgrywki. Utworzymy takĔe funkcjö o nazwie newGame odpowie- dzialnñ za wyzerowanie rundy, ustawienie wartoĈci 0 punktacji oraz wyĈwietlenie ko- munikatu o treĈci Gotowi do gry?. PoniĔej funkcji displayMessage w pliku implementacji umieĈè kod wymienionej funkcji newGame: - (void)newGame { [self reset]; // Wyzerowanie punktacji. viewScore1.text = [NSString stringWithString:@ 0 ]; viewScore2.text = [NSString stringWithString:@ 0 ]; // WyĞwietlenie komunikatu pozwalającego na rozpoczĊcie gry. [self displayMessage:@ Gotowi do gry? ]; } Metoda viewDidLoad do doskonaäe miejsce na wyĈwietlenie komunikatu pozwalajñcego graczom na rozpoczöcie rozgrywki. MoĔna w tym miejscu usunñè stoper animacji, ponie- waĔ gra oficjalnie siö rozpocznie po naciĈniöciu przycisku OK. Istniejñcy kod w metodzie viewDidLoad zastñp poniĔszym: - (void)viewDidLoad { [super viewDidLoad]; [self newGame]; } Po naciĈniöciu przycisku przez uĔytkownika klasa UIAlertView wywoäa delegata. JeĈli komunikat zawiera wiöcej niĔ tylko jeden przycisk, wówczas trzeba sprawdziè wartoĈè parametru buttonIndex w celu ustalenia, który przycisk zostaä naciĈniöty. W omawianym przypadku mamy tylko pojedynczy przycisk OK, wiöc nie ma potrzeby sprawdzania. Aby zapewniè obsäugö wywoäania zwrotnego, tuĔ za definicjñ funkcji newGame umieĈè nastö- pujñcy kod: - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { // Okno zostaáo zamkniĊte, wiĊc moĪna rozpocząü grĊ. alert = nil; // Wyzerowanie rundy. [self reset]; // RozpoczĊcie animacji. [self start]; } Wykoħczenie gry 67 PowyĔszy kod spowoduje wyzerowanie wartoĈci zmiennej alert, wyzerowanie zmien- nych rundy oraz rozpoczöcie odtwarzania animacji. Po uruchomieniu gry zostanie wyĈwie- tlony komunikat pozwalajñcy graczom na przygotowanie siö do rozgrywki przed fak- tycznym jej rozpoczöciem. Tö samñ logikö wykorzystamy do wyĈwietlenia komunikatu Koniec gry. Koniec gry Trzeba okreĈliè liczbö punktów, której osiñgniöcie przez dowolnego gracza spowoduje zakoþczenie gry i ogäoszenie zwyciözcy. Zalecam ustawienie tej wartoĈci na minimum, aby moĔna byäo äatwo przetestowaè warunek koþczñcy grö. W takich przypadkach najczö- Ĉciej korzystam z dyrektywy #define, która umoĔliwia äatwe zwiökszenie wartoĈci w przy- szäoĈci. Wspomnianñ wartoĈè prawdopodobnie trzeba bödzie zwiökszyè w przyszäoĈci lub nawet umoĔliwiè graczom jej ustalenie. Na poczñtku pliku implementacji umieĈè poniĔszy wiersz kodu: #define MAX_SCORE 3 Kolejnym krokiem jest dodanie poniĔszej metody, w której nastöpuje sprawdzenie, czy gra powinna siö oficjalnie zakoþczyè. WartoĈci obydwu etykiet punktacji sñ konwerto- wane na liczby, a nastöpnie kod sprawdza, czy którykolwiek z graczy zdobyä zdefiniowanñ maksymalnñ moĔliwñ do zdobycia liczbö punktów. Metoda informuje takĔe, który gracz zdobyä tö liczbö punktów. W pliku implementacji umieĈè przedstawiony poniĔej kod: - (int)gameOver { if ([viewScore1.text intValue] = MAX_SCORE) return 1; if ([viewScore2.text intValue] = MAX_SCORE) return 2; return 0; } Nastöpnie musimy zmodyfikowaè metodö wyĈwietlajñcñ okno komunikatu w celu do- dania operacji sprawdzenia, czy gra zostaäa zakoþczona. JeĔeli gra zostaäa zakoþczona, wówczas rozpoczynamy nowñ i pytamy graczy, czy sñ gotowi do ponownego podjöcia rozgrywki: - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { // Okno zostaáo zamkniĊte, wiĊc moĪna wyzerowaü grĊ i rozpocząü odtwarzanie animacji. alert = nil; // Sprawdzenie, czy naleĪy rozpocząü nową grĊ. if ([self gameOver]) { [self newGame]; return; } // Wyzerowanie rundy. [self reset]; // Wyzerowanie animacji. [self start]; } 68 Rozdziaĥ 2. Hello Pong Trzeba równieĔ zmodyfikowaè funkcjö odpowiedzialnñ za przyznawanie punktu gra- czowi i dodaè logikö sprawdzajñcñ, czy gracz wygraä grö. JeĔeli zdefiniowana liczba punk- tów wymaganych do wygrania gry nie zostaäa jeszcze zdobyta, wówczas podobnie jak wczeĈniej jedynie zerujemy rundö. W metodzie checkGoal dodaj wiersze, które poniĔej zostaäy pogrubione: - (BOOL)checkGoal { // Sprawdzenie, czy piáeczka wykroczyáa poza ekran. JeĞli tak, zerujemy rundĊ. if (viewPuck.center.y 0 || viewPuck.center.y = 480) { // Pobranie wartoĞci liczbowej z etykiet punktacji. int s1 = [viewScore1.text intValue]; int s2 = [viewScore2.text intValue]; // Przydzielenie punktu odpowiedniemu graczowi. if (viewPuck.center.y 0) ++s2; else ++s1; // Uaktualnienie etykiet punktacji. viewScore1.text = [NSString stringWithFormat:@ u , s1]; viewScore2.text = [NSString stringWithFormat:@ u , s2]; // Sprawdzenie zwyciĊzcy. if ([self gameOver] == 1) { // Ogáoszenie zwyciĊzcy. [self displayMessage:@ Wygraï gracz numer 1! ]; } else if ([self gameOver] == 2) { // Ogáoszenie zwyciĊzcy. [self displayMessage:@ Wygraï gracz numer 2! ]; } else { // Wyzerowanie rundy. [self reset]; } // Zwrócenie wartoĞci TRUE w przypadku zdobycia punktu. return TRUE; } // Brak punktu. return FALSE; } Uruchom grö i prowadĒ rozgrywkö do chwili, gdy jeden z graczy zdobödzie trzy punkty. Na tym etapie gra powinna ogäosiè zwyciözcö. Po zamkniöciu okna gra zostanie wyze- rowana i gracze bödñ mogli rozpoczñè rozgrywkö od poczñtku. Zwiýkszanie poziomu trudnoļci Bardzo waĔne jest znalezienie wäaĈciwego sposobu na zwiökszanie poziomu trudnoĈci gry w trakcie rozgrywki. Na obecnym etapie gra jest bardzo äatwa i istnieje moĔliwoĈè, Wykoħczenie gry 69 Ĕe Ĕaden z graczy nigdy nie „przepuĈci” piäeczki. PoniĔej znajduje siö lista, którñ przy- gotowaäem, zastanawiajñc siö nad sposobem zwiökszenia poziomu trudnoĈci gry: x zwiökszenie prödkoĈci piäeczki; x zmniejszenie wielkoĈci piäeczki; x zmniejszenie szerokoĈci paletek; x umieszczenie obiektów dodatkowych na trasie poruszania siö piäeczki. Obecnie w grze mamy zmiennñ okreĈlajñcñ szybkoĈè poruszania siö piäeczki i jest ona zerowana na poczñtku kaĔdej rundy. Zmienna okreĈlajñca prödkoĈè jest stosowana równieĔ podczas ustalania kierunku poruszania siö piäeczki podczas jej animacji. Zwiökszenie prödkoĈci poruszania siö piäeczki po kaĔdym uderzeniu jej paletkñ wydaje siö proste do implementacji. W tym miejscu trzeba pamiötaè o jednej waĔnej kwestii: istnieje prödkoĈè maksymalna, z jakñ moĔe poruszaè siö piäeczka — jej przekroczenie moĔe spowodowaè „przeskakiwanie” piäeczki ponad paletkami lub prostokñtami uĔytymi w charakterze Ĉcian po lewej i prawej stronie ekranu. Paletki majñ wysokoĈè 16 pikseli, natomiast szerokoĈè Ĉcian wynosi 20 pikseli. JeĔeli szybkoĈè piäeczki bödzie wiöksza od podanych wartoĈci, wówczas istnieje niebezpieczeþstwo przeskoczenia tych obiektów, a tym samym nie dojdzie do wykrycia kolizji. Dl
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Dotknij, przesuń, potrząśnij. Od pomysłu do gry na iPhone a i iPada
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: