KUNTOUTUSAIHEISEN MOBIILISOVELLUKSEN TOTEUTUS UNITYSSÄ



Samankaltaiset tiedostot
Android ohjelmointi. Mobiiliohjelmointi 2-3T5245

Pedacode Pikaopas. Java-kehitysympäristön pystyttäminen

Selainpelien pelimoottorit

PLA Mobiiliohjelmointi. Mika Saari

PLA Mobiiliohjelmointi. Mika Saari

Tietotalo Insight. Digitaalinen markkinointi. Beacon FAQ: Vastaukset yleisimpiin kysymyksiin beaconeista

ELM GROUP 04. Teemu Laakso Henrik Talarmo

CTRL+F Android-sovellus

Kieliversiointityökalu Java-ohjelmistoon. Ohje

Qt kaikkialla?

Älypuhelimet. Sisällysluettelo

Jypelin käyttöohjeet» Ruutukentän luominen

C-ohjelmointikielen perusteet, osa 1

Sisäänrakennettu tietosuoja ja ohjelmistokehitys

Dart. Ryhmä 38. Ville Tahvanainen. Juha Häkli

SALITE.fi -Verkon pääkäyttäjän ohje

Maastotietokannan torrent-jakelun shapefile-tiedostojen purkaminen zip-arkistoista Windows-komentojonoilla

Historiaa. Unix kirjoitettiin kokonaan uudestaan C-kielellä Unix jakautui myöhemmin System V ja BSDnimisiin. Kuutti, Rantala: Linux

Tekninen suunnitelma - StatbeatMOBILE

EDUBOX opetusvideopalvelu

Purot.net Wiki. Tutkielma. Paavo Räisänen. Centria Ammattikorkeakoulu

Pikaopas. Valintanauhan näyttäminen tai piilottaminen Avaa valintanauha napsauttamalla välilehteä, tai kiinnitä se pysyvästi näkyviin.

Googlen pilvipalvelut tutuksi / Google Drive

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

Ohjelmoinnin jatkokurssi, kurssikoe

Tietotunti klo 12 ja 17. Aiheena sosiaalisen median sovellukset: Instagram, Twitter, WhatsApp ja Facebook

Googlen pilvipalvelut tutuksi / Google Drive

Oliosuunnitteluesimerkki: Yrityksen palkanlaskentajärjestelmä

JWT 2016 luento 11. to klo Aulikki Hyrskykari. PinniB Aulikki Hyrskykari

Tiedonhallinnan perusteet. Viikko 1 Jukka Lähetkangas

Visual Basic -sovelluskehitin Juha Vitikka

AS Automaatio- ja systeemitekniikan projektityöt

PELAAJAPROFIILI Mobiilisovellus

Opinnäytteen nimi ja mahdollinen alaotsikko (tämä pohja toimii parhaiten Word2010-versiolla)

Office ohjelmiston asennusohje

Matopeli C#:lla. Aram Abdulla Hassan. Ammattiopisto Tavastia. Opinnäytetyö

Pelisuunnittelua tulevaisuudessa. Karoliina Korppoo / Colossal Order

Pythonin alkeet Syksy 2010 Pythonin perusteet: Ohjelmointi, skriptaus ja Python

Valintanauhan komennot Valintanauhan kussakin välilehdessä on ryhmiä ja kussakin ryhmässä on toisiinsa liittyviä komentoja.

DXL Library ja DXL-kielen olemus. Pekka Mäkinen SoftQA Oy http/

Web Services tietokantaohjelmoinnin perusteet

C++ Ohjelmoijan käsikirja. Johdanto

Office 365 palvelujen käyttöohje Sisällys

Skype for Business pikaohje

SQLite selvitysraportti. Juha Veijonen, Ari Laukkanen, Matti Eronen. Maaliskuu 2010

2007 Nokia. Kaikki oikeudet pidätetään. Nokia, Nokia Connecting People, Nseries ja N77 ovat Nokia Oyj:n tavaramerkkejä tai rekisteröityjä

Järjestelmäarkkitehtuuri (TK081702) Web Services. Web Services

VHOPE-sovelluksen ja VHOPE-kirjastotiedostojen asentaminen

Luo mediaopas Tarinatallentimella

Adobe Premiere Elements ohjeet

MOBISITE-TYÖKALUN SISÄLTÄMÄT TOIMINNOT

Ohjelmiston toteutussuunnitelma

Sanomapavelinohjelmiston käyttöohje (Vanha versio RO)

Tekninen suunnitelma - StatbeatMOBILE

CT50A2601 Käyttöjärjestelmät Androidin ja Symbianin vertailu Seminaarityö

Tämän lisäksi listataan ranskalaisin viivoin järjestelmän tarjoama toiminnallisuus:

OHJELMISTOKEHITYS -suuntautumisvaihtoehto

JOVISION IP-KAMERA Käyttöohje

Ohjelmointi 1. Kumppanit

Keskustelusivusto. Suunnitteludokumentti

Wordpress- ohje nettisivujen laadintaan

OP-eTraderin käyttöopas

TimeEdit opiskelijan ohje TimeEdit-instructions for students from this link

Avoimen lähdekoodin kehitysmallit

Venekilpailu! Esteiden väistely ja hahmon ohjaaminen

Koe uusi. Windows 8 viidessä minuutissa

idvd 5 ELOKUVAKASVATUS SODANKYLÄSSÄ Vasantie Sodankylä +358 (0) tommi.nevala@sodankyla.fi

Pedacode Pikaopas. Web-sovelluksen luominen

ViLLE Mobile Käyttöohje

Luku 7 Uusien Mallien Tiedostot

Mobiilisovellukset fysioterapiaasiakkaan. ONT-suunnitelma/Laura Aaltonen ja Antti Lepola 2013

Kirjoita oma versio funktioista strcpy ja strcat, jotka saavat parametrinaan kaksi merkkiosoitinta.

<e.g. must, essential, conditional>

ipad maahanmuuttajien ohjauksessa Laitteen käyttöönotto Kotomaatti 2016

Käytön aloittaminen NSZ-GS7. Verkkomediasoitin. Näyttökuvia, toimintoja ja teknisiä ominaisuuksia voidaan muuttua ilman erillistä ilmoitusta.

Visma Fivaldi -käsikirja Tehtävienhallinta- ohje käyttäjälle

DNA:n kysely esikoulu- ja ala-asteikäisten matkapuhelinten käytöstä

LoCCaM Riistakamerasovellus. Dimag Ky dimag.fi

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

Harjoitus Morphing. Ilmeiden luonti

Manager. Doro Experience. ja Doro PhoneEasy 740. Suomi

Aimo-ohjauspaneelin käyttöohje Sisällys

tään painetussa ja käsin kirjoitetussa materiaalissa usein pienillä kreikkalaisilla

Jussi Klemola 3D- KEITTIÖSUUNNITTELUOHJELMAN KÄYTTÖÖNOTTO

erasmartcardkortinlukijaohjelmiston

Tech Conference Visual Studio 2015, C#6,.NET4.6. Heikki Raatikainen. #TechConfFI

PLAY. TP1 Mobiili musiikkikasvatusteknologia MEDIAT Kuvan ja äänen tallentaminen, muokkaaminen ja jakaminen (v1.1)

Valintanauhan komentojen selaaminen Jokaisessa valintanauhassa on ryhmiä ja jokaisessa ryhmässä on joukko siihen liittyviä komentoja.

AS C-ohjelmoinnin peruskurssi 2013: C-kieli käytännössä ja erot Pythoniin

Uutta Remote Support Platform 3.0 -versiossa

Googlen palvelut synkronoinnin apuna. Kampin palvelukeskus Jukka Hanhinen, Urho Karjalainen, Rene Tigerstedt, Pirjo Salo

KYMENLAAKSON AMMATTIKORKEAKOULU Tietotekniikan koulutusohjelma / Tietoverkkotekniikka

Jouko Nielsen. Ubuntu Linux

CODEONLINE. Monni Oo- ja Java-harjoituksia. Version 1.0

Linkitetystä listasta perittyä omaa listaa käytetään muun muassa viestiin liittyvien vastausten säilömiseen.

VINKKEJÄ CV-NETIN KÄYTTÖÖN.

Kirjan toteutus BoD easybook -taittotyökalun avulla

Opiskelun ja työelämän tietotekniikka (DTEK1043)

Transkriptio:

KUNTOUTUSAIHEISEN MOBIILISOVELLUKSEN TOTEUTUS UNITYSSÄ Jaakko Rohunen Opinnäytetyö Syyskuu 2014 Tietojenkäsittely

TIIVISTELMÄ Tampereen ammattikorkeakoulu Tietojenkäsittely ROHUNEN, JAAKKO: Kuntoutusaiheisen mobiilisovelluksen toteutus Unityssä Opinnäytetyö 59 sivua Syyskuu 2014 Terveydenhuolto ja kuntoutus on tällä hetkellä yksi tärkeistä painopisteistä mobiilisovellusten sekä kuluttajille suunnattujen teknisten laitteiden kehityksessä. Niin sanottu mhealth eli terveydenhuoltoa sivuavat mobiilisovellukset ovat niin Tampereella kuin muuallakin maailmassa kiinnostuksen kohteena sekä kasvuyritysten että erilaisten asiantuntijaorganisaatioiden parissa. Tämän opinnäytetyön tavoitteena on tarkastella, kuinka kuntoutusaiheisen mobiilisovelluksen voi toteuttaa pelimoottorina tunnetussa Unity-kehitysympäristössä. Työssä esitellään niitä teknisiä menetelmiä, joita sovelluksen toteutukseen on käytetty, mutta tarkastellaan myös haasteita, joita Unityn käyttöön liittyy. Raportin johdannossa pyritään kertomaan tyhjentävästi, minkälaisista lähtökohdista sovellusta on lähdetty rakentamaan. Teoreettinen osuus keskittyy kehitysympäristön valintaan ja Unity-ohjelmointiin yleisellä tasolla. Tämän jälkeen esitellään muutamia teknisiä menetelmiä sekä lopuksi arviointia itse sovelluksen ja tämän raportin onnistuneisuudesta. Opinnäytetyön varsinainen tarkoitus ja konkreettinen lopputulos on fysioterapeuteille ja heidän asiakkailleen suunnattu mobiilisovellus, joka on edennyt kevään ja kesän 2014 aikana pilottivaiheeseen. Ensimmäiset koekäyttäjät ovatkin saaneet jo sovelluksen käsiinsä. Sovelluksen ympärille on perustettu myös Kineso Oy -niminen yritys, jossa kehitystyö jatkuu tämän opinnäytteen jälkeenkin. Asiasanat: fysioterapia, mhealth, unity, pelimoottori, ohjelmistokehitys

ABSTRACT Tampere University of Applied Sciences Degree Programme in Business Information Systems ROHUNEN, JAAKKO: Implementation of a Rehabilitation-based Mobile Application in Unity Bachelor's thesis 59 pages September 2014 Healthcare and rehabilitation is currently one of the important priorities of mobile application and consumer technology development. Mobile healthcare application sector, also known mhealth, is the target of growing interest of startup companies and varying expert organizations, both in Tampere and around the world. The objective of this thesis is to examine how the technical implementation of a rehabilitation-based mobile application can be done in development environment called Unity, which is mainly known as a game engine. The thesis describes some of the technical methods that have been used in the implementation of the application, but also highlights some of the challenges that can arise in Unity-based development process. Introduction of this thesis report aims to comprehensively describe the starting point of the application development. The theoretical part will focus on the selection of the development environment and Unity programming in general. The remaining parts describe some of the technical methods used in the implementation and finally evaluates the success of the chosen implementation and this report itself. The actual purpose and the tangible result of the thesis is a mobile application directed to physical therapists and their clients. It has progressed during the spring and summer of 2014 to the pilot phase. The first test users have already received the application. Also a company called Kineso Oy has been established around the application, which will continue the development beyond this thesis. Key words: physical therapy, mhealth, unity, game engine, software development

4 SISÄLLYS 1 JOHDANTO... 6 1.1 Hyvinvointiteknologian tulevaisuudesta... 6 1.2 RICTI-projekti ja työryhmä... 7 1.3 Fysioterapia-aiheinen mobiilisovellus... 8 2 SOVELLUKSEN TEKNINEN TAUSTA... 10 2.1 Peli- ja toimistosovellusten ohjelmoinnista... 10 2.2 Vaatimukset kehitysympäristölle... 10 2.3 Yleistä Unitystä... 12 2.3.1 Unityn työympäristö... 13 2.3.2 Ohjelmointi Unityssä... 15 2.3.3 Käyttöliittymien toteutus Unityssä... 18 2.3.4 Asset Store... 19 2.4 Microsoft Kinect... 20 3 SOVELLUKSEN TOTEUTUS... 22 3.1 Suunnittelupöydältä toteutukseen... 22 3.2 Perusrakenteen ohjelmointi... 24 3.2.1 Tietorakenteet ja datamallit... 24 3.2.2 Tapahtumapohjainen rakenne... 27 3.2.3 Animoidut 3D-hahmot... 29 3.2.4 Ainokaiset Manager-luokat... 32 3.2.5 Ulkoiset dataformaatit ja sarjallistaminen... 34 3.2.6 Omat tallennukset... 37 3.3 Käyttöliittymän ohjelmointi... 39 3.3.1 Visuaalinen editointi... 41 3.3.2 Menu stack... 45 3.3.3 ExercisePanel... 46 3.4 Testaus... 49 3.4.1 Testilaitteet... 49 3.4.2 Unity Profiler... 50 4 POHDINTA... 52 4.1 Unityn soveltuvuudesta kehitystyöhön... 52 4.2 Pohdintaa opinnäytetyöprosessista... 53 LÄHTEET... 55

