项目历程—生命数组游戏(两版本)
实现效果
(一)版本1:
生命数组游戏
效果截图1:

截图2:

(二)版本2:
生命数组游戏2
代码实现:
(一)版本一:
(一)创建AI方法类:
内含方法:
1.显现数组
2.初始化数组
3.更新数组
4.计算此处是否可存活
5.备份上一次数组
6.判断这一次数组和上一次数组是否相同
5和6方法是为了检测生命数组是否停止更新用的
package DemoProject.fjm0729_V1;import java.util.Random;public class AILife {static int g=1;public static void showUpdate(int [][] LifeArr){upDate(LifeArr);//输出更迭后的数组System.out.println("更新过"+ g++ + "次的数组生命数组为:");for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){System.out.print(LifeArr[i][j] + " ");if ( j == LifeArr[i].length-1 ){System.out.println();}}}}public static void randomInit(int [][] LifeArr){Random random = new Random();for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){int randomValue = random.nextBoolean() ? 0 : 1;LifeArr[i][j] = randomValue;}}}public static void upDate(int [][] LifeArr){int [][] CalIsAliveArr = CalSurroundAlive(LifeArr);for( int i = 0 ; i < CalIsAliveArr.length ; i++){for ( int j = 0 ; j < CalIsAliveArr[i].length ; j ++){//条件3if(LifeArr[i][j] == 0){if(CalIsAliveArr[i][j] == 3 ){LifeArr[i][j] = 1;}}else if(LifeArr[i][j] == 1){//条件2if(CalIsAliveArr[i][j] == 3 || CalIsAliveArr[i][j] == 2){LifeArr[i][j] = 1;//条件1}else if(CalIsAliveArr[i][j] > 3 || CalIsAliveArr[i][j] < 2){LifeArr[i][j] = 0;}}}}}public static int [][] CalSurroundAlive(int [][] LifeArr){int [][] CalIsAliveArr = new int[LifeArr.length][LifeArr[0].length];for( int i = 0 ; i < LifeArr.length ; i ++ ){// i为行 j为列for ( int j = 0 ; j < LifeArr[i].length ; j ++ ){//判断该点是否活着://如果上方有东西,则向上遍历,如此推广到四个方向int count = 0;if( i - 1 >= 0){if(LifeArr[i-1][j] == 1){count++;}}if( i + 1 < LifeArr.length ){if(LifeArr[i+1][j] == 1){count++;}}if( j + 1 < LifeArr[i].length){if(LifeArr[i][j+1] == 1){count++;}}if( j - 1 >= 0){if(LifeArr[i][j-1] == 1){count++;}}CalIsAliveArr[i][j] = count;}}return CalIsAliveArr;}//备份上一次数组public static int [][] backUpArr(int [][] LifeArr){int [][] Arr = new int[LifeArr.length][LifeArr[0].length];for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){Arr[i][j] = LifeArr[i][j];}}return Arr;}//判断数组元素是否相同public boolean JudgeSame(int [][] backUpArr , int [][] LifeArr){for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){if(backUpArr[i][j] != LifeArr[i][j] ){return false;}}}return true;}}
(二)创建主界面类:
package DemoProject.fjm0729_V1;import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Scanner;public class GameUI extends JFrame {int [][] LifeArr = null;int n = 0;public void showUI(){System.out.println("欢迎来到生命数组游戏!");Scanner scanner=new Scanner(System.in);System.out.print("请输入生命数组的行数:");int row=scanner.nextInt();System.out.print("请输入生命数组的列数:");int col=scanner.nextInt();System.out.println("输入成功!等待生命数组加载.....");LifeArr=new int[row][col];AILife.randomInit(LifeArr);System.out.println("生命数组初始化....");for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){System.out.print(LifeArr[i][j] + " ");if ( j == LifeArr[i].length-1 ){System.out.println();}}}setTitle("生命游戏");setSize(900,900);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);setVisible(true);while (true){try {Thread.sleep(400);} catch (InterruptedException e) {throw new RuntimeException(e);}repaint();}}public void paint(Graphics g){BufferedImage bfi = new BufferedImage(900,820,BufferedImage.TYPE_4BYTE_ABGR);Graphics graphics = bfi.getGraphics();graphics.setColor(Color.WHITE);graphics.fillRect(0,0,900,820);AILife.showUpdate(LifeArr);graphics.setColor(Color.BLACK);//绘制更迭图像(1次)for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){if(LifeArr[i][j] ==1 ){graphics.fillRect( i*9, 40+j*8,9,8);}}}System.out.println("重绘了" + ++n + "次");g.drawImage(bfi,0,0,null);}public static void main(String[] args) {new GameUI().showUI();}
}
注意:
1.不要使用for循环来重绘,因为只有最后一次循环里,paint()方法才会被执行。这涉及到repaint的异步机制,不会立即进入paint()方法中
2.Buffered.TYPE_4BYTE_ABGR为透明背景,因此需要每一次绘制,都需要先画一个与窗口齐宽高的白色面板,覆盖掉先前痕迹
(二)版本二:
(一)创建AI方法类:
package DemoProject.fjm0729_V2;import java.util.Random;public class AILife {static int g=1;public static void showUpdate(int [][] LifeArr){upDate(LifeArr);//输出更迭后的数组System.out.println("更新过"+ g++ + "次的数组生命数组为:");for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){System.out.print(LifeArr[i][j] + " ");if ( j == LifeArr[i].length-1 ){System.out.println();}}}}public static void randomInit(int [][] LifeArr){Random random = new Random();for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){int randomValue = random.nextBoolean() ? 0 : 1;LifeArr[i][j] = randomValue;}}}public static void upDate(int [][] LifeArr){int [][] CalIsAliveArr = CalSurroundAlive(LifeArr);for( int i = 0 ; i < CalIsAliveArr.length ; i++){for ( int j = 0 ; j < CalIsAliveArr[i].length ; j ++){//条件3if(LifeArr[i][j] == 0){if(CalIsAliveArr[i][j] == 3 ){LifeArr[i][j] = 1;}}else if(LifeArr[i][j] == 1){//条件2if(CalIsAliveArr[i][j] == 3 || CalIsAliveArr[i][j] == 2){LifeArr[i][j] = 1;//条件1}else if(CalIsAliveArr[i][j] > 3 || CalIsAliveArr[i][j] < 2){LifeArr[i][j] = 0;}}}}}public static int [][] CalSurroundAlive(int [][] LifeArr){int [][] CalIsAliveArr = new int[LifeArr.length][LifeArr[0].length];for( int i = 0 ; i < LifeArr.length ; i ++ ){// i为行 j为列for ( int j = 0 ; j < LifeArr[i].length ; j ++ ){//判断该点是否活着://如果上方有东西,则向上遍历,如此推广到四个方向int count = 0;if( i - 1 >= 0){if(LifeArr[i-1][j] == 1){count++;}}if( i + 1 < LifeArr.length ){if(LifeArr[i+1][j] == 1){count++;}}if( j + 1 < LifeArr[i].length){if(LifeArr[i][j+1] == 1){count++;}}if( j - 1 >= 0){if(LifeArr[i][j-1] == 1){count++;}}CalIsAliveArr[i][j] = count;}}return CalIsAliveArr;}//备份上一次数组public static int [][] backUpArr(int [][] LifeArr){int [][] Arr = new int[LifeArr.length][LifeArr[0].length];for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){Arr[i][j] = LifeArr[i][j];}}return Arr;}//判断数组元素是否相同public boolean JudgeSame(int [][] backUpArr , int [][] LifeArr){for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){if(backUpArr[i][j] != LifeArr[i][j] ){return false;}}}return true;}}
(二)创建监听器类:一方面是鼠标监听器,一方面是键盘监听器
package DemoProject.fjm0729_V2;import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;public class EleListener implements MouseListener, KeyListener {GameUI gameUI;public EleListener( GameUI gameUI){this.gameUI=gameUI;}@Overridepublic void mouseClicked(MouseEvent e) {}@Overridepublic void mousePressed(MouseEvent e) {System.out.println("鼠标可监听");int x = e.getX();//决定的是第几列int y = e.getY();//决定的是第几行int row = (y - 20) / 8; //决定第几行int col = x / 9; //决定第几列System.out.println("这是第" + row + "行第" + col + "列");gameUI.LifeArr[row][col] = 1;}@Overridepublic void mouseReleased(MouseEvent e) {}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic void keyPressed(KeyEvent e) {int Key = e.getKeyCode();switch (Key){case KeyEvent.VK_SPACE:System.out.println("键盘被点击");gameUI.state = 1;}}@Overridepublic void keyReleased(KeyEvent e) {}
}
总结:
1.通过鼠标监听器,监听鼠标位置,将鼠标位置转换成其落在数组内的位置。将此空赋值为1
2.通过键盘监听器,控制运行状态,一开始向数组内赋值,后续使用键盘控制数组的开启
(三)创建主界面
package DemoProject.fjm0729_V2;import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Scanner;public class GameUI extends JFrame {int [][] LifeArr = null;int n = 0;int state = 0;int ImageX = 900;int ImageY = 820;public void showUI(){EleListener el = new EleListener(this);System.out.println("欢迎来到生命数组游戏!");Scanner scanner=new Scanner(System.in);System.out.print("请输入生命数组的行数:");int row=scanner.nextInt();System.out.print("请输入生命数组的列数:");int col=scanner.nextInt();System.out.println("输入成功!等待生命数组加载.....");LifeArr=new int[row][col];System.out.println("生命数组初始化....");setTitle("生命游戏");setSize(900,900);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);setLocationRelativeTo(null);addKeyListener(el);addMouseListener(el);setVisible(true);while (true){if(state == 1){System.out.println("本代码被执行");}else if(state == 0){System.out.println("值未被改变");}try {Thread.sleep(400);} catch (InterruptedException e) {throw new RuntimeException(e);}repaint();}}public void paint(Graphics g){if(state == 1){System.out.println("传进来了" + CalAllEle(LifeArr) + "值");if(JudgeHave(LifeArr)){System.out.println("LifeArr被传进来值了");}BufferedImage bfi = new BufferedImage(ImageX,ImageY,BufferedImage.TYPE_4BYTE_ABGR);Graphics graphics = bfi.getGraphics();graphics.setColor(Color.WHITE);graphics.fillRect(0,0,ImageX,ImageY);AILife.showUpdate(LifeArr);graphics.setColor(Color.BLACK);//绘制更迭图像(1次)for(int i = 0 ; i < LifeArr.length ; i++){for(int j = 0 ; j < LifeArr[i].length ; j ++){if(LifeArr[i][j] ==1 ){graphics.fillRect( i*9, 20+j*8,9,8);}}}System.out.println("重绘了" + ++n + "次");g.drawImage(bfi,0,0,null);}}public boolean JudgeHave(int [][] LifeArr){for (int i = 0 ; i < LifeArr.length ; i++){for( int j = 0 ; j < LifeArr[0].length ; j ++){if(LifeArr[i][j] == 1){return true;}}}return false;}public int CalAllEle(int [][] LiffeArr){int count = 0;for (int i = 0 ; i < LifeArr.length ; i ++){for ( int j = 0 ; j < LifeArr[0].length ; j ++){if(LifeArr[i][j] == 1){count++;}}}return count;}public static void main(String[] args) {new GameUI().showUI();}
}
删改处:将面板的坐标及大小转换成一个变量
增加处:添加监听器,并在循环中加入**Thread.sleep()**方法,不仅仅是为了减缓重绘速度,更是为了使EDT(事件调度线程)不要过于堵塞,确保其能及时监听到鼠标事件。
(个人提议):
手动初始化数组,很累。因为有10000个空位,填充起来需要点好多次鼠标,并且更迭起来又会淘汰掉一大批零散的空位