Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局_第1页
Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局_第2页
Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局_第3页
Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局_第4页
Android实训案例(八)——单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Android实训案例(八)单机五子棋游戏,自定义棋盘,线条,棋子,游戏逻辑,游戏状态存储,再来一局一.棋盘我们一看就知道,我们必须自定义View,这里我们定义一个GameView来做游戏主类,第一步,先测量,我们这里不难知道,五子棋他的棋盘是一个正方形,所以我们需要去测量 /* * 测量 * * param widthMeasureSpec * param heightMeasureSpec */ Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) /获取高宽值 int widthSiz

2、e = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int hightSize = MeasureSpec.getSize(heightMeasureSpec); int hightMode = MeasureSpec.getMode(heightMeasureSpec); /拿到宽和高的最小值,也就是宽 int width = Math.min(widthSize, heightMeasureSpec); /根据测量模式细节处理 if (widthM

3、ode = MeasureSpec.UNSPECIFIED) width = hightSize; else if (hightMode = MeasureSpec.UNSPECIFIED) width = widthSize; /设置这样就是一个正方形了 setMeasuredDimension(width, width); 这里的逻辑还是十分简单的,我们拿到长和宽去比较一下,设置这个View的长宽Wie最小值,就是一个正方形了,所以我们的layout_main.xml是这样写的<?xml version="1.0" encoding="utf-8&quo

4、t;?><LinearLayout xmlns:android=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="drawable/main_bg" > <com.lgl.fiverow.GameView android:layout_width

5、="match_parent" android:layout_height="match_parent" /></LinearLayout>这里我在构造方法中设置了一个半透明的红色背景,是在我们调试的时候可以更加清晰的看清楚GameView的大小,所以,运行的结果二.线条这个应该也算是棋盘的一部分吧,就是棋盘上的线条,我们应该怎么去画,首先,我们要去定义一些属性 /线条数量 private static final int MAX_LINE = 10; /线条的宽度 private int mPanelWidth; /线条的高度 pri

6、vate float mLineHeight;然后,我们要去确定大小/* * 测量大小 * * param w * param h * param oldw * param oldh */ Override protected void onSizeChanged(int w, int h, int oldw, int oldh) super.onSizeChanged(w, h, oldw, oldh); /拿到宽 mPanelWidth = w; /分割 mLineHeight = mPanelWidth * 1.0f / MAX_LINE; 不要着急,这些都只是一些准备的工作,我们画线条

