最近突然有了一個想法--做一款android的簡單遊戲練練手,既要實現起來簡單(畢竟只有一個人,框架什麼的暫且就不用考慮了),又要能夠達到對android知識框架的複習和遊戲要有可玩性,終於用了幾個星期寫完了。和大家分享分享體會吧。
本來打算寫一個專欄的。看以後的時間吧。
首先介紹一下游戲的主要思想和SurfaceView也就是遊戲主界面的代碼分享,後續部分再更新吧。
在點擊 開始遊戲 後,進行組合數字的選擇,根據難易程度系統默認選擇2和8,選擇界面中間顯示選擇的組合數字,第一個數字表示第一個組合數字,
即在遊戲過程中能被整除的那個數字,第二個數字表示第二個組合數字,即在遊戲過程中不能被整除的那個數字。選擇結束後開始遊戲。
在遊戲準備完成後開始遊戲,隨機下落一定範圍內的數字,判斷該數字是否被第一個組合數字整除而不能被第二個數字整除,若是,點擊該數字,分數加上對應值,否則分數減去對應值。
下落數字的範圍會隨着等級的提升變大。下落速度和數字的產生速度也爲隨之加快。當分數小於0或錯過的正確值大於5時遊戲結束!
截圖
1.遊戲主界面activity
package com.gymyang.number.views;
import android.graphics.BitmapFactory;
import android.view.KeyEvent;
import android.view.View;
import com.gymyang.number.BaseActivity;
import com.gymyang.number.R;
import com.gymyang.number.utils.DeviceTools;
import com.gymyang.number.utils.GlobalFields;
/**
* Class Name: NumberGameActivity.java
* Function:
* 主邏輯activity
* Modifications:
*
* @author Administrator
* @DateTime 2014-11-11 下午8:09:55
* @version 1.0
*/
public class NumberGameActivity extends BaseActivity
{
private GameView gameView;
// private TextView noticeTx;
@Override
protected void initView()
{
loadResource();
// setContentView(R.layout.game_view);
// gameView = (GameView) findViewById(R.id.game_view_main);
// noticeTx = (TextView) findViewById(R.id.game_view_notice);
gameView = new GameView(this,this);
setContentView(gameView);
}
/**
* Function:
* 加載資源
* @author Administrator
* @DateTime 2014-11-12 上午9:22:40
*/
private void loadResource()
{
GlobalFields.DEVICE_WIDTH = DeviceTools.getDeviceInfo(this)[0];
GlobalFields.DEVICE_HEIGHT = DeviceTools.getDeviceInfo(this)[1];
GlobalFields.BG_GRAY = BitmapFactory.decodeResource(getResources(), R.drawable.number_bg_gray);
GlobalFields.BG_GREEN = BitmapFactory.decodeResource(getResources(), R.drawable.number_bg_green);
GlobalFields.BG_WHITE = BitmapFactory.decodeResource(getResources(), R.drawable.number_bg_white);
GlobalFields.BG_RED = BitmapFactory.decodeResource(getResources(), R.drawable.number_bg_red);
GlobalFields.NUMBER_1 = BitmapFactory.decodeResource(getResources(), R.drawable.num1);
GlobalFields.NUMBER_2 = BitmapFactory.decodeResource(getResources(), R.drawable.num2);
GlobalFields.NUMBER_3 = BitmapFactory.decodeResource(getResources(), R.drawable.num3);
GlobalFields.PAUSE_BG = BitmapFactory.decodeResource(getResources(), R.drawable.pause_bg);
GlobalFields.PAUSE_BTNBG = BitmapFactory.decodeResource(getResources(), R.drawable.pause_button_bg);
GlobalFields.scaleWidth = GlobalFields.DEVICE_WIDTH / (float)GlobalFields.BG_GRAY.getWidth();
GlobalFields.scaleHeight = GlobalFields.DEVICE_HEIGHT / (float)GlobalFields.BG_GRAY.getHeight();
GlobalFields.BG_GRAY = DeviceTools.resizeBitmap(GlobalFields.BG_GRAY);
GlobalFields.PAUSE_BG = DeviceTools.resizeBitmap(GlobalFields.PAUSE_BG,
GlobalFields.DEVICE_WIDTH / 5 *4, GlobalFields.DEVICE_HEIGHT / 4);
GlobalFields.PAUSE_BTNBG = DeviceTools.resizeBitmap(GlobalFields.PAUSE_BTNBG,
GlobalFields.DEVICE_WIDTH / 5 *2 - 10,GlobalFields.PAUSE_BG.getHeight() / 4);
}
@Override
protected void setListener()
{
}
@Override
protected void logicWork()
{
}
@Override
public void onClick(View v)
{
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode == KeyEvent.KEYCODE_BACK){
if(gameView.CURRENT_STATE == gameView.PREPARE_FINISH){
gameView.CURRENT_STATE = gameView.GAME_PAUSE;
}
//MyWindowManager.showErrorDialog(getBaseContext(), "遊戲暫停!");
return true;
}
return super.onKeyDown(keyCode, event);
}
}
2.遊戲主界面SurfaceView具體實現
package com.gymyang.number.views;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.Align;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.gymyang.number.sprite.BaseSprite;
import com.gymyang.number.sprite.LevelText;
import com.gymyang.number.sprite.NumberBlock;
import com.gymyang.number.sprite.NumberBlockManager;
import com.gymyang.number.sprite.ScoreText;
import com.gymyang.number.sprite.StateBar;
import com.gymyang.number.sprite.TouchAble;
import com.gymyang.number.utils.DeviceTools;
import com.gymyang.number.utils.GlobalFields;
import com.gymyang.number.utils.LevelManager;
/**
* Class Name: GameView.java
* Function:
* 大管家
* Modifications:
*
* @author Administrator
* @DateTime 2014-11-11 下午10:36:53
* @version 1.0
*/
public class GameView extends SurfaceView implements SurfaceHolder.Callback, Runnable
{
/** GameView單例存在 */
private static GameView gameView;
public static GameView getInstance(){
return gameView;
}
private NumberGameActivity activity;
private SurfaceHolder surfaceHolder;
private Paint paint;
// 遊戲進行狀態
private boolean flag = true;
private Canvas canvas;
/** 格子寬度 */
public int BLOCK_WIDTH;
/** 格子高度 */
public int BLOCK_HEIGHT;
/** 準備開始 */
private final int PREPARE_START = 200;
/** 準備完成*/
public final int PREPARE_FINISH = 201;
/** 遊戲結束 */
private final int GAME_OVER = 202;
/** 暫停 */
public final int GAME_PAUSE = 203;
/** 當前進度狀態 */
public int CURRENT_STATE = PREPARE_START;
/**
* 格子對象集合
*/
private LinkedList<BaseSprite> blockSprites;
/** 死掉了的精靈 */
private List<BaseSprite> deadSprites;
/** 數字格子管理 */
private NumberBlockManager numberBlockManager;
private StateBar stateBar;
private float dp = 1;
public GameView(Context context,NumberGameActivity activity)
{
super(context);
this.activity = activity;
paint = new Paint();
getHolder().addCallback(this);
surfaceHolder = getHolder();
gameView = this;
GlobalFields.dp = DeviceTools.getScreenDensity(context);
dp = GlobalFields.dp;
}
public GameView(Context context)
{
super(context);
paint = new Paint();
getHolder().addCallback(this);
surfaceHolder = getHolder();
gameView = this;
GlobalFields.dp = DeviceTools.getScreenDensity(context);
dp = GlobalFields.dp;
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
paint.setColor(Color.WHITE);
paint.setTextSize(30*dp);
GlobalFields.SCORE = 0;
LevelManager.initChildren();
BLOCK_WIDTH = GlobalFields.DEVICE_WIDTH / GlobalFields.CURRENT_COLUMNS;
BLOCK_HEIGHT = GlobalFields.DEVICE_HEIGHT / GlobalFields.CURRENT_LINES;
blockSprites = new LinkedList<BaseSprite>();
deadSprites = new ArrayList<BaseSprite>();
numberBlockManager = new NumberBlockManager();
stateBar = new StateBar();
resetBitmap();
new Thread(this){}.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height)
{}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{}
/**
* Function:
* 拉伸格子背景資源
* @author Administrator
* @DateTime 2014-11-12 下午2:57:30
*/
private void resetBitmap()
{
GlobalFields.BG_GREEN = DeviceTools.resizeBitmap(GlobalFields.BG_GREEN,BLOCK_WIDTH,BLOCK_HEIGHT);
GlobalFields.BG_RED = DeviceTools.resizeBitmap(GlobalFields.BG_RED,BLOCK_WIDTH,BLOCK_HEIGHT);
GlobalFields.BG_WHITE = DeviceTools.resizeBitmap(GlobalFields.BG_WHITE,BLOCK_WIDTH,BLOCK_HEIGHT);
}
@Override
public void run()
{
while (flag) {
synchronized (surfaceHolder) {
try {
canvas = surfaceHolder.lockCanvas();
canvas.drawBitmap(GlobalFields.BG_GRAY, 0, 0, paint);
updateState();
ondraw(canvas);
} catch (Exception e) {
// TODO: handle exception
} finally {
if(canvas != null){
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Function:
* 更新狀態
* @author Administrator
* @DateTime 2014-11-12 下午3:37:47
*/
private void updateState()
{
deadSprites.clear();
for(BaseSprite sprite : blockSprites){
if(!sprite.isAlive()){
deadSprites.add(sprite);
}
}
blockSprites.removeAll(deadSprites);
}
/**
* Function:
*
* @author Administrator
* @DateTime 2014-11-11 下午11:31:45
* @param canvas2
*/
private void ondraw(Canvas canvas)
{
if(CURRENT_STATE == PREPARE_START){
drawDevideLines(canvas);
}else if(CURRENT_STATE == PREPARE_FINISH){
drawDevideLines(canvas);
// 繪製數字格子
numberBlockManager.drawSelf(canvas, paint);
for(BaseSprite sprite : blockSprites){
sprite.drawSelf(canvas, paint);
}
// 繪製狀態欄
drawStateBar(canvas);
if(GlobalFields.MISSED < 0 || GlobalFields.SCORE < 0){
CURRENT_STATE = GAME_OVER;
}
}else if(CURRENT_STATE == GAME_PAUSE){
// TODO 遊戲暫停
drawPause(canvas);
//canvas.drawText("遊戲暫停", GlobalFields.DEVICE_WIDTH / 2 -20, GlobalFields.DEVICE_HEIGHT / 2 -20, paint);
}else if(CURRENT_STATE == GAME_OVER){
// TODO 遊戲結束
drawGameOver(canvas);
}
}
private int overHeight = 0;
/**
* Function:
* 遊戲結束
* @author Administrator
* @DateTime 2014-11-16 下午2:36:52
*/
private void drawGameOver(Canvas canvas){
int preColor = paint.getColor();
float textSize = paint.getTextSize();
Align preTextStyle = paint.getTextAlign();
paint.setColor(Color.RED);
paint.setTextSize(32*dp);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("Game Over !",GlobalFields.DEVICE_WIDTH / 2,
overHeight, paint);
paint.setColor(preColor);
paint.setTextSize(textSize);
paint.setTextAlign(preTextStyle);
if(overHeight < GlobalFields.DEVICE_HEIGHT / 2){
overHeight += 50;
}else if(overHeight >= GlobalFields.DEVICE_HEIGHT / 2 &&
overHeight < GlobalFields.DEVICE_HEIGHT / 2 + 20){
overHeight += 5;
}else if(overHeight >= GlobalFields.DEVICE_HEIGHT / 2 + 20 &&
overHeight < GlobalFields.DEVICE_HEIGHT){
overHeight += 50;
}else if(overHeight >= GlobalFields.DEVICE_HEIGHT){
// TODO 回到主界面
flag = false;
activity.finish();
}
}
private int pauseHeight = 0;
private int pauseWidth = (GlobalFields.DEVICE_WIDTH - GlobalFields.PAUSE_BG.getWidth()) / 2;
private int pauseTextHeight = pauseHeight + (GlobalFields.PAUSE_BG.getHeight() -
GlobalFields.PAUSE_BTNBG.getHeight());
/** 退出遊戲 觸摸區域 */
private Rect exitTouchArea;
/** 繼續遊戲 觸摸區域 */
private Rect goonTouchArea;
/**
* Function:
* 繪製暫停狀態
* @author Administrator
* @DateTime 2014-11-16 下午1:33:12
*/
private void drawPause(Canvas canvas){
if(exitTouchArea != null){
exitTouchArea = null;
}
if(goonTouchArea != null){
goonTouchArea = null;
}
exitTouchArea = new Rect(pauseWidth + 5, (pauseHeight +pauseTextHeight - 5),
(pauseWidth + 5) + GlobalFields.PAUSE_BTNBG.getWidth(),
(pauseHeight +pauseTextHeight - 5) + GlobalFields.PAUSE_BTNBG.getHeight());
goonTouchArea = new Rect((pauseWidth + GlobalFields.PAUSE_BG.getWidth() / 2 + 5),
(pauseHeight +pauseTextHeight - 5),
(pauseWidth + GlobalFields.PAUSE_BG.getWidth() / 2 + 5) + GlobalFields.PAUSE_BTNBG.getWidth(),
(pauseHeight +pauseTextHeight - 5) + GlobalFields.PAUSE_BTNBG.getHeight());
int preColor = paint.getColor();
float textSize = paint.getTextSize();
Align preTextStyle = paint.getTextAlign();
canvas.drawBitmap(GlobalFields.PAUSE_BG, pauseWidth, pauseHeight, paint);
canvas.drawBitmap(GlobalFields.PAUSE_BTNBG, pauseWidth + 5,
pauseHeight +pauseTextHeight - 5, paint);
canvas.drawBitmap(GlobalFields.PAUSE_BTNBG, pauseWidth + GlobalFields.PAUSE_BG.getWidth() / 2 + 5,
pauseHeight +pauseTextHeight - 5, paint);
paint.setColor(Color.BLUE);
paint.setTextSize(28*dp);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("遊戲暫停",pauseWidth + GlobalFields.PAUSE_BG.getWidth() / 2,
pauseHeight + GlobalFields.PAUSE_BG.getHeight() / 2, paint);
paint.setTextSize(18*dp);
canvas.drawText("返回菜單", pauseWidth + 5 + GlobalFields.PAUSE_BTNBG.getWidth() / 2,
pauseHeight +pauseTextHeight + GlobalFields.PAUSE_BTNBG.getHeight() / 2,
paint);
canvas.drawText("繼續遊戲",
pauseWidth + GlobalFields.PAUSE_BTNBG.getWidth()/2*3 + 5,
pauseHeight +pauseTextHeight + GlobalFields.PAUSE_BTNBG.getHeight() / 2, paint);
paint.setColor(preColor);
paint.setTextSize(textSize);
paint.setTextAlign(preTextStyle);
if(pauseHeight < GlobalFields.DEVICE_HEIGHT / 2 - GlobalFields.PAUSE_BG.getHeight() / 2){
pauseHeight += 60;
}
}
/**
* Function:
* 繪製狀態欄
* @author Administrator
* @DateTime 2014-11-12 下午7:50:30
*/
private void drawStateBar(Canvas canvas)
{
stateBar.drawSelf(canvas, paint);
}
private boolean isAddNumber = false;
/**
* Function:
* 請求加入格子
* @author Administrator
* @DateTime 2014-11-12 下午3:22:09
*/
public void apply2AddNumber(){
synchronized (surfaceHolder) {
int raceWay = 0, number = 0;
raceWay = (int) (Math.random() * GlobalFields.CURRENT_COLUMNS);
number = (int) (Math.random() * GlobalFields.MAX_NUMBER + 1);
isAddNumber = false;
// TODO 添加數字格子
if(blockSprites.size() > 0){
// BaseSprite sprite = blockSprites.getLast();
for(int i=blockSprites.size()-1 ; i>0 ;i--){
BaseSprite sprite = blockSprites.get(i);
if(sprite.locationX == raceWay){
if(sprite.locationY > BLOCK_HEIGHT){
blockSprites.add(new NumberBlock(raceWay, number));
}
isAddNumber = true;
break;
}
}
if(!isAddNumber){
blockSprites.add(new NumberBlock(raceWay, number));
isAddNumber = true;
}
}else{
blockSprites.add(new NumberBlock(raceWay, number));
isAddNumber = true;
}
}
}
/**
* Function:
* 請求加入加分顯示
* @author Administrator
* @DateTime 2014-11-12 下午3:22:09
*/
public void apply2AddScoreText(int x,int y,String msg,int flag){
synchronized (surfaceHolder) {
// TODO 請求加入加分顯示
blockSprites.add(new ScoreText(x, y, msg, flag));
}
}
/**
* Function:
* 等級上升
* @author Administrator
* @DateTime 2014-11-13 下午12:07:36
*/
public void requestAddLevel()
{
synchronized (surfaceHolder) {
// TODO 請求加入加分顯示
blockSprites.add(new LevelText());
}
}
/**
* Function:
* 請求重新繪製格子
* @author Administrator
* @DateTime 2014-11-13 下午12:07:36
*/
public void requestReDraw()
{
BLOCK_WIDTH = GlobalFields.DEVICE_WIDTH / GlobalFields.CURRENT_COLUMNS;
BLOCK_HEIGHT = GlobalFields.DEVICE_HEIGHT / GlobalFields.CURRENT_LINES;
DRAW_DEVIDE_LINE = 1;
DRAW_DEVIDE_COLUMN = 1;
DRAW_TIME = 1;
i=1;j=1;k=1;SPACE=6;
GlobalFields.BG_WHITE = DeviceTools.resizeBitmap(GlobalFields.BG_WHITE, BLOCK_WIDTH, BLOCK_HEIGHT);
GlobalFields.BG_GREEN = DeviceTools.resizeBitmap(GlobalFields.BG_GREEN, BLOCK_WIDTH, BLOCK_HEIGHT);
GlobalFields.BG_RED = DeviceTools.resizeBitmap(GlobalFields.BG_RED, BLOCK_WIDTH, BLOCK_HEIGHT);
CURRENT_STATE = PREPARE_START;
}
/********************************** 傳遞觸摸事件 **************************************/
@Override
public boolean onTouchEvent(MotionEvent event)
{
if(CURRENT_STATE == GAME_PAUSE){
int x = (int) event.getX();
int y = (int) event.getY();
if (exitTouchArea.contains(x, y)) {
CURRENT_STATE = GAME_OVER;
pauseHeight = 0;
return true;
}
if(goonTouchArea.contains(x, y)){
CURRENT_STATE = PREPARE_FINISH;
pauseHeight = 0;
return true;
}
}else{
for (BaseSprite sprite : blockSprites) {
if (sprite instanceof TouchAble) {
if (((TouchAble) sprite).onTouch(event)) {
return true;
}
}
}
}
return false;
}
/******************************** 繪製分割線 ****************************************/
// 列分割線遊標
private int DRAW_DEVIDE_LINE = 1;
// 行分割線遊標
private int DRAW_DEVIDE_COLUMN = 1;
// 倒計時遊標
private int DRAW_TIME = 1;
// 行列遍歷 最大值
int i=1,j=1,k=1,SPACE=6;
/**
* Function:
* 繪製分割線
* @author Administrator
* @DateTime 2014-11-12 上午9:31:11
*/
private void drawDevideLines(Canvas canvas)
{
drawNotice();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.LTGRAY);
// 繪製列分割線
for(int x=1;x<=i;x++){
canvas.drawLine(BLOCK_WIDTH * x, 0, BLOCK_WIDTH * x, GlobalFields.DEVICE_HEIGHT, paint);
}
if(DRAW_DEVIDE_LINE % SPACE == 0){
i++;
}
if(i >= GlobalFields.CURRENT_COLUMNS){
// 迴歸i,j 避免溢出
i = GlobalFields.CURRENT_COLUMNS - 1;
}else{
DRAW_DEVIDE_LINE++;
}
// 繪製行分割線
if(DRAW_DEVIDE_LINE >= (GlobalFields.CURRENT_COLUMNS - 1)*SPACE){
for(int y=1;y<=j;y++){
canvas.drawLine(0, BLOCK_HEIGHT * y, GlobalFields.DEVICE_WIDTH, BLOCK_HEIGHT * y, paint);
}
if(DRAW_DEVIDE_COLUMN % SPACE == 0){
j++;
}
if(j >= GlobalFields.CURRENT_LINES){
// 迴歸i,j 避免溢出
j = GlobalFields.CURRENT_LINES - 1;
}else{
DRAW_DEVIDE_COLUMN++;
}
}
// 準備倒計時
if(DRAW_DEVIDE_COLUMN >= (GlobalFields.CURRENT_LINES - 1)*SPACE){
int left = GlobalFields.DEVICE_WIDTH / 2 - GlobalFields.NUMBER_1.getWidth() / 2;
int top = GlobalFields.DEVICE_HEIGHT / 2 - GlobalFields.NUMBER_1.getHeight() / 2;
if(k == 1){
canvas.drawBitmap(GlobalFields.NUMBER_3, left, top, paint);
}else if(k == 2){
canvas.drawBitmap(GlobalFields.NUMBER_2, left, top, paint);
}else if(k == 3){
canvas.drawBitmap(GlobalFields.NUMBER_1, left, top, paint);
CURRENT_STATE = PREPARE_FINISH;
}
if(DRAW_TIME % SPACE == 0){
k++;
}
if(k < 3){
DRAW_TIME++;
}
}
}
private int noticeHeight = GlobalFields.DEVICE_HEIGHT/4*3;
private void drawNotice(){
int preColor = paint.getColor();
float textSize = paint.getTextSize();
Align preTextStyle = paint.getTextAlign();
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(16*dp);
paint.setColor(Color.rgb(8, 103, 23));
canvas.drawText("點擊能被組合數字一:【"+GlobalFields.SENSETIVE_NUMBER+"】",
GlobalFields.DEVICE_WIDTH / 2,
noticeHeight, paint);
canvas.drawText("但不能被組合數字二: 【"+GlobalFields.SENSETIVE_NUMBER2+"】 的數",
GlobalFields.DEVICE_WIDTH / 2, noticeHeight+30, paint);
canvas.drawText("等級越高!速度越快!數字越大!",
GlobalFields.DEVICE_WIDTH / 2, noticeHeight+60, paint);
canvas.drawText("你準備好了嗎?",
GlobalFields.DEVICE_WIDTH / 2, noticeHeight+90, paint);
noticeHeight -= 20;
paint.setColor(preColor);
paint.setTextSize(textSize);
paint.setTextAlign(preTextStyle);
}
}