126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerpackage com.android.dreamtheater; 226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.animation.PropertyValuesHolder; 426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.animation.TimeAnimator; 526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.app.Activity; 626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.content.Context; 726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.content.Intent; 826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.graphics.Canvas; 926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.graphics.Matrix; 1026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.graphics.Paint; 1126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.graphics.RectF; 1226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.os.Bundle; 1326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.util.AttributeSet; 1426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.util.Log; 1526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.view.MotionEvent; 1626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.view.View; 1726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.view.Gravity; 1826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.view.ViewGroup; 1926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.widget.Button; 2026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.widget.FrameLayout; 2126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport android.widget.ImageView; 2226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 2326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport java.util.LinkedList; 2426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerimport java.util.HashMap; 2526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 2626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandlerpublic class BouncyDroid extends Activity { 2726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean DEBUG = true; 2826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean CENTER_DROID = true; 2926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 3026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public static class BouncyView extends FrameLayout 3126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler { 3226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler boolean mShowDebug = false; 3326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 3440a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler static final int RADIUS = 100; 3526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 3626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean HAS_INITIAL_IMPULSE = true; 3726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean HAS_GRAVITY = true; 3826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean HAS_FRICTION = false; 3926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean HAS_EDGES = true; 4026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 4126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final boolean STICKY_FINGERS = true; 4226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 4326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler static final float MAX_SPEED = 5000f; 4426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 4540a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler static final float RANDOM_IMPULSE_PROB = 0.001f; 4640a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler 4726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public static class World { 4826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public static final float PX_PER_METER = 100f; 4940a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler public static final float GRAVITY = 500f; 5026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public static class Vec { 5126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float x; 5226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float y; 5326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Vec() { 5426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler x = y = 0; 5526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 5626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Vec(float _x, float _y) { 5726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler x = _x; 5826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler y = _y; 5926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 6026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Vec add(Vec v) { 6126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return new Vec(x + v.x, y + v.y); 6226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 6326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Vec mul(float a) { 6426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return new Vec(x * a, y * a); 6526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 6626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Vec sub(Vec v) { 6726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return new Vec(x - v.x, y - v.y); 6826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 6926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public float mag() { 7026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return (float) Math.hypot(x, y); 7126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 7226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Vec norm() { 7326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float k = 1/mag(); 7426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return new Vec(x*k, y*k); 7526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 7626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public String toString() { 7726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return "(" + x + "," + y + ")"; 7826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 7926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 8026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public static class Body { 8126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float m, r; 8226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Vec p = new Vec(); 8326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Vec v = new Vec(); 8426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler LinkedList<Vec> forces = new LinkedList<Vec>(); 8526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler LinkedList<Vec> impulses = new LinkedList<Vec>(); 8626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public Body(float _m, Vec _p) { 8726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler m = _m; 8826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler p = _p; 8926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 9026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void applyForce(Vec f) { 9126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler forces.add(f); 9226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 9326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void applyImpulse(Vec f) { 9426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler impulses.add(f); 9526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 9626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void clearForces() { 9726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler forces.clear(); 9826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 9926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void removeForce(Vec f) { 10026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler forces.remove(f); 10126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 10226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void step(float dt) { 10326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler p = p.add(v.mul(dt)); 10426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (Vec f : impulses) { 10526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler v = v.add(f.mul(dt/m)); 10626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 10726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler impulses.clear(); 10826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (Vec f : forces) { 10926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler v = v.add(f.mul(dt/m)); 11026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 11126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 11226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public String toString() { 11326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return "Body(m=" + m + " p=" + p + " v=" + v + ")"; 11426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 11526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 11626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler LinkedList<Body> mBodies = new LinkedList<Body>(); 11726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void addBody(Body b) { 11826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBodies.add(b); 11926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 12026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 12126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void step(float dt) { 12226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (Body b : mBodies) { 12326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler b.step(dt); 12426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 12526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 12626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 12726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 12826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 12926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler TimeAnimator mAnim; 13026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World mWorld; 13126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ImageView mBug; 13226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler View mShowDebugView; 13326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler HashMap<Integer, World.Vec> mFingers = new HashMap<Integer, World.Vec>(); 13426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Body mBody; 13526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Vec mGrabSpot; 13626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler int mGrabbedPointer = -1; 13726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 13826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public BouncyView(Context context, AttributeSet as) { 13926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler super(context, as); 14026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 14126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler /* 14226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { 14326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 14426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void onSystemUiVisibilityChange(int visibility) { 14526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (visibility == View.STATUS_BAR_VISIBLE) { 14626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ((Activity)getContext()).finish(); 14726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 14826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 14926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler }); 15026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler */ 15126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 15240a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler setBackgroundColor(0xFF444444); 15340a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler 15426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug = new ImageView(context); 15526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setScaleType(ImageView.ScaleType.MATRIX); 15626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler addView(mBug, new ViewGroup.LayoutParams( 15726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ViewGroup.LayoutParams.WRAP_CONTENT, 15826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ViewGroup.LayoutParams.WRAP_CONTENT)); 15926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 16026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (DEBUG) { 16126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Button b = new Button(getContext()); 16226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler b.setText("Debugzors"); 16326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler b.setBackgroundColor(0); // very hard to see! :) 16426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler b.setOnClickListener(new View.OnClickListener() { 16526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 16626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void onClick(View v) { 16726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler setDebug(!mShowDebug); 16826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 16926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler }); 17026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler addView(b, new FrameLayout.LayoutParams( 17126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ViewGroup.LayoutParams.WRAP_CONTENT, 17226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ViewGroup.LayoutParams.WRAP_CONTENT, 17326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Gravity.TOP|Gravity.RIGHT)); 17426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 17526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 17626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 17726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void setDebug(boolean d) { 17826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (d != mShowDebug) { 17926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (d) { 18026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mShowDebugView = new DebugView(getContext()); 18126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mShowDebugView.setLayoutParams( 18226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler new ViewGroup.LayoutParams( 18326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ViewGroup.LayoutParams.MATCH_PARENT, 18426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ViewGroup.LayoutParams.MATCH_PARENT 18526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler )); 18626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler addView(mShowDebugView); 18726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 18826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setBackgroundColor(0x2000FF00); 18926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } else { 19026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mShowDebugView != null) { 19126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler removeView(mShowDebugView); 19226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mShowDebugView = null; 19326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 19426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setBackgroundColor(0); 19526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 19626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler invalidate(); 19726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mShowDebug = d; 19826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 19926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 20026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 20126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler private void reset() { 20226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mWorld = new World(); 20326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler final float mass = 100; 20426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody = new World.Body(mass, new World.Vec(200,200)); 20526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.r = RADIUS; 20626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mWorld.addBody(mBody); 20726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mGrabbedPointer = -1; 20826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 20926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mAnim = new TimeAnimator(); 21026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mAnim.setTimeListener(new TimeAnimator.TimeListener() { 21126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 21226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (deltaTime > 0) { 21326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler int STEPS = 5; 21426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler final float dt = deltaTime / (float) STEPS; 21526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler while (STEPS-->0) { 21626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.clearForces(); 21726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 21826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (HAS_INITIAL_IMPULSE) { 21926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // initial oomph 22026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (totalTime == 0) { 22126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.applyImpulse(new World.Vec(400000, -200000)); 22226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 22326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 22426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 22526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (HAS_GRAVITY) { 22626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // gravity points down 22726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.applyForce(new World.Vec(0, mass * World.GRAVITY)); 22826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 22926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 23026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mGrabbedPointer >= 0) { 23126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Vec finger = mFingers.get(mGrabbedPointer); 23226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (finger == null) { 23326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // let go! 23426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mGrabbedPointer = -1; 23526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } else { 23626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // never gonna let you go 23726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Vec newPos = finger.add(mGrabSpot); 23826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v = mBody.v.add(newPos.sub(mBody.p).mul(dt)); 23926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.p = newPos; 24026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 24126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } else { 24226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // springs 24326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // ideal Hooke's Law plus a maximum force and a minimum length cutoff 24426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (Integer i : mFingers.keySet()) { 24526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Vec finger = mFingers.get(i); 24626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Vec springForce = finger.sub(mBody.p); 24726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float mag = springForce.mag(); 24826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 24926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (STICKY_FINGERS && mag < mBody.r*0.75) { 25026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // close enough; we'll call this a "stick" 25126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mGrabbedPointer = i; 25226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mGrabSpot = mBody.p.sub(finger); 25326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v = new World.Vec(0,0); 25426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler break; 25526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 25626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 25740a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler final float SPRING_K = 30000; 25826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler final float FORCE_MAX = 10*SPRING_K; 25926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mag = (float) Math.min(mag * SPRING_K, FORCE_MAX); // Hooke's law 26026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // float mag = (float) (FORCE_MAX / Math.pow(springForce.mag(), 2)); // Gravitation 26126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler springForce = springForce.norm().mul(mag); 26226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.applyForce(springForce); 26326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 26426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 26526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 26626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (HAS_FRICTION) { 26726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // sliding friction opposes movement 26840a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler mBody.applyForce(mBody.v.mul(-0.01f * mBody.m)); 26926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 27026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 27126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (HAS_EDGES) { 27226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mBody.p.x - mBody.r < 0) { 27326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v.x = (float) Math.abs(mBody.v.x) * 27440a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler (HAS_FRICTION ? 0.95f : 1f); 27526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } else if (mBody.p.x + mBody.r > getWidth()) { 27626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v.x = (float) Math.abs(mBody.v.x) * 27740a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler (HAS_FRICTION ? -0.95f : -1f); 27826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 27926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mBody.p.y - mBody.r < 0) { 28026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v.y = (float) Math.abs(mBody.v.y) * 28140a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler (HAS_FRICTION ? 0.95f : 1f); 28226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } else if (mBody.p.y + mBody.r > getHeight()) { 28326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v.y = (float) Math.abs(mBody.v.y) * 28440a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler (HAS_FRICTION ? -0.95f : -1f); 28526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 28626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 28726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 28826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (MAX_SPEED > 0) { 28926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mBody.v.mag() > MAX_SPEED) { 29026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBody.v = mBody.v.norm().mul(MAX_SPEED); 29126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 29226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 29326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 29426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // ok, Euler, do your thing 29526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mWorld.step(dt / 1000f); // dt is in sec 29626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 29726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 29826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setTranslationX(mBody.p.x - mBody.r); 29926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setTranslationY(mBody.p.y - mBody.r); 30026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 30126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Matrix m = new Matrix(); 30226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler m.setScale( 30326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler (mBody.v.x < 0) ? -1 : 1, 30426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler (mBody.v.y > 1500) ? -1 : 1, // AAAAAAAAAAAAAAAA 30526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler RADIUS, RADIUS); 30626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setImageMatrix(m); 30726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (CENTER_DROID) { 30826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mBug.setImageResource( 30926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler (Math.abs(mBody.v.x) < 25) 31026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler ? R.drawable.bouncy_center 31126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler : R.drawable.bouncy); 31226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 31326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 31426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mShowDebug) mShowDebugView.invalidate(); 31526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 31626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler }); 31726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 31826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 31926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 32026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler protected void onAttachedToWindow() { 32126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler super.onAttachedToWindow(); 32226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler setSystemUiVisibility(View.STATUS_BAR_HIDDEN); 32326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 32426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler reset(); 32526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mAnim.start(); 32626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 32726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 32826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 32926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler protected void onDetachedFromWindow() { 33026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler super.onDetachedFromWindow(); 33126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mAnim.cancel(); 33226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 33326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 33426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 33526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public boolean onTouchEvent(MotionEvent event) { 33626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler int i; 33726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (i=0; i<event.getPointerCount(); i++) { 33826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler switch (event.getActionMasked()) { 33926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler case MotionEvent.ACTION_DOWN: 34026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler case MotionEvent.ACTION_MOVE: 34126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler case MotionEvent.ACTION_POINTER_DOWN: 34226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mFingers.put(event.getPointerId(i), 34326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler new World.Vec(event.getX(i), event.getY(i))); 34426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler break; 34526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 34626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler case MotionEvent.ACTION_UP: 34726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler case MotionEvent.ACTION_POINTER_UP: 34826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mFingers.remove(event.getPointerId(i)); 34926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler break; 35026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 35126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler case MotionEvent.ACTION_CANCEL: 35226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mFingers.clear(); 35326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler break; 35426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 35526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 35626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // expired pointers 35726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // for (; i<mFingers.length; i++) { 35826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // mFingers[i] = null; 35926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler // } 36026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return true; 36126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 36226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 36326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 36426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public boolean isOpaque() { 36526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler return true; 36626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 36726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 36826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler class DebugView extends View { 36926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public DebugView(Context ct) { 37026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler super(ct); 37126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 37226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 37326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler private void drawVector(Canvas canvas, 37426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float x, float y, float vx, float vy, 37526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Paint pt) { 37626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler final float mag = (float) Math.hypot(vx, vy); 37726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 37826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.save(); 37926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Matrix mx = new Matrix(); 38026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mx.setSinCos(-vx/mag, vy/mag); 38126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler mx.postTranslate(x, y); 38226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.setMatrix(mx); 38326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 38426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawLine(0,0, 0, mag, pt); 38526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawLine(0, mag, -4, mag-4, pt); 38626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawLine(0, mag, 4, mag-4, pt); 38726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 38826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.restore(); 38926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 39026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 39126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 39226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler protected void onDraw(Canvas canvas) { 39326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler super.onDraw(canvas); 39426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 39526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler Paint pt = new Paint(Paint.ANTI_ALIAS_FLAG); 39626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setColor(0xFFCC0000); 39726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setTextSize(30f); 39826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setStrokeWidth(1.0f); 39926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 40026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (Integer id : mFingers.keySet()) { 40126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler World.Vec v = mFingers.get(id); 40226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float x = v.x; 40326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float y = v.y; 40426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setStyle(Paint.Style.FILL); 40526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawText("#"+id, x+38, y-38, pt); 40626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setStyle(Paint.Style.STROKE); 40726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawLine(x-40, y, x+40, y, pt); 40826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawLine(x, y-40, x, y+40, pt); 40926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawCircle(x, y, 40, pt); 41026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 41126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setStyle(Paint.Style.STROKE); 41226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler if (mBody != null) { 41326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float x = mBody.p.x; 41426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float y = mBody.p.y; 41526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler float r = mBody.r; 41626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setColor(0xFF6699FF); 41726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler RectF bounds = new RectF(x-r, y-r, x+r, y+r); 41826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler canvas.drawOval(bounds, pt); 41926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 42026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setStrokeWidth(3); 42140a5d064fc5eded6cca78c585304e46f1f3928e3Daniel Sandler drawVector(canvas, x, y, mBody.v.x/100, mBody.v.y/100, pt); 42226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 42326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler pt.setColor(0xFF0033FF); 42426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler for (World.Vec f : mBody.forces) { 42526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler drawVector(canvas, x, y, f.x/1000, f.y/1000, pt); 42626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 42726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 42826e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 42926e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 43026e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 43126e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler 43226e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler @Override 43326e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler public void onStart() { 43426e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler super.onStart(); 43526e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler setContentView(new BouncyView(this, null)); 43626e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler } 43726e4a6ce116b0a756dcaf9c80c466903789cac45Daniel Sandler} 438