最近突然有了一个想法--做一款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);
}
}