Creating Asha Games: Game Pausing, Orientation, Sensors and Gestures
-
Upload
jussi-pohjolainen -
Category
Technology
-
view
473 -
download
1
Transcript of Creating Asha Games: Game Pausing, Orientation, Sensors and Gestures
Crea%ng Asha Games: Game Pausing, Device Orienta%on, Sensors, Gestures
Jussi Pohjolainen Tampere University of Applied Sciences
GAME PAUSING
About Game Pausing
• Pause game when – Phone rings – Back – buHon is pressed
• Remember that MIDlet's pauseApp – method is never called!
• In GameCanvas, implement following – public void showNotify() // resume – public void hideNotify() // pause
About Gameloop and Threading
• Gameloop is implemented using Threading – Thread thread = new Thread(Runnable x); – thread.start(); // calls run()
• Gameloop usually: – while(gameIsOn) { …. Thread.sleep(ticks); }
• How to pause the current thread in midp?
Synchroniza%on • Let's first look at synchroniza5on. • There might be a problem, if two threads accesses the same
data – Two people each have a ATM cards that are linked to only one account – What happens when these two people accesses the account at the
same %me?
• Withdrawal is two-‐step process – Check the balance – If there's enough money int the account, make the withdrawal
• What happens if 1 and 2 are separated?
Locks
• We must guarantee that the two steps are never split apart. Use synchronized keyword
• Synchroniza%on works with locks. Every object has a lock. If one thread has picked up the lock, no other thread can use the synchronized code.
Examples
• Let's look at some synchroniza%on examples – https://dl.dropboxusercontent.com/u/874087/game-programming/examples/threading/Synchronized1.java
• See also – Synchronized2.java -> Synchronized5.java
wait()
• Object class holds a method wait() – Causes the current thread to wait un%l another thread invokes the no%fy() method for this object
• So when calling wait() it pauses the current thread and waits that some other thread calls no%fy() or no%fyAll()!
// NOTICE! This example does not work, all exception handling and synchronized blocks
// are missing
class MyApp {
public static void main(String [] args) {
new MyApp();
}
public MyApp() {
MyThread mythread;
Thread thread = new Thread(mythread = new MyThread());
thread.start();
System.out.println("Sleeping");
Thread.sleep(2000);
// Resume from wait! Calls notify from the object that is in wait…
mythread.notify();
}
}
class MyThread implements Runnable {
public void run() {
// Let's wait until someone calls notify
wait();
System.out.println("Resumed!");
}
}
wait()
• When calling wait and no%fy, it must be inside synchronized block.
synchronized(this) { // Before calling notify, the thread calling this must // own a lock. notify(); } synchronized(this) { wait(); }
Game Pausing in MIDlet • In GameCanvas, following methods are called when phone rings.
// Phone rings public void hideNotify() { pause(); // pause game – my own method } // Phone ends public void showNotify() { resume(); // resume game – my own method }
pause() and resume() public void resume() {
isPause = false;
synchronized(this) { notify(); // Notify that waiting thread can
// continue. }
} public void pause() {
isPause = true; }
Game Loop public void run() {
int i = 0;
while(true) {
checkIfPause();
checkCollisions();
moveSprites();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void checkIfPause() {
synchronized(this) {
while(isPause) { // while, just in case
try {
wait(); // Wait in current thread
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Back BuHon to Game Canvas Command backCommand = new Command("Back", Command.BACK, 0); addCommand(backCommand); setCommandListener(this); // and the listener method public void commandAction(Command c, Displayable d) { if(isPause) { midlet.notifyDestroyed(); } else { pause(); } }
DEVICE ORIENTATION
Adjus%ng Device's Orienta%on
• MIDlets can use Orienta5on API to – Change their UI orienta%on – Determine their current UI orienta%on – Determine the current display orienta%on – Receive a no%fica%on whenever the display orienta%on changes
• When MIDlet changes it's UI orienta%on, it has to redraw the low-‐level components that it uses.
Supported Orienta%ons
• ORIENTATION_LANDSCAPE • ORIENTATION_LANDSCAPE_180 • ORIENTATION_PORTRAIT • ORIENTATION_PORTRAIT_180
Se^ng UI Orienta%on
• Add following to JAD file: – Nokia-MIDlet-App-Orientation: manual
• Now it supports both portrait and landscape modes
• Add orienta%on listener – Orientation.addOrientationListener(orientationListener);
Orienta%on Listener Callback /** Orientation listener callback */ public void displayOrientationChanged( int newDisplayOrientation ){
/** Check display orientation */
switch( newDisplayOrientation ){
case Orientation.ORIENTATION_PORTRAIT:
case Orientation.ORIENTATION_PORTRAIT_180:
/** Change MIDlet UI orientation to portrait */
Orientation.setAppOrientation(Orientation.ORIENTATION_PORTRAIT);
break;
case Orientation.ORIENTATION_LANDSCAPE:
case Orientation.ORIENTATION_LANDSCAPE_180:
/** Change MIDlet UI orientation to landscape */
Orientation.setAppOrientation(Orientation.ORIENTATION_LANDSCAPE);
break;
}
}
sizeChanged()
• When UI Orienta%on changes: /** Java platform will call this when UI orientation has been changed */
protected void sizeChanged( int w, int h ){
/** Acquiring new Graphics Object since old is not valid anymore */
g = getGraphics( );
canDraw = true;
}
MOBILE SENSOR API
Mobile Sensors
• Mobile Sensor API allows MIDlets to fetch data from the sensors of the mobile device
• Sensor consists of one or more channels, in accelerometer you will get data from three channels (x, y and z)
• Sensors have common proper%es: – accuracy – max and min value
Available Sensors in Asha 50X • Accelera5on sensor
– measures accelera%on in SI units for x, y and z -‐ axis.
• Orienta5on sensor – provides informa%on of devices current orienta%on posi%on.
• Rota5on sensor – provides informa%on of devices current rota%on degree.
• Double tapping sensor – provides informa%on of double taps occurred on the phone sides.
• Proximity sensor – indicates if an obstacle is right in front of it
• BaLery sensor – shows baHery charge level in percentage. Sensor is always on.
• Charger sensor – shows whether charger is connected. Sensor is always on.
• Signal strength sensor – shows strength of network connec%on in percentage. Sensor is always on.
Using Sensors
Finding and Iden%fying a Sensor // Find all sensors
SensorInfo[] sensorInfos =
SensorManager.findSensors(null, null);
for(int i=0; i<sensorInfos.length; i++) {
SensorInfo si = sensorInfos[i];
System.out.println(si.getUrl());
}
Finding and Iden%fying a Sensor // Sensor type (quantity):
// acceleration
// orientation
// rotation
// double_tap
// proximity
// battery_charge
// charger_state
// network_field_intensity
// null
String type = "acceleration";
// Sensor Context type
// ambient
// device
// user
// vehicle
// null
String contextType = "user";
// Fetch all sensors with given information, should find only one.
SensorInfo[] si = SensorManager.findSensors(type, contextType);
// Retrieve the sensor url.
String sensorURL = si[0].getUrl();
Opening a sensor connec%on {
try {
// This may not be a good idea, fetch the URL from sensorinfo using sensor quantity and
// context type
String sensorURL = "sensor:acceleration;contextType=user;model=Nokia;location=NoLoc";
// How fast data is sent to listener!
final int BUFFER_SIZE = 1;
SensorConnection sensorConnection = (SensorConnection)Connector.open(sensorURL);
// this = any object that implements DataListener
sensorConnection.setDataListener(this, BUFFER_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
}
// Datalistener interface method
public void dataReceived(SensorConnection sensor, Data[] data,
boolean isDataLost) {
System.out.println("Here!");
}
Case: Accelera%on listening public void dataReceived(SensorConnection sensor, Data[] data,
boolean isDataLost) { // We have three channels. System.out.println("Channel amount: " + data.length); // Channel is Data object Data x = data[0]; // Each channel may hold several values. In this case // only one. double [] values = x.getDoubleValues(); System.out.println("Number of values " + values.length); // And the value is: System.out.println("x = " + values[0]); // Let's fetch the rest (y and z) in just on line System.out.println("y = " + data[1].getDoubleValues()[0]); System.out.println("z = " + data[2].getDoubleValues()[0]);
}
Case: Accelera%on listening public void dataReceived(SensorConnection sensor, Data[] data,
boolean isDataLost) {
System.out.println("x = " + data[0].getDoubleValues()[0]);
System.out.println("y = " + data[1].getDoubleValues()[0]);
System.out.println("z = " + data[2].getDoubleValues()[0]);
}
Closing connec%on
• Remember to close the connec%on if not needed! – sensorConnection.close();
GESTURES API
Really Easy to Use // STEP 1: Defines a GestureInteractiveZone for the
// whole screen and all Gesture types.
GestureInteractiveZone giz = new GestureInteractiveZone( GestureInteractiveZone.GESTURE_ALL );
// STEP 2: Register the GestureInteractiveZones for the
// GameCanvas object this.
GestureRegistrationManager.register( this, giz );
// STEP 3: Set the listener, source is this gamecanvas
// and listener is this also
GestureRegistrationManager.setListener(this, this);
Listener public void gestureAction(Object container,
GestureInteractiveZone gestureInteractiveZone,
GestureEvent gestureEvent) {
switch(gestureEvent.getType()) {
case GestureInteractiveZone.GESTURE_TAP:
Debug.printInfo("MyGameCanvas", "gestureAction", "TAP", 2);
break;
...
case GestureInteractiveZone.GESTURE_LONG_PRESS:
Debug.printInfo("MyGameCanvas", "gestureAction", "LONG PRESS", 2);
break;
}
}
Listener public void gestureAction(Object container,
GestureInteractiveZone gestureInteractiveZone,
GestureEvent gestureEvent) {
switch(gestureEvent.getType()) {
...
case GestureInteractiveZone.GESTURE_FLICK:
Debug.printInfo("MyGameCanvas", "gestureAction", "FLICK", 2);
Debug.printInfo("MyGameCanvas", "gestureAction",
"flick speed = " + gestureEvent.getFlickSpeed(), 2);
Debug.printInfo("MyGameCanvas", "gestureAction",
"flick direction = " + gestureEvent.getFlickDirection(), 2);
break;
}
}