展会信息港展会大全

android开发之SurfaceView的用法 LunarLander游戏的实现代码
来源:互联网   发布日期:2015-10-13 07:40:08   浏览:2166次  

导读:SurfaceView可以说是Android游戏开发中必须学会和掌握的。本文就通过系统自带的例子来让大家看看SurfaceView的用法。 Android SDK的Sample有有一个LunarLander游戏的例子,下面给出了其中LunarView的实现代码。 ...

SurfaceView可以说是Android游戏开发中必须学会和掌握的。本文就通过系统自带的例子来让大家看看SurfaceView的用法。 Android SDK的Sample有有一个LunarLander游戏的例子,下面给出了其中LunarView的实现代码。

大家可以把此工程导入到Eclipse,然后编译运行,试玩一下。最后对应着看代码,这样更容易理解。下面上代码:

class LunarView extends SurfaceView implements SurfaceHolder.Callback {

class LunarThread extends Thread {

/*

* Difficulty setting constants

*/

public static final int DIFFICULTY_EASY = 0;

public static final int DIFFICULTY_HARD = 1;

public static final int DIFFICULTY_MEDIUM = 2;

/*

* Physics constants

*/

public static final int PHYS_DOWN_ACCEL_SEC = 35;

public static final int PHYS_FIRE_ACCEL_SEC = 80;

public static final int PHYS_FUEL_INIT = 60;

public static final int PHYS_FUEL_MAX = 100;

public static final int PHYS_FUEL_SEC = 10;

public static final int PHYS_SLEW_SEC = 120; // degrees/second rotate

public static final int PHYS_SPEED_HYPERSPACE = 180;

public static final int PHYS_SPEED_INIT = 30;

public static final int PHYS_SPEED_MAX = 120;

/*

* State-tracking constants

*/

public static final int STATE_LOSE = 1;

public static final int STATE_PAUSE = 2;

public static final int STATE_READY = 3;

public static final int STATE_RUNNING = 4;

public static final int STATE_WIN = 5;

/*

* Goal condition constants

*/

public static final int TARGET_ANGLE = 18; // > this angle means crash

public static final int TARGET_BOTTOM_PADDING = 17; // px below gear

public static final int TARGET_PAD_HEIGHT = 8; // how high above ground

public static final int TARGET_SPEED = 28; // > this speed means crash

public static final double TARGET_WIDTH = 1.6; // width of target

/*

* UI constants (i.e. the speed & fuel bars)

*/

public static final int UI_BAR = 100; // width of the bar(s)

public static final int UI_BAR_HEIGHT = 10; // height of the bar(s)

private static final String KEY_DIFFICULTY = "mDifficulty";

private static final String KEY_DX = "mDX";

private static final String KEY_DY = "mDY";

private static final String KEY_FUEL = "mFuel";

private static final String KEY_GOAL_ANGLE = "mGoalAngle";

private static final String KEY_GOAL_SPEED = "mGoalSpeed";

private static final String KEY_GOAL_WIDTH = "mGoalWidth";

private static final String KEY_GOAL_X = "mGoalX";

private static final String KEY_HEADING = "mHeading";

private static final String KEY_LANDER_HEIGHT = "mLanderHeight";

private static final String KEY_LANDER_WIDTH = "mLanderWidth";

private static final String KEY_WINS = "mWinsInARow";

private static final String KEY_X = "mX";

private static final String KEY_Y = "mY";

/*

* Member (state) fields

*/

/** The drawable to use as the background of the animation canvas */

private Bitmap mBackgroundImage;

/**

* Current height of the surface/canvas.

*

* @see #setSurfaceSize

*/

private int mCanvasHeight = 1;

/**

* Current width of the surface/canvas.

*

* @see #setSurfaceSize

*/

private int mCanvasWidth = 1;

/** What to draw for the Lander when it has crashed */

private Drawable mCrashedImage;

/**

* Current difficulty -- amount of fuel, allowed angle, etc. Default is

* MEDIUM.

*/

private int mDifficulty;

/** Velocity dx. */

private double mDX;

/** Velocity dy. */

private double mDY;

/** Is the engine burning? */

private boolean mEngineFiring;

/** What to draw for the Lander when the engine is firing */

private Drawable mFiringImage;

/** Fuel remaining */

private double mFuel;

/** Allowed angle. */

private int mGoalAngle;

/** Allowed speed. */

private int mGoalSpeed;

/** Width of the landing pad. */

private int mGoalWidth;

/** X of the landing pad. */

private int mGoalX;

/** Message handler used by thread to interact with TextView */

private Handler mHandler;

/**

* Lander heading in degrees, with 0 up, 90 right. Kept in the range

* 0..360.

*/

private double mHeading;

/** Pixel height of lander image. */

private int mLanderHeight;

/** What to draw for the Lander in its normal state */

private Drawable mLanderImage;

/** Pixel width of lander image. */

private int mLanderWidth;

/** Used to figure out elapsed time between frames */

private long mLastTime;

/** Paint to draw the lines on screen. */

private Paint mLinePaint;

/** "Bad" speed-too-high variant of the line color. */

private Paint mLinePaintBad;

/** The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN */

private int mMode;

/** Currently rotating, -1 left, 0 none, 1 right. */

private int mRotating;

/** Indicate whether the surface has been created & is ready to draw */

private boolean mRun = false;

/** Scratch rect object. */

private RectF mScratchRect;

/** Handle to the surface manager object we interact with */

private SurfaceHolder mSurfaceHolder;

/** Number of wins in a row. */

private int mWinsInARow;

/** X of lander center. */

private double mX;

/** Y of lander center. */

private double mY;

public LunarThread(SurfaceHolder surfaceHolder, Context context,

Handler handler) {

// get handles to some important objects

mSurfaceHolder = surfaceHolder;

mHandler = handler;

mContext = context;

Resources res = context.getResources();

// cache handles to our key sprites & other drawables

mLanderImage = context.getResources().getDrawable(

R.drawable.lander_plain);

mFiringImage = context.getResources().getDrawable(

R.drawable.lander_firing);

mCrashedImage = context.getResources().getDrawable(

R.drawable.lander_crashed);

// load background image as a Bitmap instead of a Drawable b/c

// we don't need to transform it and it's faster to draw this way

mBackgroundImage = BitmapFactory.decodeResource(res,

R.drawable.earthrise);

// Use the regular lander image as the model size for all sprites

mLanderWidth = mLanderImage.getIntrinsicWidth();

mLanderHeight = mLanderImage.getIntrinsicHeight();

// Initialize paints for speedometer

mLinePaint = new Paint();

mLinePaint.setAntiAlias(true);

mLinePaint.setARGB(255, 0, 255, 0);

mLinePaintBad = new Paint();

mLinePaintBad.setAntiAlias(true);

mLinePaintBad.setARGB(255, 120, 180, 0);

mScratchRect = new RectF(0, 0, 0, 0);

mWinsInARow = 0;

mDifficulty = DIFFICULTY_MEDIUM;

// initial show-up of lander (not yet playing)

mX = mLanderWidth;

mY = mLanderHeight * 2;

mFuel = PHYS_FUEL_INIT;

mDX = 0;

mDY = 0;

mHeading = 0;

mEngineFiring = true;

}

/**

* Starts the game, setting parameters for the current difficulty.

*/

public void doStart() {

synchronized (mSurfaceHolder) {

// First set the game for Medium difficulty

mFuel = PHYS_FUEL_INIT;

mEngineFiring = false;

mGoalWidth = (int) (mLanderWidth * TARGET_WIDTH);

mGoalSpeed = TARGET_SPEED;

mGoalAngle = TARGET_ANGLE;

int speedInit = PHYS_SPEED_INIT;

// Adjust difficulty params for EASY/HARD

if (mDifficulty == DIFFICULTY_EASY) {

mFuel = mFuel * 3 / 2;

mGoalWidth = mGoalWidth * 4 / 3;

mGoalSpeed = mGoalSpeed * 3 / 2;

mGoalAngle = mGoalAngle * 4 / 3;

speedInit = speedInit * 3 / 4;

} else if (mDifficulty == DIFFICULTY_HARD) {

mFuel = mFuel * 7 / 8;

mGoalWidth = mGoalWidth * 3 / 4;

mGoalSpeed = mGoalSpeed * 7 / 8;

speedInit = speedInit * 4 / 3;

}

// pick a convenient initial location for the lander sprite

mX = mCanvasWidth / 2;

mY = mCanvasHeight - mLanderHeight / 2;

// start with a little random motion

mDY = Math.random() * -speedInit;

mDX = Math.random() * 2 * speedInit - speedInit;

mHeading = 0;

// Figure initial spot for landing, not too near center

while (true) {

mGoalX = (int) (Math.random() * (mCanvasWidth - mGoalWidth));

if (Math.abs(mGoalX - (mX - mLanderWidth / 2)) > mCanvasHeight / 6)

break;

}

mLastTime = System.currentTimeMillis() + 100;

setState(STATE_RUNNING);

}

}

/**

* Pauses the physics update & animation.

*/

public void pause() {

synchronized (mSurfaceHolder) {

if (mMode == STATE_RUNNING) setState(STATE_PAUSE);

}

}

/**

* Restores game state from the indicated Bundle. Typically called when

* the Activity is being restored after having been previously

* destroyed.

*

* @param savedState Bundle containing the game state

*/

public synchronized void restoreState(Bundle savedState) {

synchronized (mSurfaceHolder) {

setState(STATE_PAUSE);

mRotating = 0;

mEngineFiring = false;

mDifficulty = savedState.getInt(KEY_DIFFICULTY);

mX = savedState.getDouble(KEY_X);

mY = savedState.getDouble(KEY_Y);

mDX = savedState.getDouble(KEY_DX);

mDY = savedState.getDouble(KEY_DY);

mHeading = savedState.getDouble(KEY_HEADING);

mLanderWidth = savedState.getInt(KEY_LANDER_WIDTH);

mLanderHeight = savedState.getInt(KEY_LANDER_HEIGHT);

mGoalX = savedState.getInt(KEY_GOAL_X);

mGoalSpeed = savedState.getInt(KEY_GOAL_SPEED);

mGoalAngle = savedState.getInt(KEY_GOAL_ANGLE);

mGoalWidth = savedState.getInt(KEY_GOAL_WIDTH);

mWinsInARow = savedState.getInt(KEY_WINS);

mFuel = savedState.getDouble(KEY_FUEL);

}

}

@Override

public void run() {

while (mRun) {

Canvas c = null;

try {

c = mSurfaceHolder.lockCanvas(null);

synchronized (mSurfaceHolder) {

if (mMode == STATE_RUNNING) updatePhysics();

doDraw(c);

}

} finally {

// do this in a finally so that if an exception is thrown

// during the above, we don't leave the Surface in an

// inconsistent state

if (c != null) {

mSurfaceHolder.unlockCanvasAndPost(c);

}

}

}

}

/**

* Dump game state to the provided Bundle. Typically called when the

* Activity is being suspended.

*

* @return Bundle with this view's state

*/

public Bundle saveState(Bundle map) {

synchronized (mSurfaceHolder) {

if (map != null) {

map.putInt(KEY_DIFFICULTY, Integer.valueOf(mDifficulty));

map.putDouble(KEY_X, Double.valueOf(mX));

map.putDouble(KEY_Y, Double.valueOf(mY));

map.putDouble(KEY_DX, Double.valueOf(mDX));

map.putDouble(KEY_DY, Double.valueOf(mDY));

map.putDouble(KEY_HEADING, Double.valueOf(mHeading));

map.putInt(KEY_LANDER_WIDTH, Integer.valueOf(mLanderWidth));

map.putInt(KEY_LANDER_HEIGHT, Integer

.valueOf(mLanderHeight));

map.putInt(KEY_GOAL_X, Integer.valueOf(mGoalX));

map.putInt(KEY_GOAL_SPEED, Integer.valueOf(mGoalSpeed));

map.putInt(KEY_GOAL_ANGLE, Integer.valueOf(mGoalAngle));

map.putInt(KEY_GOAL_WIDTH, Integer.valueOf(mGoalWidth));

map.putInt(KEY_WINS, Integer.valueOf(mWinsInARow));

map.putDouble(KEY_FUEL, Double.valueOf(mFuel));

}

}

return map;

}

/**

* Sets the current difficulty.

*

* @param difficulty

*/

public void setDifficulty(int difficulty) {

synchronized (mSurfaceHolder) {

mDifficulty = difficulty;

}

}

/**

* Sets if the engine is currently firing.

*/

public void setFiring(boolean firing) {

synchronized (mSurfaceHolder) {

mEngineFiring = firing;

}

}

/**

* Used to signal the thread whether it should be running or not.

* Passing true allows the thread to run; passing false will shut it

* down if it's already running. Calling start() after this was most

* recently called with false will result in an immediate shutdown.

*

* @param b true to run, false to shut down

*/

public void setRunning(boolean b) {

mRun = b;

}

/**

* Sets the game mode. That is, whether we are running, paused, in the

* failure state, in the victory state, etc.

*

* @see #setState(int, CharSequence)

* @param mode one of the STATE_* constants

*/

public void setState(int mode) {

synchronized (mSurfaceHolder) {

setState(mode, null);

}

}

/**

* Sets the game mode. That is, whether we are running, paused, in the

* failure state, in the victory state, etc.

*

* @param mode one of the STATE_* constants

* @param message string to add to screen or null

*/

public void setState(int mode, CharSequence message) {

/*

* This method optionally can cause a text message to be displayed

* to the user when the mode changes. Since the View that actually

* renders that text is part of the main View hierarchy and not

* owned by this thread, we can't touch the state of that View.

* Instead we use a Message + Handler to relay commands to the main

* thread, which updates the user-text View.

*/

synchronized (mSurfaceHolder) {

mMode = mode;

if (mMode == STATE_RUNNING) {

Message msg = mHandler.obtainMessage();

Bundle b = new Bundle();

b.putString("text", "");

b.putInt("viz", View.INVISIBLE);

msg.setData(b);

mHandler.sendMessage(msg);

} else {

mRotating = 0;

mEngineFiring = false;

Resources res = mContext.getResources();

CharSequence str = "";

if (mMode == STATE_READY)

str = res.getText(R.string.mode_ready);

else if (mMode == STATE_PAUSE)

str = res.getText(R.string.mode_pause);

else if (mMode == STATE_LOSE)

str = res.getText(R.string.mode_lose);

else if (mMode == STATE_WIN)

str = res.getString(R.string.mode_win_prefix)

+ mWinsInARow + " "

+ res.getString(R.string.mode_win_suffix);

if (message != null) {

str = message + "\n" + str;

}

if (mMode == STATE_LOSE) mWinsInARow = 0;

Message msg = mHandler.obtainMessage();

Bundle b = new Bundle();

b.putString("text", str.toString());

b.putInt("viz", View.VISIBLE);

msg.setData(b);

mHandler.sendMessage(msg);

}

}

}

/* Callback invoked when the surface dimensions change. */

public void setSurfaceSize(int width, int height) {

// synchronized to make sure these all change atomically

synchronized (mSurfaceHolder) {

mCanvasWidth = width;

mCanvasHeight = height;

// don't forget to resize the background image

mBackgroundImage = mBackgroundImage.createScaledBitmap(

mBackgroundImage, width, height, true);

}

}

/**

* Resumes from a pause.

*/

public void unpause() {

// Move the real time clock up to now

synchronized (mSurfaceHolder) {

mLastTime = System.currentTimeMillis() + 100;

}

setState(STATE_RUNNING);

}

/**

* Handles a key-down event.

*

* @param keyCode the key that was pressed

* @param msg the original event object

* @return true

*/

boolean doKeyDown(int keyCode, KeyEvent msg) {

synchronized (mSurfaceHolder) {

boolean okStart = false;

if (keyCode == KeyEvent.KEYCODE_DPAD_UP) okStart = true;

if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) okStart = true;

if (keyCode == KeyEvent.KEYCODE_S) okStart = true;

boolean center = (keyCode == KeyEvent.KEYCODE_DPAD_UP);

if (okStart

&& (mMode == STATE_READY || mMode == STATE_LOSE || mMode == STATE_WIN)) {

// ready-to-start -> start

doStart();

return true;

} else if (mMode == STATE_PAUSE && okStart) {

// paused -> running

unpause();

return true;

} else if (mMode == STATE_RUNNING) {

// center/space -> fire

if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER

|| keyCode == KeyEvent.KEYCODE_SPACE) {

setFiring(true);

return true;

// left/q -> left

} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT

|| keyCode == KeyEvent.KEYCODE_Q) {

mRotating = -1;

return true;

// right/w -> right

} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT

|| keyCode == KeyEvent.KEYCODE_W) {

mRotating = 1;

return true;

// up -> pause

} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {

pause();

return true;

}

}

