The plate can be controlled using one of the following input methods, each of which offers a slightly different feel to the plate:
Keys
Touch
Tilting the device (accelerometer sensor)
When keys are used, the plate moves with constant velocity without any kind of easing. The left and right buttons are mapped to the game keys, so, depending on the keys available on the device, the plate is controlled with either the navigation keys or the number keys 4 and 6. The ball is launched with either the selection key or number key 5.
Touch input is implemented using Canvas pointer events. When a pointerPressed or pointerDragged event occurs, the x coordinate is set as the target destination for the plate. In each update cycle, while the pointer is pressed, the plate moves closer to this destination coordinate. This approach works best on resistive touch screens, since the screen can be operated with two fingers and the amount of pressure applied to the screen affects the position of the actual touch point.
The Series 40 full touch version of the MIDlet additionally implements plate control by tilting: tilting the device left or right moves the plate to the direction of the tilt. Plate movements are calculated based on data provided by the accelerometer sensor, which is accessed through the Mobile Sensor API. In every update cycle, the velocity of the plate is calculated based on the update interval and current acceleration. If the velocity is less than one pixel per update cycle, the velocity is accumulated for later updates. This ensures at least some movement, even if the acceleration is very small. Acceleration is measured in m/s^2, so the value must be converted to suite the current screen resolution by using the proper factor, which depends on the screen width.
The following code snippet shows how to move the plate based on x-axis acceleration (and target destination set by touch).
private double aX = 0; private double vX = 0; // ... private Plate plate; // ... /** * Moves plate towards set destination or according to acceleration sensors */ public void movePlate() { if (pointerPressed) { int distance = plate.getRefPixelX() - pointerX; if (distance > 0 && plate.getLeftX() > 0 || distance < 0 && plate.getRightX() < gameWidth) { distance *= 0.94; // Shorten the distance with easing } plate.setRefPixelPosition(pointerX + distance, plate.getRefPixelY()); if (distance == 0) { stopMovement(); } } else if (accelerationProvider != null) { // Calculate velocity according to acceleration on x-axis and convert vX -= gameWidth * aX * ExplonoidCanvas.INTERVAL / 5000; if (Math.abs(vX) > 1) { if (vX < 0 && plate.getLeftX() > 0 || vX > 0 && plate.getRightX() < gameWidth) { if (plate.getLeftX() + vX < 0) { vX = -plate.getLeftX(); } else if (plate.getRightX() + vX > gameWidth) { vX = gameWidth - plate.getRightX(); } plate.move((int) vX, 0); } vX = 0.0; } } }
To receive sensor data, the MIDlet must establish a connection to the sensor and register a data listener for it. The MIDlet must also implement a handler for the received data. The following code snippet shows how to create a connection to the accelerometer sensor and handle the received data.
private SensorConnection sensor; private int dataType; // ... private void initConnection() throws IOException { SensorInfo infos[] = SensorManager.findSensors("acceleration", null); if (infos.length > 0) { dataType = infos[0].getChannelInfos()[0].getDataType(); try { sensor = (SensorConnection) Connector.open(infos[0].getUrl()); sensor.setDataListener(this, 1); } catch (SecurityException se) { throw new IOException("could not open sensor"); } catch (IOException ioe) { throw new IOException("could not open sensor"); } catch (IllegalArgumentException iae) { throw new IOException("could not open sensor"); } } else { throw new IOException("acceleration sensor not found"); } } // ... public void dataReceived(SensorConnection sc, Data[] data, boolean isDataLost) { switch (dataType) { case ChannelInfo.TYPE_DOUBLE: dataReceived(ArrayUtils.getLast(data[0].getDoubleValues()), ArrayUtils.getLast(data[1].getDoubleValues()), ArrayUtils.getLast(data[2].getDoubleValues())); break; default: break; } }
To ensure that the MIDlet remains backwards-compatible with devices that do not support the Mobile Sensor API, the use of the API is isolated from the rest of the MIDlet. For more information about this design approach, see article How to use an optional API in Java ME in the Nokia Developer Wiki.