📄 lunarview.java
字号:
if (speed <= mGoalSpeed) { mScratchRect.set(4 + BAR + 4, 4, 4 + BAR + 4 + speedWidth, 4 + BAR_HEIGHT); canvas.drawRect(mScratchRect, mLinePaint); } else { // Draw the bad color in back, with the good color in front of it mScratchRect.set(4 + BAR + 4, 4, 4 + BAR + 4 + speedWidth, 4 + BAR_HEIGHT); canvas.drawRect(mScratchRect, mLinePaintBad); int goalWidth = (BAR * mGoalSpeed / SPEED_MAX); mScratchRect.set(4 + BAR + 4, 4, 4 + BAR + 4 + goalWidth, 4 + BAR_HEIGHT); canvas.drawRect(mScratchRect, mLinePaint); } // Draw the landing pad canvas.drawLine(mGoalX, 1 + screenHeight - PAD_HEIGHT, mGoalX + mGoalWidth, 1 + screenHeight - PAD_HEIGHT, mLinePaint); // Draw the ship with its current rotation canvas.save(); canvas.rotate((float)mHeading, (float)mX, screenHeight - (float)mY); if (mMode == 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); } /* * Our animation strategy is that each draw() does an invalidate(), * so we get a series of draws. This is a known animation strategy * within Android, and the system throttles the draws down to match * the refresh rate. */ if (mMode == RUNNING) { // Invalidate a space around the current lander + the bars at the top. // Note: invalidating a relatively small part of the screen to draw // is a good optimization. In this case, the bars and the ship // may be far apart, limiting the value of the optimization. invalidate(xLeft-20, yTop-20, xLeft+mLanderWidth+20, yTop+mLanderHeight+20); invalidate(0, 0, screenWidth, 4 + BAR_HEIGHT); } 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. */ public 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 * (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 = -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 * 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 = 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 = PAD_HEIGHT + mLanderHeight/2 - BOTTOM_PADDING; if (mY <= yLowerBound) { mY = yLowerBound; int result = LOSE; CharSequence message = ""; Resources res = getContext().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 > SPEED_HYPERSPACE) { result = 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 = WIN; mWinsInARow++; } setMode(result, message); } } /** * Sets if the engine is currently firing. */ public void setFiring(boolean firing) { mEngineFiring = firing; } /** * Sets the game mode, RUNNING, PAUSED, etc. * @param mode RUNNING, PAUSED, ... */ public void setMode(int mode) { setMode(mode, null); } /** * Sets the game mode, RUNNING, PAUSED, etc. * @param mode RUNNING, PAUSED, ... * @param message string to add to screen or null */ public void setMode(int mode, CharSequence message) { mMode = mode; invalidate(); if (mMode == RUNNING) { mStatusText.setVisibility(View.INVISIBLE); } else { mRotating = 0; mEngineFiring = false; Resources res = getContext().getResources(); CharSequence str = ""; if (mMode == READY) str = res.getText(R.string.mode_ready); else if (mMode == PAUSE) str = res.getText(R.string.mode_pause); else if (mMode == LOSE) str = res.getText(R.string.mode_lose); else if (mMode == 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 == LOSE) mWinsInARow = 0; mStatusText.setText(str); mStatusText.setVisibility(View.VISIBLE); } } /** * Starts the game, setter parameters for the current * difficulty. */ public void doStart() { // First set the game for Medium difficulty mFuel = FUEL_INIT; mEngineFiring = false; mGoalWidth = (int) (mLanderWidth * TARGET_WIDTH); mGoalSpeed = TARGET_SPEED; mGoalAngle = TARGET_ANGLE; //mGoalAngle = TARGET_ANGLE; int speedInit = SPEED_INIT; // Adjust difficulty params for EASY/HARD if (mDifficulty == EASY) { mFuel = mFuel * 3 / 2; mGoalWidth = mGoalWidth * 4 / 3; mGoalSpeed = mGoalSpeed * 3 / 2; mGoalAngle = mGoalAngle * 4 / 3; speedInit = speedInit * 3 / 4; } else if (mDifficulty == HARD) { mFuel = mFuel * 7 / 8; mGoalWidth = mGoalWidth * 3 / 4; mGoalSpeed = mGoalSpeed * 7 / 8; speedInit = speedInit * 4 / 3; } mX = getWidth()/2; mY = getHeight() - 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() * (getWidth() - mGoalWidth)); if (Math.abs(mGoalX - (mX - mLanderWidth/2)) > getWidth()/6) break; } mLastTime = System.currentTimeMillis() + 100; setMode(RUNNING); } /** * Resumes from a pause. */ public void doResume() { // Move the real time clock up to now mLastTime = System.currentTimeMillis() + 100; setMode(RUNNING); } /** * Pauses from the running state. */ public void doPause() { if (mMode == RUNNING) setMode(PAUSE); } /** * Standard override to get key events. */ @Override public boolean onKeyDown(int keyCode, KeyEvent msg) { boolean handled = false; boolean okStart = keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_S; boolean center = keyCode == KeyEvent.KEYCODE_DPAD_UP; // ready-to-start -> start if (okStart && (mMode == READY || mMode == LOSE || mMode == WIN)) { doStart(); handled = true; } // paused -> running else if (mMode == PAUSE && okStart) { doResume(); handled = true; } else if (mMode == RUNNING) { // center/space -> fire if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_SPACE) { setFiring(true); handled = true; // left/q -> left } else if (keyCode==KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_Q) { mRotating = -1; handled = true; // right/w -> right } else if (keyCode==KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_W) { mRotating = 1; handled = true; // up -> pause } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { doPause(); handled = true; } } return handled; } /** * 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) { boolean handled = false; if (mMode == 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; } /** * Sets the current difficulty. * @param difficulty */ public void setDifficulty(int difficulty) { mDifficulty = difficulty; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -