📄 lunarview.java
字号:
|| 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) { } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -