Skip to content

Commit ffb210c

Browse files
v 1.2: improved graphics, balls can collide
git-svn-id: https://apps-for-android.googlecode.com/svn/trunk@149 4c97771b-2a47-0410-a901-cdf36a16b7d0
1 parent a4fa618 commit ffb210c

File tree

9 files changed

+130
-123
lines changed

9 files changed

+130
-123
lines changed

DivideAndConquer/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
44
package="com.google.android.divideandconquer"
5-
android:versionName="1.1"
6-
android:versionCode="11">
5+
android:versionName="1.2"
6+
android:versionCode="12">
77

88
<uses-permission android:name="android.permission.VIBRATE"/>
99

496 Bytes
Loading

DivideAndConquer/res/layout/main.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
android:layout_width="wrap_content"
1616
android:layout_height="wrap_content"
1717
android:layout_alignParentLeft="true"
18-
android:textAppearance="?android:attr/textAppearanceSmall"
18+
android:textAppearance="?android:attr/textAppearanceMedium"
1919
/>
2020

2121
<TextView
@@ -24,14 +24,14 @@
2424
android:layout_height="wrap_content"
2525
android:layout_alignParentTop="true"
2626
android:layout_centerInParent="true"
27-
android:textAppearance="?android:attr/textAppearanceSmall"
27+
android:textAppearance="?android:attr/textAppearanceMedium"
2828
/>
2929

3030
<TextView android:id="@+id/livesLeft"
3131
android:layout_width="wrap_content"
3232
android:layout_height="wrap_content"
3333
android:layout_alignParentRight="true"
34-
android:textAppearance="?android:attr/textAppearanceSmall"
34+
android:textAppearance="?android:attr/textAppearanceMedium"
3535
/>
3636
</RelativeLayout>
3737

