03/07/2010
Bounce 4 of 4 by baz
This is the workhorse class, definitely too much stuff going on here, feel a bit guilty about it, but I’m just playing here so I’ll live with myself for now and refactor while I’m redoing it with OpenGL.
package com.sharpdev.android.bounce;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class BouncePanel extends SurfaceView implements SurfaceHolder.Callback {
public static final double GRAVITY = 500.0;
public static final double FRICTION = 0.8;
public static final double BOUNCE_LOSS = 0.85;
private BounceThread thread;
private BounceBall ball;
private int surfaceWidth;
private int surfaceHeight;
private Paint textBrush = new Paint();
private SurfaceHolder surfaceHolder;
public BouncePanel(Context context) {
super(context);
getHolder().addCallback(this);
ball = new BounceBall(20, 50, 50);
thread = new BounceThread(getHolder(), this);
surfaceHolder = getHolder();
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
Sensor sensorOrientation = sensorManager.getSensorList(Sensor.TYPE_ORIENTATION).get(0);
sensorManager.registerListener(sensorListener, sensorOrientation, SensorManager.SENSOR_DELAY_GAME);
textBrush.setColor(Color.WHITE);
Log.d("BouncePanel", "Starting BouncePanel");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
surfaceWidth = width;
surfaceHeight = height;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (thread.getState() == Thread.State.TERMINATED) {
thread = new BounceThread(holder, this);
thread.setRunning(true);
thread.start();
}
else {
thread.setRunning(true);
thread.start();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (surfaceHolder) {
ball.setX((int)event.getX());
ball.setY((int) event.getY());
ball.getSpeed().setY(0);
}
return true;
}
private int slowCount = 0;
private double lastSlow = 0;
@Override
public void onDraw(Canvas canvas) {
canvas.translate(10, 10); // For some reason my coordinates only map if I translate by 10/10 first?
canvas.drawColor(Color.BLACK);
ball.Draw(canvas);
if (lastElapsed > .1)
{
slowCount++;
lastSlow = lastElapsed;
}
canvas.drawText(String.format("Slow count: %s Last slow: %s", slowCount, lastSlow), 0, 25, textBrush);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (!hasWindowFocus) {
thread.pause();
}
else {
thread.unpause();
}
}
public Vector2D getGravity(double elapsed)
{
float[] orientation = nextOrientation;
float angleAroundZAxis = orientation[2];
double gX = Math.sin(Math.toRadians(angleAroundZAxis)) * GRAVITY;
float angleAroundXAxis = orientation[1];
double gY = Math.sin(Math.toRadians(angleAroundXAxis)) * GRAVITY;
return new Vector2D(-gX * elapsed, -gY * elapsed);
}
private double lastElapsed;
public void updatePhysics(double elapsed) {
lastElapsed = elapsed;
Vector2D gravity = getGravity(elapsed);
Vector2D newSpeed = Vector2D.add(ball.getSpeed(), gravity);
ball.setY(ball.getY() + ((newSpeed.getY() + ball.getSpeed().getY())/2) * elapsed);
ball.setX(ball.getX() + ((newSpeed.getX() + ball.getSpeed().getX())/2) * elapsed);
ball.setSpeed(newSpeed);
ball.getSpeed().adjustBy(Math.pow(FRICTION, elapsed));
int radius = ball.getRadius();
if ((ball.getY() - radius) < 0)
{
ball.setY(radius);
ball.getSpeed().setY(ball.getSpeed().getY()*-BOUNCE_LOSS);
}
if ((ball.getY() + radius) > surfaceHeight)
{
ball.setY(surfaceHeight - radius);
ball.getSpeed().setY(ball.getSpeed().getY()*-BOUNCE_LOSS);
}
if ((ball.getX() + radius) > surfaceWidth)
{
ball.setX(surfaceWidth - radius);
ball.getSpeed().setX(ball.getSpeed().getX()*-BOUNCE_LOSS);
}
if ((ball.getX() - radius) < 0)
{
ball.setX(radius);
ball.getSpeed().setX(ball.getSpeed().getX()*-BOUNCE_LOSS);
}
}
float[] nextOrientation;
private final SensorEventListener sensorListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
int type = event.sensor.getType();
switch(type) {
case Sensor.TYPE_ORIENTATION:
synchronized (surfaceHolder) {
nextOrientation = event.values.clone();
}
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
public BounceThread getThread() {
return thread;
}
public void saveState(Bundle map) {
map.putDouble("BALLX", ball.getX());
map.putDouble("BALLY", ball.getY());
map.putDouble("BALLVX", ball.getSpeed().getX());
map.putDouble("BALLVY", ball.getSpeed().getY());
}
public void restoreState(Bundle map) {
ball.setX(map.getDouble("BALLX"));
ball.setY(map.getDouble("BALLY"));
ball.getSpeed().setY(map.getDouble("BALLVX"));
ball.getSpeed().setY(map.getDouble("BALLVY"));
}
}

Comments
Something to say?