5 ERITYISSANASTO alustariippumaton editori event loop game loop gameobject indie JSON metadata metodi motion capture natiivi pelimoottori piirtokutsu pilotti primitiivi tietotyyppi scene skripti WYSIWYG usealle eri käyttöjärjestelmälle tai laitteelle tarkoitettu tässä yhteydessä: Unityn graafinen työympäristö tapahtumasilmukka, tavanomaisten sovellusten pohjalla oleva perusrakenne pelisilmukka, useimpien nykyaikaisten pelien perusrakenne tässä yhteydessä: Unity-pelimaailmassa sijaitseva objekti lyhenne sanasta independent, (suuryrityksistä) riippumaton JavaScript Object Notation, selväkielisen datan tallentamiseen tarkotettu tiedostoformaatti "dataa datasta", tässä yhteydessä: animaatioihin liittyvä muu oheisinformaatio pätkä ohjelmakoodia, joka toteuttaa yhden toiminnallisuuden liikkeenkaappaus, animointitekniikka tässä yhteydessä: tietylle kohdealustalle tarkoitettu tai sitä varten suunniteltu game engine, peleissä usein tarvittavien työkalujen kokoelma pelimoottorin näytönohjaimelle lähettämä viesti pilot, pienimuotoinen koe tai (esi)tutkimus ohjelmointikieleen sisäänrakennettu tapa tallentaa tietoa tässä yhteydessä: Unityn työtiedosto tässä yhteydessä: Unityä varten tehty, ohjelmakoodia sisältävä tiedosto "what you see is what you get", tapa suunnitella esim. sovelluksia visuaalisesti

6 1 JOHDANTO 1.1 Hyvinvointiteknologian tulevaisuudesta Terveydenhuoltoalan mobiilisovellusten ja -laitteiden kehittäminen (mhealth) on valtava kasvun ala tämän päivän Suomessa ja muualla maailmassa. Älypuhelinten huikea menestys on saanut aikaan uudenlaista liikettä monilla muillakin aloilla, mutta myös terveydenhuollossa on havahduttu siihen tosiasiaan, että sadoilla miljoonilla ihmisillä on jo erittäin monipuoliseen käyttöön soveltuva mittalaite taskussaan. Research and Marketsin toteuttama, sadoille alan mielipidejohtajille suunnattu kyselytutkimus ennustaakin, että mhealth-alan liikevaihto tulee kasvamaan noin 26 miljardiin dollariin vuoteen 2017 mennessä (Terry, 2013). Myös ns. puettavat älylaitteet ovat yksi tärkeimmistä kuluttajateknologian kasvun aloista. Nousevien teknologia-alojen kasvua tutkivan ABI Researchin mukaan vuoteen 2018 mennessä tullaan valmistamaan yli 485 miljoonaa puettavaa älylaitetta. ABI Research arvioi, että vuonna 2013 noin 61 % näistä laitteista oli erilaisia yleisen hyvinvoinnin ja terveellisten elämäntapojen tueksi tarkoitettuja laitteita, kuten aktiivisuusrannekkeita, sykevöitä tai muita vastaavia (ABI Research, 2013). Myös Kanadalaisen Vandrico Solutionsin laatiman tietokannan mukaan tällä hetkellä markkinoilla olevista puettavista älylaitteista huomattavan suuri osa on joko kuntoilua tai hyvien elämäntapojen ylläpitoa varten. Tulevaisuudessa käyttötarkoituksia tulee olemaan varmasti muitakin, mutta tällä hetkellä puettavat älylaitteet linkittyvät vahvasti mhealth-alan kasvuun (Vandrico, 2014). Mhealth-alan myönteiset tulevaisuudennäkymät ovat herättäneet kiinnostusta myös TAMKin sisällä. TAMKin tutkimus- ja kehitysyksikkö päätyikin vuonna 2013 toteuttamaan alaa sivuavan mobiilisovelluksen prototyypin. Tämän opinnäyteraportin kirjoittaja oli mukana sovelluksen tekoprosessissa alusta asti yhtenä työryhmän jäsenenä. Tämä opinnäytetyö pyrkiikin kuvailemaan, miten suosittua Unity-pelinkehitysympäristöä voidaan käytännössä hyödyntää tämänkaltaisen sovellusprototyypin toteutuksessa. Tä-

mä raportti keskittyy lähinnä sovelluksen tekniseen toteutukseen ohjelmoinnin näkökulmasta. 7 Työryhmämme tarkoituksena oli saattaa sovellus kesän 2014 aikana sille asteelle, että pystyimme syksyllä aloittamaan sovelluksen pilotoinnin yhteistyössä Pirkanmaalla toimivien kuntoutusyrittäjien kanssa. Neuvotteluja on käyty talvesta 2013-2014 lähtien ja sovelluksemme saama vastaanotto on ollut valtaosin erittäin myönteistä. Ensimmäinen pilottivaihe onkin tämän raportin kirjoitushetkellä juuri meneillään. Siihen osallistuu eräs tamperelainen, yksityinen lääkäriasema ja sen neljä polven ristisideleikkauspotilasta. Seuraavana pilottiasiakkaana on toinen yksityinen lääkäriasema, jolla on toimipisteitä ympäri Suomen. 1.2 RICTI-projekti ja työryhmä Sovelluksen kehitystyö sai alkusysäyksensä TAMKin tutkimus- ja kehitysyksikössä niin kutsutun RICTI-hankkeen nimissä. RICTI eli Re-establishing the Finnish ICT industry oli vuosina 2012-2013 Tampereen seudulla toteutettu hanke, jonka tarkoituksena oli omalta osaltaan tukea ICT-alan rakennemuutosta Pirkanmaan alueella (Tampereen Yliopisto, 2012). Rakennemuutoksella tarkoitettaneen tässä yhteydessä pitkään huhuiltua Nokian matkapuhelinyksikön myyntiä Microsoftille, joka sai vahvistuksensa vihdoin syyskuussa 2013 (Pierce, 2013). RICTI-hankkeen perustajajäsenet koostuivatkin juuri entisistä Nokiaammattilaisista. RICTI muodostui neljästä itsenäisestä työryhmästä, joista yksi oli TAMKin Kaupin kampuksen tiloissa toiminut, Social Robotics niminen ryhmämme. Meille oli alusta lähtien selvää, että haluaisimme hyödyntää kaikkia niitä mahdollisuuksia moniammatilliseen yhteistyöhön, joita Kaupin kampusalue tarjoaa tämänkaltaiselle projektille. Lyhyen välimatkan päässä toisistaan toimii sekä ICT-alan että erilaisten terveydenhuoltoalojen osaajia ja opiskelijoita. Social Robotics koostui lopulta neljästä Nokian entisestä työntekijästä, yhdestä fysioterapeutista sekä vaihtelevasta valikoimasta TAMKin ja TTY:n opiskelijoita niin tietojenkäsittelyn, median kuin fysioterapiankin alalta. Työryhmämme on toteuttanut projektin

kuluessa myös muita hankkeita, mutta tämä opinnäytetyö keskittyy niistä viimeisimpään eli aiemmin mainittuun, fysioterapeuteille suunnattuun mobiilisovellukseen. 8 TAMKilla suoritetun tutkimusvaiheen jälkeen työryhmämme ydinjoukko päätyi perustamaan sovellusprototyypin ympärille Kineso Oy nimisen yrityksen, jossa tämän raportin kirjoittaja on itsekin perustajajäsenenä ja osakkaana. Pääasiallinen toimenkuvani yrityksessä on jatkaa sovelluksen suunnittelua ja toteutusta Unity-ympäristössä potentiaalisten asiakkaiden toiveiden ja vaatimusten pohjalta. Kineso Oy toimii tällä hetkellä Tampereella, Väinö Linnan aukiolla sijaitsevassa startup-yhteisö Protomossa, jossa työskentelee muitakin terveys- ja hyvinvointialan pienyrityksiä. 1.3 Fysioterapia-aiheinen mobiilisovellus Kymmenelle eri fysioterapeutille kohdistetun kyselyn perusteella työryhmämme päätyi toteuttamaan uudenaikaisen, liikkuvaa 3D-grafiikkaa hyödyntävän mobiilisovelluksen fysioterapeuteille ja muille kuntoutusalan ammattilaisille sekä heidän asiakkailleen. Tarve sovelluksen kehittämiseen lähti siitä havainnosta, että nykyisenä menetelmänä on lähettää kuntoutuspotilaat kotiin kopiopaperille tulostetun harjoitusohjelman kanssa. Halusimme tarjota nykyaikaisen vaihtoehdon, joka ei kuitenkaan perustuisi varsinaisiin harjoitusvideoihin. Näitä on toki saatavilla runsaasti, mutta ne ovat aina rajallisia, yhdestä suunnasta kuvattuja esityksiä joissa esiintyy yksi satunnainen henkilö. Papereita tai videoita kehittyneempi ratkaisu onkin nauhoittaa harjoitteet animaatioiksi, joita sovelluksen käyttäjä voi tarkastella pelimaailman sisällä haluamastaan suunnasta tai vaihtaa koko esimerkkihahmon sellaiseen, joka miellyttää silmää enemmän. Sovelluksen myöhemmän kehitystyön kannalta harjoitteiden varastointi tietokoneanimaatioina tarjoaa muutamia muitakin kiinnostavia mahdollisuuksia. Animaatiotiedostot ovat pohjimmiltaan vain kokoelma numeerisesti määriteltyjä koordinaatteja 3Davaruudessa. Koordinaatit liikkuvat avaruudessa tietyn ajan kuluessa tietyn matkan. Niitä voidaan siis myös muokata jälkeenpäin tai niillä voidaan tehdä laskutoimituksia.

9 Sovellukseen tarvitaan toki muutakin kuin pelkät animaatiot. Haastattelujen ja fysioterapeuttien kokemusten pohjalta rakensimme animaatioiden ympärille kokonaisen mobiilisovelluksen, jonka avulla fysioterapeutti voisi laatia harjoitusohjelman asiakkaalleen ja antaa mobiililaitteen potilaalle lainaan seuraavaan tapaamiseen saakka. Potilas voi käyttää myös omaa laitettaan, mikäli mahdollista. Sovellus toimii siis paitsi interaktiivisena oppaana potilaalle, myös kuntoutuspäiväkirjana. Myöhemmässä vaiheessa sovelluksen on tarkoitus sisältää erilaisia vaihtoehtoja potilaan ja fysioterapeutin väliseen viestintään. Tämänhetkinen alansa markkinajohtaja Physio Tools toimii siten, että fysioterapeutti käy valitsemassa sovelluksesta sopivat liikkeet asiakasta varten, muokkaa sovelluksen valmiiksi tarjoamia ohjeita kyseisen asiakkaan tilanteeseen sopivaksi ja tulostaa lopuksi paperimuotoisen ja sähköpostitse toimitettavan esityksen asiakkaalle. Esityksessä on mukana piirroskuvat liikkeiden suoritustavasta sekä juuri muokatut ohjetekstit (Acute, 2014). Meidän ratkaisumme korvaa kopiopaperit ja piirroskuvat 3D-grafiikalla ja animaatioilla, mutta sisältää myös tavanomaiset kirjalliset ohjeet animaatioiden yhteydessä. Meidänkin sovelluksessamme fysioterapeutilla on mahdollisuus valita asiakkaalleen sopivat harjoitteet ja muokata ohjeita, mutta tämän jälkeen sovellus lukitaan asiakastilaan ja annetaan asiakkaan käyttöön. Asiakastilassa sovelluksella voi vain toistaa animaatioita, jotka fysioterapeutti on käynyt aiemmin lisäämässä harjoitusohjelmaan. Käytän tämän opinnäytetyöraportin yhteydessä sovelluksestamme myös epävirallista työnimeä Physio Trainer.

10 2 SOVELLUKSEN TEKNINEN TAUSTA 2.1 Peli- ja toimistosovellusten ohjelmoinnista Tietokonepelien ohjelmoinnin näkökulmasta tärkein, lähes kaikkia pelejä yhdistävä, rakenteellinen elementti on ns. game loop silmukka. Game loop tai suomeksi pelisilmukka on jokin jatkuvasti toistettava sarja komentoja. Se toistuu mahdollisimman usein, esimerkiksi jokaisen ruudunpäivityksen yhteydessä. Peleissä pitää tavanomaisesti ottaa jatkuvasti vastaan käyttäjän antamia syötteitä vaikkapa pelihahmolle ja pelihahmon täytyy vastaavasti reagoida niihin liikkumalla ruudulla niin lyhyen ajan sisällä kuin mahdollista. Game loop myös huolehtii siitä, että taustamusiikki ja ääniefektit lähtevät soimaan ajallaan ja että pelimaailma elää silloinkin, kun pelaaja ei itse tee mitään (McShaffry & Graham, 2013 tai Loki Software, 2001). Perinteisen toimistosovelluksen, vaikkapa tekstinkäsittelyohjelman ei tarvitse välttämättä toteuttaa tällaista silmukkaa. Tällaiselle sovellukselle riittää, jos se reagoi käyttäjän antamiin komentoihin muuten sen ei tarvitse tehdä mitään. Käyttäjän syötteisiin perustuvasta toimintalogiikasta voi käyttää myös vastakkaista termiä event loop eli tapahtumasilmukka (Nystrom, n.d.). Physio Trainer on siitä omalaatuinen sovelluksensa, ettei se ole peli, eikä oikein toimistosovelluskaan. Koska sovellus kuitenkin sisältää piirteitä molemmista, se myös toteuttaa molemmat silmukat. Physio Trainerin game loop huolehtii siitä, että animaatiot pyörivät ruudulla kauniisti. Event loop taas on valmiina reagoimaan käyttöliittymän tasolla tapahtuviin muutoksiin, kuten valikoissa liikkumiseen. 2.2 Vaatimukset kehitysympäristölle Physio Trainerin toteutus lähti liikkeelle eri kehitysympäristöjen vertailusta. Pyrimme saamaan sovellukselle tukevan pohjan, joka kestää mahdolliset laajentumispyrkimykset ja muut tulevaisuuden haasteet. Koska halusimme sovelluksen sisältävän näyttäviä 3Danimaatioita, katse kohdistui nopeasti eri pelimoottoreihin.

