|
Android example source code file (DivideAndConquerView.java)
The DivideAndConquerView.java Android example source code
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.divideandconquer;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.*;
import android.graphics.drawable.GradientDrawable;
import android.os.Debug;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import java.util.List;
import java.util.ArrayList;
/**
* Handles the visual display and touch input for the game.
*/
public class DivideAndConquerView extends View implements BallEngine.BallEventCallBack {
static final int BORDER_WIDTH = 10;
// this needs to match size of ball drawable
static final float BALL_RADIUS = 5f;
static final float BALL_SPEED = 80f;
// if true, will profile the drawing code during each animating line and export
// the result to a file named 'BallsDrawing.trace' on the sd card
// this file can be pulled off and profiled with traceview
// $ adb pull /sdcard/BallsDrawing.trace .
// traceview BallsDrawing.trace
private static final boolean PROFILE_DRAWING = false;
private boolean mDrawingProfilingStarted = false;
private final Paint mPaint;
private BallEngine mEngine;
private Mode mMode = Mode.Paused;
private BallEngineCallBack mCallback;
// interface for starting a line
private DirectionPoint mDirectionPoint = null;
private Bitmap mBallBitmap;
private float mBallBitmapRadius;
private final Bitmap mExplosion1;
private final Bitmap mExplosion2;
private final Bitmap mExplosion3;
/**
* Callback notifying of events related to the ball engine.
*/
static interface BallEngineCallBack {
/**
* The engine has its dimensions and is ready to go.
* @param ballEngine The ball engine.
*/
void onEngineReady(BallEngine ballEngine);
/**
* A ball has hit a moving line.
* @param ballEngine The engine.
* @param x The x coordinate of the ball.
* @param y The y coordinate of the ball.
*/
void onBallHitsMovingLine(BallEngine ballEngine, float x, float y);
/**
* A line made it to the edges of its region, splitting off a new region.
* @param ballEngine The engine.
*/
void onAreaChange(BallEngine ballEngine);
}
/**
* @return The ball engine associated with the game.
*/
public BallEngine getEngine() {
return mEngine;
}
/**
* Keeps track of the mode of this view.
*/
enum Mode {
/**
* The balls are bouncing around.
*/
Bouncing,
/**
* The animation has stopped and the balls won't move around. The user
* may not unpause it; this is used to temporarily stop games between
* levels, or when the game is over and the activity places a dialog up.
*/
Paused,
/**
* Same as {@link #Paused}, but paints the word 'touch to unpause' on
* the screen, so the user knows he/she can unpause the game.
*/
PausedByUser
}
public DivideAndConquerView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(2);
mPaint.setColor(Color.BLACK);
// so we can see the back key
setFocusableInTouchMode(true);
drawBackgroundGradient();
mBallBitmap = BitmapFactory.decodeResource(
context.getResources(),
R.drawable.ball);
mBallBitmapRadius = ((float) mBallBitmap.getWidth()) / 2f;
mExplosion1 = BitmapFactory.decodeResource(
context.getResources(),
R.drawable.explosion1);
mExplosion2 = BitmapFactory.decodeResource(
context.getResources(),
R.drawable.explosion2);
mExplosion3 = BitmapFactory.decodeResource(
context.getResources(),
R.drawable.explosion3);
}
final GradientDrawable mBackgroundGradient =
new GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
new int[]{Color.RED, Color.YELLOW});
void drawBackgroundGradient() {
setBackgroundDrawable(mBackgroundGradient);
}
/**
* Set the callback that will be notified of events related to the ball
* engine.
* @param callback The callback.
*/
public void setCallback(BallEngineCallBack callback) {
mCallback = callback;
}
@Override
protected void onSizeChanged(int i, int i1, int i2, int i3) {
super.onSizeChanged(i, i1, i2,
i3);
// this should only happen once when the activity is first launched.
// we could be smarter about saving / restoring across activity
// lifecycles, but for now, this is good enough to handle in game play,
// and most cases of navigating away with the home key and coming back.
mEngine = new BallEngine(
BORDER_WIDTH, getWidth() - BORDER_WIDTH,
BORDER_WIDTH, getHeight() - BORDER_WIDTH,
BALL_SPEED,
BALL_RADIUS);
mEngine.setCallBack(this);
mCallback.onEngineReady(mEngine);
}
/**
* @return the current mode of operation.
*/
public Mode getMode() {
return mMode;
}
/**
* Set the mode of operation.
* @param mode The mode.
*/
public void setMode(Mode mode) {
mMode = mode;
if (mMode == Mode.Bouncing && mEngine != null) {
// when starting up again, the engine needs to know what 'now' is.
final long now = SystemClock.elapsedRealtime();
mEngine.setNow(now);
mExplosions.clear();
invalidate();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// the first time the user hits back while the balls are moving,
// we'll pause the game. but if they hit back again, we'll do the usual
// (exit the activity)
if (keyCode == KeyEvent.KEYCODE_BACK && mMode == Mode.Bouncing) {
setMode(Mode.PausedByUser);
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
if (mMode == Mode.PausedByUser) {
// touching unpauses when the game was paused by the user.
setMode(Mode.Bouncing);
return true;
} else if (mMode == Mode.Paused) {
return false;
}
final float x = motionEvent.getX();
final float y = motionEvent.getY();
switch(motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mEngine.canStartLineAt(x, y)) {
mDirectionPoint =
new DirectionPoint(x, y);
}
return true;
case MotionEvent.ACTION_MOVE:
if (mDirectionPoint != null) {
mDirectionPoint.updateEndPoint(x, y);
} else if (mEngine.canStartLineAt(x, y)) {
mDirectionPoint =
new DirectionPoint(x, y);
}
return true;
case MotionEvent.ACTION_UP:
if (mDirectionPoint != null) {
switch (mDirectionPoint.getDirection()) {
case Unknown:
// do nothing
break;
case Horizonal:
mEngine.startHorizontalLine(SystemClock.elapsedRealtime(),
mDirectionPoint.getX(), mDirectionPoint.getY());
if (PROFILE_DRAWING) {
if (!mDrawingProfilingStarted) {
Debug.startMethodTracing("BallsDrawing");
mDrawingProfilingStarted = true;
}
}
break;
case Vertical:
mEngine.startVerticalLine(SystemClock.elapsedRealtime(),
mDirectionPoint.getX(), mDirectionPoint.getY());
if (PROFILE_DRAWING) {
if (!mDrawingProfilingStarted) {
Debug.startMethodTracing("BallsDrawing");
mDrawingProfilingStarted = true;
}
}
break;
}
}
mDirectionPoint = null;
return true;
case MotionEvent.ACTION_CANCEL:
mDirectionPoint = null;
return true;
}
return false;
}
/** {@inheritDoc} */
public void onBallHitsBall(Ball ballA, Ball ballB) {
}
/** {@inheritDoc} */
public void onBallHitsLine(long when, Ball ball, AnimatingLine animatingLine) {
mCallback.onBallHitsMovingLine(mEngine, ball.getX(), ball.getY());
mExplosions.add(
new Explosion(
when,
ball.getX(), ball.getY(),
mExplosion1, mExplosion2, mExplosion3));
}
static class Explosion {
private long mLastUpdate;
private long mProgress = 0;
private final float mX;
private final float mY;
private final Bitmap mExplosion1;
private final Bitmap mExplosion2;
private final Bitmap mExplosion3;
private final float mRadius;
Explosion(long mLastUpdate, float mX, float mY,
Bitmap explosion1, Bitmap explosion2, Bitmap explosion3) {
this.mLastUpdate = mLastUpdate;
this.mX = mX;
this.mY = mY;
this.mExplosion1 = explosion1;
this.mExplosion2 = explosion2;
this.mExplosion3 = explosion3;
mRadius = ((float) mExplosion1.getWidth()) / 2f;
}
public void update(long now) {
mProgress += (now - mLastUpdate);
mLastUpdate = now;
}
public void setNow(long now) {
mLastUpdate = now;
}
public void draw(Canvas canvas, Paint paint) {
if (mProgress < 80L) {
canvas.drawBitmap(mExplosion1, mX - mRadius, mY - mRadius, paint);
} else if (mProgress < 160L) {
canvas.drawBitmap(mExplosion2, mX - mRadius, mY - mRadius, paint);
} else if (mProgress < 400L) {
canvas.drawBitmap(mExplosion3, mX - mRadius, mY - mRadius, paint);
}
}
public boolean done() {
return mProgress > 700L;
}
}
private ArrayList<Explosion> mExplosions = new ArrayList
Other Android examples (source code examples)Here is a short list of links related to this Android DivideAndConquerView.java source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.