Android OpenGL Animace a ovládání pomocí dotykové obrazovky
Principy animace • Animace udává pohyb objektů v čase • Může být reprezentována mnoha způsoby • Procedurální – Pozice objektů se počítá přímo v programu
• Keyframe – Animace je uložená jako data (klíčové snímky pozic objektů v čase) – Program potom pozice jen interpoluje
• Další možnosti animace
Principy animace • Pro účely animace je nutné mít přesnou časomíru – Nemusí se jednat o absolutní čas a datum – Důležité je rozlišení (méně než milisekundy)
Třída Timer • Obsahuje jen dvě metody • Reset() – Nastaví čas na nulu
• f_Time() – Vrátí čas od vytvoření časovače nebo od Reset()
Třída Timer • Implementace na všech platformách podobná • Obsahuje čas a poslední časovou značku protected double time = 0; protected long lastStamp;
• Časová značka se získá pomocí lastStamp = System.nanoTime nanoTime(); nanoTime
Třída Timer • Při volání f_Time() – přečte se další časová značka long newStamp = System.nanoTime nanoTime(); nanoTime
– spočte se uplynulý čas od poslední značky long delta; if(newStamp >= lastStamp) delta = newStamp - lastStamp; else { delta = (Long.MAX_VALUE - lastStamp) + (newStamp - Long.MIN_VALUE); // přetečení! }
Třída Timer • Při volání f_Time() – uplynulý čas se připočte k času time += delta * 1e-9;
– poslední časová značka se přepíše aktuální lastStamp = newStamp;
Třída Timer • Pro každý snímek by se měl určovat čas pouze jednou – V průběhu kreslení snímku se čas může změnit a mohlo by dojít k viditelnému oddělení objektů jež se měly pohybovat spolu – Toto je obzvlášť rušivé protože rozdíl mezi časy je na pomezí přesnosti časovače a zpravidla mezi snímky kolísá
Jednoduchá animace
Jednoduchá animace • Musíme upravit výpočet matice objektu Matrix.setIdentityM setIdentityM(modelview, 0); setIdentityM Matrix.translateM translateM(modelview, 0, 0, 0, -2.5f); translateM // nastavení pozice objektu Matrix.rotateM rotateM(modelview, 0, 30, 1, 0, 0); rotateM 0, 10, 0, 1, 0); Matrix.rotateM rotateM(modelview, rotateM // počáteční rotace Matrix.rotateM rotateM(modelview, 0, timer.f_Time() * 10, 0, 1, 0); rotateM // + součin úhlové rychlosti a času
Dotyková obrazovka • V mobilních aplikacích je často vyžadována interakce uživatele • Lze přitom využít stejné principy jako při animaci pohybu objektů v čase – Jen čas nahradíme pohybem prstu po dotykové obrazovce
Dotyková obrazovka • Na platformě android pomocí třídy OnTouchListener • Chceme se dotýkat přímo obrazu, voláme mGLView.setOnTouchListener setOnTouchListener(listener); setOnTouchListener
• Potom musíme implementovat třídu, jejíž objektem je právě listener
OnTouchListener • Třída s jedinou metodou public boolean onTouch(View onTouch view, MotionEvent event)
• objekt event obsahuje zajímavé metody • getAction() – typ akce: ACTION_DOWN, ACTION_MOVE a ACTION_UP (stlačení, pohyb, uvolnění)
• getX(), getY() – Souřadnice středu prstu, v pixelech
OnTouchListener • Událost MotionEvent typu ACTION_MOVE může obsahovat více než jeden bod pohybu (pohyb je snímán na vysoké frekvenci) – getX() a getY() vracejí poslední souřadnice, pro animaci postačující
• Sled událostí stlačení, pohyb, uvolnění nemusí být nutně zachován, aplikace s tím musí počítat
Rotace objektu dotykem • Postačí sledovat pozici dotyku a akumulovat rozdíly v pohybu float mX = 0, mY = 0; // poslední hodnoty pozice (v pixelech) float mDeltaX = 0, mDeltaY = 0; // akumulované změny
Rotace objektu dotykem public boolean onTouch(View view, MotionEvent event) onTouch { if(event.getAction() == MotionEvent.ACTION_DOWN) { mX = event.getX(); mY = event.getY(); // uložení pozice dotyku } else if(event.getAction() == MotionEvent.ACTION_MOVE) { float newX = event.getX(); float newY = event.getY(); // pohyb na novou pozici mDeltaX += newX - mX; mDeltaY += newY - mY; // spočítáme rozdíl a akumulujeme mX = newX; mY = newY; // zapamatujeme si novou pozici } return true; }
Rotace objektu dotykem • Proměnné mDeltaX a mDeltaY lze použít přímo jako úhly na jednotlivých osách, případně jako argument funkce jež tyto úhly určí • Při derivaci změn v čase lze jednoduše spočítat i setrvačnost rotace i poté co uživatel uvolnil dotyk, takže ovládaný pohyb se nezastaví najednou ale pozvolna – Lze použít diferenci a klouzavý průměr
Konec