11 Pelimoottorilla tarkoitetaan peliohjelmoinnin tueksi tarkoitettua ohjelmistokehystä eli peleissä tarvittavien ohjelmointikirjastojen ja -rajapintojen kokonaisuutta. Peleissä tyypillisesti halutaan esimerkiksi näyttää liikkuvaa grafiikkaa ruudulla ja pelin pitää olla valmiina ottamaan käyttäjän syötteet vastaan näppäimistön, hiiren tai erillisen peliohjaimen kautta. Näiden toiminnallisuuksien matalan tason ohjelmointi jokaista eri peliä varten on toki mahdollista, mutta hyvin vaikeaa ja raskasta. Se myös tuntuisi huonolta ajankäytöltä, kun innokas pelinkehittäjä haluaisi keskittyä vain tekemään sitä, mikä erottaa juuri hänen pelinsä muista (Ward, 2008). Physio Trainerin kaksi tärkeintä vaatimusta kehitysympäristölle oli mahdollisuus alustariippumattomaan kehitystyöhön ja hyvät, valmiit välineet 3D-animaatioiden kanssa työskentelyyn. Luonnollisesti työryhmä halusi myös päästä nopeasti käsiksi itse toteutukseen, joten oman pelimoottorin kirjoittaminen ei tullut kysymykseen. Koska 3Danimaatiot olivat alusta lähtien koko sovelluskonseptin keskiössä, ei varsinaisten pelimoottorien ulkopuolisia vaihtoehtoja edes harkittu. Kolmas tärkeä valintaan vaikuttanut tekijä oli pelimoottorin suosio, koska kehittäjäyhteisön laajuus tuntuu heijastuvan suoraan esimerkiksi saatavilla olevan ohje- ja opetusmateriaalin määrään. Pelimoottorin suosio näkyy myös siten, että siihen on saatavilla runsaasti laajennusosia vaikkapa erilaisten tiedostotyyppien käsittelyyn. Käytännössä näillä vaatimuksilla jäljelle jää Unityn lisäksi vain kourallinen suosituimpia pelimoottoreita: Epic Gamesin kehittämä Unreal Engine, Crytekin CryEngine, Havok.com Incin Havok sekä viimeksi mainitun indie-kehittäjille suunnattu ilmaisversio Project Anarchy. Tämän lisäksi on toki valtava määrä muitakin, vähemmän tunnettuja vaihtoehtoja (Chapple, 2014). Kaikki luetellut pelimoottorit olisivat varmasti soveltuneet Physio Trainerinkin tarpeisiin. Unreal Engine, CryEngine ja Havok ovatkin monille tuttuja ennen muuta niistä peleistä, joita varten nämä moottorit on kehitetty. Ensimmäinen versio esimerkiksi CryEnginestä kehitettiin samanaikaisesti Crytekin ensimmäistä peliä, Far Cryta, varten (Crytek, 2014). Valinta käyttää juuri Unityä kehitysympäristönä Physio Trainerin toteutuksessa ei pohjautunut perinpohjaiseen pelimoottorien vertailuun. Lopulta yksi tärkeimmistä syistä oli

12 se, että marraskuussa 2012 eli muutama kuukausi ennen projektin alkua Unity oli juuri saanut ison versiopäivityksen 4.0:aan, jonka yhteydessä Unityn peruspakettiin sisällytettiin uusi, helppokäyttöinen animaatiojärjestelmä Mecanim (Lee, 2012). Android-käyttöjärjestelmän valinta ensimmäiseksi tuetuksi sovellusalustaksi oli pitkälti ryhmän yhteinen päätös, johon vaikuttivat lähinnä työryhmän henkilökohtaiset mieltymykset. Nykyisessä vaiheessaan, kun sovellus on vasta prototyypin asteella, yrityksellämme on tarkoitus lainata myös itse taulutietokoneita pilottiasiakkaiden käyttöön siten, että sovellus on valmiiksi esiasennettuna. Käyttöjärjestelmällä ei siis ole testikäyttäjien kannalta juuri merkitystä, ja sovelluksen virallinen julkaisu on vielä kaukana tulevaisuudessa. Pienimmäksi tuetuksi Android-versioksi valittiin 4.0.3 (API 15) eli Ice Cream Sandwichin. Tällä saavuttaa Googlen elokuun 2014 tilastojen mukaan 85,7 % osuuden kaikista Android-laitteista (Android Developers: Dashboards, 2014). Suurin haaste Unity-pelimoottorin sovittamisessa tämän sovelluksen kehitystarpeisiin oli Unityn varsin vaatimattomat työkalut graafisten käyttöliittymien luomiseen. Unityssä on kyllä valmiit työkalut huipputason fysiikkamallinnukseen, valaistukseen ja moneen muuhun teknisesti vaativaan osa-alueeseen, mutta käyttöliittymien osalta tilanne on tähän asti ollut hyvin heikko verrattuna esimerkiksi natiiviin Android-kehitystyöhön. Tarvitsimme siis Unityn lisäksi myös erillisen käyttöliittymäkirjaston, jonka avulla voisimme selviytyä kaikista niistä toiveista ja vaatimuksista, joita tämänkaltaisen sovelluksen toteutus edellyttää. Valitsimme saatavilla olevista vaihtoehdoista Daikon Forge UI Library nimisen laajennoksen. Kerron Daikon Forgesta tarkemmin alaluvussa 3.3. 2.3 Yleistä Unitystä Unity (ennen myös Unity 3D) on Unity Technologiesin kehittämä pelimoottori, jossa on mukana varsin hyvin varusteltu kehitysympäristö (development environment, IDE). Käytän Unityn kehitysympäristöstä myös nimiä työympäristö tai melko vakiintunutta termiä editori, erotuksena tavanomaisempiin ohjelmointikeskeisiin kehitysympäristöihin kuten esimerkiksi Eclipse, Qt Creator tai Android Studio. Tämä luku perustuu suurimmalta osin Unityn itsensä tarjoamaan referenssi- ja markkinointimateriaaliin.

13 Unity sisältää perinteiset pelinkehityksessä tarvittavat kirjastot sekä lukuisia muita pelien tarvitsemia yleisiä rajapintoja ja kaupallisia kirjastoja kuten DirectX 11:n, Box 2D fysiikkakirjaston 2D-fysiikkamallinnusta varten ja PhysX:n 3D-fysiikkamallinnusta varten. Unity on kehitetty alustariippumattomaan pelikehitykseen. Unity tarjoaa yhden ylimääräisen abstraktiotason, jonka puitteissa kehittäjä voi suunnitella ja toteuttaa pelinsä ilman, että kehittäjän tarvitsee perehtyä vaikkapa 3D-grafiikan renderöintiin tarvittavien rajapintojen käyttöön. Toisaalta Unityn alustariippumattomuuden hyödyt näkyvät siinä, että kun kehittäjä haluaa sovelluksensa eri alustalle, Unity vaihtaa mm. renderöintirajapintaa tarpeen mukaan alustalle sopivaksi. Tällä hetkellä Unityllä toteutettuja pelejä ja sovelluksia voi kääntää ainakin seuraaville alustoille: ios, Android, Windows, Windows Store ja Windows Phone 8, BlackBerry 10, OSX, Linux, PlayStation 3, XBOX 360 ja Wii U. Lisäksi Unity-sovelluksia voi ajaa myös yleisimmillä nettiselaimilla, mutta se vaatii erillisen selaimeen asennettavan laajennoksen (Unity Web Plugin). Physio Trainerin toteutuksessa on käytetty maksullista Unity Pro lisenssiä, joka sisältää muutamia oleellisia lisäominaisuuksia ilmaiseen lisenssiin nähden. Suuri osa näistä lisäominaisuuksista on varsinkin 3D-pelien graafiseen ulkoasuun liittyviä parannuksia ja erikoistehosteita, joita ei tämän projektin yhteydessä ole ainakaan toistaiseksi tarvittu. Tarvitsimme Unity Pro lisenssiä sen sijaan siksi, että se mahdollistaa tuen natiivisti toteutetuille Unity-laajennoksille sekä Unity Profilerin, jolla voi tarkastella sovelluksen suoritusta reaaliajassa ohjelmakoodin tasolla. Palaan Unity Profilerin käyttöön myöhemmin luvussa 3.5.2. 2.3.1 Unityn työympäristö Kun Unityn käynnistää, näytölle avautuu Unityn graafinen työympäristö, josta käytän myöhemmin myös nimeä editori. Unityn editori muistuttaa ulkoasultaan, ja hieman myös toimintalogiikaltaan, tavanomaisia 3D-mallinnus- tai kuvankäsittelyohjelmia.

14 Tekeillä oleva projekti tai sen osa on nähtävänä scene- tai game-ikkunoissa (kuvassa 1 vasemmalle ylänurkassa). Scene-näkymässä voi liikkua 3D-avaruudessa vapaasti ja tutkia pelimaailman sisältöä, ikään kuin ulkopuolisena tarkkailijana, kuten 3Dmallinnusohjelmissa on tapana. Game-näkymä taas tarjoaa reaaliajassa päivittyvän esityksen tekeillä olevasta pelistä tai projektista suurin piirtein sellaisena, kuin se lopulliselle käyttäjälle tulee näkymään. Game-näkymässä voi siis koska tahansa pelata tekeillä olevaa peliä, tai kuten tämän opinnäytteen tapauksessa, käyttää sovellusta. KUVA 1 Yleiskuva Unityn työympäristöstä, Physio Trainer game-ikkunassa Suurimman osan kehitystyöhön liittyvästä työvaiheiden toistosta ja ideoiden käytännön testauksesta voi tehdä suoraan editorissa, ilman aikaavievää käännösvaihetta kohdealustalle. Tämä on nopeuttanut ja helpottanut työskentelyä huomattavasti ainakin tämän opinnäyteprosessin kohdalla. Ainoastaan sellaiset erityisominaisuudet, jotka edellyttävät fyysistä mobiililaitetta, täytyy testata itse laitteella. Tällaisia ominaisuuksia ovat esimerksiksi useampaa samanaikaista kosketusta tukeva näyttö, värinähälytykset tai mobiililaitteen käyttöjärjestelmään integroidut erityispalvelut kuten virtuaalinen näppäimistö tai yleiset järjestelmänotifikaatiot. Scene- ja game-näkymien lisäksi Unityn työympäristöön kuuluu myös Hierarchy-, Project- ja Inspector-näkymät (kuvassa 1 oikealla). Project-näkymässä voi tarkastella kaik-

15 kia avonaisen projektikansion sisältämiä tiedostoja. Project-näkymään kasataan kaikki kulloisenkin projektin tarvitsema sisältö: ohjelmakoodi eli skriptit, kuvat, äänet, 3Dmallit ja niin edelleen. Hierarchy-näkymässä on samankaltainen puumainen rakenne kuin Project-näkymässäkin, mutta siinä näkyy vain avonaisen scenen eli Unityn työtiedoston sisältö. Hierarchy-näkymän sisältämät objektit ovat scenellä. Tämä tarkoittaa sitä, että jos Unity-sovelluksen käynnistää nyt, juuri nuo kyseiset objektit näytetään käyttäjälle. Inspector-näkymä näyttää kulloinkin valittuna olevan objektin tilan ja kaikki objektiin liitetyt komponentit. Komponenteista kerron tarkemmin seuraavassa alaluvussa. Inspector-näkymään tiivistyy ainakin kirjoittajan näkemyksen mukaan Unityn suurin vahvuus, sillä juuri inspector yhdistää graafisen työympäristön ja ohjelmointiympäristön. 2.3.2 Ohjelmointi Unityssä Ohjelmointi Unityssä perustuu komponenttipohjaiseen arkkitehtuuriin. Komponentilla tarkoitetaan yhtä pientä sovelluksen osaa, jolla on oma erityinen tehtävänsä, eikä se parhaassa tapauksessa tarvitse tuekseen tietoa muiden komponenttien tai minkään yksittäisen komponentin yläpuolella olevan kokonaisuuden toiminnasta (Porter, 2013). Jokaisella komponentilla on Unityssä oma isäntäobjekti eli GameObject-luokan olio (myöhemmin myös gameobject). Gameobject voi olla mikä tahansa pelimaailmassa esiintyvä objekti, jolla on sijainti 3D-avaruudessa: pelaaja, puu, pyssy tai painonappi. Gameobject voi olla myös tyhjä, jolloin se toimii pelkkänä isäntänä sellaisille komponenteille, jotka eivät tarvitse graafista ilmiasua. Mikään ei tietenkään estä hyödyntämästä Unity-ohjelmoinnissa myös perinteisiä olioohjelmoinnin käytäntöjä, mutta komponenttiajattelu on Unityn yhteydessä hyvin luontevaa. Ohjelmointi Unityssä on vahvasti sidoksissa Unityn graafiseen työympäristöön. Kaikki komponenttiluokat (myöhemmin myös skriptit) periytyvät oletusarvoisesti MonoBehaviour-yläluokasta, joka kytkee ne työympäristöön ja mahdollistaa niiden liittämisen gameobjecteihin (Unity Technologies: MonoBehaviour, 2014). Gameobjecteihin liitettyjä skriptejä voi muokata ja tarkastella ilman varsinaiseen ohjelmakoodiin puuttumista. Työympäristön tai tarkemmin Inspector-näkymän kautta voi-

