zoukankan      html  css  js  c++  java
  • JAVA——贪吃蛇

    转载请注明出处: https://www.cnblogs.com/love-fromAtoZ/p/11781329.html 

    Project共有3个类:

      UI类:主要负责绘制界面以及时间监听和键盘监听。

      Snake类:负责内部的地图(int数组),蛇身移动的算法,随机食物位置以及吃掉食物的算法,以及对于是否撞墙和撞到身体的判断。

      Main类:程序入口。

    运行效果:

      

    程序代码:

    UI.java

      1 package Snake;
      2 
      3 import java.awt.event.*;
      4 import javax.swing.*;
      5 import javax.swing.Timer;
      6 import javax.swing.border.EmptyBorder;
      7 import javax.swing.table.*;
      8 import java.awt.*;
      9 import java.util.*;
     10 import java.math.*;
     11 
     12 public class UI extends JFrame implements KeyListener{
     13     static Timer timer;
     14     static Font enFont1 = new Font("Times New Roman",Font.BOLD,15);
     15     static Font enFont2 = new Font("Times New Roman",Font.BOLD,20);
     16     static Queue<Integer> Q = new LinkedList<Integer>();
     17     static JTextField mmp[][] = new JTextField[30][30];
     18     static JPanel drawPanel,scorePanel;
     19     static JLabel scoreText,scoreNum,readMe;
     20     static JButton newGame,Help,Pause;
     21     static Snake snake;
     22     static String HelpMessage = ""
     23             + "Game Rules :
    "
     24             + "Use the direction keys to control the snake on your keyboard.
    "
     25             + "Use the space key to pause/continue the game.
    "
     26             + "The snake can grows longer by eatting food.
    "
     27             + "Snake head can not touch the edges of the map.
    "
     28             + "Snake head can not touch his body.
    "
     29             + "
    "
     30             + "Happy game, happy life!
    
    "
     31             + "Copyright © J_Coder 2019. All rights reserved.";
     32     static int diff = 300;
     33     public UI(){
     34         snake = new Snake();
     35         snake.newSnake();
     36         //timer 被不断 new 会导致计时器间隔越来越小
     37         timer = new Timer(diff, new TimerListener());
     38         //set drawPanel
     39         drawPanel = new JPanel();
     40         drawPanel.setLayout(null);
     41         drawPanel.setBounds(10,5,440,440);
     42         drawPanel.setBackground(Color.DARK_GRAY);
     43         drawPanel.setFocusable(false);
     44         this.add(drawPanel);
     45         for(int i = 0;i <= 21;i ++){
     46             for(int j = 0;j <= 21;j ++){
     47                 mmp[i][j] = new JTextField();
     48                 mmp[i][j].setEditable(false);
     49                 mmp[i][j].setBounds(20*j,20*i,20,20);
     50                 mmp[i][j].setBorder(new EmptyBorder(0,0,0,0));
     51                 if(i == 0 || j == 0 || i == 21 || j == 21) {
     52                     mmp[i][j].setBackground(new Color(0,155,155));
     53                 }
     54                 else mmp[i][j].setBackground(Color.WHITE);
     55                 mmp[i][j].setFocusable(false);
     56                 drawPanel.add(mmp[i][j]);
     57             }
     58         }
     59         //set scorePanel
     60         scorePanel = new JPanel();
     61         scorePanel.setLayout(null);
     62         scorePanel.setBounds(460,5,160,440);
     63         scorePanel.setBackground(Color.LIGHT_GRAY);
     64         scorePanel.setFocusable(false);
     65         this.add(scorePanel);
     66         readMe = new JLabel();
     67         readMe.setBounds(0,0,160,150);
     68         readMe.setOpaque(true);
     69         readMe.setBackground(Color.white);
     70         readMe.setFont(enFont1);
     71         readMe.setText(readMe.getText() + "<html>Description<br>Press ↓ to move up.<br>");
     72         readMe.setText(readMe.getText() + "Press ↑ to move down.<br>");
     73         readMe.setText(readMe.getText() + "Press ← to move left.<br>");
     74         readMe.setText(readMe.getText() + "Press → to move right.<br>");
     75         readMe.setText(readMe.getText() + "Press SPACE to pause or continue the game.</html>");
     76         readMe.setFocusable(false);
     77         scorePanel.add(readMe);
     78         scoreText = new JLabel("SCORE",JLabel.CENTER);
     79         scoreText.setFont(enFont2);
     80         scoreText.setBounds(15,170,130,30);
     81         scoreText.setOpaque(true);
     82         scoreText.setBackground(Color.white);
     83         scoreText.setFocusable(false);
     84         scorePanel.add(scoreText);
     85         scoreNum = new JLabel("0",JLabel.CENTER);
     86         scoreNum.setFont(enFont2);
     87         scoreNum.setBounds(15,210,130,30);
     88         scoreNum.setOpaque(true);
     89         scoreNum.setBackground(Color.white);
     90         scoreNum.setFocusable(false);
     91         scorePanel.add(scoreNum);
     92         newGame = new JButton("New Game");
     93         newGame.setFont(enFont2);
     94         newGame.setBounds(15,260,130,40);
     95         newGame.addActionListener(new ActionListener(){
     96             public void actionPerformed(ActionEvent e){
     97                 snake.newSnake();
     98                 draw();
     99                 timer.start();
    100                 scoreNum.setText("0");
    101                 Pause.setText("Pause");
    102             }
    103         });
    104         newGame.setFocusable(false);
    105         scorePanel.add(newGame);
    106         Pause = new JButton("Pause");
    107         Pause.setFont(enFont2);
    108         Pause.setBounds(15,310,130,40);
    109         Pause.addActionListener(new ActionListener(){
    110             public void actionPerformed(ActionEvent e){
    111                 if(timer == null) return ;
    112                 if(Pause.getText().charAt(0) == 'P') {PauseGame();}
    113                 else {ContinueGame();}
    114             }
    115         });
    116         Pause.setFocusable(false);
    117         scorePanel.add(Pause);
    118         Help = new JButton("Help");
    119         Help.setFont(enFont2);
    120         Help.setBounds(15,360,130,40);
    121         Help.addActionListener(new ActionListener(){
    122             public void actionPerformed(ActionEvent e){
    123                 if(timer != null) PauseGame();
    124                 JOptionPane.showMessageDialog(null, HelpMessage, "Help", JOptionPane.INFORMATION_MESSAGE);
    125             }
    126         });
    127         Help.setFocusable(false);
    128         scorePanel.add(Help);
    129         //set frame
    130         this.setTitle("Snake");
    131         this.setLayout(null);
    132         this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    133         this.setSize(640, 480);
    134         Dimension winSize = Toolkit.getDefaultToolkit().getScreenSize();   
    135         this.setLocation((winSize.width - this.getWidth()) / 2,(winSize.height - this.getHeight()) / 2);
    136         this.setResizable(false);
    137         this.setVisible(true);
    138         addKeyListener(this);
    139         this.setFocusable(true);
    140     }
    141     
    142     void draw() {
    143         for(int i = 1;i <= 20;i ++){
    144             for(int j = 1;j <= 20;j ++){
    145                 mmp[i][j].setBackground(Color.white);
    146                 if(snake.mmp[i][j] == snake.L) {
    147                     mmp[i][j].setBackground(new Color(200,50,50));
    148                 }
    149                 else if(snake.mmp[i][j] != 0 && snake.mmp[i][j] != 1000) {
    150                     mmp[i][j].setBackground(new Color(50,50,200));
    151                 }
    152                 else if(snake.mmp[i][j] == 1000){
    153                     mmp[i][j].setBackground(new Color(50,200,50));
    154                 }
    155             }
    156         }
    157     }
    158     
    159     static void PauseGame(){
    160         timer.stop();
    161         Pause.setText("Continue");
    162     }
    163     static void ContinueGame(){
    164         timer.start();
    165         Pause.setText("Pause");
    166     }
    167 
    168     public void gameOver(){
    169         timer.stop();
    170         int nowScore = Integer.valueOf(scoreNum.getText());
    171         String Title = "GameOver";
    172         String loseMessage = "Your score is " + scoreNum.getText() + " .
    ";
    173         if(nowScore <= 300){loseMessage += "Your evaluation : Too weak !";}
    174         else if(nowScore <= 800){loseMessage += "Your evaluation : Just so so !";}
    175         else if(nowScore <= 1300){loseMessage += "Your evaluation : Good job !";}
    176         else if(nowScore <= 2000){loseMessage += "Your evaluation : Incredible !";}
    177         else if(nowScore < 3500){loseMessage += "Your evaluation : Holy crap !";}
    178         else{
    179             Title = "Congratulations";
    180             loseMessage = "You are already finish this stage !
    Thank you for your playing !";
    181         }
    182         JOptionPane.showMessageDialog(null, loseMessage, Title, JOptionPane.INFORMATION_MESSAGE);
    183     }
    184     
    185     class TimerListener implements ActionListener {
    186         public void actionPerformed(ActionEvent e) {
    187 //            for(int i = 0;i <= 21;i ++) {
    188 //                for(int j = 0;j <= 21;j ++) {
    189 //                    System.out.printf("%2d",snake.mmp[i][j]);
    190 //                }System.out.println();
    191 //            }
    192             if(Q.size() > 0) snake.dir = Q.poll();
    193             Q.clear();
    194             int tmp = snake.moveForward();
    195             draw();
    196             if(tmp == -1){gameOver();}
    197             else scoreNum.setText(String.valueOf(Integer.valueOf(scoreNum.getText()) + tmp));
    198             if(Integer.valueOf(scoreNum.getText()) >= 3500){
    199                 gameOver();
    200             }
    201         }
    202     }
    203     //使用 setFocusable() 将 JFrame 设置为 true 
    204     //其他组件设置为 false 可以避免点击其他按钮等操作将焦点转移至其他控件
    205     public void keyPressed(KeyEvent e) {
    206         if(e.getKeyCode() == KeyEvent.VK_SPACE) {
    207             if(timer != null) {
    208                 if(Pause.getText().charAt(0) == 'P') {PauseGame();}
    209                 else {ContinueGame();}
    210             }
    211             return ;
    212         }
    213         if(Pause.getText().charAt(0) == 'C') {return ;}
    214         if(e.getKeyCode() == KeyEvent.VK_UP) {
    215             if(snake.dir != 2) Q.offer(1);
    216             //if(snake.dir != 2) {snake.dir = 1;}
    217             //System.out.println("up");
    218             return ;
    219         }
    220         if(e.getKeyCode() == KeyEvent.VK_DOWN) {
    221             if(snake.dir != 1) Q.offer(2);
    222             //if(snake.dir != 1) {snake.dir = 2;}
    223             //System.out.println("down");
    224             return ;
    225         }
    226         if(e.getKeyCode() == KeyEvent.VK_LEFT) {
    227             if(snake.dir != 4) Q.offer(3);
    228             //if(snake.dir != 4) {snake.dir = 3;}
    229             //System.out.println("left");
    230             return ;
    231         }
    232         if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
    233             if(snake.dir != 3) Q.offer(4);
    234             //if(snake.dir != 3) {snake.dir = 4;}
    235             //System.out.println("right");
    236             return ;
    237         }
    238     }
    239     public void keyReleased(KeyEvent e) {}
    240     public void keyTyped(KeyEvent e) {}
    241 }

    Snake.java

     1 package Snake;
     2 
     3 import java.util.*;
     4 import javax.swing.Timer;
     5 import java.awt.event.ActionEvent;
     6 import java.awt.event.ActionListener;
     7 import java.math.*;
     8 import javafx.util.*;
     9 
    10 public class Snake {
    11     public class pair{
    12         int first,second;
    13         public pair(int x,int y) {first = x;second = y;}
    14     }
    15     static int[][] mmp = new int[30][30];
    16     static int foodX,foodY;
    17     static pair[] body = new pair[500];//max number is head
    18      static int Dir[][] = {{0,0},{-1,0},{1,0},{0,-1},{0,1}}; // 1 = up; 2 = down; 3 = left; 4 = right
    19     static int L,dir;
    20     
    21     void newSnake() {
    22         dir = 4;L = 3;
    23         init();
    24         for(int i = 0;i < 400;i ++) {body[i] = new pair(-1,-1);}
    25         body[0] = new pair(3,3);
    26         body[1] = new pair(3,4);
    27         body[2] = new pair(3,5);
    28         mmp[3][3] = 1;
    29         mmp[3][4] = 2;
    30         mmp[3][5] = 3;
    31         randFood();
    32     }
    33     
    34     public void randFood() {
    35         int x = (int)(Math.random() * 1000) % 20 + 1;
    36         int y = (int)(Math.random() * 1000) % 20 + 1;
    37         while(mmp[x][y] != 0) {
    38             x = (int)(Math.random() * 1000) % 20 + 1;
    39             y = (int)(Math.random() * 1000) % 20 + 1;
    40         }
    41         foodX = x;
    42         foodY = y;
    43         mmp[x][y] = 1000;
    44     } 
    45     
    46     public void init() {
    47         for(int i = 0;i <= 21;i ++) {
    48             for(int j = 0;j <= 21;j ++) {
    49                 if(i == 0 || j == 0 || i == 21 || j == 21) {mmp[i][j] = -1;}
    50                 else mmp[i][j] = 0;
    51             }
    52         }
    53     }
    54     
    55     public int moveForward() {
    56         int ret = 0;
    57         body[L].first = body[L-1].first + Dir[dir][0];
    58         body[L].second = body[L-1].second + Dir[dir][1];
    59         for(int i = 0;i < L;i ++) {
    60             body[i] = body[i + 1];
    61         }
    62         body[L] = new pair(-1,-1);
    63         //eat food
    64         if(body[L-1].first == foodX && body[L-1].second == foodY){
    65             for(int i = L;i >= 1;i --) {
    66                 body[i] = body[i - 1];
    67             }
    68             L ++;
    69             ret += 10;
    70             randFood();
    71         }
    72         //touch wall or touch body
    73         if(body[L-1].first == 0 || body[L-1].second == 0 || body[L-1].first == 21 || body[L-1].second == 21){
    74             return -1;
    75         }
    76         for(int i = L - 2;i >= 0;i --){
    77             if(body[L - 1].first == body[i].first && body[L - 1].second == body[i].second){
    78                 return -1;
    79             }
    80         }
    81         init();
    82         for(int i = 0;i < L;i ++) {
    83             mmp[body[i].first][body[i].second] = i + 1;
    84 //            System.out.print(body[i].first);
    85 //            System.out.print("  ");
    86 //            System.out.println(body[i].second);
    87         }
    88         mmp[foodX][foodY] = 1000;
    89         return ret;
    90     }
    91     
    92 
    93 }

    Main.java

    1 package Snake;
    2 
    3 public class Main {
    4     public static void main(String[] args) {
    5         new UI();
    6     }
    7 }

    问题以及解决方案:

    问题一:添加控件或者点击按钮导致键盘监听无效。

    解决方法:将JFrame的setFocusable()设置为true,并将所有控件的setFocusable()都设置为false。原因是在添加或点击控件时,焦点脱离了我们添加键盘监听的东西(JPanle或JFrame等),跑到了我们添加或者点击的控件上,此时执行的是这个控件上的键盘监听,所以将所有的其他控件设置为不可获取焦点可以避免焦点丢失。

    问题二:蛇会“回头”,假设蛇往右走,快速连续按下方向键下和右会导致蛇向当前方向的负方向移动。

    解决方法:设置一个队列来存储计时器在一次计时内的所有按键,在每次计时结束的时候只执行队首的操作,并将队列清空,这样就保证了每个计时时间内只有一次操作。

    问题三:一直点击NewGame按钮会导致计时间隔越来越小。

    解决方案:不能多次new Timer(),只在构造函数内new一个Timer,其余的部分用stop()和start()进行操作。

  • 相关阅读:
    第一阶段冲刺(6)--每日立会--个人工作总结
    第一阶段冲刺--每日立会(5)--个人工作总结
    第一阶段冲刺--每日立会(4)--个人工作总结
    第十一周学习记录表
    第一阶段冲刺--每日立会(3)个人工作总结
    第一阶段冲刺--每日立会(2)--个人工作总结
    第一阶段冲刺--每日立会(1)--个人工作总结
    第十周学习记录表
    第九周学习进度表
    输入法
  • 原文地址:https://www.cnblogs.com/love-fromAtoZ/p/11781329.html
Copyright © 2011-2022 走看看