• me on stackoverflow

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

Nice code comments...
Rune on 03/29/2010
Aren't they just.
baz on 03/30/2010

Something to say?

name
ramble