16 daan, jopa ajonaikaisesti, vaikuttaa komponenttien julkisten muuttujien arvoihin sekä kytkeä komponentteja pois päältä tai takaisin päälle. Esimerkiksi julkiseksi merkittyä, valon kirkkauteen vaikuttavaa muuttujaa voi säätää sovelluksen suorituksen aikana mieleisekseen. Unity tarjoaa mahdollisuuden sovelluskehitykseen kolmella eri ohjelmointikielellä: C#:lla, UnityScriptillä ja Boolla (Unity Technologies; Unity Scripting, 2014). Kaikki tuetut kielet hyödyntävät Microsoftin kehittämää.net-ohjelmistokehystä ja sen tarjoamia luokkakirjastoja. Unity ei varsinaisesti käytä.net-kehystä sellaisenaan, vaan Monoa, joka on avoimeen lähdekoodiin perustuva implementaatio dot netistä. Mono on lähtökohtaisesti alustariippumaton (Mono Project, 2014). C# on Microsoftin juuri.net:iä varten kehittämä yleiskäyttöinen ja olioperustainen ja vahvasti tyypitetty ohjelmointikieli (ECMA, 2006). UnityScript on JavaScriptiä muistuttava kieli, joka on nimensä mukaisesti kehitetty vain Unityä varten. UnityScript muistuttaa JavaScriptiä kuitenkin vain syntaksiltaan, kääntäjän osalta UnityScript toimii kuten muutkin vaihtoehdot (Loewald, 2013). Boo on C#:n tavoin jo lähtökohtaisesti dot net arkkitehtuuriin perustuva, mutta vähemmän tunnettu kieli. Ohjelmointikielten suosiota listaavan TIOBE Indexin mukaan Boo ei mahdu ainakaan tämän opinnäytetyön kirjoitushetkellä edes viidenkymmenen suosituimman kielen joukkoon. C# on samalla listalla kuudentena (TIOBE, 2014). Kaikki kolme edellämainittua kieltä ovat ns. korkean tason ohjelmointikieliä, joilla laadittua ohjelmakoodia ei käännösvaiheessa vielä suoraan muuteta konekielelle. Unityn ajonaikainen ydin (ns. runtime library) sinänsä on toteutettu C++-kielellä, joka lopulta käännetään valitulle kohdealustalle. Ydinkerroksen ympärillä on eräänlainen välikerros, joka mahdollistaa dot netin luokkakirjastojen käytön ja varsinaisen tuen käyttäjän omille skripteille (Johansen, 2010). Tämän opinnäytteen kohteena oleva sovellus on toteutettu kokonaisuudessaan C#:lla, sillä se on dot net -yhteytensä vuoksi luontevin ratkaisu tilanteessa, jossa ei ole mitään erityistä syytä suosia UnityScriptiä tai Boota. Koska C# on näistä kielistä suosituin ja

monikäyttöisin, on myös syytä olettaa, että C#-ohjelmoinnista hankittu kokemus on helpommin siirrettävissä myös tämän projektin ulkopuolisiin käyttötarkoituksiin. 17 C#-kielen käyttäjällä on lisäksi mahdollisuus hyödyntää Microsoftin tarjoamaa, todella kattavaa.net-ohjelmointiopasta sellaisenaan ja käyttää ohjelmointiympäristönä Microsoftin Visual Studiota sekä Microsoftin tuoreeltaan ostamaa UnityVS-laajennosta, joka parantaa Visual Studion ja Unityn integraatiota entisestään (Somasegar, 2014). Tästä voi päätellä, että Microsoft ottaa Unity-kehittäjien tarpeet vakavasti. Aiemmin tässä luvussa mainitusta MonoBehaviour-yläluokasta siis periytyvät käytännössä lähes kaikki Unity-sovelluskehittäjän itse tekemät skriptit. Tästä on mahdollisuus poiketa C#-kielessä tai Boossa, JavaScript-muotoisissa koodinpätkissä MonoBehaviour on jo automaattisesti peritty (Unity Technologies: MonoBehaviour, 2014). Mikäli aikoo tehdä jotakin puhtaasti.net-ohjelmistokehykseen liittyvää, täysin Unitystä riippumatonta C#-muotoista kehitystyötä, ei MonoBehaviour-kytkentää tarvita. Esimerkkinä tällaisesta skriptistä voisi olla vaikkapa levylle kirjoittamiseen tarvittava luokka, joka voi toimia täysin Unity-projektista irrallaan. Useimmiten MonoBehaviouria kuitenkin tarvitaan. MonoBehaviourista periytyviä skriptejä voi myös raahata ja pudottaa gameobjecteille Unityn työympäristön sisällä, kuten mitä tahansa muitakin valmiita komponentteja. Aiemmin mainitsin, että MonoBehaviourista perittyjen skriptien julkisia muuttujia voi muokata Inspector-näkymässä. Vieläkin tärkeämpi syy kytkeä skriptit MonoBehaviouriin on kuitenkin se, että tämän ansiosta ne alkavat vastaanottaa Unityn ydinkirjastojen lähettämiä viestejä pelin sisäisistä tapahtumista. Jatkuvaan ruudunpäivitykseen pohjautuvien Unity-sovellusten tärkein tapahtuma on Update-metodi, jota kutsutaan aina ruudunpäivityksen yhteydessä. Kiinnostavaa Update-metodissa onkin, että sen toiminta todellakin riippuu vaihtelevasta ruudunpäivityksen tiheydestä. Update-metodi toteuttaa jo itsessään pelimoottorien tavanomaisen toiminnallisuuden game loopin. Muita tärkeitä, yleisiä Unity-tapahtumia ovat Awake-metodi, jota kutsutaan heti, kun skripti on ladattu muistiin ensimmäistä kertaa ja Start-metodi, jota kutsutaan kerran ennen ensimmäistäkään ruudunpäivitystä, mutta kuitenkin Awake-metodin jälkeen.

18 Tällä toiminnallisuudella on eräs pitkälle kantava seuraus. Mikäli Unity-skriptit sisältävät keskinäisiä riippuvuuksia ja viittauksia ulkoisiin gameobjecteihin ja niiden alla toimiviin skripteihin, on kaikki viittaukset syytä määritellä Awake-metodissa. Tämän ansiosta voi olla varma, että Start-metodin yhteydessä viittaukset on luotu ja niitä voi kutsua turvallisesti eli sovelluksen suoritus ei katkea ajonaikaiseen virheeseen ainakaan tästä syystä (Unity Technologies: Execution Order of Event Functions, 2014). Physio Trainerin skripteissä haen tavanomaisesti Awaken yhteydessä aina viittauksen siihen gameobjectiin tai komponenttiin, johon skriptin on tarkoitus suoraan vaikuttaa. Mikäli joku muu skripti haluaa myös vaikuttaa tai tietää edellä mainitusta objektista, voi se Start-metodinsa yhteydessä pyytää viittausta tähän, sillä objekti on jo luonut kytkennän omassa Awake-metodissaan. Physio Trainerissa käsittelen näiden lisäksi myös OnEnable- ja OnDisable-tapahtumat. Kerron tästä tarkemmin tapahtumankäsittelijöitä koskevassa luvussa. 2.3.3 Käyttöliittymien toteutus Unityssä Unityn tarjoamat työkalut ja rajapinnat kaksiulotteisten graafisten käyttöliittymien toteutukseen ovat olleet jo vuosia varsin vaatimattomalla tolalla. Käyttöliittymien rakentaminen Unityn nykyisillä työkaluilla on vaivaannuttavaa ja täysin manuaalista pikselien paikkojen määrittelyä, joka tuo mieleen lähinnä 1990-lukulaisen tyylin toteuttaa verkkosivuja. Esimerkiksi painonapin voisi toteuttaa skriptissä komennolla: GUI.Button(new Rect(20, 40, 80, 20), "Level 1"); Esimerkkirivillä luodaan uusi painonappi, jonka alue on määritelty täysin staattisina pikselikoordinaatteina (20, 40, 80, 20). Tämän lisäksi sovellus on pakko ajaa joka kerta, kun haluaa katsoa, miltä painonappi käytännössä näyttäisi. Tämä on paitsi hidasta, myös hyvin epäkäytännöllistä tilanteessa, jossa meillä ei ole mitään mahdollisuutta selvittää kohdelaitteen ruudun kokoa tai resoluutiota etukäteen. Käyttöliittymäsuunnittelu on siis kaikkea muuta kuin responsiivista, kohdealustan mittasuhteisiin mukautuvaa (Leiniö, 2012).

19 Tämän lisäksi jokainen erillinen käyttöliittymäelementti kuten painonappi vaatii Unityltä oman piirtokutsun. Piirtokutsuilla tarkoitetaan pelimoottorin näytönohjaimelle lähettämiä viestejä. Piirtokutsujen määrän kasvu vaikuttaa negatiivisesti sovelluksen ruudunpäivityksen tiheyteen. Piirtokutsujen määrän pitäminen mahdollisimman matalana on yksi tapa huolehtia siitä, että sovellusta on miellyttävää käyttää eri tehoisilla laitteilla (Barraza, 2010). Tilanne on johtanut siihen, että Unity-kehittäjien itse tekemiä laajennusosia myyvä Asset Store kauppa tarjoaakin nykyään lukuisia hyviä vaihtoehtoja käyttöliittymien suunnittelua ja toteutusta varten. Näitä ulkoisia käyttöliittymäkirjastoja ovat muun muassa NGUI: Next Gen UI, Daikon Forge GUI Library, Coherent UI, Scaleform ja niin edelleen. Näistä ensin mainittu, NGUI, on Asset Storen oman listauksen mukaan suosituin käyttöliittymälaajennos (Unity Technologies: Asset Store, 2014). NGUI on Michael Lyashenkon kehittämä käyttöliittymäkirjasto, joka on ollut suosittu jo pitkään. Tämän seurauksena Unity palkkasikin Lyashenkon Unitylle töihin, tarkoituksena tuoda NGUIn toiminnallisuus osaksi Unityn peruspakettia (Unity Technologies: The State of (New) GUI in Unity 4.x, 2013). Elokuussa 2014, Unityn oman, uuden käyttöliittymäkirjaston julkaisu on lähempänä kuin koskaan, sillä se on sisällytetty osaksi Unity 4.6:n julkista betaversiota. Tämän sovelluksen toteutuksen aikana tästä uudesta kirjastosta ei ollut saatavilla minkäänlaista varmaa tietoa, joten tarvitsimme kipeästi ulkoista käyttöliittymäkirjastoa. Päädyimme ostamaan sovelluskehityksen tueksi Daikon Forge GUI kirjaston, josta myöhemmin käytän myös lyhennettyä nimeä DF-GUI. Vielä keväällä 2014 kyseessä oli NGUI:n jälkeen toisiksi suosituin ulkoinen käyttöliittymäkirjasto, mutta nyt sen kehitystyö on lopetettu eikä sitä myydä enää uusille asiakkaille (Daikon, 2014). On hyvin todennäköistä, että Physio Trainerkin saattaa siirtyä käyttämään Unityn omaa käyttöliittymäkirjastoa, kunhan se julkaistaan virallisesti. 2.3.4 Asset Store Yksi Unityn suosion syistä on myös sen kehittäjäyhteisö. Kehittäjät ovat vapaaehtoisesti laatineet paitsi lukemattomia hyviä tuki- ja ohjesivuja, myös kattavan valikoiman ilmai-

sia tai maksullisia laajennusosia Unityyn. Näitä laajennusosia voi ostaa ja ladata Unityn Asset Storesta (Unity Technologies: Asset Store, 2014). 20 Asset Store on hieman Applen App Storea tai Googlen Playta muistuttava suljettu verkkokauppa, jossa on valmiiden sovellusten sijasta myynnissä kaikkea Unity-kehittäjiä kiinnostavaa sisältöä: valmiita koodinpätkiä, tekstuureja, ääniä, erikoisefektejä ja muuta enimmäkseen pelinkehittäjille suunnattua sisältöä. Asset Storesta ostamaansa sisältöä saa tavanomaisesti käyttää myös kaupallisiin tarkoituksiin. Myös Physio Trainerin tekemiseen tarvittiin Asset Storen apua. Vaikka olimme animaatioiden suhteen omavaraisia, tarvitsimme ohjelmointityötä nopeuttavia laajennoksia eli muutamia ilmaisia tai maksullisia kirjastoja. Koko sovelluksen graafinen käyttöliittymä lepää Asset Storesta ostetun Daikon Forge UI kirjaston varassa. Muita vähemmän käytettyjä, mutta Physio Trainerin tarvitsemia laajennoksia ovat JSON-jäsennin eli parseri SimpleJSON, kamera-ajojen rakentamiseen tarvittava kirjasto itween ym. Kerron Daikon Forgesta ja muistakin laajennoksista myöhemmissä luvuissa tarkemmin. 2.4 Microsoft Kinect Microsoft Kinect on marraskuussa 2010 julkaistu, ihmisten liikkeiden tunnistukseen tarkoitettu lisälaite Microsoftin Xbox 360 pelikonsolille. Syvyyskuvaa tallentavan infrapunasensorin ja tavallista RGB-kuvaa tallentavan kameran yhdistelmä oli tarkoitettu alun perin vaihtoehtoiseksi peliohjaimeksi mm. urheilu- ja kuntoilupelejä varten. Kinectin avulla pelaaja saattoi liikuttaa itse itseään omassa olohuoneessaan ja pelihahmo toisti nuo liikkeet televisiossa (Chen, 2010). Hieman myöhemmin, kesällä 2011, Microsoft julkaisi ensimmäisen betaversion Kinect Software Development Kitistä. Kinect SDK:n avulla laitteen saattoi liittää pelikonsolin sijasta Windows-tietokoneeseen ja hyödyntää kameroiden keräämää dataa haluamallaan tavalla myös pelimaailmoiden ulkopuolella (Stevens, 2011). Kuluneiden muutaman vuoden aikana markkinoille onkin ilmestynyt useita eri sovelluksia, joiden avulla Kinectiä voidaan käyttää yleiseen liikkeenkaappaukseen. Liikkeenkaappaus eli motion capture on elokuva- ja peliteollisuuden hyödyntämä menetelmä, jossa ihmisen tuottamat liikkeet tallennetaan tietokoneelle animaatiotiedostoiksi. Liik-

keenkaappausta voi tehdä monella eri tekniikalla, kuten erilaisten puettavien sensoripukujen avulla, mutta Kinect on varsin edullinen tapa päästä alkuun. 21 Myös Kinectin sekä Unityn yhteiskäytöstä on paljon dokumentaatiota saatavilla ja se oli työryhmälle muutenkin entuudestaan tuttua, joten päädyimme tässäkin projektissa hyödyntämään Kinectejä. Projektin aikana Microsoft julkaisi uuden Xbox One pelikonsolin ja sen mukana myös uuden Kinectin, mutta meidän työryhmämme turvautui tältä osin vielä vanhaan teknologiaan. SDK uutta Kinectiä varten on jo muutamien harvojen hallussa ja testikäytössä, mutta sitä ei vielä ole virallisesti julkaistu (Microsoft, 2014). Kinectiä voi toki myös käyttää sen alkuperäiseen tarkoitukseen eli reaaliaikaiseen liikkeentunnistukseen. Työryhmämme onkin suunnitellut menetelmää, jossa Kinectiä käytettäisiin fysioterapeuttien asiakkaiden ym. kuntoutuspotilaiden liikkeentunnistukseen ja tämän toiminnallisuuden integrointia itse pääsovellukseen. Tarkoituksena on vertailla käyttäjän suorittamia liikesarjoja koneoppimisen ja lukuisten esimerkkisuoritusten pohjalta tallennettuihin valmiisiin liikkeisiin (Kertész, 2013). Tämän opinnäytetyöraportin aihepiirinä on sovelluksemme toteutus nimenomaan Unitynäkökulmasta, joten olen pyrkinyt jättämään liikkeenkaappauksen ja siihen käytetyt sovellukset enimmäkseen työn ulkopuolelle. Liikkeenkaappaus Kinectin avulla oli kuitenkin tärkeä osa projektikokonaisuutta, ja siitä saisi varmasti kirjoitettua vaikka toisen opinnäytetyön.