return false;

}

}

/**

* Handles a key-up event.

*

* @param keyCode the key that was pressed

* @param msg the original event object

* @return true if the key was handled and consumed, or else false

*/

boolean doKeyUp(int keyCode, KeyEvent msg) {

boolean handled = false;

synchronized (mSurfaceHolder) {

if (mMode == STATE_RUNNING) {

if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER

|| keyCode == KeyEvent.KEYCODE_SPACE) {

setFiring(false);

handled = true;

} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT

|| keyCode == KeyEvent.KEYCODE_Q

|| keyCode == KeyEvent.KEYCODE_DPAD_RIGHT

|| keyCode == KeyEvent.KEYCODE_W) {

mRotating = 0;

handled = true;

}

}

}

return handled;

}

/**

* Draws the ship, fuel/speed bars, and background to the provided

* Canvas.

*/

private void doDraw(Canvas canvas) {

// Draw the background image. Operations on the Canvas accumulate

// so this is like clearing the screen.

canvas.drawBitmap(mBackgroundImage, 0, 0, null);

int yTop = mCanvasHeight - ((int) mY + mLanderHeight / 2);

int xLeft = (int) mX - mLanderWidth / 2;

// Draw the fuel gauge

int fuelWidth = (int) (UI_BAR * mFuel / PHYS_FUEL_MAX);

mScratchRect.set(4, 4, 4 + fuelWidth, 4 + UI_BAR_HEIGHT);

canvas.drawRect(mScratchRect, mLinePaint);

// Draw the speed gauge, with a two-tone effect

double speed = Math.sqrt(mDX * mDX + mDY * mDY);

int speedWidth = (int) (UI_BAR * speed / PHYS_SPEED_MAX);

if (speed <= mGoalSpeed) {

mScratchRect.set(4 + UI_BAR + 4, 4,

4 + UI_BAR + 4 + speedWidth, 4 + UI_BAR_HEIGHT);

canvas.drawRect(mScratchRect, mLinePaint);

} else {

// Draw the bad color in back, with the good color in front of

// it

mScratchRect.set(4 + UI_BAR + 4, 4,

4 + UI_BAR + 4 + speedWidth, 4 + UI_BAR_HEIGHT);

canvas.drawRect(mScratchRect, mLinePaintBad);

int goalWidth = (UI_BAR * mGoalSpeed / PHYS_SPEED_MAX);

mScratchRect.set(4 + UI_BAR + 4, 4, 4 + UI_BAR + 4 + goalWidth,

4 + UI_BAR_HEIGHT);

canvas.drawRect(mScratchRect, mLinePaint);

}

// Draw the landing pad

canvas.drawLine(mGoalX, 1 + mCanvasHeight - TARGET_PAD_HEIGHT,

mGoalX + mGoalWidth, 1 + mCanvasHeight - TARGET_PAD_HEIGHT,

mLinePaint);

// Draw the ship with its current rotation

canvas.save();

canvas.rotate((float) mHeading, (float) mX, mCanvasHeight

- (float) mY);

if (mMode == STATE_LOSE) {

mCrashedImage.setBounds(xLeft, yTop, xLeft + mLanderWidth, yTop

+ mLanderHeight);

mCrashedImage.draw(canvas);

} else if (mEngineFiring) {

mFiringImage.setBounds(xLeft, yTop, xLeft + mLanderWidth, yTop

+ mLanderHeight);

mFiringImage.draw(canvas);

} else {

mLanderImage.setBounds(xLeft, yTop, xLeft + mLanderWidth, yTop

+ mLanderHeight);

mLanderImage.draw(canvas);

}

canvas.restore();

}

