flatCube: a komponens – iOS

Lassan elértük a célt, itt a flatCube komponens, amely a projekt végcélja volt. Kezdetben azt gondoltuk, hogy ez egy kicsi és egyszerű feladat, de végül mégsem úgy lett. Végül kiderült, hogy sokan sokkal egyszerűbbnek gondoltuk a feladatot.

A lényeg mindenesetre, hogy elkészültünk, így már csak a grafikai dizájn van hátra, illetve ki kell találni valami keretet, hogy a komponens hasznos része legyen egy kis programnak amelyben számos kocka kirakható. Nézzük miből és hogyan állt össze a flatCube komponens.

A komponens elkészítéséhez már minden technikai kérdést tisztáztunk a korábban publikált POC-okban. Mégis érdemes néhány szóban végigszaladni azokon a buktatókon, amelyekbe a komponens készítése közben beleütközhetünk.

Ebben a cikkben lesz ugyan néhány iOS specifikus gondolat, de többnyire a megoldásban alkalmazott szerkezeti elemek tárgyaljuk a következő pontokban:

- Felépítés
- Megjelenítés
- Mozgatás

Az alkalmazás felépítése

Bár a jó komponens minden környezetben könnyen felhasználható, mégis első nekifutásra azt gondoltam érdemes megnézni hol és hogyan fogjuk felhasználni, így szerkezeti kérdésekben mindjárt többet tudunk majd.

Nos, az én elképzelésem szerint lenne egy GameManager, ami “kontrollálja” a teljes játékot. Van egy rakás megoldandó kockánk kiindulási és végállapotokkal, a GameManager ezeket adja sorban megoldásra a játékosnak. Mindezek mellett kell még valami ami képes megjeleníteni egy megoldandó kockát és kontrollálni a játékos “akció”-it. Tehát minden kocka megoldásához létre kell hozni egy GameSet-et amely tartalmazza a kockához tartozó model-t view-t és controller-t is.

A kocka megjelenítése

A kocka megjelenítéséhez, a kockát alkotó tile-ok tologatásához választanunk kell egy módszert. Több lehetőség is van, melyek közül én azt választottam, hogy amint a tile eltűnik az egyik oldalon, azzal egyidőben jelenik meg a másik oldalon egy vele azonos színű. Ennek megoldásához biztosan kelleni fog plusz egy tile így a mozgatott sorban vagy oszlopban eggyel több lesz mint máshol (a mellékelt képen az első oszlopot kezdtük mozgatni lefelé). Kezdetben úgy gondoltam érdemes körbe rakni a kockát tile-okkal, amelyek megjelennek majd, ha egy sor vagy oszlopot mozgatunk. Később egy egyszerű szabályt alkalmazva, mely szerint egy mozgatási akció maximálisan a következő “tile pozició” (amikor minden tile valamely lehetséges végpozícióban áll) eléréséig történhet, kiderült, hogy elegendő a “swap területen” (azaz a kockán kívüli területek valamelyikén) egyetlen tile-t fenntartani minden színből és a mozgatás megkezdésekor a megfelelő helyre mozgatni.

A másik érdekes kérdés, hogy a ki- és beúszó tile-ok elrejtését hogyan oldjuk meg.

Az iOS framework-ben ezzel nem kell túl sokat dolgozni, bár azt gondolom ez szinte mindenhol épp így megoldható. A homogénnek tűnő háttér itt igazából öt részből áll. A cube container a kocka látható területe, míg az őt körülvevő további négy “takaró view” sorrendben utána következik, így minden ami a cube container-ben kerül megjelenítésre ezen takaró view-k alatt jelenik majd meg, így nem lesz látható. (Zárójeles megjegyzésként érdemes megemlíteni, hogy iOS framework a view-n kívül is megjeleníti a view tartalmat, azaz lehetséges a -1000 vízszintes pozícióra is elhelyezni valamit.)

Mozgatás – gesture érzékelés

A mozgatással kapcsolatos első gondolatunk, hogy bármely tile megfogható és elmozdítható a kockában. Ehhez kapcsolódóan azonnal társul az ötlet, hogy akkor minden tile-hoz kapcsolunk egy gesture recognizer-t. Elsőre én is ezt választottam, aztán később áttértem egy erőforrás takarékosabb megoldásra, mely szerint csak a cube container view-hoz rendelek egy gesture ricognizer-t, amivel a kockán kezdeményezett valamennyi gesture-t fel lehet dolgozni, csak azt kell azonosítani, hogy mely sort vagy oszlopot érintette meg a felhasználó. Mint az előző képkivágáson látható, ennek a választásnak járulékos apró előnye, hogy a pan gesture recognizer-t így design-time hozzá tudom rendelni a view-hoz.