22 3 SOVELLUKSEN TOTEUTUS 3.1 Suunnittelupöydältä toteutukseen Sovelluksemme, työnimeltään Physio Trainer, on siis fysioterapeuteille ja muille fysikaalisen kuntoutuksen ammattilaisille suunnattu mobiilisovellus. Physio Trainerin keskipisteenä on 3D-mallinnetut avatar-hahmot, jotka esittävät erilaisia animoituja kuntoutusharjoitteita pelimaailman sisällä. Physio Trainer ei kuitenkaan ole varsinaisesti peli. Physio Trainerilla on kaksi eri käyttäjäryhmää: fysioterapeutti itse sekä hänen asiakkaansa. Fysioterapeutti voi valita listasta haluamansa harjoitteet, asettaa ne tietyille päiville potilaan kotiharjoituksia varten sekä tarvittaessa muokata kirjallisia ohjeita potilaan tarpeisiin paremmin sopivaksi. Kun harjoitusohjelma on valmis, sovelluksen voi lukita eräänlaiseen asiakastilaan, jossa harjoiteanimaatioita voi katsella ja lukea niihin liitettyjä ohjetekstejä, mutta mitään ei voi muokata. Sovelluksemme prototyyppi on suunniteltu käytettäväksi nimenomaan Androidtableteilla, mutta mitään varsinaista teknistä estettä ei ole sovelluksen käyttöön myös älypuhelimilla. Käyttöliittymäelementit saattavat kyllä olla liian pieniä kosketettavaksi puhelimen näytöltä, ja toisaalta itse animaatioiden katselu saattaa olla isonkin älypuhelimen pieneltä ruudulta melko haastavaa. Sovellus sisältää työryhmämme fysioterapeuttijäsenen opastuksella laaditun pienen yleiskokoelman animaatioita kuntoutusharjoitteista sekä muutamia pilottiasiakkaiden toiveiden pohjalta laadittuja animaatioita polvi- ja lonkkapotilaita varten. Nämä animaatiot on toteutettu motion capture tekniikalla kahden Kinect-kameran ja niitä varten hankitun erillisen ipi Mocap Studio sovelluksen avulla. Unityn tehtävänä on integroida nämä animaatiot pelimaailmaan, melko pelkistettyyn huoneeseen, jossa käyttäjän valitsema 3D-avatarhahmo toistaa liikkeitä musiikkisoittimista tuttujen painikkeiden ohjaamana. Sovelluksen ulkoasusta ja käyttöliittymän suunnittelusta vastaa työryhmämme graafinen suunnittelija Heidi Mäenpää. Olen pyrkinyt toteuttamaan sovelluksen siten, että se vas-

23 taisi mahdollisimman hyvin hänen tarjoamiaan mallikuvia ja muita konsepteja (kuvat 2 ja 3). Tarkkasilmäinen katsoja saattaa kuvien perusteella havaita, että käyttöliittymän suunnittelun taustalla on ajatus käyttää natiivien Android-sovellusten käyttöliittymäkomponentteja. Sovelluksemme käyttöliittymä olikin eräässä vaiheessa projektia toteutettu natiivina Android-sovelluksena ja vain animaatiohahmo liikkeineen oli Unityn vastuulla. Luovuimme tästä ajatuksesta projektin edetessä ja myös käyttöliittymän toteutus siirrettiin Unityn harteille. Päätimme silti jatkaa työskentelyä aiempien mallikuvien pohjalta. KUVA 2 Paperiarkille tehty hyvin varhainen käyttöliittymäluonnos (Heidi Mäenpää).

24 KUVA 3 Käyttöliittymäluonnoksen seuraava aste (Heidi Mäenpää). Paneudun tämän kolmosluvun edetessä sovelluksen toteutukseen yksityiskohtaisemmin, juuri Unity-ohjelmoinnin näkökulmasta, muutamien valikoitujen esimerkkien avulla. Tarkoituksenani on selventää, miten edellä kuvatun kaltainen kummallinen yhdistelmä pelimoottoria ja toimistosovellusta saadaan toimimaan. 3.2 Perusrakenteen ohjelmointi Perusrakenteeltaan Physio Trainer on melko yksinkertainen sovellus, eikä se varsinaisesti noudata orjallisesti mitään olemassa olevaa ohjelmistoarkkitehtuurien suunnittelumallia. Olen kuitenkin pyrkinyt lähestymään käytännön ohjelmointityötä siten, että se noudattaisi mahdollisimman usein Unityn komponenttipohjaista rakennetta. Sovellus myös pohjautuu vahvasti tapahtumien käsittelyyn. 3.2.1 Tietorakenteet ja datamallit Physio Trainerin tietojenkäsittelyn pohjana on muutama itse laatimani tietotyyppi, joka pyrkii vastaamaan jotakin todellisen maailman objektia tai ainakin jotain sellaista, jolla on melko suora vastine myös sovelluksen ulkopuolella. Tällaisten luokkien laadintaa kutsutaan tavanomaisessa olio-ohjelmoinnissa datan mallintamiseksi (Ambler, 2013).

25 Tällaisia tietotyyppejä ovat esimerkiksi Exercise-, CustomExercise- ja Protocol-luokat. Nämä tietotyypit rakentavat sen harjoitusohjelman, jota Physio Trainer pitää sisällään ja jota käyttäjä voi itse muokata. Exercise-luokan (kuvassa 4) oliot koostuvat uniikista harjoitteen avaimesta (name), joka yhdistää eri kieliset ohjetekstit ja animaatiot toisiinsa, viittauksesta animaatiotiedoston nimeen (clipname) sekä vaihtelevasta määrästä harjoitteeseen liittyvää metadataa, kuten harjoitteen aktivoimat lihasryhmät (highlights) tai harjoitteen tekemiseen vaadittavat apuvälineet (requiredequipment). KUVA 4 Exercise-tietotyyppi Nämä yksinkertaiset tietorakenteet ovat Physio Trainerin rakenteellinen perusta ja niistä käydään jatkuvaa keskustelua työryhmän kesken sekä myös potentiaalisten asiakkaiden kanssa. Ne koostuvat käytännössä vain eri tavoin järjestetyistä kokoelmista primitiivitietotyyppejä. Primitiivitietotyypit tarkoittavat kunkin ohjelmointikielen sisäänrakennettuja, valmiita tapoja varastoida tietoa. Tyypillisiä primitiivejä ovat esimerkiksi kokonaislukuja sisältävä int tai merkkijonoja sisältävä string (Brookshear, 2012). Pienestä mallikuvasta ilmenee muitakin Physio Trainerin kannalta oleellisia seikkoja. Kerron sarjallistamisesta tekstitiedostojen yhteydessä tarkemmin luvussa 3.3.6., mutta tässä yhteydessä lienee sopivaa mainita lyhyesti, miksi olen erikseen merkinnyt itse laatimani tietotyypit Serializable-attribuutilla (kuva 4, rivi 6).

26 Alaluvussa 2.2.2. kerroin Unity-sovellusten yleisestä rakenteesta ja C++-perustaisesta ytimestä, jonka ympärillä toimii dot net johdannainen Mono-ohjelmistokehys. Tästä seuraa se, että Unityn täytyy aina vähintään jokaisen sovelluksen suorituksen yhteydessä rakentaa uudestaan C++-muotoinen esitys Mono-välikerroksen sisältämästä datasta. Tässä yhteydessä kaikki ei-sarjallistetut tietotyypit nollautuvat (Cooper, 2014). Unity ei myöskään paljasta kehittäjän itse laatimia tietotyyppejä editorin puolella Inspector-näkymässä, vaikka ne olisi merkitty public-suojausmääreellä, jos niitä ei ole sarjallistettu. Koska haluan muokata Exercise-listaa myös editorissa, käytän Serializable-attribuuttia. Erityisen kovassa käytössä Physio Trainerin tietojen hallinnassa on C#-kielen geneeriset listat, eli mistä tahansa muista tietotyypeistä koostetut vapaamuotoiset listat, joiden kokoa tai sisältöä ei ole rajoitettu. List-tietotyyppi sisältää valmiiksi monia hyödyllisiä metodeja, joiden avulla esimerkiksi harjoitteista koostettuun listaan voi kohdistaa erilaisia hakuja. (Microsoft Developer Network: List<T> Class, 2014). Jos nämä valmiit hakutoiminnot eivät riitä, on mahdollisuus turvautua ns. LINQhakuihin ja lambda-lausekkeisiin (Microsoft Developer Network: LINQ (Language Integrated Query), 2014 ja Microsoft Developer Network: How to: Use Lambda Expressions in a Query, 2014). Lambda-lausekkeet ovat hyvin tiiviissä muodossa ilmaistuja nimettömiä metodeja, joilla voidaan suorittaa esimerkiksi LINQ-hakuja. Seuraavassa lyhyt esimerkkilauseke LINQ-haun käytöstä. public List<Exercise> GetExercisesAlphabetically() { var list = exercises.orderby(e => Language.Get(e.name)).ToList(); return list; } Oheisessa pätkässä ohjelmakoodia on nähtävillä yksinkertainen mutta tehokas lambdalauseke, joka järjestää senhetkisen harjoitelistan aakkosjärjestykseen valitun kielen perusteella. OrderBy-haussa määritellään nimetön metodi, jonka ainut parametri on harjoiteolio e ja palautusarvona harjoitteen otsikko valitulla kielellä. OrderBy-haku kohdistuu

koko harjoitelistaan ja se järjestää merkkijonoista koostuvat listat oletusarvoisesti aakkosjärjestykseen. 27 Käyttöliittymän ohjelmoinnin yhteydessä käytän myös pino-tietorakennetta. Kerron tästä tarkemmin luvussa 3.4.2. 3.2.2 Tapahtumapohjainen rakenne Olen pyrkinyt toteuttamaan sovelluksen siten, että se hyödyntää C#-kielen natiivisti tarjoamia mahdollisuuksia tapahtumankäsittelyyn niin usein kuin mahdollista. Tästä syystä luonnehdin itse sovelluksen rakennetta tapahtumiin pohjautuvaksi. Tapahtuma eli event on eri ohjelmointikielistä tuttu ohjelmistokehityksen perusominaisuus, jossa jokin luokka määritellään ilmoittamaan mahdollisista objektin tilassa ym. tapahtuvista muutoksista. Kaikki halukkaat oliot voivat ottaa tämän ilmoituksen vastaan ja reagoida siihen haluamallaan tavalla. (Microsoft Developer Network: Events Tutorial, 2014). C#-kielessä tapahtumalle määritellään delegaatti-tyyppinen tapahtumankäsittelijä. Delegaatti on C#-kielen tapa luoda ja kapseloida viittauksia erillisiin metodeihin hieman samaan tapaan, kuin tavanomaisesti viitataan perinteisiin tietotyyppeihin. Delegaatin ei tarvitse vielä käännösvaiheessa tietää, mikä metodi tulee suorituksen aikana kutsutuksi. Delegaatti muistuttaa C- tai C++-kielestä tuttua function pointeria. (Microsoft Developer Network: Delegates Tutorial, 2014). Olen kerännyt omassa sovelluksessani kaikki tapahtumadelegaatit ja niitä kutsuvat julkiset metodit yhteen staattiseen luokkaan nimeltä EventManager (kuvassa 5). Tämä luokka ei siis millään tavalla ota kantaa siihen, mikä objekti lähettää ilmoituksia tapahtumista tai mikä toinen objekti niitä mahdollisesti ottaa vastaan.

28 KUVA 5 Katkelma EventManager-luokasta Tällä luokalla on vain kaksi yksinkertaista tehtävää. Se pitää kirjaa erilaisten tapahtumien nimistä, sekä pitää huolen siitä, ettei sovellus kaadu ajonaikaiseen virheeseen siinäkään tapauksessa, ettei mikään objekti aio käsitellä lähetettyä tapahtumailmoitusta kyseisellä hetkellä. Suorituksen aikana EventManager ottaa vastaan minkä tahansa objektin lähettämiä ilmoituksia tapahtumista, esim. EventManager.OnExerciseChanged, ja lähettää niitä edelleen kaikille halukkaille. Tällä esimerkkitapahtumalla monia eri käsittelijöitä. Joka kerta kun harjoitusta vaihdetaan, ylävalikkoon päivittyy harjoitteen nimi valitulla kielellä, animaatiohahmo vaihtuu kyseisen harjoitteen alkuasentoon, sovelluksen ohjeteksteistä vastaava luokka hakee kyseisen harjoituksen kirjalliset ohjeet ja niin edelleen. C#-kielen natiivien tapahtumien käyttö on yksi tärkeimmistä Physio Trainerin ohjelmointityötä edistäneistä tekijöistä. Tapahtumapohjainen rakenne on mahdollistanut sen, että käyttöliittymäkomponentteja on voitu vaihtaa projektin edetessä moneen kertaan,

