智能终端软件开发_课程设计报告
中国地质大学(武汉)
智能终端软件开发
标题:智能终端课程设计
指导老师:徐战亚
班级:116101
学号:[1**********]
学生:高亚兵
2014年1月13日
摘要
本次课程设计主要内容是双人五子棋游戏的开发。主要内容是界面布局、判断输赢,记录输赢次数。开发想法来源,纯属娱乐。
关键词:益智游戏 Android
第一部分 分析游戏
一、 游戏功能简述
1、 界面布局
按照象棋的表格图案绘制布局,在画布上设计表格,并标记红黑方位置。
2、 棋子连线分析
标明五子棋的颜色,记录分析棋子的位置,判断是否取胜。
3、 记录输赢次数
记录红黑双方输赢次数。
二、游戏核心技术
1、基本技术组成
判断路径,数据结构算法。
2、关键技术难点分析
1、技术难点
分析棋子连线是否可以取胜。
2、作为难点的原因
棋子之间有三种连线情况,横向连续连接、纵向连续连接、对角线连续连接。
3、准备突破方法
将同类棋子之间,有位置关系的棋子进行进栈处理,如果在棋盘范围内,有连续的五个棋子则为取胜。
第二部分 设计与开发
一、 前期准备工作
软件环境:
Windows
Android SDK;
Eclipse (windows 版)
环境配置:
Windows 下AndroidSDK 安装。
安装步骤:
1、下载SDK 包,Android-SDK ,下载地址:
http://developer.android.com/tools/sdk/ndk/index.html
2、配置SDK
导入sdk 文件
二、 游戏预期效果
1、 U I 设计
背景画布选择恰当,布局清晰,结构清晰,使用简单。
2、 棋盘设计
方格大小,连线之间的距离适中,确保棋子在连线上,避免棋子在棋盘上混乱摆放。
3、 提示框
出现下棋位置不在棋盘内或者不在合法范围内是出现错误提示
当由一方取得胜利时,出现提示框。
三、 开发过程
1、布局设计
package cn.m.xys;
//Download by http://www.codefans.net
import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;
public class FiveChessActivity extends Activity
{
GameView gameView = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// 隐藏标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 全屏显示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 获取屏幕宽高
Display display = getWindowManager().getDefaultDisplay();
// 现实GameView
GameView.init(this, display.getWidth(), display.getHeight());
gameView = GameView.getInstance();
setContentView(gameView);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
return super.onKeyDown(keyCode, event);
}
}
2、算法设计
package cn.m.xys;
//Download by http://www.codefans.net
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* @author Administrator
*
*/
public class GameView extends SurfaceView implements Const, SurfaceHolder.Callback, Runnable
{
static GameView sInstance = null;
public static void init(Activity mActivity, int screenWidth, int screenHeight) {
sInstance = new GameView(mActivity, screenWidth, screenHeight);
}
public static GameView getInstance()
{
return sInstance;
}
// 控制循环
boolean mbLoop = false;
// 定义SurfaceHolder 对象
SurfaceHolder mSurfaceHolder = null;
public static Paint sPaint = null;
public static Canvas sCanvas = null;
public static Resources sResources = null;
private int mGameState = 0;
private int mScreenWidth = 0;
private int mScreenHeight = 0;
public int[][] mGameMap = null;
private int mMapHeightLengh = 0;
private int mMapWidthLengh = 0;
private int mMapIndexX = 0;
private int mMapIndexY = 0;
public int mCampTurn = 0;
public int mCampWinner = 0;
private float mTitleSpace = 0;
private int mTitleHeight = 0;
private float mTitleIndex_x = 0;
private float mTitleIndex_y = 0;
Bitmap bitmapBg = null;
Bitmap mBlack = null;
Bitmap mWhite = null;
Context mContext = null;
public GameView(Activity activity, int screenWidth, int screenHeight)
{
super(activity);
sPaint = new Paint();
sPaint.setAntiAlias(true);
sResources = getResources();
mContext = activity;
mScreenWidth = screenWidth;
mScreenHeight = screenHeight;
mSurfaceHolder = this.getHolder();
mSurfaceHolder.addCallback(this);
setFocusable(true);
mbLoop = true;
bitmapBg = CreatMatrixBitmap(R.drawable.status, mScreenWidth, mScreenHeight);
mBlack = BitmapFactory.decodeResource(GameView.sResources, R.drawable.ai); mWhite = BitmapFactory.decodeResource(GameView.sResources, R.drawable.human);
mTitleSpace = (float) mScreenWidth / CHESS_WIDTH;
mTitleHeight = mScreenHeight / 3;
mTitleIndex_x = (float) (mTitleSpace / 2);
mTitleIndex_y = (float) (mTitleSpace / 2);
setGameState(GS_GAME);
}
public void setGameState(int newState)
{
mGameState = newState;
switch (mGameState)
{
case GS_GAME:
mGameMap = new int[CHESS_HEIGHT][CHESS_WIDTH];
mMapHeightLengh = mGameMap.length;
mMapWidthLengh = mGameMap[0].length;
mCampTurn = CAMP_HERO;
break;
}
}
protected void Draw()
{
sCanvas = mSurfaceHolder.lockCanvas();
if (mSurfaceHolder == null || sCanvas == null)
{
return;
}
RenderGame();
mSurfaceHolder.unlockCanvasAndPost(sCanvas);
}
private void RenderGame()
{
switch (mGameState)
{
case GS_GAME:
DrawRect(Color.WHITE, 0, 0, mScreenWidth, mScreenHeight);
RenderMap();
break;
case GS_END:
DrawRect(Color.RED, 0, 0, mScreenWidth, mScreenHeight);
DrawString(Color.WHITE, sResources.getString(mCampWinner) + " 胜利点击继续游戏", 50, 50);
break;
}
}
private void RenderMap()
{
int i, j;
DrawImage(bitmapBg, 0, 0, 0);
for (i = 0; i
{
for (j = 0; j
{
int CampID = mGameMap[i][j];
float x = (j * mTitleSpace) + mTitleIndex_x;
float y = (i * mTitleSpace) + mTitleHeight + mTitleIndex_y;
if (CampID == CAMP_HERO)
{
DrawImage(mBlack, x, y, ALIGN_VCENTER ALIGN_HCENTER);
}
else if (CampID == CAMP_ENEMY)
{
DrawImage(mWhite, x, y, ALIGN_VCENTER ALIGN_HCENTER);
}
}
}
}
private void DrawRect(int color, int x, int y, int width, int height)
{
sPaint.setColor(color);
sCanvas.clipRect(x, y, width, height);
sCanvas.drawRect(x, y, width, height, sPaint);
}
private void DrawString(int color, String str, int x, int y)
{
sPaint.setColor(color);
sCanvas.drawText(str, x, y, sPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event)
{ | |
} int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: UpdateTouchEvent(x, y); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: break; } return super.onTouchEvent(event); public boolean CheckPiecesMeet(int Camp) { int MeetCount = 0; // 横向 for (int i = 0; i = mMapWidthLengh) { if (MeetCount == CALU_SINGLE_COUNT) { return true; } MeetCount = 0; continue; } if (mGameMap[mMapIndexY][index] == Camp) { MeetCount++; if (MeetCount == CALU_SINGLE_COUNT) { return true; } } else { MeetCount = 0; } } // 纵向
MeetCount = 0;
for (int i = 0; i
{
int index = mMapIndexY - CALU_SINGLE_COUNT + i;
if (index = mMapHeightLengh)
{
if (MeetCount == CALU_SINGLE_COUNT)
{
return true;
}
MeetCount = 0;
continue;
}
if (mGameMap[index][mMapIndexX] == Camp)
{
MeetCount++;
if (MeetCount == CALU_SINGLE_COUNT)
{
return true;
}
} else
{
MeetCount = 0;
}
}
// 右斜
MeetCount = 0;
for (int i = 0; i
{
int indexX = mMapIndexX - CALU_SINGLE_COUNT + i;
int indexY = mMapIndexY - CALU_SINGLE_COUNT + i;
if ((indexX = mMapWidthLengh) || (indexY = mMapHeightLengh))
{
if (MeetCount == CALU_SINGLE_COUNT)
{
return true;
}
MeetCount = 0;
continue;
}
if (mGameMap[indexY][indexX] == Camp)
{
MeetCount++;
if (MeetCount == CALU_SINGLE_COUNT)
{
return true;
}
} else
{
MeetCount = 0;
}
}
// 左斜
MeetCount = 0;
for (int i = 0; i
{
int indexX = mMapIndexX - CALU_SINGLE_COUNT + i;
int indexY = mMapIndexY + CALU_SINGLE_COUNT - i;
if ((indexX = mMapWidthLengh) || (indexY = mMapHeightLengh))
{
if (MeetCount == CALU_SINGLE_COUNT)
{
return true;
}
MeetCount = 0;
continue;
}
if (mGameMap[indexY][indexX] == Camp)
{
MeetCount++;
if (MeetCount == CALU_SINGLE_COUNT)
{
return true;
}
} else
{
MeetCount = 0;
}
}
return false;
}
private void UpdateTouchEvent(int x, int y)
{
switch (mGameState) { case GS_GAME: if (x > 0 && y > mTitleHeight) { mMapIndexX = (int) (x / mTitleSpace); mMapIndexY = (int) ((y - mTitleHeight) / mTitleSpace); if (mMapIndexX > mMapWidthLengh) { mMapIndexX = mMapWidthLengh; } if (mMapIndexX mMapHeightLengh) { mMapIndexY = mMapHeightLengh; } if (mMapIndexY
{
mGameMap[mMapIndexY][mMapIndexX] = CAMP_ENEMY;
if (CheckPiecesMeet(CAMP_ENEMY))
{
mCampWinner = R.string.Role_white;
setGameState(GS_END);
} else
{
mCampTurn = CAMP_HERO;
}
}
}
}
break;
case GS_END:
setGameState(GS_GAME);
break;
}
}
public boolean isCheckInvite(String body)
{
if (body.indexOf("invite") >= 0)
{
if (mGameState != GS_INVITING && mGameState != GS_COMFIRE && mGameState != GS_GAME)
{
return true;
}
}
return false;
}
/**
* 创建一个缩小或放大的新图片
*
* @param resourcesID
* @param scr_width
* @param res_height
* @return
*/
private Bitmap CreatMatrixBitmap(int resourcesID, float scr_width, float res_height)
} Bitmap bitMap = null; bitMap = BitmapFactory.decodeResource(sResources, resourcesID); int bitWidth = bitMap.getWidth(); int bitHeight = bitMap.getHeight(); float scaleWidth = scr_width / (float) bitWidth; float scaleHeight = res_height / (float) bitHeight; Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); bitMap = Bitmap.createBitmap(bitMap, 0, 0, bitWidth, bitHeight, matrix, true); return bitMap; /** * 绘制一个字符串 * * @param text * @param x * @param y * @param anchor * @param Canvas * @param paint */ private void DrawString(int color, String text, int x, int y, int anchor) { Rect rect = new Rect(); sPaint.getTextBounds(text, 0, text.length(), rect); int w = rect.width(); int h = rect.height(); int tx = 0; int ty = 0; if ((anchor & ALIGN_RIGHT) != 0) { tx = x - w; } else if ((anchor & ALIGN_HCENTER) != 0) { tx = x - (w >> 1); } else { tx = x; }
} { ty = y + h; } else if ((anchor & ALIGN_VCENTER) != 0) { ty = y + (h >> 1); } else { ty = y; } sPaint.setColor(color); sCanvas.drawText(text, tx, ty, sPaint); /** * 绘制一张图片可以选择图片的锚点位置 * * @param canvas * @param paint * @param bitmap * @param x * @param y * @param angle */ private void DrawImage(Bitmap bitmap, float x, float y, int anchor) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); float tx = 0; float ty = 0; if ((anchor & ALIGN_RIGHT) != 0) { tx = x - w; } else if ((anchor & ALIGN_HCENTER) != 0) { tx = x - (w >> 1); } else { tx = x; }
} if((anchor & ALIGN_TOP) != 0) { ty = y + h; } else if ((anchor & ALIGN_VCENTER) != 0) { ty = y - (h >> 1); } else if ((anchor & ALIGN_BOTTOM) != 0) { ty = y - h; } else { ty = y; } sCanvas.drawBitmap(bitmap, tx, ty, sPaint); //@Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub } //@Override public void surfaceCreated(SurfaceHolder arg0) { new Thread(this).start(); } //@Override public void surfaceDestroyed(SurfaceHolder arg0) { mbLoop = false; } //@Override public void run() { while (mbLoop)
} } } try { Thread.sleep(200); } catch (Exception e) { } synchronized (mSurfaceHolder) { Draw(); }
四、 技术关键和需要解决的关键问题
1、 棋盘上棋子和交线的相对位置
交线,方格大小,和棋子大小,棋子间的相对位置之间的距离,棋子和棋盘交点之间的距离。
2、 快速判断
每次点击棋盘都会有一个棋子出现,之后会作出快速判断,判断当前棋子和周围棋子是否有可能组成5个连续的一串;如果可以,则判断是黑子可以还是白子可以,然后弹出相应的取胜提示框。之后,再自动清屏,重新开始游戏,并记录上次输赢情况。
第三部分 游戏成果分析
效果截图:
1、游戏分析:
游戏只实现了基本的游戏规则,具体游戏规则细节不明确,用户体验一般,没有记录输赢情况,不能保存游戏进度。
2、改进的地方:
完善记录功能,增加保存功能,设置推出提示,修改取胜提示,修改棋子和棋盘线的相对位置。
五 总结与体会
本次智能终端课程设计开发的一款益智游戏五子棋;选择开发题目的原因是基本实现简单,工作量在预期时间范围内。开发中遇到的主要问题是棋子之间路径的算法和判断,还有界面设计中棋盘交线和棋子相对位置的设计问题。经过不断的改进之后才有了初步的游戏功能。本次开发给我最多的启示就是前期的准备工作很重要,环境搭建,材料准备很重要,这样开发过程会减少一些麻烦,此次开发有很多经验可以积累,比如算法的分析,以便以后开发积累经验。