Android用SurfaceView写一个简单有趣的游戏--《数字组合》之一
最近突然有了一个想法--做一款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); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。