eikä lopulta ole tarvinnut kuin huolehtia siitä, että ne lähettävät oikean ilmoituksen oikeasta tapahtumasta tapahtuman käsittelijä on pysynyt ennallaan. 29 Tapahtumapohjainen rakenne saa pelinkehitysympäristössä toteutetun sovelluksen muistuttamaan enemmän perinteistä toimistosovellusta. Jokainen painonapin painallus ruudulla lähettää ainakin yhden tapahtuman. Tämän lisäksi Physio Trainer, kuten muutkin Unity-sovellukset, toteuttavat myös perinteisen game loopin. Unity kutsuu kaikkia MonoBehaviourista periytyviä skriptejä jokaisen ruudunpäivityksen yhdessä ja toteuttaa kaiken Update-metodeihin kirjatun ohjelmakoodin. Tämän lisäksi FixedUpdate-metodit suoritetaan ennalta määritellyin väliajoin ja LateUpdate kyllä jokaisen ruudunpäivitysten yhteydessä, mutta aina fysiikkamoottorin tekemien muutosten jälkeen. 3.2.3 Animoidut 3D-hahmot Kuten aiemmissa luvuissa olen maininnut, yksi tärkeimmistä syistä käyttää juuri Unityä Physio Trainerin sovelluskehityksessä on sen tarjoamat hyvät välineet animaatioiden kanssa työskentelyyn. Unityn uusi Mecanim-animaatiojärjestelmä julkaistiin vuoden 2012 lopulla, Unityn versiopäivityksen 4.0:n yhteydessä. Yksi Mecanimin merkittävä parannus Unityn vanhaan järjestelmään on ns. animation retargeting -menetelmä. En ole löytänyt termille vakiintunutta suomennosta, mutta puhuttakoon tämän raportin yhteydessä vaikkapa animaatioiden uudelleenkiinnityksestä. Tällä tarkoitetaan menetelmää, jossa animaatiohahmot ja itse animaatiot pelkät liikesarjat voidaan erottaa toisistaan ja yksi animaatio voidaan kiinnittää uudelleen toiseen hahmoon, mikäli hahmojen luurakenteet eli rigit ovat jokseenkin samankaltaisia keskenään. (Unity Technologies: Retargeting of Humanoid animations, 2014). Physio Trainerin tapauksessa tämä toiminnallisuus oli alusta lähtien etusijalla: halusimme laatia kirjaston animaatioista, meidän tapauksessamme kuntoutusharjoitteista, jotka eivät kuitenkaan ole sidoksissa yhteen tiettyyn animaatiohahmoon. Halusimme mahdollisuuden vaihtaa hahmoa käyttäjän mieltymyksien mukaan: mies tai nainen, hoikka tai hieman tukevampi ja niin edelleen. Ensimmäisessä pilottikäyttöön suunnatussa sovellusprototyypissä käytämme vain yhtä hahmoa, mutta kaikki hahmojen vaihtami-

30 seen liittyvä perustoiminnallisuus on jo ohjelmoitu valmiiksi. Sovelluksen tapahtumapohjaisen rakenteen ansiosta hahmoa voidaan vaihtaa jopa lennosta, kesken liikkeen suorituksen. Kuvassa 6 (seuraavalla sivulla) on katkelma AvatarController-komponentista, jonka olen liittänyt jokaiseen avatariin eli sovelluksen sisältämään animaatiohahmoon. AvatarController on projektin ainut skripti, jolla on suoraan pääsy Animator-luokan komponentteihin ja skripti myös edellyttää Animator-komponentin olemassaoloa saman gameobjectin yhteydessä. Haluan sovelluksen rakenteellisen selkeyden vuoksi rajoittaa pääsyn Animatoriin vain tälle komponentille. Animator-luokka tarjoaa rajapinnan Mecanim-animoituihin pelihahmoihin ja se on yksi Unityn vakiokomponentteja. (Unity Technologies: Animator, 2014). AvatarController sisältää mm. OnExerciseChanged-metodin eli tapahtumankäsittelijän, joka reagoi hakemalla tapahtuman mukana lähetetyltä Exercise-luokan oliolta siihen liittyvän animaation nimen ja toistamalla sen Animatorin avulla. animator.play(statename); Mikäli valittu harjoite ei sisällä animaatiota, toistetaan sen tilalla SceneManagerainokaisessa määritelty oletusanimaatio. Osa harjoitteisiin liittyvistä ohjeteksteistä saattaa olla sovelluksessa saatavilla, vaikka niitä varten ei ole vielä ehditty tekemään omaa animaatiota. AvatarControllerin muiden tapahtumankäsittelijöiden avulla voi myös esimerkiksi vaihtaa nopeutta, jolla animaatiot toistetaan (OnAnimatorSpeedChanged) tai kelaamalla animaatiota hieman eteen tai taaksepäin haluttuun ajankohtaan (OnAnimatorRewind).

31 KUVA 6 Katkelma AvatarController-luokasta Kaikki scenelle lisätyt animaatiohahmot, jotka sisältävät AvatarControllerkomponentin, pääsevät näin lähes suoraan kiinni sovelluksen toimintaan. Ne voivat ryhtyä ottamaan vastaan käyttöliittymän kautta tai jostakin muusta lähteestä saapuvia viestejä animaation vaihdoista. Hahmon gameobject itse tai siihen liitetyt skriptit eivät kuitenkaan tiedä, missä ja miten animaatiota vaihdetaan. Hahmoja näytetään käyttäjälle vain yksi kerrallaan. Hahmot kytketään päälle tai pois päältä erillisen skriptin avulla, joka sisältää viittaukset kaikkiin saatavilla oleviin hah-

