Online Android szakkör (DKRMG)
A korábbi leckékben elkezdtünk megismerkedni a telefonokban található érzékelőkkel (közelségérzékelő, iránytű). Ez idáig egyszerre mindig egy értéket közöltek velünk a szenzoraink (távolság, elfordulás szöge). Most azonban megnézzük, hogy mi történik, amikor kilépünk ebből az egysíkú, egydimenziós világból. Néhány szenzor ugyanis képes egyszerre több mindent is érzékelni!
Ebben a leckében egy egyszerű játékot fogunk elkészíteni, amiben egy golyó gurul össze-vissza a képernyőn aszerint, hogy épp milyen gyorsulási erők hatnak a telefonunkra (hogyan tartjuk, merre forgatjuk és merre mozgatjuk).
Induláskor jelenjen meg egy golyó(t ábrázoló kép) a képernyő közepén. Ha jobbra-balra illetve előre-hátra billentjük a telefont, a golyó induljon el a megfelelő irányba, engedelmeskedve a gravitáció csábításának.
Ebben a leckében is egy szenzort fogunk igénybe venni, mégpedig az ACCELEROMETER
szenzort, azaz a gyorsulásmérőt.
Ez a szenzor közvetlenül elárulja nekünk, hogy a képernyő tetején pihenő képzeletbeli golyó merre gyorsulna.
Most is az lesz a feladatunk, hogy feliratkozzunk a szenzorra, új adat érkezésekor az kiolvasott értékeknek megfelelően módosítsuk a golyó pozícióját, majd a program leállásakor leiratkozzunk a szenzorról.
Vázlatosan tehát:
ACCELEROMETER
(gyorsulásmérő) szenzorra
onSensorChanged
függvény törzsének befejezése, hogy a szenzortól érkező adatoknak megfelelően arrébb mozdítsa a golyót.Előfordulhat, hogy több olyan játékkal is találkoztatok már, amit a telefon mozgatásával kellett vezérelni (pl.: SpeedX 3D, Doodle Jump, aTilt 3D Labyrinth Free). Ezek mind úgy működnek, mint a mi egyszerű Guruló golyó játékunk. A különbség csak annyi, hogy a kiolvasott értékeket máshogy használják fel. Ha az alapok megvannak, akkor már csak egy jó ötlet kell, és ilyen népszerű játékok születhetnek nem túl sok munkával!
A komponenseket, mint amilyen az ImageView is, csak Android 3.0 (API 11) óta lehet kényelmesen forgatni és arrébb tologatni. Szerencsére majdnem mindenkinek ennél újabb készüléke van, de ha esetleg mégis egy régebbi (pl.: API 9 Gingerbread-et futtató) készüléken dolgoznál, van megoldás. Figyeld az utasításokat!
Ebben a leckében szakítunk az eddigi gyakorlattal, és Ti fogjátok előkészíteni a projektet! Nem kell megijedni, nem olyan nagy ördöngösség, csak oda kell figyelni pár dologra. Emlékeztetésként: a második leckében (Hellow World) is csináltatok már hasonlót!
File -> Close project
menüvel zárjuk be!A következő lépésben adjuk meg az alkalmazásunk alap adatait:
Application name: RollingBall
(Ez jelenik meg az ikon alatt a telefonon)
Felmerülhet a kérdés, hogy miért nem magyar nevet adunk a programunknak. Azért, mert itt a projekt létrehozásakor nagyon sok mindent a név alapján állít be az Android Studio, és mivel a "Guruló golyó" szóközt és ékezetet is tartalmaz, furcsa dolgok történhetnének. Sajnos az informatika mai gyakorlatainak megalapozásakor nem gondoltak a magyarhoz hasonló egzotikus nyelvekre :)
Később lesz lehetőség a feliratot átírni magyarra.
Company domain: android.dkrmg.hu
Mint a második leckében is írtuk, Java-s körökben az a szokás, hogy minden cég/szervezet a saját weboldalának címével azonosítja az általa írt kódokat. Mi a DKRMG-n belül az Android csoport vagyunk, így ez a képzeletbeli weboldalunk címe.
Project location:
Ebbe a könyvtárba fogja létrehozni a projektet az Android Studio.
Célszerű ott megadni egy könyvtárat, ahol a korábbi leckékhez tartozó projektek is vannak. pl.: C:\DkrmgAndroid\L07-RollingBall
vagy Win7 alatt gyakran: C:\Users\[felhasznalo]\AndroidStudioProjects\L07-RollingBall
.
Lépjünk tovább a következő oldalra.
Ezen az oldalon megadhatjuk, hogy milyen eszközökre szeretnénk fejleszteni.
Egyelőre maradjunk a Phone and Tablet
opciónál!
A "Minimum SDK" mező jelzi, hogy mi legyen a legrégebbi Android verzió, amire fel lehet majd telepíteni az appot.
FONTOS!!! Itt mindenképp (akkor is ha régebbi telefonod van) az API 19: Android 4.4 (KitKat)
legyen kiválasztva!
Ez azért szükséges, mert az Android Studio ebben ay esetben kicsit túlzottan is segítőkész, és ha alacsonyabb verziód adunk meg,
akkor mindenféle kiegészítő dolgokat is belerak a projektbe, ami egy komolyabb alkalmazásnál jó lehet,
de minket most csak zavarna!
Lépjünk tovább a következő oldalra.
Innentől ismerős lesz a folyamat, ugyanis most következik a kiinduló Acitivity hozzáadása.
Az előző leckéhez hasonlóan válasszuk a Empty Activity
lehetőséget; a következő oldalon pedig
a neve legyen GolyoActivity
.
Végül kattintsunk a Finish
gombra!
Némi gondolkodás után (ami számítógéptől függően sajnos akár pár percig is eltarthat) el is készült az új projektünk! Még annyi dolgunk van, hogy visszaállítsuk a Minimum SDK verziót a telefonunknak megfelelően. Ellenkező esetben az SDK 19-nél régebbi telefonokon nem indulna el az alkalmazásunk.
Győződjünk meg arról, hogy bal oldalt a projektünk fájlai Android
nézetben láthatóak.
Bal oldalt nyissuk meg a Gradle Scripts -> build.gradle (app)
fájlt.
Ebben keressük meg a minSdkVersion 21
sort és írjuk át a számot:
Android 2.3.3 Gingerbread
-es telefonunk van, akkor 10
-re11
-re.Ha a kedves kis Android ikonon kívül más képeket is szeretnénk használni az Android projektünkben, akkor a képfájlokat előbb elérhetővé kell tennünk az Android rendszer számára.
Ehhez a képfájlokat be kell másolnunk az Android Studio projektünkbe, hogy aztán az Android Studio bepakolhassa őket az alkalmazásba és elküldje a telefonnak is.
Ahhoz, hogy az Android Studio megtalálja a képfájlodat, először is keresd meg a Windows fájlkezelővel az app\src\main\res
mappát a projekteden belül.
(Ezt úgy is megteheted, hogy az Android Studioban a res
mappára rákattintasz jobb gombbal, majd kiválasztod a Show in Explorer
menüpontot)
Készíts a res mappában egy új mappát drawable néven, és másold bele ezt a képet!
Ezzel pedig elérhetővé vált a golyó képe a programod számára. Mostantól kezdve a fájl nevével (R.drawable.ball
) tudsz hivatkozni rá (pl. megjeleníteni)
Amikor saját képet másolsz be a projektbe, vigyázz, hogy a fájl neve csak
az angol abc kisbetűit és a _
karaktert tartalmazhatja.
Nagybetűk és ékezetek nem megengedettek.
Valamint az is fontos, hogy a drawable mappába kerüljenek a képek, különben nem lesznek elérhetőek!
Pl. egy jó fájl: drawable/ez_egy_kep.png
Ha most futtatod az alkalmazásodat, akkor bizonyára észreveszed, hogy a telefon elforgatásakor a kijelzően az applikáció ablaka mindnent megtesz azért, hogy továbbra is a jó irányba forduljon.
Ez a viselkedés sokszor hasznos, azonban (mint remélhetőleg emlékeztek rá), minden elfordításnál egy pillanatig leáll az alkalmazásunk (onPause
), majd újraindul (onResume
).
Tehát az automatikus elforgatás egy olyan játéknál, ami a képernyő elforgatására épül, komoly gondokat okozhat.
Szerencsére az alkalmazásunk tulajdonságaiban meghatározhatjuk azt, hogy szeretnénk-e élni az automatikus elforgatás lehetőségével.
Ennek a beállításához nyisd meg bal oldalt az app -> manifests -> AndroidManifest.xml
fájlt!
Ez az Xml fájl tartalmazza az applikációnk néhány fontos beállítását.
Nem szeretnénk részletekbe bocsátkozni a manifeszt fájllal kapcsolatban (bár az érdeklődőbbek
megnézhetik az android:icon
vagy épp az android:label
tulajdonságokat is)
Készíts egy új sort az activity
pont tulajdonságain belül (pl. android:name=".GolyoActivity"
alá),
és másold be az alábbi szöveget. Figyelj, hogy a záró >
elé írd be!
android:screenOrientation="portrait"
portrait
nézethez; és köszönjük, de nem szeretnénk, hogy minket bárki is elforgasson.
layout szerkesztő
A felhasználói felületünk igen egyszerű, és nagyban hasonlít az előző leckében használtakhoz. A következőket kell tenned (ha bizonytalan vagy, ott a gyorssegély, vagy vissza is olvashatsz egy kicsit a korábbi leckékben)
ImageView
komponenst a telefon kijelzőjére. Az ImageView
legyen A bal felső sarokban.
ImageView
-nak egy id tulajdonságot is. Mondjuk golyo
layout:centerInParent
tualjdonság legyen üres. Ellenkező esetben a golyó nem fog rendesen mozogni.ball
képnek. Ezt válaszd is ki!
root
.
background
) feketére. Némely telefonnál ez az alapértelmezett szín, de menjünk inkább biztosra.
Ezt (emlékeztetésként) vagy úgy tudod megtenni, hogy beírod a fekete szín kódját (#ff000000
),
vagy a sor végén lévő […] gombra kattintasz, majd a Colour fülön kiválasztod a tetszőleges színt. .
RelativeLayout
a teljes képernyőt kihasználja, és nincsen semmilyen belső margó beállítva.
Ehhez állítsuk a padding
tulajdonságot üresre (vagy mindenhol 0
-ra).
Az Android Studio újabb verzióiban előfordulhat, hogy hiába futtatod a programot, a kép valamiért nem jelenik meg a képernyőn. Esetlegesen még egy hibaüzenet is fogadhat:
Error:(13) No resource identifier found for attribute 'srcCompat' in package 'hu.dkrmg.android.rollingball'
A hiba áthidalásához sajnos egy kicsit bele kell másznunk a layout fájl szöveges verziójába.
Text
nézetet.ImageView
pont alá tartozó app:srcCompat="@drawable/ball"
sort, és írd át
erre: app:src="@drawable/ball"
Érdemes most még az elején létrehozni az ImageView típusú változónkat (az onCreate fölött!), és hozzárendelni a valódi képhez. Ezt javasolnánk, hogy az onCreate függvényben tedd meg a findViewById segítségével. Így a program indulásakor már túl is essünk a munka ezen részén.
Javaslatunk az, hogy legyen az ImageView
változónk neve golyoKep
(mivel ez a kép mutatja magát az golyót).
Ezen kívül a golyó mozgatása során szeretnénk a háttér (root
) szélességére is hivatkozni. Ezért érdemes a hátteret még most elmenteni egy változóba.
Készítsünk egy RelativeLayout
típusú változót is a program elején. A neve lehet root
. Ne felejtsd el ehhez a változóhoz is hozzárendelni a megfelelő értéket
az onCreate
függvényben!
Az Android Studio megint segíteni szeretett vonlna, ezért beleírt két függvényt a GolyoActivity
fájlba (onCreateOptionsMenu
és onOptionsItemSelected
). Ezek a menü kezelésére szolgálnak, de mi nem fogjuk használni őket.
Ha zavarnak, nyugodtan töröld ki őket, de ekkor nagyon figyelj, hogy minden részét töröld
(@Override
-al kezdődik, és a vele egy oszlopban lévő }
jellel végződik)!!! Ha inkább benne hagynád, akkor sem történik semmi.
TYPE_ACCELEROMETER
)Ez a rész egy az egyben megegyezik az előző két leckének az idevágó feladatával, a szenzor típusától eltekintve. Javasoljuk, hogy lapozz vissza az ötödik leckére, ha bizonytalan vagy. Különben pedig itt a Gyorssegély is.
public class GolyoActivity…
sor megfelelő pontjára az implements SensorEventListener szavakat. Így jelezve, hogy képes az Activitynk üzeneteket fogadni.
SensorManager
típusú változót (a neve lehet sensorManager
kisbetűvel), és rendeld hozzá a rendszer szenzor managerét.
Ezt az onCreate
függvényben tettük meg a getSystemService(SENSOR_SERVICE) függvénnyel.
A hozzárendelés teljes parancsa szerepelt már a korábbi leckében is:
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
onResume
függvényt (az Android Studio segít, ha elkezded beírni)getDefaultSensor
és a regesiterListener
függvényeket.
Csak annyi a dolgod, hogy átírod a TYPE_PROXIMITY
-t TYPE_ACCELEROMETER
-re.
Ezzel máris a gyorsulásmérő szenzorra iratkozunk fel.
Tényleg megnézted az előző leckéket?! Most még itt megadjuk a megoldást, de ezt a két sort vésd a fejedbe!
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
Ne felejts el leiratkozni sem az üzenetekről az onPause
függvényben! Ehhez először meg kell
írnod az onPause
függvényt (az Android Studio segít).
sensorManager.unregisterListener(this);
Kész is! Ha elakadtál, vagy nem vagy benne biztos, hogy jól csináltad-e,
akkor hasonlítsd össze az előző lecke megoldásával. Ne feledd, ezen a ponton az
onSensorChanged
függvényed még üres (a két kapcsos zárójel között nincs semmi).
Futtasd le a programodat! De honnan tudod, hogy működik-e?
Akik megcsinálták a negyedik lecke Logging szorgalmiját, azok remélhetőleg itt felhasználják a tudásukat. Ha te nem vagy ennek a szorgalmas társaságnak a tagja, akkor olvass tovább!
Az eddigi leckék során találkoztunk már egyszerű/primitív típusokkal (int, long, float), amelyek csupán egy értéket tárolnak. Illetve kissé felszínesen megismerkedtünk az összetettebb osztályokkal is (pl Button, SensorManager, Activity...), melyek egy rakás érdekes belső tulajdonsággal és belső függvénnyel rendelkeznek.
A mai napon pedig bemutatjuk az egyik legfontosabb adatszerkezetet: a tömböt.
A tömb képes több azonos típusú változót tárolni. A tömb elemei a sorszámuk alapján érhetőek el, értékük bármikor változtatható.
Például ha van egy t
nevű tömbünk, akkor az elemei:t[0]
, t[86]
, t[242]
, stb.
Ez eddig nagyban hasonlít a Pascal/Lazarus tömbjeihez. Fontos azonban megjegyeznünk, hogy a fenti nyelvektől eltérően a Java 0-tól indexeli a tömbjeit.
Ez azt jelenti, hogy az első elem a tömbben a t[0], a második a t[1], harmadik a t[2] és így tovább.
Tehát ha van egy 10 elemű tömbünk, akkor annak elemei: t[0]
, t[1]
, t[2]
, … , t[7]
, t[8]
, t[9]
.
Az összes többi változóhoz hasonlóan a tömbünket is deklarálni kell valahol.
Itt adjuk meg a változó nevét és a típusát. Ezt pedig úgy tehetjük meg, hogy a típus után illesztjük a []
jeleket.
Pl. egy tömb, amelynek minden eleme int típusú
int[] szamokatTartalmazoTomb;
Egy másik tömb, melynek minden eleme a Button osztályba tartozik
Button[] gombok;
Egy létező tömbnek így nyerhetjük ki a harmadik elemét:
int harmadikElem = szamokatTartalmazoTomb[2];
De hozzá is rendelhetünk új értéket valamelyik elemhez. Pl.
gombok[1] = findViewById(R.id.button);
ha egy teljesen új tömböt szeretnénk használni, akkor azt nem elég deklarálni, létre is kell hoznunk első használat előtt (pl. az onCreate
függvényben).
Ilyenkor kell megadnunk a tömb hosszát is, azaz hogy összesen hány elemet tárol. Pl. a szamokatTartalmazoTomb
tömb inicializálása úgy, hogy 100 elemet tartalmazzon (0.. 99).
szamokatTartalmazoTomb = new int[100];
Amikor egy függvény paramétereként kapjuk a tömböt, erre a fenti parancsra nincs szükség, hiszen a tömbünket (remélhetőleg) az Android rendszer már inicializálta / létrehozta és feltöltötte hasznos adatokkal.
A golyó mozgatását első megközelítésben nagyon egyszerűen fogjuk megoldani:
Amikor érkezik egy új mérés a telefon gyorsulásmérőjéről, annyiszor arrébb toljuk a golyót mutató képet a megfelelő irányba.
Természetesen a golyó nem tud kilépni a telefon síkjából, így csak két tengely (x,y) mentén mozgunk. A golyót a gyorsulásmérő által mért értékkel fogjuk arréb tolni. Ez a megoldásunk fizikailag nem teljesen helyes (gyorsulás nem egyenlő sebesség, lásd szorgalmik), de egy ilyen egyszerű programnál megengedhetünk magunknak ennyi csalást.
A golyó mindenkori pozícióját két int
típusú változóban fogjuk tárolni (xPos
, yPos
). Amikor új mérés érkezik, akkor
ezeknek a változóknak az értékét frissítjük, majd beállítjuk, hogy az ImageView
komponensünk is a megfelelő helyen legyen.
Hozz létre két int
típusú változót (xPos
és yPos
) az osztályod elején. Az onCreate
függvényedben adj értéket mind a két változódnak.
A golyó eleinte a bal felső sarokban van, így xPos = 0;
és yPos = 0;
.
A tömbökkel kapcsolatos új tudás birtokában talán nem túl meglepő ha itt megállapítjuk:
az event.values változónk float[]
típusú, tehát egy olyan tömb, melynek minden eleme float
típusú. (event.values
változóval az onSensorEvent
függvényben találkoztunk).
Gondoljunk vissza a korábbi leckékre, ahol az event.value[0]
kifejezést használtuk. Hiszen ezzel valójában az event.values
tömb első elemét nyertük ki, nem?
Most nézzük meg, hogy a gyorsulásmérő mit is küld nekünk pontosan az event.values tömbben:
[0]: első elem | [1]: második elem | [2]: harmadik elem |
---|---|---|
gyorsulás az x tengely mentén | gyorsulás az y tengely mentén | gyorsulás a z tengely mentén |
A képről is láthatjuk, hogy a harmadik érték (z tengely) számunkra haszontalan, hiszen a telefonunk (3D-s kijelző híján) nem tudja kiemelni a golyót a saját síkjából. Viszont a másik két értéket használni tudjuk!
Az onSensorEvent
függvényben hozzunk létre két float típusú változót (xGyorsulas
, yGyorsulas
.
Majd rendeljük hozzá a változónkhoz a megfelelő értéket az event.values
tömbből.
Az új pozíció kiszámítása az egyszerűsített modellünkben elég egyszerű. Mint említettük, egy kis csalással azt feltételezzük, hogy az új pozíció nem más, mint a régi pozíció + a mért gyorsulás.
Tehát például:
float ujX = xPos + xGyorsulas;
Hasonlóan írd meg az ujY változót is!
Ha kiszámítottuk az új pozíciót, akkor frissítsük erre az xPos
és az yPos
változó értékét.
Óvatosnak kell lennünk, hiszen az xPos
és yPos
változóink egész számokat tartalmaznak (int
), míg ujX
és ujY
változónk float
típusúak.
Tehát könnyedén lehet, hogy a tartalmuk nem egész szám. Az értékadás közben emiatt kerekítenünk is kell egyet! Ezt szerencsére az Android segítségével könnyen megtehetjük.
xPos = Math.round(ujX);
Ez alapján írd meg az yPos értékadását is!
A negyedik szorgalmiban megnézzük, hogy ez a modell fizikailag miért nem helyes, és hogyan lehetne javítani.
Ha a telefonunk Android 3.0 (API 11), vagy annál újabb rendszert futtat, akkor nagyon egyszerűen megadhatjuk az ImageView
komponenseink helyét.
Annyit kell csak tennünk, hogy meghívjuk az ImageView
setX
és setY
függvényeit az x és y ko-ordináta megadásához.
Tehát például ha például ha azt akarjuk elérni, hogy a golyó a bal felső sarokban legyen (kezdéskor remélhetőleg már ott van), akkor az alábbi két parancsot használjuk:
golyoKep.setX(0); // vizszintes
golyoKep.setY(0); // fuggoleges
Ha esetleg egy kicsit öregebb telefonod lenne, akkor se csüggedj. Van mód a képek áthelyezésére így is, bár kicsit bonyolultabb. Hogy ne érjen hátrány ebben a leckében, így írtunk neked egy segédfüggvényt, ami elvégzi helyetted a piszkos munkát.
ImageViewHelper.setImageViewPosition(imageViewValtozo, xErtek, yErtek);
(Ez a függvény egy általunk írt osztályban található. Mivel ebben a leckében saját projektet használtok, ezért ezt a java fájlt le kell töltenetek, és be kell másolnotok a MainActivity.java fájl mellé.)
Most írd meg azt a két parancsot az onSensorEvent
függvényben, ami a golyoKep változónkat nem az origóra, hanem az (xPos
;yPos
) pontra helyezi!
Futtasd a programot, és nézd meg, hogy működik-e. Előfordulhat, hogy a golyó a várttal ellentétes irányba indul el (x irányban). Ezt a hibát remélhetőleg könnyedén tudod javítani az előző lecke után ( +
helyett -
).
Ne feledd, a golyó ilyenkor még könnyedén kiléphet a telefon kijelzőjéről. Ezt az első szorgalmiban fogjuk orvosolni. Javasoljuk, hogy mindenki nézze ezt meg
Ha esetleg úgy érzed, hogy a golyó nem mozog elég gyorsan, akkor próbáld az xGyorsulas változót megszorozni mondjuk 3-al. pl.:
float ujY = yPos+ yGyorsulas * 3;
Ha végeztél és minden működik, töltsd fel a projektedet tömörített (pl zip) formátumban a szakkör feltöltő oldalán keresztül!
Bizonyára észrevetted, hogy amikor a golyó eléri a képernyő szélét, akkor egyszerűen tovább gurul. Mi persze azt szeretnénk, hogy a golyó soha ne kerüljön le a képernyőről. Ehhez nem kell mást tennünk, mint hogy elvégzünk néhány ellenőrzést az ujX és az ujY változóinkon, még mielőtt naívan felhasználjuk őke
Tehát mire kell vigyáznunk?
ujX
változó nem lehet kisebb, mint 0.ujY
változó sem lehet kisebb, mint 0ujX
változó nem lehet nagyobb, mint a képernyő szélessége mínusz a golyoKep
ImageView
szélességeujY
változó nem lehet nagyobb, mint a képernyő magassága mínusz a golyoKep
ImageView
magasságaHogyan tudjuk ezt leprogramozni? A legegyszerűbb, ha az ujX
, ujY
változók értékadása után
(de még az előtt, hogy az értékeiket tovább adnánk kerekítéssel a posX
és posY
változóknak),
írunk 4 if
-elágazást az alábbi formában
HA (ujX túl kicsi) {
ujX = 0;
}
pl.:
if (ujX < 0) {
ujX = 0;
}
A golyoKep méreteit a golyoKep.getWidth()
és golyoKep.getHeight()
függvényekkel lehet lekérdezni:
if (ujX > root.getWidth() - golyoKep.getWidth())
{
ujX = root.getWidth() - golyoKep.getWidth();
}
Most már a golyó nem fog eltűnni a képernyő bal és jobb oldalán.
A képernyő magassága ehhez hasonlóan megkapható a root.getHeight()
függvénnyel. Ez alapján írjál még két elágazást, ami eléri, hogy a golyó ne tűnjön el a képernyő alján és tetején sem!
Közeledik a karácsony (a leckék írásakor legalábbis december eleje van már). Cseréld le a golyót valami karácsonyi hangulatúra!
Ehhez:
res\drawable
mappába (pl. karácsonyi gömb). Ne feledd, a kép neve csak az angol abc kisbetűit és a _
karaktert tartalmazhatjalayout szerkesztőben
az ImageView
képed src
tulajdonságát. Emlékeztetésként, ez a tulajdonság határozza meg, hogy milyen kép jelenjen meg.100
ms)
Ehhez az alábbiakat kell tenned:
A hozzárendelés teljes parancsa szerepelt már a korábbi leckében is:
rezgoMotor = (Vibrator) getSystemService(VIBRATOR_SERVICE);
Fontos!!! Ha most elindítod a programodat, akkor a rezgés még nem fog működni. Az Android rendszer ugyanis bizonyos erőforrásokhoz (pl. rezgő motor) csak olyan alkalmazásoknak hajlandó hozzáférést biztosítani, akik előre engedélyt kértek.
Ha telepítettél már Android programokat a telefonodra, akkor minden bizonnyal találkoztál már egy olyan a dialógussal, ami kiírja, hogy "az alkalmazás az alábbi erőforrásokhoz kér hozzáférést:".
A rezgő motor is egy ilyen védett erőforrás, ezért az alkalmazásunknak a manifeszt fájlban jeleznie kell, hogy használni szeretné.
app -> manifests -> AndroidManifest.xml
application
pont fölé szúrd be az alábbi elemet:
<uses-permission android:name="android.permission.VIBRATE"/>
Most már futtathatod az alkalmazást. Ezzel az egy sorral jelezted az Android rendszernek, hogy a programod szeretné a rezgő motort (a korábbi leckékben ezt a sort mi beleírtuk az előkészített projektekbe).
Számos fizikatanár kapna szívrohamot, ha meglátná azt a módszert, amivel a golyót egészen idáig mozgattuk. A helyes képlet természetesen azt mondja ki, hogy az elmozdulás (megtett út) egyenlő a sebesség és az eltelt idő szorzatával. A sebesség pedig egyenlő a gyorsulás és az eltelt idő szorzatával.
Az ehhez hasonló (ún. diszkrét) szimulációknál ezért inkább az alábbi képleteket használjuk (delta (Δ) a változást jelenti. pl. sebesség változása):
Tehát nem elég csak a pozíciónkat tárolni! Szükség lesz két új változóra (vX
és vY
), ami tárolja a golyó x és y irányú sebességét. Ezek a változók legyenek float
típusúak.
A sebesség változók kezdeti értéke legyen 0.
Ahhoz, hogy kiszámoljuk a sebesség változását, előbb meg kell tudnunk, hogy mennyi idő telt el a golyó utolsó mozgatása óta (Δt). Ehhez pedig szükség lesz még egy változóra, ami rögzíti, hogy
mikor mozgattuk utoljára a golyót. A neve mondjuk legyen ido
, a típusa pedig long
.
A rendszertől lekérdezhetjük a jelenlegi időt. Ehhez felhasználhatod a System.currentTimeMillis()
függvény visszatérési értékét,
ami egy long típusú egész szám, és a UNIX Epoch, azaz 1970. jan. 01. óta eltelt milliszekundumok számát tartalmazza.
Az onSensorChanged
függvény végén frissíted az ido
változódat a System.currentTimeMillis();
értékére.
Az eltelt időt a függvényed elején kiszámíthatod az alábbi képlettel:
float dt = (System.currentTimeMillis() - ido) / 1000.0f;
Ne felejtsd el az ido
változó kezdeti értékét is megadni. Ezt az onCreate
függvényben teheted meg.
Ha a végeredménynél a golyó túl gyorsan vagy túl lassan mozog, az nem nagy gond. Nem a fizika törvényei csaltak meg, csak a képernyő működik más mértékegységekkel, mint a telefon érzékelője. Nyugodtan megszorozhatod egy állandóval (pl. 30)
Ütközésnél ne felejtsd el lenullázni a golyó sebességét, különben érdekes dolgok történhetnek. Ha ennél látványosabb ütközéseket is szeretnél látni, akkor nézd meg az utolsó szorgalmit is.
Főként a fizikát kedvelőknek javasoljuk, hogy vizsgálják meg, mi történik, ha az álló telefont hirtelen megmozdítjuk. Hogyan reagál a golyó? Mi a helyzet akkor, ha az egyenletesen mozgó telefont hirtelen megállítjuk? Mit csinál ilyenkor a golyó? Milyen magyarázatot tudsz adni minderre?
Jelenleg a golyó, amikor eléri a képernyő szélét, egyszerűen megáll. Bizonyára azonban a való életben tapasztalhattátok, hogy a falnak lökött golyók és labdák egyáltalán nem így viselkednek! Az elmozdíthatatlan fal és a kemény fémgolyó ütközésekor a golyónak legalább egy kicsit vissza kéne pattannia!
Az ütközésre vonatkozó szabályok szerencsére elég egyszerűek (bár fizikailag ezek sem tökéletesek, de egy Android programnál már így is nagyon jól néznek ki
x=0
-nál ütközik, akkor az vízszintes irányú sebessége tükröződik (vX = -vX;
). A függőleges irányú sebessége változatlan maradujX
változót így is 0-ra kell állítanunk.A valódi életben az ütközéskor valamennyit veszítene a golyó a sebességéből. Az elveszített energia mértéke pedig sokban függene a golyó anyagától. Gondolj bele: amikor egy kosárlabdát elengedsz, akkor majdnem az ugyanolyan magasra visszajön (de csak majdnem). Egy fémgolyó is pattan, de kisebbet
Próbáld meg ezt úgy szimulálni, hogy ütközéskor megszorzod a sebességet (mind a két irányban) egy állandóval. Például 0.35
-el. Minél nagyobb az érték, annál nagyobbat pattan a golyó!