jsr256是感应器的api,现在手机中比较常见是中立感应Sensor,有了这个api之后,我们可以多了很多玩法,这次,我要用它来完成一个利用重力感应控制的小球。
开发环境:javaME Platform SDK3.0(Eclipse存在ClassDefNotFound错误,至今未解决。。。。)
四个java文件,
主midlet,画布,小球,辅助向量。下面是每个类得代码:
主midlet,主要用于控制游戏进度,接受传感器信息
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import javax.microedition.io.Connector;
import java.io.IOException;
import java.util.Vector;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.sensor.ChannelInfo;
import javax.microedition.sensor.Data;
import javax.microedition.sensor.DataListener;
import javax.microedition.sensor.SensorConnection;
import javax.microedition.sensor.SensorInfo;
import javax.microedition.sensor.SensorManager;
/**
* @author Administrator
*/
public class BallMidlet extends MIDlet implements DataListener{
private BallCanvas ballCanvas;
private SensorConnection sensor;
private String[] channelNames;
private boolean sensorSelected;
private SensorInfo[] sensorInfos;
public BallMidlet() throws IOException {
if (System.getProperty("microedition.sensor.version") == null) {
Display.getDisplay(this).setCurrent(
new Alert("JSR256 is not supported!"),
new TextBox("ERROR", "JSR256 is not supported!", 255, 0));
return;
// throw new IllegalArgumentException("JSR256 is not supported!");
}
ballCanvas = new BallCanvas();
sensorInfos = getSensorInfos();
System.out.println("sensorInfos.length: "+sensorInfos.length);
if (sensorInfos == null) {
Display.getDisplay(this).setCurrent(
new Alert("Valid accelerometer sensor not found"),
new TextBox("ERROR",
"Valid accelerometer sensor not found", 255, 0));
return;
}
new Thread() {
public void run() {
channelNames =
getSensorInfoChannelsNames(sensorInfos[0]);
try {
sensor =
(SensorConnection) Connector
.open(sensorInfos[0].getUrl());
ballCanvas.start();
sensor.setDataListener(BallMidlet.this, 1);
sensorSelected = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
private SensorInfo[] getSensorInfos() {
// Find all device accelerometers
SensorInfo[] sensorInfos = SensorManager.findSensors("acceleration", null);
Vector validInfos = new Vector();
for (int i = 0; i < sensorInfos.length; i++) {
if (getSensorInfoChannelsNames(sensorInfos[i]).length > 2) {
validInfos.addElement(sensorInfos[i]);
}
}
SensorInfo[] ret = null;
if (validInfos.size() > 0) {
ret = new SensorInfo[validInfos.size()];
validInfos.copyInto(ret);
}
return ret;
}
private String[] getSensorInfoChannelsNames(SensorInfo sensorInfo) {
Vector channelNames = new Vector();
ChannelInfo[] channelInfos = sensorInfo.getChannelInfos();
// Accelerometer must support at least 3 channels
if (channelInfos.length > 2) {
for (int i = 0; i < channelInfos.length; i++) {
// The channel type must be double
if (ChannelInfo.TYPE_DOUBLE == channelInfos[i].getDataType()
|| ChannelInfo.TYPE_INT == channelInfos[i]
.getDataType()) {
channelNames.addElement(channelInfos[i].getName());
}
}
// We found at least 3 double channels
if (channelNames.size() > 2) {
String[] names = new String[3];
names[0] = (String) channelNames.elementAt(0);
names[1] = (String) channelNames.elementAt(1);
names[2] = (String) channelNames.elementAt(2);
return names;
}
}
return new String[0];
}
public void dataReceived(SensorConnection sensor, Data[] data,
boolean isDataLost) {
double[] accel = new double[3];
for (int i = 0; i < data.length; i++) {
for (int c = 0; c < 3; c++) {
if (channelNames[c].equals(data[i].getChannelInfo().getName())) {
double val;
switch (data[i].getChannelInfo().getDataType()) {
case ChannelInfo.TYPE_DOUBLE:
val = data[i].getDoubleValues()[0];
break;
case ChannelInfo.TYPE_INT:
val = data[i].getIntValues()[0];
break;
default:
val = 0;
}
accel[c] =
unscaleValue(val, data[i].getChannelInfo()
.getScale());
break;
}
}
}
ballCanvas.accelerate(accel[0], accel[1], accel[2]);
}
private final double unscaleValue(double scaledValue, int scale) {
double mult = 1.0;
for (int i = 0; i < Math.abs(scale); i++) {
mult *= 10.0;
}
return (scale > 0) ? scaledValue * mult : scaledValue / mult;
}
public void startApp() {
ballCanvas.resetBoard();
Display.getDisplay(BallMidlet.this).setCurrent(ballCanvas);
//sensor.setDataListener(BallMidlet.this, 1);
System.out.println("Come here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
public void pauseApp() {
sensor.removeDataListener();
}
public void destroyApp(boolean unconditional) {
if (sensor != null) {
try {
sensor.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
notifyDestroyed();
}
}
小球类:
import java.io.IOException;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
public class Ball {
private Image img;
private Vector lastPos;
private Vector pos;
private Vector speed;
final static double ROLLING_FRICTION = 0.001;
private double bounceFriction;
private double radius;
public Ball() throws IOException {
this(0, 0);
}
public Ball(double x, double y) throws IOException {
img = Image.createImage("/black_marble.png");
pos = new Vector(x, y);
lastPos = new Vector(x, y);
speed = new Vector(0, 0);
radius = img.getWidth() / 2.0;
bounceFriction = 0.5;
}
public void resetPosition(double x, double y) {
speed = new Vector(0, 0);
pos.setX(x - getRadius());
pos.setY(y - getRadius());
}
public void paint(Graphics g) {
lastPos = new Vector(pos);
g.drawImage(img, (int) pos.getX(), (int) pos.getY(),
Graphics.HCENTER | Graphics.VCENTER);
}
public void clear(Graphics g) {
g.setColor(0xbbbbff);
g.fillRect((int) (lastPos.getX() - getRadius()), (int) (lastPos
.getY() - getRadius()), (int) (getRadius() * 2),
(int) (getRadius() * 2));
}
public void accelerate(double accelX, double accelY, double accelZ) {
double frictionF = (Math.max(0, accelZ) * ROLLING_FRICTION * 2);
speed.add(accelX, accelY);
if (frictionF > 0 && speed.getLen2() > 0) {
Vector friction = speed.inv().norm().mul(Math.sqrt(frictionF));
speed.add(friction);
}
}
public void calcNewPosition() {
pos.add(speed);
}
public double getRadius() {
return radius;
}
public void collideBorders(Canvas canvas) {
Vector newPos = Vector.add(pos, speed);
if (newPos.getY() - getRadius() < 0) {
speed.setY(speed.getY() * (bounceFriction - 1));
pos.setY(getRadius());
} else if (newPos.getY() + getRadius() > canvas.getHeight()) {
speed.setY(speed.getY() * (bounceFriction - 1));
pos.setY(canvas.getHeight() - getRadius());
}
if (newPos.getX() - getRadius() < 0) {
speed.setX(speed.getX() * (bounceFriction - 1));
pos.setX(getRadius());
} else if (newPos.getX() + getRadius() > canvas.getWidth()) {
speed.setX(speed.getX() * (bounceFriction - 1));
pos.setX(canvas.getWidth() - getRadius());
}
}
}
主Canvas,继承的是Canvas,实现Runnable接口
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author Administrator
*/
import java.io.IOException;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
public class BallCanvas extends Canvas implements Runnable {
private static final double PPCM = 80 * 100; // pixels per meter
public static final long TICK_SLEEP_MILLIS = 5;
/**
* Marble mass in kg. This demo is optimized for marbles with equal masses.
*/
final static double MARBLE_MASS = 0.000742179;
/**
* Multipliers convert m/s^2 to pixel/tick^2.
*/
private final double accelMultX;
private final double accelMultY;
private final double accelMultZ;
private Ball ball;
private volatile boolean stop;
private double accelX;
private double accelY;
private double accelZ;
volatile boolean firstPaint = true;
public BallCanvas() throws IOException {
// Tick cycles per s^2
setFullScreenMode(true);
double d = (1000 / TICK_SLEEP_MILLIS) * (1000 / TICK_SLEEP_MILLIS);
accelMultX = -1.0 * PPCM / d;
accelMultY = 1.0 * PPCM / d;
accelMultZ = -1.0 * PPCM / d;
ball = new Ball();
}
public synchronized void resetBoard() {
accelX = 0;
accelY = 0;
ball.resetPosition(getWidth() * 0.5, getHeight() * 0.5);
firstPaint = true;
}
public void start() {
stop = false;
resetBoard();
System.out.println("this.isDoubleBuffered()~~~~~~~~~~~~~~~~~~~~~~~~~~~~"+this.isDoubleBuffered());
new Thread(this).start();
}
public void stop() {
stop = true;
}
public void run() {
long st=0,et=0,diff=0;
int rate=50;//16-17 frame per second
while (!stop)
{
st=System.currentTimeMillis();
calculatePositions();
repaint();
et=System.currentTimeMillis();
diff=et-st;
if(diff<rate){
//System.out.println("Sleep "+(rate-diff));
try {
Thread.sleep(rate - diff);
}
catch (InterruptedException ex) {}
}
}
}
public void paint(Graphics g) {
if (firstPaint) {
g.setColor(0xbbbbff);
g.fillRect(0, 0, getWidth(), getHeight());
firstPaint = false;
}
ball.clear(g);
ball.paint(g);
}
private static final int SMOOTH_CNT = 2;
double avgX[] = new double[SMOOTH_CNT];
double avgY[] = new double[SMOOTH_CNT];
double avgZ[] = new double[SMOOTH_CNT];
public synchronized void accelerate(double x, double y, double z) {
double xx = x;
double yy = y;
double zz = z;
for (int i = 0; i < avgX.length - 1; i++) {
xx += avgX[i];
yy += avgY[i];
zz += avgZ[i];
avgX[i] = avgX[i + 1];
avgY[i] = avgY[i + 1];
avgZ[i] = avgZ[i + 1];
}
avgX[avgX.length - 1] = x;
avgY[avgY.length - 1] = y;
avgZ[avgZ.length - 1] = z;
xx /= avgX.length + 1;
yy /= avgY.length + 1;
zz /= avgZ.length + 1;
accelX = xx * accelMultX;
accelY = yy * accelMultY;
accelZ = zz * accelMultZ;
}
private synchronized void calculatePositions() {
ball.accelerate(accelX, accelY, accelZ);
System.out.println("calculatePositions~~~~~~~~~~~~~~~~");
ball.collideBorders(this);
ball.calcNewPosition();
}
}
向量类,类似辅助计算:
public class Vector {
private double x;
private double y;
public Vector(double x, double y) {
this.x = x;
this.y = y;
}
public Vector(Vector v) {
this(v.getX(), v.getY());
}
public static Vector add(Vector a, Vector b) {
return new Vector(a.getX() + b.getX(), a.getY() + b.getY());
}
public static Vector mul(Vector v, double d) {
return new Vector(v.getX() * d, v.getY() * d);
}
public static double dot(Vector a, Vector b) {
return a.getX() * b.getX() + a.getY() * b.getY();
}
public static Vector sub(Vector v1, Vector v2) {
return new Vector(v1.getX() - v2.getX(), v1.getY() - v2.getY());
}
public Vector inv() {
return new Vector(getX() * -1.0, getY() * -1.0);
}
public Vector norm() {
double l = Math.sqrt(getX() * getX() + getY() * getY());
return new Vector(getX() / l, getY() / l);
}
public double getY() {
return y;
}
public double getX() {
return x;
}
public Vector mul(double d) {
return new Vector(getX() * d, getY() * d);
}
public void add(Vector vector) {
add(vector.x, vector.y);
}
public void add(double d) {
add(d, d);
}
public void add(double x, double y) {
this.x += x;
this.y += y;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
public double getLen2() {
return getX() * getX() + getY() * getY();
}
public double getLen() {
return Math.sqrt(getLen2());
}
public String toString() {
return "[" + getX() + ";" + getY() + "]";
}
}