7、是必须要在onDraw(0方法里的,但是前期我们要准备一只画笔,对吧,所以我们要初始化画笔 /* * 初始化画笔 */ private void initPaint() /设置颜色 mPaint.setColor(0x88000000); /抗锯齿 mPaint.setAntiAlias(true); /设置防抖动 mPaint.setDither(true); /设置Style mPaint.setStyle(Paint.Style.STROKE); 现在我们可以去绘制了,我们在OnDraw(0方法里写一个drawLine方法来专门绘制线条 /* * 绘制棋盘的方法 * * param ca

8、nvas */ private void drawLine(Canvas canvas) /获取高宽 int w = mPanelWidth; float lineHeight = mLineHeight; /遍历,绘制线条 for (int i = 0; i < MAX_LINE; i+) /横坐标 int startX = (int) (lineHeight / 2); int endX = (int) (w - lineHeight / 2); /纵坐标 int y = (int) (0.5 + i) * lineHeight); /绘制横 canvas.drawLine(star

9、tX, y, endX, y, mPaint); /绘制纵 canvas.drawLine(y, startX, y, endX, mPaint); 我们运行一下好的,这里,注意一下,我在activity_main.xml中定义了一个android:gravity="center"属性,所以让他居中,同样的,我们在initPaint中加上点代码让我们看的更加直观一点/设置颜色mPaint.setColor(Color.BLACK);/设置线条宽度mPaint.setStrokeWidth(3);同样的,我们把构造法里的设置背景的测试代码注释掉/测试代码/setBackgro

10、undColor(0x44ff0000);这样,我们运行一下得,我们现在有模有样了三.棋子棋子我们事先准备好了两张图片,但是这里我们要考虑他的大小的问题了,我们的思路是让他是行高的四分之三大小,所以先声明 /黑棋子 private Bitmap mBlack; /白棋子 private Bitmap mWhite;/比例,棋子的大小是高的四分之三 private float rowSize = 3 * 1.0f / 4;然后我们定义一个方法区初始化Bitmap /* * 初始化棋子 */ private void initBitmap() /拿到图片资源 mBlack = BitmapFact

11、ory.decodeResource(getResources(), R.drawable.stone_black); mWhite = BitmapFactory.decodeResource(getResources(), R.drawable.stone_white); 拿到资源之后我们就可以设置大小了,我们在onSizeChanged()里面设置 /棋子宽度 int mWhiteWidth = (int) (mLineHeight * rowSize); /修改棋子大小 mWhite = Bitmap.createScaledBitmap(mWhite, mWhiteWidth, mW

12、hiteWidth, false); mBlack = Bitmap.createScaledBitmap(mBlack, mWhiteWidth, mWhiteWidth, false);不过棋子可没我们想象的那么简单,我们要点击一下再去绘制一个棋子,这样的思路该怎么去实现呢?我们实现它的点击事件,这里先定义几个变量 /存储用户点击的坐标 private List<Point> mWhiteArray = new ArrayList<>(); private List<Point> mBlackArray = new ArrayList<>()

13、; /标记,是执黑子还是白子 ,白棋先手 private boolean mIsWhite = true;这样才和触摸事件相得映彰 /* * 触摸事件 * * param event * return */ Override public boolean onTouchEvent(MotionEvent event) switch (event.getAction() /按下事件 case MotionEvent.ACTION_UP: int x = (int) event.getX(); int y = (int) event.getY(); /封装成一个Point Point p = ge

14、tValidPoint(x, y); /判断当前这个点是否有棋子了 if(mWhiteArray.contains(p) | mBlackArray.contains(p) /点击不生效 return false; /判断如果是白子就存白棋集合,反之则黑棋集合 if (mIsWhite) mWhiteArray.add(p); else mBlackArray.add(p); /刷新 invalidate(); /改变值 mIsWhite = !mIsWhite; break; return true;这样,有几点是要说明一下的,首先我们new Point的时候为了避免重复绘制我们是实现了一个

15、方法/* * 不能重复点击 * * param x * param y * return */ private Point getValidPoint(int x, int y) return new Point(int) (x / mLineHeight), (int) (y / mLineHeight); 紧接着我们就判断,要是重复点击,返回false,而且我们在action选择也是选择了ACTION_UP,为什么?为什么不是ACTION_DOWN?因为这个毕竟是一个View,父View会拦截(某些场景),所以我们选在UP上才是合情合理的好的,当我们点击之后就要绘制棋子了,这里我们也写一个

16、方法 /* * 绘制棋子的方法 * * param canvas */ private void drawPieces(Canvas canvas) for (int i = 0; i < mWhiteArray.size(); i+) /获取白棋子的坐标 Point whitePoint = mWhiteArray.get(i); canvas.drawBitmap(mBlack, (whitePoint.x + (1 - rowSize) / 2) * mLineHeight, (whitePoint.y + (1 - rowSize) / 2) * mLineHeight, nul

17、l); for (int i = 0; i < mBlackArray.size(); i+) /获取黑棋子的坐标 Point blackPoint = mBlackArray.get(i); canvas.drawBitmap(mWhite, (blackPoint.x + (1 - rowSize) / 2) * mLineHeight, (blackPoint.y + (1 - rowSize) / 2) * mLineHeight, null); OK,我们实际运行一下四.游戏逻辑现在什么都有了,基本上都可用玩了,但是还少了重要的一点就是游戏结束,你到了五颗也需要判断是否胜利呀,

18、对吧,我们写一个方法,在每次绘制完成之后就去判断是否有赢家 /* * 判断是否胜利 */ private void checkWin() /判断白棋是否有五个相同的棋子相连 boolean mWhiteWin = checkFiveLine(mWhiteArray); /判断黑棋是否有五个相同的棋子相连 boolean mBlackWin = checkFiveLine(mBlackArray); /只要有一个胜利,游戏就结束 if (mWhiteWin | mBlackWin) mIsGameOver = true; mIsWhiteWin = mWhiteWin; Toast.makeTe

19、xt(getContext(), mIsWhiteWin ? "白棋胜利" : "黑棋胜利", Toast.LENGTH_SHORT).show(); 好的,我们重点逻辑就在checkFiveLine这个方法上了,这里,我们所知道的胜利有四种情况我们先定义一个常量 /胜利棋子数量 private static final int MAX_COUNT_IN_LINE = 5;OK,接下来我们可以实现以下胜利的逻辑了 /* * /判断棋子是否有五个相同的棋子相连 * * param points * return */ private boolean che

20、ckFiveLine(List<Point> points) /遍历棋子 for (Point p : points) /拿到棋盘上的位置 int x = p.x; int y = p.y; /* * 四种情况胜利,横,竖,左斜,右斜 */ /横 boolean win = checkHorizontal(x, y, points); if (win) return true; /竖 win = checkVertical(x, y, points); if (win) return true; /左斜 win = checkLeft(x, y, points); if (win)

21、 return true; /右斜 win = checkRight(x, y, points); if (win) return true; return false; 我们不管哪个方向只要返回true就返回true,然后弹Toast,这里,四个方向的逻辑横 /* * 判断横向的棋子 * * param x * param y * param points */ private boolean checkHorizontal(int x, int y, List<Point> points) /棋子标记,记录是否有五个 =1是因为自身是一个 int count = 1; /左 f

22、or (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x - i, y) count+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; /右 for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x + i, y) count+; else break; /有五个就为true if (count

23、= MAX_COUNT_IN_LINE) return true; return false; 横 /* * 判断纵向的棋子 * * param x * param y * param points */ private boolean checkVertical(int x, int y, List<Point> points) /棋子标记,记录是否有五个 =1是因为自身是一个 int count = 1; /上 for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x,

24、y - i) count+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; /下 for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x, y + i) count+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; return false; 左斜 /* * 判断左斜向的棋子 * * param x * para

25、m y * param points */ private boolean checkLeft(int x, int y, List<Point> points) /棋子标记,记录是否有五个 =1是因为自身是一个 int count = 1; for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x - i, y + i) count+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; fo