/**

* Figures the lander state (x, y, fuel, ...) based on the passage of

* realtime. Does not invalidate(). Called at the start of draw().

* Detects the end-of-game and sets the UI to the next state.

*/

private void updatePhysics() {

long now = System.currentTimeMillis();

// Do nothing if mLastTime is in the future.

// This allows the game-start to delay the start of the physics

// by 100ms or whatever.

if (mLastTime > now) return;

double elapsed = (now - mLastTime) / 1000.0;

// mRotating -- update heading

if (mRotating != 0) {

mHeading += mRotating * (PHYS_SLEW_SEC * elapsed);

// Bring things back into the range 0..360

if (mHeading < 0)

mHeading += 360;

else if (mHeading >= 360) mHeading -= 360;

}

// Base accelerations -- 0 for x, gravity for y

double ddx = 0.0;

double ddy = -PHYS_DOWN_ACCEL_SEC * elapsed;

if (mEngineFiring) {

// taking 0 as up, 90 as to the right

// cos(deg) is ddy component, sin(deg) is ddx component

double elapsedFiring = elapsed;

double fuelUsed = elapsedFiring * PHYS_FUEL_SEC;

// tricky case where we run out of fuel partway through the

// elapsed

if (fuelUsed > mFuel) {

elapsedFiring = mFuel / fuelUsed * elapsed;

fuelUsed = mFuel;

// Oddball case where we adjust the "control" from here

mEngineFiring = false;

}

mFuel -= fuelUsed;

// have this much acceleration from the engine

double accel = PHYS_FIRE_ACCEL_SEC * elapsedFiring;

double radians = 2 * Math.PI * mHeading / 360;

ddx = Math.sin(radians) * accel;

ddy += Math.cos(radians) * accel;

}

double dxOld = mDX;

double dyOld = mDY;

// figure speeds for the end of the period

mDX += ddx;

mDY += ddy;

// figure position based on average speed during the period

mX += elapsed * (mDX + dxOld) / 2;

mY += elapsed * (mDY + dyOld) / 2;

mLastTime = now;

// Evaluate if we have landed ... stop the game

double yLowerBound = TARGET_PAD_HEIGHT + mLanderHeight / 2

- TARGET_BOTTOM_PADDING;

if (mY <= yLowerBound) {

mY = yLowerBound;

int result = STATE_LOSE;

CharSequence message = "";

Resources res = mContext.getResources();

double speed = Math.sqrt(mDX * mDX + mDY * mDY);

boolean onGoal = (mGoalX <= mX - mLanderWidth / 2 && mX

+ mLanderWidth / 2 <= mGoalX + mGoalWidth);

// "Hyperspace" win -- upside down, going fast,

// puts you back at the top.

if (onGoal && Math.abs(mHeading - 180) < mGoalAngle

&& speed > PHYS_SPEED_HYPERSPACE) {

result = STATE_WIN;

mWinsInARow++;

doStart();

return;

// Oddball case: this case does a return, all other cases

// fall through to setMode() below.

} else if (!onGoal) {

message = res.getText(R.string.message_off_pad);

} else if (!(mHeading <= mGoalAngle || mHeading >= 360 - mGoalAngle)) {

message = res.getText(R.string.message_bad_angle);

} else if (speed > mGoalSpeed) {

message = res.getText(R.string.message_too_fast);

} else {

result = STATE_WIN;

mWinsInARow++;

}

setState(result, message);

}

}

}