DivideAndConquer/src/com/google/android/divideandconquer/AnimatingLine.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class AnimatingLine extends Shape2d {
3535
float mMax;
3636

3737
private long mLastUpdate = 0;
38-
private float mPixelsPerSecond = 100.0f;
38+
private float mPixelsPerSecond = 101.0f;
3939

4040
/**
4141
* @param direction The direction of the line

DivideAndConquer/src/com/google/android/divideandconquer/Ball.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,27 @@ public void setNow(long now) {
107107
mLastUpdate = now;
108108
}
109109

110+
public boolean isCircleOverlapping(Ball otherBall) {
111+
final float dy = otherBall.mY - mY;
112+
final float dx = otherBall.mX - mX;
113+
114+
final float distance = dy * dy + dx * dx;
115+
116+
return (distance < ((2 * mRadiusPixels) * (2 *mRadiusPixels)))
117+
// avoid jittery collisions
118+
&& !movingAwayFromEachother(this, otherBall);
119+
}
120+
121+
private boolean movingAwayFromEachother(Ball ballA, Ball ballB) {
122+
double collA = Math.atan2(ballB.mY - ballA.mY, ballB.mX - ballA.mX);
123+
double collB = Math.atan2(ballA.mY - ballB.mY, ballA.mX - ballB.mX);
124+
125+
double ax = Math.cos(ballA.mAngle - collA);
126+
double bx = Math.cos(ballB.mAngle - collB);
127+
128+
return ax + bx < 0;
129+
}
130+
110131
public void update(long now) {
111132
if (now <= mLastUpdate) return;
112133

@@ -180,6 +201,44 @@ private void bounceOffLeft() {
180201
}
181202

182203

204+
/**
205+
* Given that ball a and b have collided, adjust their angles to reflect their state
206+
* after the collision.
207+
*
208+
* This method works based on the conservation of energy and momentum in an elastic
209+
* collision. Because the balls have equal mass and speed, it ends up being that they
210+
* simply swap velocities along the axis of the collision, keeping the velocities tangent
211+
* to the collision constant.
212+
*
213+
* @param ballA The first ball in a collision
214+
* @param ballB The second ball in a collision
215+
*/
216+
public static void adjustForCollision(Ball ballA, Ball ballB) {
217+
218+
final double collA = Math.atan2(ballB.mY - ballA.mY, ballB.mX - ballA.mX);
219+
final double collB = Math.atan2(ballA.mY - ballB.mY, ballA.mX - ballB.mX);
220+
221+
final double ax = Math.cos(ballA.mAngle - collA);
222+
final double ay = Math.sin(ballA.mAngle - collA);
223+
224+
final double bx = Math.cos(ballB.mAngle - collB);
225+
final double by = Math.cos(ballB.mAngle - collB);
226+
227+
final double diffA = Math.atan2(ay, -bx);
228+
final double diffB = Math.atan2(by, -ax);
229+
230+
ballA.mAngle = collA + diffA;
231+
ballB.mAngle = collB + diffB;
232+
}
233+
234+
235+
@Override
236+
public String toString() {
237+
return String.format(
238+
"Ball(x=%f, y=%f, angle=%f)",
239+
mX, mY, Math.toDegrees(mAngle));
240+
}
241+
183242
/**
184243
* A more readable way to create balls than using a 5 param
185244
* constructor of all numbers.
@@ -244,6 +303,5 @@ public Builder setRadiusPixels(float pixels) {
244303
mRadiusPixels = pixels;
245304
return this;
246305
}
247-
248306
}
249307
}

DivideAndConquer/src/com/google/android/divideandconquer/BallRegion.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,6 @@ public void setNow(long now) {
128128
}
129129
}
130130

131-
// /**
132-
// * @return the area in the region in pixel*pixel
133-
// */
134-
// public float getArea() {
135-
// return (mRight - mLeft) * (mBottom - mTop);
136-
// }
137-
138-
139131
/**
140132
* Update the balls an (if it exists) the animating line in this region.
141133
* @param now in millis
@@ -150,8 +142,9 @@ public BallRegion update(long now) throws BallHitMovingLineException {
150142
final boolean newRegion =
151143
(mAnimatingLine != null && mAnimatingLine.update(now));
152144

153-
// update the balls, look for collision
154145
final int numBalls = mBalls.size();
146+
147+
// move balls, check for collision with animating line
155148
for (int i = 0; i < numBalls; i++) {
156149
final Ball ball = mBalls.get(i);
157150
ball.update(now);
@@ -160,8 +153,20 @@ public BallRegion update(long now) throws BallHitMovingLineException {
160153
}
161154
}
162155

156+
// update ball to ball collisions
157+
for (int i = 0; i < numBalls; i++) {
158+
final Ball ball = mBalls.get(i);
159+
for (int j = i + 1; j < numBalls; j++) {
160+
Ball other = mBalls.get(j);
161+
if (ball.isCircleOverlapping(other)) {
162+
Ball.adjustForCollision(ball, other);
163+
break;
164+
}
165+
}
166+
}
167+
163168
handleShrinkToFit(now);
164-
169+
165170
// no collsion, new region means we need to split out the apropriate
166171
// balls into a new region
167172
if (newRegion) {

DivideAndConquer/src/com/google/android/divideandconquer/DivideAndConquerActivity.java

Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,6 @@ public class DivideAndConquerActivity extends Activity
4242
NewGameCallback,
4343
DialogInterface.OnCancelListener {
4444

45-
/**
46-
* Each level has a different background color and ball color.
47-
*/
48-
static class LevelStyle {
49-
private final int mBgColor;
50-
private final int mBallColor;
51-
52-
LevelStyle(int bgColor, int ballColor) {
53-
mBgColor = 0xFF000000 | bgColor;
54-
mBallColor = 0xFF000000 |ballColor;
55-
}
56-
}
57-
58-
/**
59-
* The styles we cycle through when leveling up.
60-
*/
61-
static LevelStyle[] LEVEL_STYLES = new LevelStyle[] {
62-
new LevelStyle(0xFFD162FF, 0xFF76A7FF),
63-
new LevelStyle(0xFF76A7FF, 0xFF75FFE9),
64-
new LevelStyle(0xFF7E33, 0x8DBDD9),
65-
new LevelStyle(0x61FF6E, 0xD9B4D6),
66-
new LevelStyle(0x2BA7FF, 0xFF842B),
67-
};
68-
6945
private static final int NEW_GAME_NUM_BALLS = 1;
7046
private static final double LEVEL_UP_THRESHOLD = 0.8;
7147
private static final int TRY_AGAIN_PAUSE = 1000;
@@ -91,29 +67,6 @@ static class LevelStyle {
9167

9268
private Toast mCurrentToast;
9369

94-
// usefull for playing around with colors
95-
// private int theindex = 0;
96-
// public boolean onKeyUp(int i, KeyEvent event) {
97-
// if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
98-
// theindex++;
99-
// theindex = theindex % LEVEL_STYLES.length;
100-
// mBallsView.setColors(
101-
// LEVEL_STYLES[theindex].mBgColor,
102-
// LEVEL_STYLES[theindex].mBallColor
103-
// );
104-
// return true;
105-
// } else if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
106-
// theindex--;
107-
// if (theindex < 0) theindex = LEVEL_STYLES.length - 1;
108-
// mBallsView.setColors(
109-
// LEVEL_STYLES[theindex].mBgColor,
110-
// LEVEL_STYLES[theindex].mBallColor
111-
// );
112-
// return true;
113-
// }
114-
// return false;
115-
// }
116-
11770
@Override
11871
public void onCreate(Bundle savedInstanceState) {
11972
super.onCreate(savedInstanceState);
@@ -136,10 +89,6 @@ public void onCreate(Bundle savedInstanceState) {
13689
public void onEngineReady(BallEngine ballEngine) {
13790
// display 10 balls bouncing around for visual effect
13891
ballEngine.reset(SystemClock.elapsedRealtime(), 10);
139-
mBallsView.setColors(
140-
LEVEL_STYLES[0].mBgColor,
141-
LEVEL_STYLES[0].mBallColor
142-
);
14392
mBallsView.setMode(DivideAndConquerView.Mode.Bouncing);
14493

14594
// show the welcome dialog
@@ -233,7 +182,8 @@ public void onOptionsMenuClosed(Menu menu) {
233182
private void saveMode() {
234183
// don't want to restore to a state where user can't resume game.
235184
final DivideAndConquerView.Mode mode = mBallsView.getMode();
236-
final DivideAndConquerView.Mode toRestore = mode == DivideAndConquerView.Mode.Paused ? DivideAndConquerView.Mode.PausedByUser : mode;
185+
final DivideAndConquerView.Mode toRestore = (mode == DivideAndConquerView.Mode.Paused) ?
186+
DivideAndConquerView.Mode.PausedByUser : mode;
237187
mRestoreMode.push(toRestore);
238188
}
239189

@@ -291,7 +241,6 @@ private void levelUp(final BallEngine ballEngine) {
291241
updatePercentDisplay(0);
292242
updateLevelDisplay(mNumBalls);
293243
ballEngine.reset(SystemClock.elapsedRealtime(), mNumBalls);
294-
updateLevelColors();
295244
mBallsView.setMode(DivideAndConquerView.Mode.Bouncing);
296245
showToast("level " + mNumBalls);
297246
}
@@ -326,22 +275,10 @@ public void onNewGame() {
326275
updatePercentDisplay(0);
327276
updateLivesDisplay(mNumLives, false);
328277
updateLevelDisplay(mNumBalls);
329-
updateLevelColors();
330278
mBallsView.getEngine().reset(SystemClock.elapsedRealtime(), mNumBalls);
331279
mBallsView.setMode(DivideAndConquerView.Mode.Bouncing);
332280
}
333281

334-
/**
335-
* Update the background color and ball color appropriate to the current level.
336-
*/
337-
private void updateLevelColors() {
338-
final int index = (mNumBalls - 1) % LEVEL_STYLES.length;
339-
mBallsView.setColors(
340-
LEVEL_STYLES[index].mBgColor,
341-
LEVEL_STYLES[index].mBallColor
342-
);
343-
}
344-
345282
/**
346283
* Update the header displaying the current level
347284
*/

0 commit comments

Comments
 (0)