android自定义View实现简单五子棋游戏
作者:SakuraMashiro 发布时间:2022-09-16 14:52:30
标签:android,view,五子棋
做一个五子棋练练手,没什么特别的,再复习一下自定义View的知识,onMeasure,MeasureSpec , onDraw以及OnTouchEvent方法等。
效果图
代码如下:
package com.fivechess;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class GamePanel extends View {
? ? //棋盘宽度
? ? private int mPanelWidth ;
? ? //每一个棋格的宽
? ? private float mLineHeight ;
? ? //棋盘最大的行数
? ? private int MAX_LINE = 10 ;
? ? //最多连线的棋子个数
? ? private int MAX_COUNT_IN_LINE = 5 ;
? ? private Paint mPaint = new Paint();
? ? //定义黑白棋子的Bitmap
? ? private Bitmap mWhitePiece ;
? ? private Bitmap mBlackPiece ;
? ? //棋子占一个棋格的比例,这里是3/4
? ? private float ratioPieceOfLineHeight = 3 * 1.0f / 4 ;
? ? private boolean isWhite = false ;
? ? //存放已下过的棋子的数组
? ? private ArrayList<Point> mWhiteArray = new ArrayList<>();
? ? private ArrayList<Point> mBlackArray = new ArrayList<>();
? ? //标识对局是否结束
? ? private boolean isGameOver ;
? ? //判断白棋是否获胜
? ? private boolean isWhiteWinner ;
? ? //构造方法
? ? public GamePanel(Context context, AttributeSet attrs) {
? ? ? ? super(context, attrs);
? ? ? ? setBackgroundColor(0x80f8c866);
? ? ? ? init();
? ? }
? ? //初始化画笔及Bitmap
? ? private void init() {
? ? ? ? mPaint.setColor(0x88000000);
? ? ? ? mPaint.setAntiAlias(true);
? ? ? ? mPaint.setDither(true);
? ? ? ? mPaint.setStyle(Paint.Style.STROKE);
? ? ? ? mWhitePiece = BitmapFactory.decodeResource(getResources() , R.drawable.white_chess) ;
? ? ? ? mBlackPiece = BitmapFactory.decodeResource(getResources() , R.drawable.black_chess) ;
? ? }
? ? //测量过程
? ? @Override
? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
? ? ? ? int widthSize = MeasureSpec.getSize(widthMeasureSpec) ;
? ? ? ? int widthMode = MeasureSpec.getMode(widthMeasureSpec) ;
? ? ? ? int heightSize = MeasureSpec.getSize(heightMeasureSpec);
? ? ? ? int heightMode = MeasureSpec.getMode(heightMeasureSpec);
? ? ? ? int width = Math.min( widthSize , heightSize );
? ? ? ? if( widthMode == MeasureSpec.UNSPECIFIED){
? ? ? ? ? ? width = heightSize ;
? ? ? ? }else if( heightMode == MeasureSpec.UNSPECIFIED){
? ? ? ? ? ? width = widthSize ;
? ? ? ? }
? ? ? ? setMeasuredDimension(width,width);
? ? }
? ? @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 ;
? ? ? ? int pieceWidth = (int) (mLineHeight * ratioPieceOfLineHeight);
? ? ? ? mWhitePiece = Bitmap.createScaledBitmap(mWhitePiece , pieceWidth , pieceWidth , false);
? ? ? ? mBlackPiece = Bitmap.createScaledBitmap(mBlackPiece, pieceWidth , pieceWidth , false);
? ? }
? ? //绘制过程
? ? @Override
? ? protected void onDraw(Canvas canvas) {
? ? ? ? super.onDraw(canvas);
? ? ? ? drawBoard(canvas);
? ? ? ? drawPieces(canvas) ;
? ? ? ? checkGameOver();
? ? }
? ? //判断是否结束
? ? private void checkGameOver() {
? ? ? ? boolean whiteWin = checkFiveInLine( mWhiteArray );
? ? ? ? boolean blackWin = checkFiveInLine( mBlackArray );
? ? ? ? if( whiteWin || blackWin ){
? ? ? ? ? ? isGameOver = true ;
? ? ? ? ? ? isWhiteWinner = whiteWin ;
? ? ? ? ? ? String text = isWhiteWinner ? "白棋胜利" : "黑棋胜利" ;
? ? ? ? ? ? Toast.makeText(getContext() , text , Toast.LENGTH_SHORT).show();
? ? ? ? }
? ? }
? ? //判断是否五子连珠
? ? private boolean checkFiveInLine(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 = checkLeftDown( x , y , points) ;
? ? ? ? ? ? if( win ) return true ;
? ? ? ? ? ? win = checkRightDown( x , y , points) ;
? ? ? ? ? ? if( win ) return true ;
? ? ? ? }
? ? ? ? return false;
? ? }
? ? /**
? ? ?* 判断x,y位置的棋子是否横向有相邻的5个一致
? ? ?* @param x
? ? ?* @param y
? ? ?* @param points
? ? ?* @return
? ? ?*/
? ? private boolean checkHorizontal(int x, int y, List<Point> points) {
? ? ? ? //五个子的计数器
? ? ? ? int count = 1 ;
? ? ? ? //判断左边
? ? ? ? for( int i = 1 ; i < MAX_COUNT_IN_LINE ; i ++ ){
? ? ? ? ? ? if( points.contains(new Point(x - i , y ))){
? ? ? ? ? ? ? ? count ++ ;
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? break ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? 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 ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if( count == MAX_COUNT_IN_LINE ) return true ;
? ? ? ? return false ;
? ? }
? ? /**
? ? ?* 判断x,y位置的棋子是否垂直方向有相邻的5个一致
? ? ?* @param x
? ? ?* @param y
? ? ?* @param points
? ? ?* @return
? ? ?*/
? ? private boolean checkVertical(int x, int y, List<Point> points) {
? ? ? ? //五个子的计数器
? ? ? ? int count = 1 ;
? ? ? ? //判断上边
? ? ? ? for( int i = 1 ; i < MAX_COUNT_IN_LINE ; i ++ ){
? ? ? ? ? ? if( points.contains(new Point(x , y - i ))){
? ? ? ? ? ? ? ? count ++ ;
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? break ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? 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 ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if( count == MAX_COUNT_IN_LINE ) return true ;
? ? ? ? return false ;
? ? }
? ? private boolean checkLeftDown(int x, int y, List<Point> points) {
? ? ? ? //五个子的计数器
? ? ? ? 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 ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? 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 ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if( count == MAX_COUNT_IN_LINE ) return true ;
? ? ? ? return false ;
? ? }
? ? private boolean checkRightDown(int x, int y, List<Point> points) {
? ? ? ? //五个子的计数器
? ? ? ? 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 ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? 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 ;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if( count == MAX_COUNT_IN_LINE ) return true ;
? ? ? ? return false ;
? ? }
? ? //绘制棋子的方法
? ? private void drawPieces(Canvas canvas) {
? ? ? ? for( int i = 0 , n = mWhiteArray.size() ; i < n ; i ++ ){
? ? ? ? ? ? Point whitePoint = mWhiteArray.get(i);
? ? ? ? ? ? canvas.drawBitmap(mWhitePiece, ( whitePoint.x + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight ,
? ? ? ? ? ? ? ? ? ? ( whitePoint.y + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight , null ?);
? ? ? ? }
? ? ? ? for( int i = 0 , n = mBlackArray.size() ; i < n ; i ++ ){
? ? ? ? ? ? Point blackPoint = mBlackArray.get(i);
? ? ? ? ? ? canvas.drawBitmap(mBlackPiece, ( blackPoint.x + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight ,
? ? ? ? ? ? ? ? ? ? ( blackPoint.y + ( 1- ratioPieceOfLineHeight) / 2 ) * mLineHeight , null ?);
? ? ? ? }
? ? }
? ? //绘制棋盘的方法
? ? private void drawBoard(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 );
? ? ? ? }
? ? }
? ? @Override
? ? public boolean onTouchEvent(MotionEvent event) {
? ? ? ? if( isGameOver ) return false ;
? ? ? ? int action = event.getAction() ;
? ? ? ? if( action == MotionEvent.ACTION_UP){
? ? ? ? ? ? int x = (int) event.getX();
? ? ? ? ? ? int y = (int) event.getY();
? ? ? ? ? ? Point p = getValidPoint( x , y ) ;
? ? ? ? ? ? if( ?mWhiteArray.contains(p) || mBlackArray.contains(p) ){
? ? ? ? ? ? ? ? return false ;
? ? ? ? ? ? }
? ? ? ? ? ? if( isWhite ){
? ? ? ? ? ? ? ? mWhiteArray.add(p);
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? mBlackArray.add(p);
? ? ? ? ? ? }
? ? ? ? ? ? invalidate();
? ? ? ? ? ? isWhite = !isWhite ;
? ? ? ? }
? ? ? ? return true;
? ? }
? ? //获取点击的有效地址
? ? private Point getValidPoint(int x, int y) {
? ? ? ? return new Point( (int )(x / mLineHeight) , (int ) (y / mLineHeight) );
? ? }
? ? //再来一局
? ? public void restart(){
? ? ? ? mWhiteArray.clear();
? ? ? ? mBlackArray.clear();
? ? ? ? isGameOver = false ;
? ? ? ? isWhiteWinner = false ;
? ? ? ? invalidate();
? ? }
/*
? ? //定义常量
? ? private static final String INSTANCE = "instance" ;
? ? private static final String INSTANCE_GAME_OVER = "instance_game_over";
? ? private static final String INSTANCE_WHITE_ARRAY = "instance_white_array";
? ? private static final String INSTANCE_BLACK_ARRAY = "instance_black_array";
? ? //保存当前游戏状态
? ? @Override
? ? protected Parcelable onSaveInstanceState() {
? ? ? ? Bundle bundle = new Bundle();
? ? ? ? bundle.putParcelable(INSTANCE , super.onSaveInstanceState());
? ? ? ? bundle.putBoolean(INSTANCE_GAME_OVER , isGameOver);
? ? ? ? bundle.putParcelableArray(INSTANCE_WHITE_ARRAY , ?mWhiteArray);
? ? ? ? bundle.putParcelableArray(INSTANCE_BLACK_ARRAY , ?mBlackArray);
? ? ? ? return bundle ;
? ? }
? ? //恢复棋局状态
? ? @Override
? ? protected void onRestoreInstanceState(Parcelable state) {
? ? ? ? if( state instanceof ?Bundle ){
? ? ? ? ? ? Bundle bundle = (Bundle) state;
? ? ? ? ? ? isGameOver = bundle.getBoolean( INSTANCE_GAME_OVER);
? ? ? ? ? ? mWhiteArray = bundle.getParcelableArrayList( INSTANCE_WHITE_ARRAY );
? ? ? ? ? ? mBlackArray = bundle.getParcelableArrayList( INSTANCE_BLACK_ARRAY );
? ? ? ? ? ? super.onRestoreInstanceState(bundle.getParcelable(INSTANCE));
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? super.onRestoreInstanceState(state);
? ? }*/
}
在布局文件中引入该View
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
? ? xmlns:tools="http://schemas.android.com/tools"
? ? android:id="@+id/activity_main"
? ? android:layout_width="match_parent"
? ? android:layout_height="match_parent"
? ? tools:context="com.fivechess.MainActivity"
? ? android:background="@drawable/board_bg">
? ? <com.fivechess.GamePanel
? ? ? ? android:id="@+id/game_panel"
? ? ? ? android:layout_width="match_parent"
? ? ? ? android:layout_height="match_parent" />
? ? <Button
? ? ? ? android:id="@+id/button"
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:text="再来一局"
? ? ? ? android:layout_alignParentBottom="true"/>
</RelativeLayout>
MainActivity的代码
package com.fivechess;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
? ? private Button button ;
? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_main);
? ? ? ? button = (Button) findViewById(R.id.button);
? ? ? ? final GamePanel gamePanel = (GamePanel) findViewById(R.id.game_panel);
? ? ? ? button.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onClick(View view) {
? ? ? ? ? ? ? ? gamePanel.restart();
? ? ? ? ? ? }
? ? ? ? });
? ? }
}
来源:https://blog.csdn.net/SakuraMashiro/article/details/75093214