moihin. Päälle kytketty hahmo on heti valmiina toistamaan uusia liikkeitä, jos se saa viestin OnExerciseChanged-tapahtumasta. 32 Mecanim-työkalu edellyttää myös animaatioiden lisäämistä ns. tilakoneeseen (state machine), joka voi pelisovellusten tapauksessa ohjata pelihahmon siirtymistä animaatiosta toiseen. Koska meidän sovelluksessamme animaatioiden vaihto tapahtuu manuaalisesti listalta valitsemalla, tilakoneen tehtäväksi jää lähinnä toimia linkkinä AvatarControllerin ja Mecanimin välillä (kuvassa 7). KUVA 7 Animator-ikkunassa näkyy tilakoneeseen syötetyt animaatiot ja niiden yhteydet 3.2.4 Ainokaiset Manager-luokat Singleton eli ainokainen on yleinen olio-ohjelmoinnin peruskäsite ja suunnittelumalli. Sillä tarkoitetaan luokkaa, josta voi luoda vain yhden olion ja johon kaikki muut oliot voivat viitata globaalisti. (Gamma, Helm, Johnson & Vlissides, 1994 ja Microsoft Developer Network: Implementing Singleton in C#, 2014). Ainokaista on kritisoitu valtavasti. Joissakin kokeneissa ohjelmoijissa se tuntuu herättävän suoranaisia vihan tunteita. On helppo löytää lukuisia lähteitä siihen, miksi ainokaisia ei olisi suotavaa käyttää juuri missään tilanteissa (Yegge, 2004 ja Miller, 2007).

33 Näistä varoituksista huolimatta päädyin käyttämään ainokaisia Physio Trainerissa varsin runsaasti, mutta pitäen kuitenkin mielessäni niihin liittyvät sudenkuopat ja muut mahdolliset ongelmat. Suurin osa käyttämistäni ainokaisista on ns. Manager-luokkia, joiden tarkoituksena on huolehtia jonkin tietyn perustoiminnallisuuden vaatimuksista ja mahdollisista globaaleista asetuksista. Yhtäältä tämä tekee ohjelmakoodin hyvin riippuvaiseksi näistä luokista, mikä on huono asia. Toisaalta se helpottaa omaa työskentelyäni, jos voin varmistua siitä, että esimerkiksi animaatiotiedostoihin liittyvä ohjelmakoodi ja julkiset muuttujat sijaitsevat kaikki AnimationManager-luokassa. Olen järjestänyt Manager-skriptit yhden tyhjän gameobjectin alle komponenteiksi. Tässä on myös tausta-ajatuksena se, että näihin skripteihin liittyviä julkisia muuttujia on päästävä tarkastelemaan ja muokkaamaan suoraan Unityn editorissa, ilman ohjelmakoodiin puuttumista (kuvassa 8, seuraavalla sivulla). Esimerkkinä tästä on viittaukset harjoitteiden ohjeteksteihin. Nämä ovat varsinaisen ohjelmakoodin ulkopuolisia tiedostoja, joita haluan käydä usein vaihtamassa. Myös kuka tahansa muu työryhmämme jäsen voi sen tehdä, ilman mitään kokemusta ohjelmoinnista. Edellisessä luvussa mainitsemani tapahtumapohjainen rakenne on toisaalta vähentänyt huomattavasti tarvetta ainokaisten Manager-luokkien käytölle, sillä varsinkin ajonaikaiset muutokset sovelluksen tilassa siirtyvät varsin kätevästi oliosta toiseen juuri tapahtumien kautta.

34 KUVA 8 Manager-luokkien julkiset kentät Unityn editorissa 3.2.5 Ulkoiset dataformaatit ja sarjallistaminen Kolmosluvun alussa kerroin, että Physio Trainerissa on kaksi toisiaan täydentävää puolta: harjoitteista laaditut animaatiot ja tavanomaiset kirjalliset ohjetekstit. Pelkät animaatiot eivät riitä välittämään suoritusohjeita, vaikka se onkin staattiseen piirroskuvaan tai videoonkin verrattuna parempi vaihtoehto.

35 Haastattelemamme fysioterapeutit olivat tottuneet nykyisissä järjestelmissä siihen, että piirroskuvien lisäksi saatavilla on myös kirjalliset ohjeet, mutta toisaalta he olivat tottuneet myös muokkaamaan ohjetekstejä potilaan tarpeisiin sopivammaksi. Hyvin tärkeänä ominaisuutena pidettiin myös jonkinlaisen harjoitusohjelman laadintaa: harjoitteet pitäisi saada asetettua tietyille päiville, harjoitteiden toistokertoja pitää voida muokata ja niin edelleen. Kirjallisia suoritusohjeita varten olemme laatineet sekä Google Docs dokumentteja että hienostuneempia tietokantapohjaisia ratkaisuja, mutta ne eivät olleet tämän raportin kirjoittajan vastuualueella, enkä näin ollen käsittele niitä tässä työssä sen syvällisemmin. Eri ratkaisujen lopputuloksena on kuitenkin aina samankaltaiset, JSON-muotoiset tiedostot, jotka sisältävät ohjetekstit eri kielillä (kuvassa 9) sekä erillinen JSON-tiedosto muuta harjoitteisiin liittyvää metadataa varten. Nämä tiedostot kulkevat mukana Unityn projektikansiossa. JSON (lyhenne sanoista JavaScript Object Notation) on yksinkertainen, standardoitu tiedostomuoto selväkielisen datan liikutteluun eri sovellusten välillä. Se perustuu vapaamuotoisiin nimi-arvopareihin kuten nimi : Seppo. KUVA 9 Katkelma harjoitteiden ohjetekstejä sisältävästä JSON-tiedostosta JSON-formaatin valinta työryhmän sisäiseen käyttöön ei edellyttänyt suurta harkintaa. Useilla työryhmän jäsenillä oli JSONista aiempia kokemuksia. JSONin jäsentäminen Unity-sovelluksessa ei ole vaikeaa, mutta Unityn mukana ei tule omaa jäsennintä, toisin kuin Android-natiivisovelluksissa (Android Developers: JsonReader, 2014). Näin ollen

oli järkevää valita käyttöön sellainen tiedostomuoto, jonka käsittelyyn on saatavilla useita valmiita ja ilmaisia laajennoksia. 36 JSONin jäsentämistä kiinnostavampi ratkaisu on tapa säilöä JSON-tiedostot Unityn projektikansiossa, sillä Unity itse muuttaa selväkieliset tekstitiedostot TextAsset-luokan olioiksi. TextAsset on Unityn sisäinen tapa säilyttää tekstiä, esimerkiksi juuri JSONtiedostoja, sarjallistettuina sovelluksen sisällä. Sarjallistaminen tarkoittaa olioiden tai olioryhmien muuntamista ja tallentamista siirreltävään muotoon siten, että alkuperäinen sarjallistettu olio (tai sen kopio) voidaan palauttaa tai rakentaa uudestaan myöhemmin (Cline, 2012). Tämän luvun yhteydessä tarkoitan sarjallistamisella erityisesti olioiden tallentamista binäärimuotoon. (Microsoft Developer Network: Serialization (C# and Visual Basic), 2014). Unity sarjallistaa TextAssetit käännösvaiheessa kuten kaiken muunkin, ohjelmakoodin, kuvat ja äänet. Tekstitiedostot eivät näin ollen siirry ohjelman mukana enää erillisinä tiedostoinaan, vaan ne on sisällytetty osaksi Unityn koostamaa binäärimuotoista, ajettavaa tiedostoa. Androidin tapauksessa tämä on.apk-päätteinen asennuspaketti. (Unity Technologies: TextAsset, 2014). TextAssetin etu erillisiin tiedostoihin nähden on helppo ymmärtää. Alustariippumatonkin sovelluskehitys eroaa huomattavasti juuri levyn lukemiseen ja kirjoittamiseen liittyvissä kysymyksissä. Sovelluksen mukana kulkevat, mutta kuitenkin erilliset tiedostot edellyttävät, että sovelluksella on ensinnäkin lupa lukea ja kirjoittaa levylle ja toiseksi se vaatii jokaista alustaa varten sovitetun ohjelmakoodin näihin toimintoihin. TextAsset-muotoiset tiedostot eivät vaadi mitään näistä. TextAssetin huono puoli on se, ettei sitä ole tarkoitettu sovelluksen ajonaikaiseen tekstitiedostojen luomiseen tähän vaaditaan edelleen levyn kirjoitusoikeutta. TextAsset on tarkotettu ainoastaan valmiiden tekstitiedostojen tuontiin, kun sovellus on vielä tekovaiheessa. Kerron seuraavassa alaluvussa toisesta tavasta käsitellä sovelluksen ulkopuolisia tiedostoja Unityssä.

37 3.2.6 Omat tallennukset Physio Trainerin toteutuksen edetessä meille ilmeni muutamia tarpeita, joita varten sovelluksen piti voida kirjoittaa levylle pysyvästi. Yksi tärkeimmistä tarpeista oli mahdollisuus tallentaa paikallisia sovellusasetuksia niin, että ne säilyvät senkin jälkeen, kun sovellus on suljettu. Paikallisilla asetuksilla tarkoitan tässä yhteydessä sovelluksen mukana kohdelaitteen muistiin tallennettuja asetuksia. Toinen vaatimus oli mahdollisuus tallentaa potilasta varten muokattuja ohjetekstejä ja muuta harjoitusohjelmaan liittyvää dataa. Unity tarjoaa näihin tarpeisiin kaksi erilaista lähestymistapaa, joista esittelen tässä lyhyesti molemmat. Paikallisia sovellusasetuksia varten Unity tarjoaa staattisen PlayerPrefs-luokan ja sen julkiset metodit. PlayerPrefs on tarkotettu muutaman perustietotyypin datan tallennukseen. Tuettuja tietotyyppejä on tasan kolme: int, float ja string eli kokonaisluvut, liukuluvut ja merkkijonot. PlayerPrefsin suurin etu on se, että Unity hoitaa kaikki levylle kirjoittamiseen liittyvät muodollisuudet eikä siten edellytä mitään alustariippuvaisia muutoksia ohjelmakoodissa. PlayerPrefs on käytettävissä myös selaimessa toimivissa Unity-sovelluksissa, mutta sen suurin ongelma on rajoittuneisuus näihin kolmeen tietotyyppiin. Mikäli ne riittävät, PlayerPrefs on oivallinen tapa tallentaa pysyvää tietoa Unityssä. (Unity Technologies: PlayerPrefs, 2014). Hyödynnän Physio Trainerissa PlayerPrefsiä omassa SettingsManager-luokassani (kuvassa 10, seuraavalla sivulla). SettingsManager huolehtii tämän raportin kirjoitushetkellä vain kahden muuttujan arvon tallentamisesta levylle ja näiden arvojen palauttamisen sovelluksen käynnistyksen yhteydessä. Tallennettavia muuttujia ovat viimeksi käytetty kielivalinta (langcode) ja sovelluksen tila (appmode). Nämä muuttujat eivät kuitenkaan sovelluksen sisäisessä käytössä ole merkkijonoja vaan enumeraatioita eli ennalta määriteltyyn, muuttumattomaan listaan perustuvia vaihtoehtoja (Microsoft Developer Network: enum (C# Reference), 2014). Esimerkiksi kielivalinnan käsittely vapaasti määriteltävänä merkkijonona ei ole mielekästä, sillä kielivalintoja on joka tapauksessa vain rajoitettu määrä: meidän tapauksessamme FI, EN ja FR eli suomi, englanti ja ranska.

38 KUVA 10 Katkelma SettingsManager-luokasta PlayerPrefsin rajoitusten takia kuitenkin tallennan kielivalinnan juuri merkkijonona eli stringinä. Kuvan 10 riveillä 54 ja 55 muunnan ensin enum-tyyppisen muuttujan merkkijonoksi ja tallennan sen PlayerPrefsin avulla pysyvään muistiin. Saman kuvan rivillä 65 haen merkkijonosta alkuperäisen enumeraation: var langcode = (LangCode)Enum.Parse(typeof(LangCode), lang, true); SettingsManager hyödyntää myös aiemmin esittelemääni tapahtumiin perustuvaa sovellussuunnittelua. Joka kerta kun vaikkapa kielivalintaa muutetaan, SettingsManager kä-

39 sittelee muutoksesta lähetetyn tapahtumailmoituksen ja tallentaa muutokset välittömästi levylle. Levyltä lukemisen yhteydessä, sovellusta avattaessa, SettingsManager lukee mahdolliset tallennetut arvot muistista ja lähettää itse tapahtumailmoituksen, että on muuttanut arvoja. Physio Trainer tarvitsi kuitenkin vielä PlayerPrefsiä monipuolisemman tavan tallentaa tietoja, sillä sovelluksen yksi perustoiminnallisuuksista on juuri mahdollisuus luoda harjoitusohjelmia valittujen animaatioiden pohjalta. Tätä varten sovelluksen täytyi sarjallistaa ja kirjoittaa levylle itse luomieni tietotyyppien olioiden sisältö, kuten listat Exercise-luokan olioista. PlayerPrefs ei tue kuin kolmea edellä mainitsemaani tietotyyppiä ja tämän rajoituksen kiertäminen harjoitusohjelmien kohdalla olisi ollut kohtuuton vaiva, joten turvauduin ratkaisuun, joka vaatii ainakin rajattua käyttöoikeutta kohdekoneen levyjärjestelmään. Vaatimus levyjärjestelmän käytöstä rajaa ainakin yhden Unityn mahdollisista sovellusalustoista, selaimessa ajettavan Unity-sovelluksen, pois laskuista. Selainkäyttöön tarkoitetuilla Unity-sovelluksilla ei ole mitään pääsyä levyjärjestelmään, sillä tämä on turvallisuussyistä kokonaan estetty (Unity Technologies: Security Sandbox of the Webplayer, 2014). Selaimessa toimivat Unity-pelit ja muut sovellukset voivat toki tallentaa ja hakea asetuksia tavallisen WWW-kutsun avulla. Physio Traineria ei kuitenkaan olla toistaiseksi toteuttamassa selaimia varten, ja halusimme sovelluksen toimivan vielä tässä vaiheessa täysin ilman verkkoyhteyttä, joten saatoimme vaatia sovellukselle oikeuksia levyjärjestelmään. 3.3 Käyttöliittymän ohjelmointi Tässä alaluvussa kerron muutaman esimerkin avulla käyttöliittymän ohjelmoinnista ja muusta toteutuksesta Unityssä. Ulkoisena käyttöliittymäkirjastona käytän Daikon Forge UI:ta, joka on maksullinen Unity-laajennos. Tämä mahdollistaa muun muassa käyttöliittymän visuaalisen editoinnin ja muutamia muita kehittyneempiä toimintoja (Daikon Forge, 2014). Physio Trainerin graafisen käyttöliittymän ohjelmointi noudatteli karkeasti seuraavaa kaavaa: asettelin staattiset käyttöliittymäelementit paikoilleen scene-näkymässä niin

40 pitkälle kuin mahdollista, mallikuvien pohjalta. Kaikki dynaamiset elementit luodaan ajonaikaisesti. Staattisilla elementeillä tarkoitan kohtalaisen pysyviä valikkorakenteita, jotka eivät muutu käyttäjän toimien perusteella, kuten alkuvalikkoa. Dynaamisilla elementeillä tarkoitan puolestaan esimerkiksi listaa harjoitteista, joka luodaan uudelleen käyttäjän tekemien valintojen tai hakutermien perusteella. Toisaalta myös harjoitelistan sijanti ruudulla, esitystapa ym. on staattisesti määritelty etukäteen vain itse listan sisältö luodaan ajonaikaisesti. Lähes jokaisella käyttöliittymäelementillä on oma skripti, useimmiten mahdollisimman lyhyt pätkä ohjelmakoodia, joka vaikuttaa kyseiseen elementtiin suoraan ja mahdollisimman vähän mihinkään muuhun kyseisen elementin ulkopuolella. Esimerkkinä tällaisesta hyvin pelkistetystä yhden asian skriptistä on seuraava kuva AddExerciseLabelluokasta, jonka saatan esittää tässä lyhyytensä vuoksi kokonaisuudessaan (kuvassa 11). KUVA 11 AddExerciseLabel-luokka Hieman kuvan 11 kaltaisia skriptejä projektissa on kymmeniä. Luokka edellyttää liittämistä tietyn nimiseen komponenttiin (rivi 4), eikä sovellusta voi käynnistää tai kääntää ennen kuin kyseisen skriptin kanssa samassa gameobjectissa oleva komponentti vastaa

kääntäjälle annettua RequireComponent-attribuuttia (Unity Technologies: RequireComponent, 2014). 41 Kuvan skriptin käyttö edellyttää dflabel-nimisen käyttöliittymäelementin läsnäoloa. Attribuutin tarkoitus on suojella sovellusta ajonaikaisilta virheilmoituksilta, mikäli olisin jostain syystä päätynyt epähuomiossa liittämään skriptin väärään paikkaan. Koska haen Awake-metodissa viittauksen dflabel-olioon (kuva 11, rivi 17), enkä käsittele mahdollisia poikkeuksia mitenkään, minun täytyy tavalla tai toisella varmistua siitä, että viittauksen takana on todellakin aina dflabel-olio. Tämä attribuutti pitää siitä huolen. Tällä skriptillä on vain yksi tehtävä: vaihtaa siihen liitetyn dflabel-olion tekstikentän sisältöä aina, kun harjoitetta vaihdetaan. Sitä varten se tarvitsee tapahtumankäsittelijän, OnExerciseChanged (kuva 11, rivi 20-22) ja pari riviä joilla EventManagerille ilmoitetaan, että tämä skripti kuuntelee tapahtumailmoituksia aina kun skripti on päällä ja lopettaa kuuntelemisen, jos se on pois päältä (OnEnable- ja OnDisable-metodit). Myös sovelluksen valikkojen lokalisointi eli käännös eri kielille toimii hyvin samantyyppisten skriptien avulla: aktiiviset valikkoelementit kuuntelevatkin OnLanguageChanged-tapahtumaa ja vaihtavat tekstikenttiensä sisältöä asianmukaisesti. Dynaamisten eli muuttuvien elementtien, kuten aiemmin mainitun harjoitelistan, yhteydessä käytän yhtä yhteistä valikkoskriptiä, joka luo aina tarvittaessa valikon sisällön uudestaan. Valikon sisältämät elementit ja niihin liittyvät gameobjectit lisätään valikkoobjektin lapsiksi ja valikkoskripti pitää kirjaa lapsiobjekteistaan ja myös tuhoaa ne aina kun uutta listaa tarvitaan. Dynaamisetkin elementit huolehtivat silti omasta sisällöstään ja omista sisäisistä toiminnoistaan mikäli mahdollista. Ainoastaan näiden elementtien elinkaari on toisen skriptin harteilla. 3.3.1 Visuaalinen editointi Daikon Forge UI tarjoaa mahdollisuuden nopeaan käyttöliittymäprototyyppien laatimiseen, sillä käyttöliittymäelementit voi tarvittaessa asetella paikalleen samassa scenenäkymässä, missä itse pelimaailmakin on. Tällaista lähestymistapaa ohjelmistosuunnitteluun kutsutaan myös nimellä WYSIWYG, what you see is what you get. (Dictionary.com, 2014).

42 Käyttöliittymää varten scene-näkymässä on oma ortografinen (kaksiulotteisena projisoitu) kameransa, joka kuvaa kaksiulotteisia käyttöliittymäelementtejä suoraan edestäpäin siten, että katsojalle syntyy vaikutelma käyttöliittymästä. Pohjimmiltaan käyttöliittymäkin on samassa 3D-avaruudessa kuin kaikki muutkin gameobjectit, mutta se vain on kuva-alalla kaiken muun edessä. Käyttöliittymäelementit Unityssä ovat oikeastaan vain litteitä levyjä, joiden pinnalle heijastetaan tekstuuriksi haluttu kuva. Kuvassa 12 yritän havainnollistaa, miltä käyttöliittymä näyttäisi hieman etuviistosta kuvattuna. Kuvassa näkyvä harmaa laatikko esittää käyttöliittymäkameran rajoja. Laatikon sisällä käyttöliittymä tietysti projisoituu käyttäjän näytölle suoraan. KUVA 12 Sovelluksen graafinen käyttöliittymä etuviistosta kuvattuna Daikon Forge käyttöliittymän toteutus aloitetaan UI Root nimisestä gameobjectista, joka on kaikkien muiden käyttöliittymäelementtien äitiobjekti. UI root objektiin liittyy aina käyttäjän syötteistä (hiiri, näppäimistö, kosketus) vastaava DfInputManagerkomponentti sekä käyttöliittymän ydinkomponentti DfGUIManager, jossa määritellään tietyt perusasetukset. Näitä ovat muun muassa käyttöliittymäkameran määritykset, oletuskirjasinlaji ja tekstuuriatlas, joka on yhteen suureen kuvatiedostoon kasattu kokoelma yksittäisten käyttöliittymäelementtien tekstuureja.

43 Tekstuuriatlas on muun muassa pelituotannossa yleisesti käytetty menetelmä vähentää suoritintehon käyttöä erillisten kuvatiedostojen lataamiseen, vaihtamiseen ja ruudulla esittämiseen (Ivanov, 2006). Unity osaa automaattisesti hyödyntää valmista atlasta yhdistämällä samaa materiaalia käyttävien objektien piirtokutsut yhteen (Unity Technologies: Draw Call Batching, 2014). Koska Physio Trainerin tekstuuriatlas (kuvassa 13) sisältää käytännössä kaikki käyttöliittymäelementtien tarvitsemat kuvat yhden kuvatiedoston alla, käyttöliittymän esittäminen ruudulla vaatii siis vain yhden piirtokutsun. Tämä on huomattavan suuri parannus vaihtoehtoisiin menetelmiin, varsinkin Unityn omaan käyttöliittymäkirjastoon, nähden. KUVA 13 Tekstuuriatlas, alkuperäinen kuvan koko 2048x2048. Atlaksen koostaminen valmiista kuvista olisi kuitenkin vaivalloista käsityötä ja edellyttäisi paljon askartelua kuvankäsittelyohjelman parissa. Daikon Forge UI sisältää tähän valmiin työkalun, DfAtlasin, jonka avulla atlaksen voi koostaa Unityn editorissa vain vetämällä ja tiputtamalla haluamansa kuvatiedostot yhteen. Kun kirjasinlajin, atlaksen ja kameran on saanut määriteltyä mieleisekseen, UI Root objektin alle voi alkaa rakentaa varsinaista käyttöliittymähierarkiaa. Koska kaikki muutkin gameobjectit Unity-scenellä käyttävät samaa hierarkianäkymää, on mielekästä rakentaa myös käyttöliittymä samankaltaista äiti-lapsi-suhdetta hyödyntäen. Hierarkian yläpäässä (kuva 14, seuraavalla sivulla) minulla on neljä valikkoa: Header Container, Menu Container, Footer Container ja Settings Container. Nämä ovat tyhjiä valikkorakenteita, jotka määrittelevät lähinnä kyseisten valikkoruutujen sijainnin ja suhteellisen

44 koon ruudulla. Tätä menetelmää voisi verrata vaikkapa natiivien Android-sovellusten View-luokan käyttöön (Android Developers: View, 2014) tai HTML-kehityksestä tuttuun div-elementtiin (Erack Network, 2008). KUVA 14 UI Root hierarkia ja Inspector Tyhjien valikkorakenteiden sisällä toistuvat elementit on toteutettu Unityn omaa ns. prefab-menetelmää hyödyntäen. Prefabit (lyhennys englannin kielen sanasta prefabricated, esivalmistettu) ovat gameobjekteja, joita on tarkoitus luoda ja monistaa sovelluksen suorituksen aikana. Prefabeille voi määritellä valmiit muuttujien arvot etukäteen, jolloin kaikki kyseisestä prefabista luodut objektit ovat identtisiä ainakin sillä hetkellä, kun ne luodaan (Unity Technologies: Prefabs, 2014). Prefabien etu onkin juuri siinä, että yhtä malliobjektia pystyy vaikuttamaan kerralla kaikkiin sen pohjalta luotuihin objekteihin. Peleissä sillä voitaisiin monistaa vaikkapa

45 vihollisen avaruusaluksia, mutta Physio Trainerissa se soveltuu mainiosti toistuvien käyttöliittymäelementtien kuten painonappien oletusasetusten määrittelyyn. Käsittelen prefabien avulla koostettua valikkoa tarkemmin luvussa 3.3.3. 3.3.2 Menu stack Physio Trainer oli varhaisessa kehitysvaiheessaan toteutettu siten, että käyttöliittymä oli toteutettu Androidin natiivien työkalujen avulla, ja Unity-ikkuna näkyi ainoastaan yhtenä osana varsinaisen pohjasovelluksen sisällä eli ns. fragmenttina (Android Developers: Fragment, 2014). Vaikka työryhmämme siirsi myös sovelluksen käyttöliittymän toteutuksen Unityyn, halusin säilyttää sovelluksessa mahdollisuuden liikkua valikoissa eteenpäin ja taaksepäin natiiveista Android-sovelluksista tutulla tavalla. Edelliseen valikkoon (tai jopa aiemmin avattuun sovellukseen) pääsee back-napilla, joka joissain Android-laitteissa on yksi fyysisistä painonapeista. Valitsin tähän tarkoitukseen Stack-tietotyypin muuttujan eli ns. pinon (Kolehmainen, 2001). Pino soveltuu hyvin tilanteisiin, joissa halutaan pitää muita objekteja tietyssä järjestyksessä listattuna. Pinon sisältämiin objekteihin pääsee käsiksi vain laittamalla uuden objektin pinon päällimmäiseksi tai ottamalla päällimmäisen objektin listasta pois. Näitä toimintoja kutsutaan nimillä push ja pop (Duke University, 2004). Sovelluksemme siis pitää kirjaa kaikista edellisistä valikoista, joita käyttäjä on avannut. Tällä on kauaskantoisia ja toisinaan ikäviäkin seurauksia. Objektien tila on saattanut muuttua valikoista toiseen siirryttäessä niin, ettei edellisiin valikkoihin palaaminen ole enää mielekästä tai mahdollistakaan. Esimerkkinä tästä vaikkapa tilanne, jossa käyttäjä on valinnut harjoitteen listasta, poistanut sen toisessa valikossa, mutta haluaisikin palata takaisin valikkoon, jossa harjoite oli vielä valittuna. Tällaisten tapausten varalle olen tehnyt erilaisia erityissääntöjä. Nykymuodossaan sovellus ohjaa käyttäjän automaattisesti suoraan alkuvalikkoon, jos harjoite poistetaan. Tapahtumien lähettäminen käyttäjän liikkeistä valikkorakenteissa on silti ehdottoman hyödyllistä. Työryhmällämme onkin tulevaisuuden pyrkimyksenä analysoida, miten pilottivaiheen käyttäjät todellisuudessa käyttävät sovellustamme. Kun jokaisesta liik-

46 keestä valikkorakenteissa lähtee tapahtumailmoitus, voimme myös helposti kirjata ylös, miten käyttäjä liikkuu valikoista toiseen ja kuinka kauan hän viettää aikaa kussakin valikossa. 3.3.3 ExercisePanel ExercisePanel-luokka on Physio Trainerin tärkein yksittäinen komponentti, sillä juuri harjoitelistassa yhdistyy kaikista eri lähteistä koostetut tiedot yksinkertaiseksi käyttöliittymäelementiksi. Laajuutensa vuoksi en erittele ExercisePanelia tässä yhteydessä kokonaisuudessaan, mutta selostan sen yleisen toimintaperiaatteen muutaman esimerkin avulla. ExercisePanel on vastuussa näkymästä (kuvassa 15 vasemmalla), josta sovelluksen käyttäjä voi käydä valitsemassa haluamansa harjoitteen. Se on käytännössä vain lista painikkeista, joita painamalla valittu harjoite vaihtuu ja animaatiohahmo siirtyy kyseisen harjoitteen aloitusasentoon. Lista koostetaan aiemmissa valikoissa tehtyjen muutosten perusteella ja sen sisältöön vaikuttaa esimerkiksi harjoitekategoria, sovelluksen yleinen tila (fysioterapeutti- tai asiakasnäkymä), mahdollisen harjoiteohjelman valittu päivä ja niin edelleen. Edellinen lista tuhotaan ja uusi näkymä rakennetaan joka kerta, kun listan sisältöön vaikuttavat tekijät muuttuvat. KUVA 15 Näkymä sovelluksesta, kun ExercisePanel on käytössä

47 Kerroin luvun 3.3.1 lopussa lyhyesti prefabeista, eli valmiiksi määritellyistä gameobjekteista, joita on tarkoitus monistaa ajon aikana. Kuvassa 16 näkyy Exercise Panelin julkiset kentät, eli viittaukset niihin prefabeihin, joista harjoitelista rakennetaan. Esimerkiksi Exercise Button Prefab -kenttään voi editorissa kiinnittää viittauksen oletusarvoiseen painonappiin, jota monistetaan ja muokataan senhetkisen listan tarpeiden mukaisesti. Prefabeja varten suunnittellut painonapin mallin WYSIWYG-periaatetta hyödyntäen. KUVA 16 ExercisePanel-luokan editorinäkymä Kuvassa 17 (seuraavalla sivulla) on nähtävillä pieni katkelma CreateExerciseListmetodista, joka sisältyy Exercise Panel luokkaan. Riveillä 57-61 haetaan tarvittavat viittaukset, joiden pohjalta lista rakennetaan. Rivillä 65 pysäytetään metodin suoritus, kunnes listan tuhoamisesta vastaava metodi ClearExerciseList on suoritettu. Riveillä 70-95 esitetään silmukka, jonka sisällä lista rakentuu. DfPanel-luokan olioista koostuvia painonappeja monistetaan kulloinkin tarvittava määrä ja niihin tehdään muutamia tarvittavia muutoksia, kuten vaihdetaan painonappien tekstit vastaamaan harjoitteiden otsikoita. Exercise Panelissa on kaksi perustavaa laatua olevaa vikaa, joita en ole vielä onnistunut tämän raportin kirjoitushetkellä ratkaisemaan. Ensimmäinen ongelma on, että listaa päivitetään usein ja hitaimmilla laitteilla listan tuhoamiseen ja uudelleen rakentamiseen menee muutamia sekunteja.

48 KUVA 17 Katkelma CreateExerciseList-metodista Toinen, varsinkin sovelluksen tulevaisuuden suorituskykyä koskeva ongelma on, että listaa ei ole virtualisoitu. Virtualisoinnilla tarkoitetaan tässä yhteydessä käyttöliittymäohjelmoinnin menetelmää, jossa laajasta listasta tai muusta kokonaisuudesta ladataan kerrallaan ruudulle vain näkyvä osa, Physio Trainerin tapauksessa siis noin kymmenen harjoitetta (Microsoft Developer Network: Optimizing Performance: Controls, 2014). Hieman samankaltaisesta, yleisestä ohjelmoinnin suunnittelumallista, jossa käyttöliittymäelementit, kuvat tai oliot luodaan vasta tarpeen mukaan, käytetään myös termiä lazy loading tai lazy initialization, laiska lataus (Gamma, Helm, Johnson & Vlissides, 1994). Tällä hetkellä Exercise Panel rakentaa aina listan, jossa on kyseisen kategorian kaikki harjoitteet. Mikäli yhden kategorian alla harjoitteita olisi satoja tai tuhansia, listan rakentaminen ja sen tuhoaminen kestäisi minuutteja tai jopa tunteja. Tämän lisäksi pelkästään listan selailu on äärimmäisen hidasta. Tämä ei tietenkään ole suotavaa. Listan virtualisointi onkin yksi Physio Trainerin tärkeimmistä tulevaisuuden kehitystehtävistä.

49 Toistaiseksi se on jäänyt tekemättä, koska harjoitteita on enimmillään saatavilla vain muutamia kymmeniä, eikä se siten ole vielä muodostunut kohtuuttoman suureksi ongelmaksi. 3.4 Testaus 3.4.1 Testilaitteet Työryhmällämme on käytössä kuusi kappaletta eri kokoisia ja tasoisia Androidtabletteja. Näiden ohella vapaamuotoista testausta on suoritettu myös työryhmän jäsenten mahdollisilla omilla Android-laitteilla. Sovelluksen kehitystyön yhtenä päämääränä on, että valmiin sovelluksen suorituskyky eli lähinnä ruudunpäivitys ja valikoissa liikkuminen toimii riittävän nopeasti kaikilla testilaitteilla, eikä muitakaan laitekohtaisia eroja löytyisi. Myöskään eri kokoiset näyttöresoluutiot eivät saa rikkoa käyttöliittymän ulkoasua. Ulkoasun osalta en ole havainnut mainittavia poikkeuksia, mutta suorituskyky eri laitteilla on hieman toivottua heikommalla tasolla. Tavoitteena minulla on ollut säilyttää ruudunpäivitys kaikilla testilaitteilla ainakin noin 30 ruudunpäivityksessä sekuntia kohden. Suoritin kaikille käytössäni oleville Android-tableteille pienen ruudunpäivitystestin, jossa vertailin eri laitteiden suorituskykyä kahdessa eri tilanteessa. Suorituskykyvertailun tulokset ovat nähtävillä oheisessa taulukossa 1. Olin ensiksi kiinnostunut ruudunpäivityksen nopeudesta (frames per second, ruutua sekunnissa) sovelluksen alkuvalikossa, ilman että käyttäjä tekee sovelluksella mitään. Toiseksi halusin selvittää, kuinka alas saan ruudunpäivitysnopeuden putoamaan, jos käytän kaikkia sovelluksen toimintoja samanaikaisesti (minimi). TAULUKKO 1 Taulutietokoneiden suorituskykyvertailu laitemalli resoluutio ytimet kellotaajuus keskusmuisti alkuvalikko minimi Archos Platinum 101 1280x800 4 1.6 GHz 2 GB 40-47 25 Asus MeMO Pad 10 1920x1200 2 1.6 GHz 2 GB 47-52 21 Lenovo Yoga Tablet 10 1280x800 4 1.2 GHz 1 GB 25-31 25 Nexus 10 (2012) 2560x1600 2 1.7 GHz 2 GB 47-53 42 Nexus 7 (2012) 1280x800 4 1.2 GHz 1 GB 49-50 24 Samsung Galaxy Tab3 10.1 1280x800 2 1.6 GHz 1 GB 37-45 15

50 Ylimalkaisen vertailun perusteella voi vetää ainakin sen johtopäätöksen, ettei pelkästään suorittimen ydinten lukumäärää, kellotaajuutta ja keskusmuistia tarkastelemalla voi ennustaa Physio Trainerin suorituskykyä mitenkään mielekkäällä tavalla. Nexus 7 menestyy testissä varsin hyvin ja Lenovon Yoga melko huonosti, vaikka taulukon valossa molempien pitäisi olla samantasoisia. Unityn omissa ohjeissa selitetään, että piirtokutsujen määrää vähentämällä voi vähentää suoraan oman sovelluksensa suoritinkäyttöä. (Unity Technologies: Optimizing Graphics Performance, 2014). Tältä osin sovellusta onkin jo optimoitu melko hyvin. Piirtokutsuista puhutaan yleisesti luvussa 2.3.3. ja tämän sovelluksen osalta luvussa 3.3.1. Syy merkittävään eroon suorituskyvyssä siis lienee jossakin muualla, kuten eritasoisissa näytönohjainpiireissä, joita ei tässä taulukossa ole huomioitu. 3.4.2 Unity Profiler Unity Profiler on yksi maksullisen Unity Pro version sisältämistä lisäominaisuuksista. Profilerin avulla voi seurata, miten sovellus käyttäytyy ajonaikaisesti ja kuinka suuren määrän prosessoritehoa tai keskusmuistia mikäkin sovelluksen osa-alue vaatii. Profiler jaottelee sovelluksen metodikohtaisesti ja päivittyy reaaliajassa. Profiler kuitenkin vaikuttaa merkittävästi sovelluksen ajonaikaiseen suoritusnopeuteen, joten sen jatkuva käyttö vaatii huomattavan suurta prosessoritehoa. Tästä huolimatta se on erinomainen työkalu vaikkapa muistivuotojen tai poikkeuksellisen raskaiden metodikutsujen löytämisessä. Physio Trainerin kehitystyön aikana olen useita kertoja törmännyt tilanteeseen, että huolimattomasti ohjelmoitu metodi kuluttaa prosessoritehoa paljon tavallista enemmän. Tämä korostuu, mikäli kyseistä metodia on tarkoitus kutsua jokaisen ruudunpäivityksen yhteydessä. Profilerin avulla (kuvassa 18, seuraavalla sivulla) voi esimerkiksi tarkastella, mikä metodi aiheuttaa suorittimen käytössä (CPU Usage) näkyvät kaksi selvää piikkiä. Mikäli tällaisia piikkejä näkyy Profiler-ruudussa jatkuvasti, voi syynä olla huonosti kirjoitettu ohjelmakoodi. Profilerin avulla oppiikin siirtämään raskaimmat algoritmit ulos Unityn Update-loopista.

KUVA 18 Unity Profiler 51