diff --git a/Make/java/Snake/src/C.java b/Make/java/Snake/src/C.java new file mode 100644 index 0000000..3bf0b0c --- /dev/null +++ b/Make/java/Snake/src/C.java @@ -0,0 +1,30 @@ +import java.awt.Color; + +public final class C { + // 格子行列数 + public static final int LINE_NUM = 20; + + // 格子宽度 + public static final int UNIT_WIDTH = 20; + + // Frame的宽度 + public static final int FRAME_W = LINE_NUM * UNIT_WIDTH + 16; + + // Frame的高度 + public static final int FRAME_H = LINE_NUM * UNIT_WIDTH + 39; + + // 速度 范围为1~10 + public static final int SPEED = 5; + + // 背景颜色 + public static final Color BGCOLOR = Color.GRAY; + + // 格子线颜色 + public static final Color GRIDCOLOR = new Color(120, 120, 120); + + // 蛇身颜色 + public static final Color SNAKECOLOR = Color.BLACK; + + // 食物颜色 + public static final Color FOODCOLOR = Color.GREEN; +} diff --git a/Make/java/Snake/src/Main.java b/Make/java/Snake/src/Main.java new file mode 100644 index 0000000..0a176fe --- /dev/null +++ b/Make/java/Snake/src/Main.java @@ -0,0 +1,10 @@ + +public class Main { + + public static void main(String[] args) { + // TODO Auto-generated method stub + new SnakeFrame("贪吃蛇"); + } + + +} diff --git a/Make/java/Snake/src/Makefile b/Make/java/Snake/src/Makefile new file mode 100644 index 0000000..59bbd2d --- /dev/null +++ b/Make/java/Snake/src/Makefile @@ -0,0 +1,18 @@ +snake.jar : C.class Main.class SnakeFrame.class SnakePanel.class + jar -cvfe snake.jar Main *.class + +C.class : C.java + javac C.java + +Main.class : Main.java + javac Main.java + +SnakeFrame.class : SnakeFrame.java + javac SnakeFrame.java + +SnakePanel.class : SnakePanel.java + javac SnakePanel.java + +.PHONY: clean +clean: + rm *.class *.jar \ No newline at end of file diff --git a/Make/java/Snake/src/SnakeFrame.java b/Make/java/Snake/src/SnakeFrame.java new file mode 100644 index 0000000..f5553a9 --- /dev/null +++ b/Make/java/Snake/src/SnakeFrame.java @@ -0,0 +1,43 @@ +import java.awt.Color; +import java.awt.Dimension; +import java.awt.HeadlessException; +import java.awt.Toolkit; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; + +@SuppressWarnings("serial") +public class SnakeFrame extends JFrame { + + private SnakePanel snakePanel; + + public SnakeFrame() throws HeadlessException { + this(""); + } + + public SnakeFrame(String title) throws HeadlessException { + super(title); + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Dimension dim = toolkit.getScreenSize(); + this.setBounds((dim.width - C.FRAME_W) / 2, (dim.height - C.FRAME_H) / 2, C.FRAME_W, C.FRAME_H); + this.snakePanel = new SnakePanel(); + this.setContentPane(this.snakePanel); + + this.setVisible(true); + this.setResizable(false); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + this.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + SnakeFrame.this.windowOpened(e); + } + }); + } + + private void windowOpened(WindowEvent e) { + this.snakePanel.initSomething(); + } + +} diff --git a/Make/java/Snake/src/SnakePanel.java b/Make/java/Snake/src/SnakePanel.java new file mode 100644 index 0000000..6431a6f --- /dev/null +++ b/Make/java/Snake/src/SnakePanel.java @@ -0,0 +1,237 @@ +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.LinkedList; +import java.util.function.Consumer; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.Timer; + +@SuppressWarnings("serial") +public class SnakePanel extends JPanel { + + private JLabel infoStart; + private JLabel infoOver; + + private boolean inited; + private boolean gameOver; + private boolean gamePause; + private boolean gameStart; + + private int direction; + private int food; + private int nextNode; + private LinkedList snakeNodes; + + private Timer timer; + + public SnakePanel() { + this.setBackground(C.BGCOLOR); + this.setLayout(null); + this.setFocusable(true); + this.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + SnakePanel.this.keyPressed(e); + } + }); + + Font font = new Font("黑体", Font.BOLD, 28); + this.infoOver = new JLabel("游戏结束"); + this.infoOver.setHorizontalAlignment(JLabel.CENTER); + this.infoOver.setFont(font); + this.infoStart = new JLabel("按空格键开始或暂停游戏"); + this.infoStart.setHorizontalAlignment(JLabel.CENTER); + this.infoStart.setFont(font); + this.add(this.infoOver); + this.add(this.infoStart); + this.hideInfo(); + this.gameStart = false; + + this.direction = 1; + + this.snakeNodes = new LinkedList<>(); + this.food = -1; + + this.timer = new Timer(1000 / C.SPEED, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + SnakePanel.this.snakeMove(); + } + }); + } + + private void generateFood() { + do { + this.food = (int)(Math.random() * C.LINE_NUM * C.LINE_NUM); + } while(this.snakeNodes.contains(this.food)); + } + + private void showInfo() { + if(this.gameOver) { + this.infoOver.setVisible(true); + } + this.infoStart.setVisible(true); + } + + private void hideInfo() { + this.infoOver.setVisible(false); + this.infoStart.setVisible(false); + } + + + @Override + public void paint(Graphics g) { + super.paint(g); + if(!this.inited) { + this.initPaint(g); + this.inited = true; + } + + } + + private void initPaint(Graphics g) { + g.setColor(C.GRIDCOLOR); + + for(int i = 0; i <= C.LINE_NUM; i++) { + g.drawLine(0, i * C.UNIT_WIDTH, this.getWidth(), i * C.UNIT_WIDTH); + g.drawLine(i * C.UNIT_WIDTH, 0, i * C.UNIT_WIDTH, this.getHeight()); + } + + // ???我当时为什么要用forEach这个写法?不是有简单写法??? + this.snakeNodes.forEach(new Consumer() { + @Override + public void accept(Integer t) { + SnakePanel.this.paintUnit(g, C.SNAKECOLOR, t); + } + }); + this.paintUnit(g, C.FOODCOLOR, this.food); + } + + private void paintUnit(Graphics g, Color color, int pos) { + g.setColor(color); + g.fillRect(X(pos) + 1, Y(pos) + 1, C.UNIT_WIDTH - 1, C.UNIT_WIDTH - 1); + } + + private int X(int pos) { + return pos % C.LINE_NUM * C.UNIT_WIDTH; + } + + private int Y(int pos) { + return pos / C.LINE_NUM * C.UNIT_WIDTH; + } + + + + + + + private void keyPressed(KeyEvent e) { + int temDirect = this.direction; + switch (e.getKeyCode()) { + case KeyEvent.VK_SPACE: + if(!this.gameStart) { + this.hideInfo(); + this.snakeNodes.clear(); + this.snakeNodes.add(3); + this.snakeNodes.add(2); + this.snakeNodes.add(1); + this.direction = 1; + this.nextNode = 4; + this.generateFood(); + this.gameOver = false; + this.gamePause = false; + this.gameStart = true; + this.inited = false; + this.update(this.getGraphics()); + } else if (!this.gameOver) { + this.gamePause = !this.gamePause; + } + if(!this.timer.isRunning()) { + this.inited = false; + this.timer.start(); + } + break; + + case KeyEvent.VK_LEFT: + this.setDirection(-1); + break; + + case KeyEvent.VK_UP: + this.setDirection(-C.LINE_NUM); + break; + + case KeyEvent.VK_RIGHT: + this.setDirection(1); + break; + + case KeyEvent.VK_DOWN: + this.setDirection(C.LINE_NUM); + break; + + default: + break; + } + } + + private void setDirection(int direction) { + if (this.gameOver || this.gamePause) { + return ; + } + int currentDirection = this.snakeNodes.get(0) - this.snakeNodes.get(1); + this.direction = (direction == -currentDirection) ? currentDirection : direction; + } + + private void snakeMove() { + this.nextNode = this.snakeNodes.get(0) + this.direction; + this.judgeOver(); + if(this.gameOver || this.gamePause) { + this.timer.stop(); + return ; + } + this.snakeNodes.addFirst(this.nextNode); + this.paintUnit(this.getGraphics(), C.SNAKECOLOR, this.nextNode); + if(this.nextNode == this.food) { + this.generateFood(); + this.paintUnit(this.getGraphics(), C.FOODCOLOR, this.food); + } else { + this.paintUnit(this.getGraphics(), C.BGCOLOR, this.snakeNodes.removeLast()); + } + + } + + private void judgeOver() { + boolean hitSelf = this.snakeNodes.contains(this.nextNode); + boolean hitWall = (this.nextNode < 0) || (this.nextNode > (C.LINE_NUM * C.LINE_NUM)) + || ((this.direction == 1) && (this.nextNode % C.LINE_NUM == 0)) + || ((this.direction == -1) && (this.nextNode % C.LINE_NUM == C.LINE_NUM - 1)); + if(hitSelf || hitWall) { + this.gameOver = true; + this.gameStart = false; + this.gamePause = false; + this.showInfo(); + } + } + + public void initSomething() { + this.infoOver.setBounds(0, 0, this.getWidth(), 30); + this.infoStart.setBounds(0, 40, this.getWidth(), 30); + this.showInfo(); + } + + + + + + + + + + + +}