As a base device I used SonyEricsson W910i which supports JSR256 quite well. Very first thing I had to do was enabling and implementing entire sensor related functionality.
I moved entire sensor implementation to the separated class which is called Accelerometer. This is how it looks:
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.microedition.sensor.*;
public class Accelerometer implements DataListener {
public int m_accX, m_accY;
private SensorConnection m_conn = null;
public SensorInfo m_sensorInfo;
public static final String STR_QUANTITY = "acceleration";
private int m_sensitivity;
private int m_samples;
public int m_delta;
public static int THRESHOLD = 50;
public Accelerometer(int samples, int sensitivity) {
m_sensitivity = sensitivity;
m_samples = samples;
m_delta = 1000 / sensitivity;
}
public boolean init() {
SensorInfo[] info = SensorManager.findSensors(
STR_QUANTITY, SensorInfo.CONTEXT_TYPE_USER);
if (info != null && info.length > 0) {
m_sensorInfo = info[ 0];
return true;
} else {
return false;
}
}
public void connect(boolean useListener) {
try {
if (m_conn == null) {
m_conn = (SensorConnection) Connector.open(m_sensorInfo.getUrl());
if (useListener) {
m_conn.setDataListener(this, m_samples);
}
}
} catch (Exception e) {
}
}
public void disconnect() {
try {
m_conn.close();
m_conn.removeDataListener();
m_conn = null;
} catch (Exception e) {
}
}
int getValueX() {
return m_accX / m_delta;
}
int getValueY() {
return m_accY / m_delta;
}
public void update() {
try {
Data[] data = m_conn.getData(1);
m_accX = data[0].getIntValues()[0];
m_accY = data[1].getIntValues()[0];
} catch (IOException ex) {
ex.printStackTrace();
}
}
/* dataReceived() is not optimized yet and contains some weird calcs */
public void dataReceived(SensorConnection connection, Data[] data, boolean b) {
int[] x = data[0].getIntValues();
int[] y = data[1].getIntValues();
m_accX = x[0];
m_accY = y[0];
int tmp = 0;
m_accX = (m_accX < 0) ? Math.max(-1000, m_accX) : Math.min(1000, m_accX);
m_accY = (m_accY < 0) ? Math.max(-1000, m_accY) : Math.min(1000, m_accY);
final int abs_accX = Math.abs( m_accX );
final int abs_accY = Math.abs( m_accY );
m_accX = ( tmp = abs_accX - THRESHOLD ) <= 0 ? 0 : tmp * ( m_accX / abs_accX );
m_accY = ( tmp = abs_accY - THRESHOLD ) <= 0 ? 0 : tmp * ( m_accY / abs_accY );
}
}
The class implements simple features:
- reading sensor asynchronously
- reading sensor synchronously
- sensor threshold
- sensor sensitivy
Game uses only asynchronous reading because it’s simply faster. Method dataReceived() processes all data provided by sensor. It’s not optimized at all but still it works fast. So I’ve left it as it is for now.
Since it’s possible to read the sensor, the game can use it and change into ball motion. This implies simple physics. Nothing special, just combining gravity and friction forces:
public void updatePositionBySensor() {
Accelerometer m_accControl = Context.m_acc;
float ax = ((m_accControl.getValueX() / 100.0f) * F_GRAVITY);
float ay = ((m_accControl.getValueY() / 100.0f) * F_GRAVITY);
l_vx += ax;
l_vy += ay;
l_vx -= (l_vx * CFRICTION);
l_vy -= (l_vy * CFRICTION);
if (Math.abs(l_vx) > MAX_SPEED) {
l_vx = MAX_SPEED * (l_vx / Math.abs(l_vx));
}
if (Math.abs(l_vy) > MAX_SPEED) {
l_vy = MAX_SPEED * (l_vy / Math.abs(l_vy));
}
float m_lastPosX = m_posX;
float m_lastPosY = m_posY;
m_posX -= l_vx;
m_posY += l_vy;
m_drawX = (int) m_posX;
m_drawY = (int) m_posY;
if (doVibraX || doVibraY) {
DeviceControl.startVibra( 80, 20 );
}
}
At the end of method you may notice a line containing startVibra(). The phone vibrates whenever ball hits any edge of screen. It makes nice illusion that ball weights and moreover it really feels like it hits specified edge. Method updatePositionBySensor() keeps maximum speed limited so the ball will never move too fast.
This is how the game looks:
No comments:
Post a Comment