猜你喜欢
- 在 Android 系统中,一般使用 AudioRecord 或者 MediaRecord 来采集音频。AudioRecord 是一个比较偏
- 简介使用RecyclerView实现网格布局,实现手机界面应用列表 效果效果如下图: 详细代码XML布局文件在布局中使用
- 一、Widget设计步骤需要修改三个XML,一个class:1.第一个xml是布局XML文件(如:main.xml),是这个widget的。
- 因重定向无法正常goBack()解决方案首先说下问题,初始页面为A,点击某个链接跳转到B(http://xxx.com.cn/),B页面重定
- 不讲太多理论知识,官网都有,直接上手。1.测试表DROP TABLE IF EXISTS `user`;CREATE TABLE `user
- 在了解HTTP断点续传的原理之前,让我们先来了解一下HTTP协议,HTTP协议是一种基于tcp的简单协议,分为请求和回复两种。请求协议是由客
- JPA Specification常用查询+排序1.第一步:继承父类public interface TblCarton2RCardLogR
- 1.包1.包的三大作用区分相同名字的类当类很多时,可方便管理控制访问范围2.包的基本语法package abc.www;3.包的本质实际上就
- 本文实例为大家分享了Android调用外置摄像头的具体代码,供大家参考,具体内容如下1、布局文件<?xml version="
- 遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。它能解决很多问题,
- 本文实例为大家分享了Android仿美团下拉菜单的实现代码,分类进行选择,供大家参考,具体内容如下效果图操作平台AS2.0第三方框架:but
- Spring-boot JMS 发送消息慢的问题解决1、在《ActiveMQ 基于zookeeper的主从(levelDB Master/S
- 这个其实很简单,思路是这样的,就是拿view的宽度,除以点的点的宽度+二个点 之间的间距,就可以算出大概能画出几个点
- 1. pom.xml文件配置<?xml version="1.0" encoding="UTF-8&qu
- 简介MapStruct 是一个代码生成器(可以生成对象映射转换的代码),它基于约定优于配置的方法,极大地简化了 Java bean 类型之间
- 本例子演示如何添加一个简单的单页导航,在此基础上,再演示如何在第2个页面中显示第1个页面中拨打过的所有电话号码。(1)通过该例子理解Andr
- 假设你已经装了texlive打开cmd输入latex --version应该能输出打开vscode,安装这几个插件设置->Settin
- AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作。AtomicInteger 作为java.util.
- logback自定义指定日志文件存储目录1、正常使用定义一个logback.xml配置文件即可:<?xml version="
- 最近项目需求中有需要导出Execl表格的要求,而且还是大量的数据,于是把之前的整理了一下,抽成了一个统一的工具类,需要时直接调用工具类即可,