Model

A kockához tartozó modell nem túl bonyolult, csak a kocka méretét, az egyes pozíciókon található színeket kell tárolni, valamint biztosítani a sorok és oszlopok mozgatásának lehetőségét.

Természetesen a tényleges tárolás megoldására meg kell találni a leghatékonyabb módszert, amely talán minden platformon a maximális méretű kocka tárolására alkalmas két dimenziós tömb lesz.

Megjelenítés támogatása

A kocka megjelenítése több szinten is támogatásért kiált. Egyrészt kell valami amelyben a megjelenítésben felhasznált grafikai elemeket tároljuk, másrészt kell egy logika, melyet a view controller fel tud használni a felhasználói akciók lekezelésére.

Tile tároló

Ebben a tárolóban vannak azok a grafikai elemek (színek és tile grafika), amelyek segítségével a kockát a kijelzőn megjelenítjük. Első gondolatként eszembe nem jutott, hogy ezeket külön tárolóba helyezzem, mivel a hozzájuk tartozó cube container view tárolja őket, de amint a mozgatást kellett adminisztrálni, már írtam is a tárolót.

Legfontosabb különbség a model szerkezete és e tároló szerkezete között, hogy ebben a tárolóban a swap területen lévő tile-ok is nyilván vannak tartva, valamint a tároló csatlakozik egy tile factory-hoz, melynek segítségével olyan tile-t tud létrehozni a swap területen amelyből ott még nincs egyetlen példány sem.

Tile mozgatáshoz kapcsolódó logika

A tile-ok mozgatása a megjelenítő felületen más dimenzió mentén valósul meg mint ahogy a modellben van. A megjelenítés alapegysége iOS framework-ben a pont (erről az Univerzácis alkalmazások cikkben részletesen olvashatunk). Ehhez mérten a mozgatás logikája is pont alapegységgel kell, hogy dolgozzon.

Alapvetően két dolgot kell megvalósítani. Egyrészt a mozgatást adott irányba adott pont elmozdulással, melyet a felhasználó tap gesture feldolgozására használunk, másrészt a mozgatás befejezését, azaz amikor a felhasználó felengedi az érintést, a legközelebbi tile pozicióba kell juttatni a tile-okat. Ez utóbbi kapcsán szintén érdekes elgondolkodni az ideális megoldáson, azaz megtalálni a leginkább “komfortos” megoldást, hogy minél természetesebben tűnjön a mozgatás.

Mint ahogy korábban a swap terület kialakításánál említettem bevezettem egy szabályt, mely szerint egy tap esemény feldologozásakor legfeljebb a következő tile pozícióig mozgatom a tile-okat, azaz ha a tile méret 100 pont és már mozgattam 90 pontot jobbra, akkor a következő jobbra mozgatás feldolgozásakor maximum 10 pontot fog mozogni a tile, még ha a felhasználó hirtelen 20 pontra is rántotta az ujját. Ez alapján mindig elegendő egyetlen tile-t a swap területen tartani.

Mozgatás befejezése – tile pozícióba vitel

azaz mit kell tenni, ha a felhasználó felengedte az érintést:

  • Első és legegyszerűbb megoldás, a közelebb lévő tile pozícióba vitel, azaz ha a mozgatás mértéke a tile méret fele vagy kevesebb akkor visszafelé, egyébként a mozgatás irányába.
  • Egy másik lehetőség a mozgatás irányába a következő tile pozícióba mozgatás függetlenül attól, hogy mennyi volt a mozgatásból származó elmozdulás.
  • További lehetőség az előzőek mellett a mozgatás dinamikájának figyelembe vétel azaz minél határozottabb a felhasználó mozdulata, annál nagyobb a mozgatás irányába történő helyre vitel súlya.

További megfontolások

Mint látható a tile tároló egy factory-t használ a hiányzó tile-ok létrehozására. Ez azon túl, hogy nincs a tárolóba betonozva a tile gyártó algoritmus, azért is hasznos, mert így a tesztelésnél a gyártó kicserélhető (mock-olható) és ezáltal a teszteléshez sokkal jobban használható komponenst állíthatunk elő, valamint a gyártó felhasználását is ellenőrizhetjük.

MVC minta alkalmazása

Az alábbi osztálydiagram remekül szemlélteti, hogy a megoldás valóban megfelel az MVC minta által előírt konvencióknak. Jó látható, hogy a Model-View-Controller egymással kizárólag interfészek mentén kommunikál:


Take canada homework help a ton more farmers to join democratic republicans b
Kategória: Általános | A közvetlen link.