Android游戏开发中SurfaceView类的应用实例分析

本篇文章给大家分享的是有关Android游戏开发中SurfaceView类的应用实例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

大家可以把此工程导入到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) {                }            }        }    }

以上就是Android游戏开发中SurfaceView类的应用实例分析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。