/** Handle to the application context, used to e.g. fetch Drawables. */

private Context mContext;

/** Pointer to the text view to display "Paused.." etc. */

private TextView mStatusText;

/** The thread that actually draws the animation */

private LunarThread thread;

public LunarView(Context context, AttributeSet attrs) {

super(context, attrs);

// register our interest in hearing about changes to our surface

SurfaceHolder holder = getHolder();

holder.addCallback(this);

// create thread only; it's started in surfaceCreated()

thread = new LunarThread(holder, context, new Handler() {

@Override

public void handleMessage(Message m) {

mStatusText.setVisibility(m.getData().getInt("viz"));

mStatusText.setText(m.getData().getString("text"));

}

});

setFocusable(true); // make sure we get key events

}

/**

* Fetches the animation thread corresponding to this LunarView.

*

* @return the animation thread

*/

public LunarThread getThread() {

return thread;

}

/**

* Standard override to get key-press events.

*/

@Override

public boolean onKeyDown(int keyCode, KeyEvent msg) {

return thread.doKeyDown(keyCode, msg);

}

/**

* Standard override for key-up. We actually care about these, so we can

* turn off the engine or stop rotating.

*/

@Override

public boolean onKeyUp(int keyCode, KeyEvent msg) {

return thread.doKeyUp(keyCode, msg);

}

