自定义view二五子棋.docx
《自定义view二五子棋.docx》由会员分享,可在线阅读,更多相关《自定义view二五子棋.docx(18页珍藏版)》请在冰点文库上搜索。
自定义view二五子棋
自定义view
(二)五子棋
画棋盘
首先自定义view的四部曲
1,在attrs中申明自定义的属性
2,在View的构造方法中获得我们自定义的属性
3,重写onMeasure方法
4,重写ondraw方法
五子棋的自定义属性我都写死了,也可以不写死,写在attrs中动态的改变,这样都可以
生成构造方法
publicWuZiQiView(Contextcontext,AttributeSetattrs){
super(context,attrs);
//设置一个背景颜色用来区分我们自定义的view的大小最后的时候去掉
setBackgroundColor(0x44ff0000);
init();
}
//棋盘的线条数
privateintmaxline=10;
//棋盘的宽度
privateintmpanelWidth;
//每一行的高度
privatefloatmLineHeight;
//新建一只画棋盘的画笔
privatePaintmPaint=newPaint();
重写onmeasure方法
@Override
protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
intheightSize=MeasureSpec.getSize(heightMeasureSpec);
intheightMode=MeasureSpec.getMode(heightMeasureSpec);
intwidthSize=MeasureSpec.getSize(widthMeasureSpec);
intwidthMode=MeasureSpec.getMode(widthMeasureSpec);
//取view的宽度
intwidth=Math.min(widthSize,heightSize);
if(heightMode==MeasureSpec.UNSPECIFIED){
//测量模式为不确定的时候也取view的宽度
width=widthSize;
}elseif(widthMode==MeasureSpec.UNSPECIFIED){
width=heightSize;
}
//设置自定义view的宽度和高度
setMeasuredDimension(width,width);
}
获取棋盘的高度
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
//设置view的宽度为棋盘的宽度
mpanelWidth=w;
//获取每一行的宽度=棋盘的宽度/行数
mLineHeight=mpanelWidth*1.0f/maxline;
}
重写ondraw方法
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
//画棋盘
doawBoard(canvas);
}
//初始化画笔
privatevoidinit(){
//设置颜色
mPaint.setColor(0x88000000);
//抗锯齿
mPaint.setAntiAlias(true);
//防抖动
mPaint.setDither(true);
//Paint.Style.STROKE仅描边
mPaint.setStyle(Paint.Style.STROKE);
}
privatevoiddoawBoard(Canvascanvas){
intw=mpanelWidth;
intLineHeight=(int)mLineHeight;
for(inti=0;i//不能从起点开始画,因为我们还需要放置旗子,所以这里取行宽的2分之1
intstartX=(int)(mLineHeight/2);
intendX=(int)(w-mLineHeight/2);
//Y坐标根据行数进行变化
inty=(int)((0.5+i)*LineHeight);
canvas.drawLine(startX,y,endX,y,mPaint);
canvas.drawLine(y,startX,y,endX,mPaint);
}
}
画棋子
首先在网上找俩张资源图,棋子的,放在drawble中
首先初始化它
privatevoidinit(){
mPaint.setColor(0x88000000);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
//根据资源文件获取白棋黑棋对应的bitmap
mWhitePiece=BitmapFactory.decodeResource(getResources(),R.drawable.stone_w2);
mBlancPiece=BitmapFactory.decodeResource(getResources(),R.drawable.stone_b1);
}
画棋子大概的思路如下
俩个list用来存取2种颜色的棋子的坐标,用一个常量区分当前是下白子还是黑子,重写ontouchevent方法,在手势抬起的时候绘制棋子,之所以不是手势按下就绘制就考虑到玩家按下后平移,但是发现棋子已经绘制好了,所以把棋子的绘制放在手势抬起的时候
//白棋
privateBitmapmWhitePiece;
//黑棋
privateBitmapmBlancPiece;
//百分比用来设置棋子的宽度
privatefloatratioPieceOfLineHeight=1.0f*3/4;
//常量用来区分当前的状态
privatebooleanmeisWhite=false;
//存放白棋坐标的list
privateArrayListmWhiteList=newArrayList<>();
//存放黑棋坐标的list
privateArrayListmBlackList=newArrayList<>();
//获取棋子的宽度
@Override
protectedvoidonSizeChanged(intw,inth,intoldw,intoldh){
super.onSizeChanged(w,h,oldw,oldh);
mpanelWidth=w;
mLineHeight=mpanelWidth*1.0f/maxline;
//棋子的宽度去行宽的3/4
intpipcewidth=(int)(mLineHeight*ratioPieceOfLineHeight);
//根据棋子的宽度重新定制棋子的大小和尺寸
mWhitePiece=Bitmap.createScaledBitmap(mWhitePiece,pipcewidth,pipcewidth,false);
mBlancPiece=Bitmap.createScaledBitmap(mBlancPiece,pipcewidth,pipcewidth,false);
}
@Override
publicbooleanonTouchEvent(MotionEventevent){
if(mIsGameOver){
returnfalse;
}
intaction=event.getAction();
if(action==MotionEvent.ACTION_UP){
//记录手势的坐标并且将坐标存在list中
intx=(int)event.getX();
inty=(int)event.getY();
//使用系统自带的point类,用来存放x,y
Pointp=getVaildPoint(x,y);
//避免重复绘制
if(mWhiteList.contains(p)||mBlackList.contains(p)){
returnfalse;
}
//用一个常量来区分当前下的棋子是白色还是黑色
if(meisWhite){
mWhiteList.add(p);
}else{
mBlackList.add(p);
}
//刷新界面
invalidate();
//每次都取反,这样白子和黑子一人一轮
meisWhite=!
meisWhite;
}
returntrue;
}
//获取棋子的坐标
privatePointgetVaildPoint(intx,inty){
returnnewPoint((int)(x/mLineHeight),(int)(y/mLineHeight));
}
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
doawBoard(canvas);
//画棋子
drawPiece(canvas);
}
privatevoiddrawPiece(Canvascanvas){
//根据存放的list的大小绘制棋子
for(inti=0;iPointwhitePoint=mWhiteList.get(i);
//画棋子,棋子的坐标加上行宽的1/8,保持绘制的棋子处于线条交叉正中心的位置
canvas.drawBitmap(mWhitePiece,(whitePoint.x+(1-ratioPieceOfLineHeight)/2)*mLineHeight,(whitePoint.y+(1-ratioPieceOfLineHeight)/2)*mLineHeight,ull);
}
for(inti=0;iPointmBlackPoint=mBlackList.get(i);
canvas.drawBitmap(mBlancPiece,(mBlackPoint.x+(1-ratioPieceOfLineHeight)/2)*mLineHeight,(mBlackPoint.y+(1-ratioPieceOfLineHeight)/2)*mLineHeight,null);
}
}
检查游戏是否结束
最后检查游戏的结束状态
//是否是白棋胜利
privatebooleanmisWhiteWinner;
//游戏是否结束
privatebooleanmIsGameOver;
//同色的相邻棋子最大数
privateintMaxCountLine=5;
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
doawBoard(canvas);
drawPiece(canvas);
/检查游戏是否结束
checkGameOver();
}
privatevoidcheckGameOver(){
//检查的逻辑算法
booleanwhiteWin=checkFiveInLine(mWhiteList);
booleanblackWin=checkFiveInLine(mBlackList);
if(whiteWin||blackWin){
mIsGameOver=true;
misWhiteWinner=whiteWin;
//弹出toast
Stringtext=misWhiteWinner?
"白棋胜利":
"黑期胜利";
Toast.makeText(getContext(),text,Toast.LENGTH_SHORT).show();
//游戏结束后弹出对话框,
AlertDialog.BuilderalertDialog=newAlertDialog.Builder(getContext());
alertDialog.setTitle("游戏结束").setMessage("在来一局吗").setPositiveButton("确定",newDialogInterface.OnClickListener(){
@Override
publicvoidonClick(DialogInterfacedialog,intwhich){
//重置游戏
reStart();
}
}).setNegativeButton("取消",newDialogInterface.OnClickListener(){
@Oride
publicvoidonClick(DialogInterfacedialog,intwhich){
}
}).show();
}
}
检查的逻辑算法:
再用户当前放置棋子的坐标开始判断,横,竖,左斜,右斜,进行5次循环判断,判断list中是否存在有相邻的棋子,如果有则用index++,当index达到5的时候代表游戏结束
privatebooleancheckFiveInLine(Listpoints){
for(Pointpoint:
points){
intx=point.x;
inty=point.y;
booleanhorizontalwin=checkHorizontal(x,y,points);
booleanverticalwin=checkvertical(x,y,points);
booleanleftwin=checkleftDiagonal(x,y,points);
booleanrightwin=checkRightDigonal(x,y,points);
if(horizontalwin||verticalwin||leftwin||rightwin){
returntrue;
}
}
returnfalse;
}
privatebooleancheckvertical(intx,inty,Listpoints){
intcount=1;
for(inti=1;iif(points.contains(newPoint(x,y+i))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
for(inti=1;iif(points.contains(newPoint(x,y-i))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
returnfalse;
}
privatebooleancheckleftDiagonal(intx,inty,Listpoints){
intcount=1;
for(inti=1;iif(points.contains(newPoint(x-i,y+i))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
for(inti=1;iif(points.contains(newPoint(x+i,y-i))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
returnfalse;
}
privatebooleancheckRightDigonal(intx,inty,Listpoints){
intcount=1;
for(inti=1;iif(points.contains(newPoint(x+i,y+i))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
for(inti=1;iif(points.contains(newPoint(x-i,y-i))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
returnfalse;
}
/**
*检查横向的是否胜利
*
*@paramx
*@paramy
*@parampoints
*/
privatebooleancheckHorizontal(intx,inty,Listpoints){
intcount=1;
//左边
for(inti=1;iif(points.contains(newPoint(x-i,y))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
for(inti=1;iif(points.contains(newPoint(x+i,y))){
count++;
}else{
break;
}
}
if(count==MaxCountLine){
returntrue;
}
returnfalse;
}
重置的代码
publicvoidreStart(){
//清楚所有的list
mWhiteList.clear();
mBlackList.clear();
//标识位恢复
mIsGameOver=false;
misWhiteWinner=false;
invalidate();
}
屏幕状态改变后,保存当前的棋盘信息
privatestaticfinalStringINSTANCE="instance";//主标识,用来存放super
//存放游戏是否结束
privatestaticfinalStringINSTANCE_GAME_OVER="instance_game_over";
//存放当前轮到什么颜色的棋子下
privatestaticfinalStringINSTANCE_ME_ISWHITE="instance_me_iswhite";
//存放白棋的list
privatestaticfinalStringINSTANCE_WHITE_ARRAY="instance_white_array";
privatestaticfinalStringINSTANCE_BLACK_ARRAY="instance_black_array";
//重写,存储
@Override
protectedParcelableonSaveInstanceState(){
Bundlebundle=ewBundle();
bundle.putParcelable(INSTANCE,super.onSaveInstanceState());
bundle.putBoolean(INSTANCE_GAME_OVER,mIsGameOver);
bundle.putBoolean(INSTANCE_ME_ISWHITE,meisWhite);
bundle.putParcelableArrayList(INSTANCE_WHITE_ARRAY,mWhiteList);
bundle.putParcelableArrayList(INSTANCE_BLACK_ARRAY,mBlackList);
returnbundle;
}
//恢复
@Override
protectedvoidonRestoreInstanceState(Parcelablestate){
if(stateinstanceofBundle){
Bundlebundle=(Bundle)state;
mIsGameOver=bundle.getBoolean(INSTANCE_GAME_OVER);
mBlackList=bundle.getParcelableArrayList(INSTANCE_BLACK_ARRAY);
mWhiteList=bundle.getParcelab