Cyh的博客

          Email:kissyan4916@163.com
          posts - 26, comments - 19, trackbacks - 0, articles - 220

          Android游戲開發之旅(八)SurfaceView類實例

          Posted on 2010-12-03 10:21 啥都寫點 閱讀(371) 評論(0)  編輯  收藏 所屬分類: Android

          有關SurfaceView 我們將通過三個系統 自帶的例子 來深入掌握Android繪圖必會的SurfaceView,今天我們以SDK中的Sample 游戲 lunarlander中的LunarView具體實現,Android123建議大家導入該游戲工程到你的Eclipse 然后自己編譯 先玩一下這個游戲,然后再看代碼 比較好理解。

          view plaincopy to clipboardprint?
          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);  
                      }  
                  } 

           

          本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/JavaTiger427/archive/2010/11/25/6034565.aspx



                                                                                                                 --    學海無涯
                  

          主站蜘蛛池模板: 周宁县| 华坪县| 杭锦旗| 义马市| 清流县| 金寨县| 哈巴河县| 六安市| 视频| 含山县| 城固县| 苍山县| 永城市| 兰坪| 南木林县| 奉贤区| 梨树县| 辽阳县| 莎车县| 九龙城区| 洪泽县| 莱州市| 靖宇县| 和政县| 哈密市| 龙州县| 昌乐县| 莫力| 军事| 常宁市| 尉氏县| 白银市| 玛曲县| 龙游县| 凌云县| 通榆县| 辰溪县| 大荔县| 河间市| 淮滨县| 昆明市|