/**

* Standard window-focus override. Notice focus lost so we can pause on

* focus lost. e.g. user switches to take a call.

*/

@Override

public void onWindowFocusChanged(boolean hasWindowFocus) {

if (!hasWindowFocus) thread.pause();

}

/**

* Installs a pointer to the text view used for messages.

*/

public void setTextView(TextView textView) {

mStatusText = textView;

}

/* Callback invoked when the surface dimensions change. */

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

thread.setSurfaceSize(width, height);

}

/*

* Callback invoked when the Surface has been created and is ready to be

* used.

*/

public void surfaceCreated(SurfaceHolder holder) {

// start the thread here so that we don't busy-wait in run()

// waiting for the surface to be created

thread.setRunning(true);

thread.start();

}

/*

* Callback invoked when the Surface has been destroyed and must no longer

* be touched. WARNING: after this method returns, the Surface/Canvas must

* never be touched again!

*/

public void surfaceDestroyed(SurfaceHolder holder) {

// we have to tell thread to shut down & wait for it to finish, or else

// it might touch the Surface after we return and explode

boolean retry = true;

thread.setRunning(false);

while (retry) {

try {

thread.join();

retry = false;

} catch (InterruptedException e) {

}

}

}

}

赞助本站

人工智能实验室

相关热词: SurfaceView

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港