26、r (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x + i, y - i) count+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; return false; 右斜 /* * 判断右斜向的棋子 * * param x * param y * param points */ private boolean checkRight(int x, int y, List<Point> po

27、ints) /棋子标记,记录是否有五个 =1是因为自身是一个 int count = 1; for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x - i, y - i) unt+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; for (int i = 1; i < MAX_COUNT_IN_LINE; i+) /如果有 if (points.contains(new Point(x + i

28、, y + i) count+; else break; /有五个就为true if (count = MAX_COUNT_IN_LINE) return true; return false; 这样,我们运行一下嘿嘿,好玩吧!五.游戏状态存储这个就是当我们游戏挂后台之后,再回来游戏就没了,我们应该存储他的状态,让他每一次进入的时候要是上一句没有下完接着下,那我们该怎么去实现呢?和Activity一样,我们View也有存储状态的方法 /* * 存储状态 * * return */ Override protected Parcelable onSaveInstanceState() Bundl

29、e bundle = new Bundle(); bundle.putParcelable(INSTANCE, super.onSaveInstanceState(); bundle.putBoolean(INSTANCE_GAMEOVER, mIsGameOver); bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY, mWhiteArray); bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY, mBlackArray); return bundle; /* * 重新运行 * * par

30、am state */ Override protected void onRestoreInstanceState(Parcelable state) /取值 if (state instanceof Bundle) Bundle bundle = (Bundle) state; mIsGameOver = bundle.getBoolean(INSTANCE_GAMEOVER); mWhiteArray = bundle.getParcelableArrayList(INSTANCE_WHITE_ARRAY); mBlackArray = bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY); /调用 super.onRestoreInstanceState(bundle.getParcelable(INSTANCE); return; super.onRestoreInstanceState(state); 这样就可以了,但是,有一点要知道,不要忘记在布局文件上给控件加上ID,不然状态不会存储哦 <com.lgl.fiverow.GameView andro

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论