棋盘是15*15(可以自己规定)
游戏规则:
Java开发用到了Swing轻量级组件用来处理游戏界面,判断胜利的逻辑代码是核心。
1.整体的设计
public class MyJpanel extends JFrame {
PicJpanel pj;
public MyJpanel() {
init();
}
private void init() {
// 逻辑代码处理部分
}
public static void main(String[] args) {
new MyJpanel();
}
}
class PicJpanel extends JPanel {
MyJpanel mj;
public PicJpanel(MyJpanel mj) {
// 设定面板在窗体中的位置以及高度和宽度
this.setBounds(0, 0, mj.getWidth(), mj.getHeight());
this.mj = mj;
}
/**
* 画组件
*/
@Override
protected void paintComponent(Graphics g) {
// 设置一个背景
try {
BufferedImage bi = ImageIO.read(new File("img/bj.jpg"));
g.drawImage(bi, 0, 0, this);
} catch (IOException e) {
e.printStackTrace();
}
}
class MyMouse extends MouseAdapter {
MyJpanel mj;
public MyMouse(MyJpanel mj) {
super();
this.mj = mj;
}
@Override
public void mousePressed(MouseEvent e) {
//点击事件的处理
}
}
MyJpanel 继承Jfram作为整体的一个框架,PicJpanel继承JPanel描绘图画,两者是通过双向关联来互相取值的.MyMouse用来处理点击时间(也是双向关联Jfram)。
2.整体设计模式确定后,就是画图了
在MyJpanel的Init()方法里设置大小,布局方式等,在PicJanel里的paintComponent(Graphics g)方法里通过画图工具画出棋盘。
画图的思路是通过循环画一个15*15的格子。
init()和paintComponent(Graphics g)里的代码:
private void init() {
// 窗体的常用设置
this.setSize(750, 780);// 设置窗体的大小,宽度和高度,单位是像素
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);// 设置窗体关闭时主线程自动关闭
this.setLocationRelativeTo(null);// 设置窗体出现的位置在显示器正中间
this.setResizable(false);// 设置窗体固定大小
this.setLayout(null);// 不启用布局管理器,改为手动布局
this.setTitle("画图");
// 添加面板到窗体
pj = new PicJpanel(this);
this.add(pj);
this.setVisible(true);
}
protected void paintComponent(Graphics g) {
// 设置一个背景
try {
BufferedImage bi = ImageIO.read(new File("img/bj.jpg"));
g.drawImage(bi, 0, 0, this);
} catch (IOException e) {
e.printStackTrace();
}
g.setColor(Color.BLACK);
//通过循环画格子
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
g.drawRect(50 * i, 50 * j, 50, 50);
}
}
}
画好之后就是这样
3.接着添加点击事件
1.精确点击
2.首先落子的是黑棋
2.每次一方下完棋子颜色改变
说一下思路,我这里是750*750的,行和列都是15,这样就很容易获取x和y的值(通过鼠标点击事件getX和getY再除以50则可得到x,y),说到x,y大家肯定想到要使用二维数组,每错,我们在前台看到的是棋盘,但是实际存储值的地方在二维数组,所以要定义一个二维数组map[15][15]。每次获取到x和y则将map[x][y]=1或2(黑子或白子),每次点击之后都要调用repaint()方法重新绘制图画。看看MyMouse里的mousePressed()方法。
在这之前先在MyJpanel里设置2个全局变量
int map[][] = new int[15][15]; // 棋盘
int flag = 2; // 1为白 2为黑 黑白交替默认为黑
由于MyMouse 关联了MyJpanel 所以可以获取到MyJpanel 的值
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();// 获取鼠标点下的位置的坐标
// 点击之后map值发生改变
int x = (int) p.getX() / (750 / 15);
int y = (int) p.getY() / (750 / 15);
System.out.println("x=" + p.getX() + " y=" + p.getY());
System.out.println("x=" + x + " y=" + y);
// 改变棋子的颜色
if (map[y][x] == 0) {
map[y][x] = mj.flag;
}
// 改变顺序
if (mj.flag == 1) {
mj.flag = 2;
} else if(mj.flag==2){
mj.flag = 1;
}
//重置绘图
mj.pj.repaint();
}
做完点击事件处理后,要回到图像处理部分PicJpanel在循环里添加一行代码如下:
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
g.drawRect(50 * i, 50 * j, 50, 50);
// 1为白
if (map[i][j] == 1) {
g.setColor(Color.WHITE);
g.fillOval(50 * j, 50 * i, 50, 50);
}
g.setColor(Color.black);
// 2为黑
if (map[i][j] == 2) {
g.setColor(Color.black);
g.fillOval(50 * j, 50 * i, 50, 50);
}
}
看看效果
点击第一行一列后台处理之后输出结果。嗯差不多做了一大半了。剩下来的就是核心部分了
4.胜负判断
每次调用鼠标点击时间都要判断一次输赢。
讲一下思路。要判断输赢。要判断每次落子的地方该子的四个大方向是否有五颗连续的子,4个大方向为上下,左右,左斜,右斜,想一下米子的写法就可以了。同方向上是否有五颗颜色一样的棋子,实际上就是连续问题,这里有很多处理方法。博主给出的不是最佳方案。
4步完成后稍微修改处理一下代码就可以了。
博主的代码如下,这个小游戏主要是画图和数组两个部分的内容,基础稍好的同学可以试着自己实现一下,可以参照博主的设计思路,细节上可以自己处理。不懂的可以留言
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MyJpanel extends JFrame {
PicJpanel pj;
int map[][] = new int[16][16]; // 棋盘
int flag = 2; // 1为白 2为黑 黑白交替默认为黑
int winer=0; //规定赢者
public int[][] getMap() {
return map;
}
public void setMap(int[][] map) {
this.map = map;
}
public MyJpanel() {
init();
}
private void init() {
// 窗体的常用设置
this.setSize(750, 780);// 设置窗体的大小,宽度和高度,单位是像素
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);// 设置窗体关闭时主线程自动关闭
this.setLocationRelativeTo(null);// 设置窗体出现的位置在显示器正中间
this.setResizable(false);// 设置窗体固定大小
this.setLayout(null);// 不启用布局管理器,改为手动布局
this.setTitle("画图");
// 添加面板到窗体
pj = new PicJpanel(this);
pj.addMouseListener(new MyMouse(this));// 给面板添加一个鼠标监听事件
this.add(pj);
this.setVisible(true);
}
public static void main(String[] args) {
new MyJpanel();
}
}
class PicJpanel extends JPanel {
MyJpanel mj;
public PicJpanel(MyJpanel mj) {
// 设定面板在窗体中的位置以及高度和宽度
this.setBounds(0, 0, mj.getWidth(), mj.getHeight());
this.mj = mj;
}
/**
* 画组件
*/
@Override
protected void paintComponent(Graphics g) {
try {
BufferedImage bi = ImageIO.read(new File("img/bj.jpg"));
g.drawImage(bi, 0, 0, this);
} catch (IOException e) {
e.printStackTrace();
}
int map[][] = mj.map;
g.setColor(Color.BLACK);
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
g.drawRect(50 * i, 50 * j, 50, 50);
// 1为白
if (map[i][j] == 1) {
g.setColor(Color.WHITE);
g.fillOval(50 * j, 50 * i, 50, 50);
}
g.setColor(Color.black);
// 2为黑
if (map[i][j] == 2) {
g.setColor(Color.black);
g.fillOval(50 * j, 50 * i, 50, 50);
}
}
}
// g.setColor(Color.RED);//设置画笔为红色
// g.drawRect(50, 50, 100, 100);//画一个矩形.前面两个参数决定位置,后两个参数决定大小
// g.setColor(Color.BLUE);
// g.fillRect(200,50, 100, 100);//画一个实心的矩形
// g.drawOval(50, 200, 100, 100);
// g.fillOval(200, 200, 100, 100);
}
}
class MyMouse extends MouseAdapter {
MyJpanel mj;
public MyMouse(MyJpanel mj) {
super();
this.mj = mj;
}
@Override
public void mousePressed(MouseEvent e) {
//重置1
if(mj.winer!=0){
mj.setMap(new int[16][16]);
mj.winer=0;
mj.pj.repaint();
return;
}
int map[][] = mj.map;
Point p = e.getPoint();// 获取鼠标点下的位置的坐标
// 点击之后map值发生改变
int x = (int) p.getX() / (750 / 15);
int y = (int) p.getY() / (750 / 15);
System.out.println("x=" + p.getX() + " y=" + p.getY());
System.out.println("x=" + x + " y=" + y);
// 改变棋子的颜色
if (map[y][x] == 0) {
map[y][x] = mj.flag;
}
// 改变顺序
if (mj.flag == 1) {
mj.flag = 2;
} else if(mj.flag==2){
mj.flag = 1;
}
//判断输赢
MyMouse mouse=new MyMouse(mj);
if(mouse.isWin(y, x, map)){
if(map[y][x]==1){
mj.winer=1;
mj.pj.repaint();
//弹出获胜信息
JOptionPane.showMessageDialog(mj, "白子胜");
//重置棋子颜色为黑棋
mj.flag=2;
}
if(map[y][x]==2){
mj.winer=2;
mj.pj.repaint();
JOptionPane.showMessageDialog(mj, "黑子胜");
//重置棋子颜色为黑棋
mj.flag=2;
}
}
//先调整数组 在绘图
mj.setMap(map);
mj.pj.repaint();
}
public boolean isWin(int x, int y, int map[][]) {
// 对胜负判断
// 4个方向 左右 上下 左斜 右斜
// 对一个棋子的一个方向的10颗棋子进行判断 是否满足5子连续
// 左右
int num = 1;
for (int i = 0; i < 14; i++) {
if (map[x][i] != 0) {
if (map[x][i] == map[x][i + 1]) {
num++;
if (num >= 5) {
System.out.println("win");
return true;
}
} else {
num = 1;
}
}
}
// 上下
num = 1;
for (int i = 0; i < 14; i++) {
if (map[i][y] != 0) {
if (map[i][y] == map[i + 1][y]) {
num++;
if (num >= 5) {
System.out.println("win");
return true;
}
} else {
num = 1;
}
}
}
num=1;
// 右斜 x-1 j+1
for (int i = 0; i < map.length*2-1; i++) {
for (int j = 1; j < map.length ; j++) {
if (((i - j) >= 0) && ((i - j) < map.length)) {
if(map[j][i-j]!=0){
if(map[j][i-j]==map[j-1][i-j+1]){
num++;
if (num >= 5) {
System.out.println("win");
return true;
}
}else{
num=1;
}
}
}
}
}
num=1;
//左斜 x+1 y+1
for (int i = -map.length; i < map.length; i++) {
for (int j = 1; j < map.length; j++) {
if(((i+j)>=0)&&((i+j)<map.length)){
if(map[j][j+i]!=0){
if(map[j][i+j]==map[j+1][i+j+1]){
num++;
if (num >= 5) {
System.out.println("win");
return true;
}
}else{
num=1;
}
}
}
}
}
return false;
}
}