- package com.snake.controller;
-
- import javax.swing.JFrame;
- import javax.swing.JOptionPane;
-
- import com.snake.view.SnakeJPanel;
-
- public class SnakeStart {
- public static void main(String[] args) {
-
- int speed = 0;
- String showInputDialog = null;//初始化时间
- //得到速度
- while(true) {
- showInputDialog = JOptionPane.showInputDialog("蛇移动速度(1 - 5)","3");
-
- if(showInputDialog == null) {
- showInputDialog = "3";//默认速度
- break;
- }
- if(showInputDialog.length() > 1) {
- continue;
- }
- char[] a = showInputDialog.toCharArray();
- if(a[0] >= '1' && a[0] <= '5') {
- break;
- }
- }
-
- speed = Integer.parseInt(showInputDialog) * 50;
-
-
- SnakeJPanel snakeJPanel = new SnakeJPanel(speed);
-
- //创建一个JFrame窗口,将游戏面板添加进行窗口中
- JFrame jFrame = new JFrame();
- //设置窗口的某些属性
- jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- jFrame.setSize(920, 750);
- jFrame.add(snakeJPanel);
- jFrame.setLocationRelativeTo(null);
- jFrame.setVisible(true);
- }
-
- }
- package com.snake.view;
-
- import java.awt.Color;
- import java.awt.EventQueue;
- import java.awt.Font;
- import java.awt.Frame;
- import java.awt.Graphics;
- import java.awt.Image;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
-
- import javax.swing.ImageIcon;
- import javax.swing.JFrame;
- import javax.swing.JOptionPane;
- import javax.swing.JPanel;
- import javax.swing.Timer;
- import javax.swing.border.EmptyBorder;
-
-
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.KeyAdapter;
- import java.awt.event.KeyEvent;
-
- public class SnakeJPanel extends JPanel implements ActionListener{
-
- private boolean start;//当前游戏状态
-
- private int speed;//速度
-
- private boolean exist;//当前是否存在食物
-
- private int foodType;//食物种类
-
- private int x;//豆子的横坐标
- private int y;//豆子的纵坐标
-
- private ArrayList<int[]> localList;//蛇
-
-
- public String direction;//方向
-
- private String direction2;//引导方向
-
- public boolean flag;
-
- Random rand = new Random();
-
- private ImageIcon up;
-
- private ImageIcon down;
-
- private ImageIcon right;
-
- private ImageIcon left;
-
- private ImageIcon body;
-
- private ImageIcon food;
-
- private ImageIcon title;
-
- Timer time;
-
- private int score;//当前得分情况
-
- private int num;//吃到的食物个数
-
- // private Image offScreenImage; //图形缓存
-
-
- //图片绘制
- @Override
- public void paint(Graphics g) {
-
- direction = direction2;
-
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, 900, 700);
-
- //绘制游戏框
- //标题框
- // g.drawRect(25, 30, 800, 75);
- title.paintIcon(this, g, 25, 10);
-
- //内容框
- g.setColor(Color.black);
- g.fillRect(25, 75, 850, 600);
-
- //绘制食物的坐标位置
- if(!exist) {//如果当前不存在豆子,随机绘制一个豆子
- if(num % 5 == 0) {
- foodType = 1;
- }else {
- foodType = 0;
- }
- boolean isProduce = true;
- while(isProduce) {
- isProduce = false;
- x = rand.nextInt(33) * 25 + 25;
- y = rand.nextInt(23) * 25 + 75;
- for (int[] arr:localList) {
- if(x == arr[0] && y == arr[1]) {
- isProduce = true;
- break;
- }
- }
-
- }
- System.out.println(x + "---" + y);
- }
-
- if(eat()) {
- exist = false;
- }else {
- exist = true;
- }
-
-
- if(foodType == 0) {
- //绘制食物
- g.setColor(Color.blue);
- // g.fillRect(x, y, 25, 25);
- g.drawImage(food.getImage(),x, y, 25, 25,null);
- }else {
- //绘制食物
- g.setColor(Color.WHITE);
- g.fillRect(x, y, 25, 25);
- // g.drawImage(food.getImage(),x, y, 25, 25,null);
- }
-
-
- //绘制头
- g.setColor(Color.red);
- // g.fillRect(localList.get(0)[0], localList.get(0)[1], 25, 25);
- ImageIcon head = null;
- //判断当前方向
- if(direction.equals("R")) {
- head = right;
- }else if(direction.equals("L")) {
- head = left;
- }else if(direction.equals("U")) {
- head = up;
- }else if(direction.equals("D")) {
- head = down;
- }
- // g.drawImage(head.getImage(), localList.get(0)[0], localList.get(0)[1], 25, 25,null);
- head.paintIcon(this, g,localList.get(0)[0], localList.get(0)[1]);
-
- //绘制身体
- g.setColor(Color.white);
- for (int i = 1; i < localList.size(); i++) {
- // g.fillRect(localList.get(i)[0], localList.get(i)[1], 25, 25);
- // g.drawImage(body.getImage(), localList.get(i)[0], localList.get(i)[1], 25, 25,null);
- body.paintIcon(this, g, localList.get(i)[0], localList.get(i)[1]);
- }
- // g.fillRect(localList.get(1)[0], localList.get(1)[1], 25, 25);
- // g.fillRect(localList.get(2)[0], localList.get(2)[1], 25, 25);
-
-
- //绘制分数和长度
- //长度
- g.setColor(Color.GREEN);
- g.setFont(new Font("宋体", Font.BOLD, 18));
- g.drawString("长度:" + (localList.size() - 1), 25, 30);
-
- //分数
- g.drawString("分数:" + score, 25, 48);
-
- if(!start) {//如果游戏未启动,结束移动和重绘
- g.setColor(Color.white);
- g.setFont(new Font("宋体", Font.BOLD, 30));
- g.drawString("暂停/开始(请按任意键开始,空格键暂停)", 150, 300);
- time.stop();
-
- }else {
- time.start();
- }
-
- // speed();
- //移动后进行下一次绘制
- // move();//移动
- // repaint();//重新绘制
- }
-
- // //解决闪烁问题
- // //如果为JFrame 为重量级 程序不会调用update()方法
- // //如果为Frame 为轻量级 重写update()方法 做双缓冲
- // //如果为JPanel 不会闪烁
- // @Override
- // public void update(Graphics g)
- // {
- // System.out.println("update");
- // if(offScreenImage == null)
- // offScreenImage = this.createImage(900, 700); //新建一个图像缓存空间,这里图像大小为800*600
- // Graphics gImage = offScreenImage.getGraphics(); //把它的画笔拿过来,给gImage保存着
- // paint(gImage); //将要画的东西画到图像缓存空间去
- // g.drawImage(offScreenImage, 0, 0, null); //然后一次性显示出来
- // }
-
-
- @Override
- public void actionPerformed(ActionEvent e) {
- //移动后进行下一次绘制
- move();//移动
- repaint();//重新绘制
-
- }
-
- /**
- * 绘制速度
- */
- // private void speed() {
- // try {//按一定速度进行移动
- // Thread.sleep(speed);//控制移动速度
- // } catch (InterruptedException e) {
- // // TODO 自动生成的 catch 块
- // e.printStackTrace();
- // }
- // }
-
- /**
- * 初始化图片
- */
- private void drawImage() {
- up = new ImageIcon("images/up.png");
- down = new ImageIcon("images/down.png");
- right = new ImageIcon("images/right.png");
- left = new ImageIcon("images/left.png");
- body = new ImageIcon("images/body.png");
- food = new ImageIcon("images/food.png");
- title = new ImageIcon("images/title.jpg");
- }
-
- private boolean eat() {
- if(localList.get(0)[0] == x && localList.get(0)[1] == y) {//如果当前蛇头吃到了豆子
- System.out.println("eat");
- num++;
- if(foodType == 0) {
- score += 10;
- }else {
- score += (rand.nextInt(5) * 10 + 10);
- }
- int last = localList.size() - 1;//蛇尾
- //在蛇尾后面添加一节身体
- localList.add(new int[] {localList.get(last)[0],localList.get(last)[1]});
- return true;
- }
- return false;
- }
-
- //移动方法
- public void move() {
- //判断是否游戏结束
- if(isbody()) {
- System.out.println("game over");
- start = false;//结束游戏移动
- JOptionPane.showMessageDialog(null,"游戏已结束!");
- time.stop();
- init();
- }
-
- if(flag && localList != null) {//如果长度不为空且游戏未结束
- int last = localList.size() - 1;//记录蛇尾
-
- for (int i = last; i > 0; i--) {//从蛇尾开始,每节身体移动到前一节身体的位置上
- localList.set(i,new int[] {localList.get(i - 1)[0],localList.get(i - 1)[1]});
- }
-
- //记录头位置
- int[] local = localList.get(0);
- //判断当前方向,并进行模拟移动,判断是否与边界重合
- if(direction.equals("R")) {
- if(local[0] >= 850) {
- local[0] = 25;
- }else {
- local[0] += 25;
- }
-
- }else if(direction.equals("L")) {
- if(local[0] <= 25) {
- local[0] = 850;
- }else {
- local[0] -= 25;
- }
-
- }else if(direction.equals("U")) {
-
- if(local[1] <= 75) {
- local[1] = 650;
- }else {
- local[1] -= 25;
- }
-
- }else if(direction.equals("D")) {
- if(local[1] >= 650) {
- local[1] = 75;
- }else {
- local[1] += 25;
- }
-
- }
-
- //更改头的位置
- localList.set(0, local);
- }
- }
-
- //判断下一步是否为蛇身
- private boolean isbody() {
- // TODO 自动生成的方法存根
- //记录头位置
- int x = localList.get(0)[0];
- int y = localList.get(0)[1];
-
- //判断当前方向,并进行模拟移动,判断是否与边界重合
- if(direction.equals("R")) {
- x += 25;
- }else if(direction.equals("L")) {
- x -= 25;
- }else if(direction.equals("U")) {
- y -= 25;
- }else if(direction.equals("D")) {
- y += 25;
- }
-
- for (int i = 1; i < localList.size(); i++) {
- if(localList.get(i)[0] == x && localList.get(i)[1] == y) {
- return true;
- }
- }
- return false;
-
- }
-
- // //判断下一步是否为边界
- // private boolean isborder() {
- // // TODO 自动生成的方法存根
- // //记录头位置
- // // TODO 自动生成的方法存根
- // //记录头位置
- // int x = localList.get(0)[0];
- // int y = localList.get(0)[1];
- //
- // //判断当前方向,并进行模拟移动,判断是否与边界重合
- // if(direction.equals("R")) {
- // x += 25;
- // }else if(direction.equals("L")) {
- // x -= 25;
- // }else if(direction.equals("U")) {
- // y -= 25;
- // }else if(direction.equals("D")) {
- // y += 25;
- // }
- //
- // if(x < 25 || x > (33 * 25 + 25)) {
- // return true;//当x坐标超出边界,则返回true
- // }
- // if(y < 105 || y > (23 * 25 + 105)) {
- // return true;//当y坐标超出边界,则返回true
- // }
- // return false;//蛇头移动后未超出边界,返回false
- //
- // }
-
- /**
- * Create the frame.
- */
- public SnakeJPanel(int speed) {
-
- this.speed = speed; //初始化速度
-
- //初始化游戏面板的基本信息
- this.setSize(900, 700);
- this.setLocation(0, 30);
- this.setFocusable(true);
-
- init();//初始化界面
- drawImage();//绘制图片
- moveByKey();//给界面添加一个键盘监听
-
- }
-
- /*
- * 键盘监听
- * 通过键盘输入上下左右来控制当前蛇头移动的方向
- * 先判断当前蛇头方向,再来改变引导方向
- * 当进行绘制时再修改蛇的方向
- * 保证不会因为在短时间内快速变换方向导致蛇头逆向转向
- */
- private void moveByKey() {
- addKeyListener(new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e) {
- int key = e.getKeyCode();
- //边界值判断
- switch(key) {
- case 65:
- case 37:{//向左走
- if(!direction.equals("R")) {
- direction2 = "L";
-
- }
- break;
- }
- case 87:
- case 38:{//向上走
- if(!direction.equals("D")) {
- direction2 = "U";
- }
- break;
- }
- case 68:
- case 39:{//向右走
- if(!direction.equals("L")) {
- direction2 = "R";
- }
- break;
- }
- case 83:
- case 40:{//向下走
- if(!direction.equals("U")) {
- direction2 = "D";
- }
- break;
- }
- case KeyEvent.VK_SPACE:{//如果当前键盘输入为空格
- start = !start;//调整游戏状态
- System.out.println("暂停/开始");
- repaint();//重绘
- }
- }
-
- //任意键开始
- if(!start && key != KeyEvent.VK_SPACE) {//如果当前状态为暂停状态,且键盘输入不是空格
- start = true;
- repaint();//重绘
-
- }
- }
- });
- }
-
- /**
- * 初始化游戏基本信息
- */
- private void init() {
- start = false;
-
- exist = true;
-
- direction2 = "U";
-
- flag = true;
-
- localList = new ArrayList<int[]>();
-
- localList.add(0,new int[] {75,125});//蛇头
- localList.add(1,new int[] {75,150});//蛇身1
- localList.add(2,new int[] {75,175});//蛇身2
-
- //创建第一个食物的位置
- //通过循环保证当前生成的食物不在身体所在的坐标上
- boolean isProduce = true;
- while(isProduce) {//循环生成食物坐标
- isProduce = false;//结束本次循环
- x = rand.nextInt(33) * 25 + 25;
- y = rand.nextInt(23) * 25 + 75;
- for (int[] arr:localList) {//循环遍历蛇头及蛇身的坐标
- if(x == arr[0] && y == arr[1]) {//如果食物坐标和蛇的某一节坐标重合
- isProduce = true;//跳转循环状态,继续下一次食物生成
- break;
- }
- }
- //蛇身遍历完成,没有重合坐标,结束食物坐标生成
-
- }
-
- time = new Timer(speed, this);
- setLayout(null);
-
- score = 0;
-
- num = 0;
-
- foodType = 0;
-
- // repaint();
-
- }
-
-
- }
结束力