Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

鸿洋大神也顺势出了篇五子棋单机游戏的视频,我看到了就像膜拜膜拜,就学习了一下,写篇博客梳理一下自己的思路,加深一下印象视频链接:http://w

阿法狗让围棋突然就被热议了,鸿洋大神也顺势出了篇五子棋单机游戏的视频,我看到了就像膜拜膜拜,就学习了一下,写篇博客梳理一下自己的思路,加深一下印象

视频链接:http://www.imooc.com/learn/641

一.棋盘

我们一看就知道,我们必须自定义View,这里我们定义一个GameView来做游戏主类,第一步,先测量,我们这里不难知道,五子棋他的棋盘是一个正方形,所以我们需要去测量

/**

* 测量

*

* @param widthMeasureSpec

* @param heightMeasureSpec

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//获取高宽值

int widthSize = 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 (widthMode == 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″?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”

xmlns:tools=”http://schemas.android.com/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=”match_parent”

android:layout_height=”match_parent” />

</LinearLayout>

这里我在构造方法中设置了一个半透明的红色背景,是在我们调试的时候可以更加清晰的看清楚GameView的大小,所以,运行的结果

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

二.线条

这个应该也算是棋盘的一部分吧,就是棋盘上的线条,我们应该怎么去画,首先,我们要去定义一些属性

//线条数量

private static final int MAX_LINE = 10;

//线条的宽度

private int mPanelWidth;

//线条的高度

private 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;

}

不要着急,这些都只是一些准备的工作,我们画线条是必须要在onDraw(0方法里的,但是前期我们要准备一只画笔,对吧,所以我们要初始化画笔

/**

* 初始化画笔

*/

private void initPaint() {

//设置颜色

mPaint.setColor(0x88000000);

//抗锯齿

mPaint.setAntiAlias(true);

//设置防抖动

mPaint.setDither(true);

//设置Style

mPaint.setStyle(Paint.Style.STROKE);

}

现在我们可以去绘制了,我们在OnDraw(0方法里写一个drawLine方法来专门绘制线条

/**

* 绘制棋盘的方法

*

* @param canvas

*/

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(startX, y, endX, y, mPaint);

//绘制纵

canvas.drawLine(y, startX, y, endX, mPaint);

}

}

我们运行一下

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

好的,这里,注意一下,我在activity_main.xml中定义了一个

android:gravity=”center”

属性,所以让他居中,同样的,我们在initPaint中加上点代码让我们看的更加直观一点

//设置颜色

mPaint.setColor(Color.BLACK);

//设置线条宽度

mPaint.setStrokeWidth(3);

同样的,我们把构造法里的设置背景的测试代码注释掉

//测试代码

//setBackgroundColor(0x44ff0000);

这样,我们运行一下

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

得,我们现在有模有样了

三.棋子

棋子我们事先准备好了两张图片,但是这里我们要考虑他的大小的问题了,我们的思路是让他是行高的四分之三大小,所以先声明

//黑棋子

private Bitmap mBlack;

//白棋子

private Bitmap mWhite;

//比例,棋子的大小是高的四分之三

private float rowSize = 3 * 1.0f / 4;

然后我们定义一个方法区初始化Bitmap

/**

* 初始化棋子

*/

private void initBitmap() {

//拿到图片资源

mBlack = BitmapFactory.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, mWhiteWidth, false);

mBlack = Bitmap.createScaledBitmap(mBlack, mWhiteWidth, mWhiteWidth, false);

不过棋子可没我们想象的那么简单,我们要点击一下再去绘制一个棋子,这样的思路该怎么去实现呢?我们实现它的点击事件,这里先定义几个变量

//存储用户点击的坐标

private List<Point> mWhiteArray = new ArrayList<>();

private List<Point> mBlackArray = new ArrayList<>();

//标记,是执黑子还是白子 ,白棋先手

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 = getValidPoint(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的时候为了避免重复绘制我们是实现了一个方法

/**

* 不能重复点击

*

* @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上才是合情合理的

>好的,当我们点击之后就要绘制棋子了,这里我们也写一个方法

/**

* 绘制棋子的方法

*

* @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, null);

}

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,我们实际运行一下

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

四.游戏逻辑

现在什么都有了,基本上都可用玩了,但是还少了重要的一点就是游戏结束,你到了五颗也需要判断是否胜利呀,对吧,我们写一个方法,在每次绘制完成之后就去判断是否有赢家

/**

* 判断是否胜利

*/

private void checkWin() {

//判断白棋是否有五个相同的棋子相连

boolean mWhiteWin = checkFiveLine(mWhiteArray);

//判断黑棋是否有五个相同的棋子相连

boolean mBlackWin = checkFiveLine(mBlackArray);

//只要有一个胜利,游戏就结束

if (mWhiteWin || mBlackWin) {

mIsGameOver = true;

mIsWhiteWin = mWhiteWin;

Toast.makeText(getContext(), mIsWhiteWin ? “白棋胜利” : “黑棋胜利”, Toast.LENGTH_SHORT).show();

}

}

好的,我们重点逻辑就在checkFiveLine这个方法上了,这里,我们所知道的胜利有四种情况

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

我们先定义一个常量

//胜利棋子数量

private static final int MAX_COUNT_IN_LINE = 5;

OK,接下来我们可以实现以下胜利的逻辑了

/**

* //判断棋子是否有五个相同的棋子相连

*

* @param points

* @return

*/

private boolean checkFiveLine(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) 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;

//左

for (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 == 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, 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

* @param 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;

}

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;

}

return false;

}

– 右斜

/**

* 判断右斜向的棋子

*

* @param x

* @param y

* @param points

*/

private boolean checkRight(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;

}

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;

}

return false;

}

这样,我们运行一下

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

嘿嘿,好玩吧!

五.游戏状态存储

这个就是当我们游戏挂后台之后,再回来游戏就没了,我们应该存储他的状态,让他每一次进入的时候要是上一句没有下完接着下,那我们该怎么去实现呢?和Activity一样,我们View也有存储状态的方法

/**

* 存储状态

*

* @return

*/

@Override

protected Parcelable onSaveInstanceState() {

Bundle 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;

}

/**

* 重新运行

*

* @param 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

android:id=”@+id/mGameView”

android:layout_width=”match_parent”

android:layout_height=”match_parent” />

六.再来一局

既然我们的游戏逻辑差不多了,那我们应该考虑一下当你胜利的时候,你是不是应该再来一局,所以我们还要实现这个逻辑,这个很简单

/**

* 再来一局

*/

public void RestartGame() {

mWhiteArray.clear();

mBlackArray.clear();

mIsGameOver = false;

mIsWhiteWin = false;

invalidate();

}

这样,我们就可以直接调用了,我们来看看MainActivity

package com.lgl.fiverow;

import android.support.design.widget.FloatingActionButton;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

/**

* 五子棋游戏

*/

public class MainActivity extends AppCompatActivity {

//重来按钮

private FloatingActionButton fab;

//游戏

private GameView game;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

game = (GameView) findViewById(R.id.mGameView);

fab = (FloatingActionButton) findViewById(R.id.fab);

fab.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

game.RestartGame();

}

});

}

}

OK,我们最终运行一下

Android五子棋游戏,自定义棋盘,线条,棋子,游戏状态存储

OK,到这里,就算开发完成了
Demo下载:http://download.csdn.net/detail/qq_26787115/9521011
我的群:555974449欢迎你加入!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/56008.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信