package start; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; public class GamePanel extends JPanel implements KeyListener, ActionListener { //设置蛇的长度和蛇的x轴以及y轴坐标 int len; int[] snakeX = new int[600]; int[] snakeY = new int[500]; //这里在定义一个方向,并且默认是R String fx;//可以是R L U D //这里再初始化一个用来判断游戏是否开始的,如果没开始的话,就可以进行一些文字提示 boolean isStart = false; //这里需要初始化调用init,所以直接在构造函数里调用 //创建一个timer 参数就是隔着的时间和当前需要监听的对象 Timer timer = new Timer(100, this); //然后再这边定一个一个食物的属性,有坐标,还有一个随机数 int foodx; int foody; Random rand = new Random(); //再定义一个游戏失败 boolean isFail = false; //这里再加一个分数系统 int score; GamePanel() { init(); //也不知道为什么,反正就是需要有,获取到键盘的监听事件 this.setFocusable(true); this.addKeyListener(this); } //然后对这个蛇进行初始化 public void init() { //让蛇的长度为3,并且是头部,第一部分以及第二部分身体的长度设置好 len = 3; snakeX[0] = 100; snakeY[0] = 100; snakeX[1] = 75; snakeY[1] = 100; snakeX[2] = 50; snakeY[2] = 100; //把方向放到这来初始化 fx = "R"; //初始化的时候也要让他启动 timer.start(); //再把食物给初始化了,主要是位置 foodx = 25 + 25 * rand.nextInt(24); foody = 75 + 25 * rand.nextInt(24); //把分数初始化为0 score = 0; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g);//作用是清屏 //可以先设置一下背景颜色 this.setBackground(Color.BLACK); //再这个的基础之上,绘制游戏的区域 g.fillRect(25, 75, 850, 600); //然后开始话一个静态的小蛇,因为最初蛇头是朝右边的,所以头是right,然后就是两个位置 /*Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);*/ //这里通过方向也优化一下 if (fx.equals("R")) { Data.right.paintIcon(this, g, snakeX[0], snakeY[0]); } else if (fx.equals("L")) { Data.left.paintIcon(this, g, snakeX[0], snakeY[0]); } else if (fx.equals("U")) { Data.up.paintIcon(this, g, snakeX[0], snakeY[0]); } else if (fx.equals("D")) { Data.down.paintIcon(this, g, snakeX[0], snakeY[0]); } /*Data.body.paintIcon(this,g,snakeX[1],snakeY[1]); Data.body.paintIcon(this,g,snakeX[2],snakeY[2]);*/ //优化一下 for (int i = 1; i < len; i++) { Data.body.paintIcon(this, g, snakeX[i], snakeY[i]); } //这里就需要把食物给画出来了 Data.food.paintIcon(this, g, foodx, foody); //这里插入把分数和成绩也画出来好了 g.setColor(Color.WHITE); //类型和大小 g.setFont(new Font("楷体", Font.BOLD, 20)); //这个是对应的位置 g.drawString("长度" + len, 750, 200); g.drawString("分数" + score, 750, 250); //这里画完小蛇之后,就进行游戏是否开始的判断 if (!isStart) { //如果没开始,就要进行设置 //先设置字体颜色和位置 g.setColor(Color.WHITE); //类型和大小 g.setFont(new Font("楷体", Font.BOLD, 40)); //这个是对应的位置 g.drawString("按下空格开始", 300, 300); } if (isFail) { //如果他失败了的话 //如果没开始,就要进行设置 //先设置字体颜色和位置 g.setColor(Color.RED); //类型和大小 g.setFont(new Font("楷体", Font.BOLD, 40)); //这个是对应的位置 g.drawString("游戏失败按空格重新开始", 300, 300); } } //然后再是需要有键盘的参与,先是继承键盘的方法,这里就会重写一些方法 @Override public void keyPressed(KeyEvent e) { //这个方法是键盘按下了,但是没有释放 //首先是让他来获取到当前按下的键是什么 int keyCode = e.getKeyCode(); //然后来判断这个按下的键是不是空格,如果是的话,就让游戏开始,或者也可以从启动变成暂停 if (keyCode == KeyEvent.VK_SPACE) { //所以这里也需要改一下,分成两种情况 if (isFail) { //如果是游戏失败导致的空格,就把游戏失败改回来,而且还需要初始化 isFail = false; init(); } else { isStart = !isStart; //这里很关键的就是还需要刷新界面 } repaint(); } //并且在这边来控制键盘走向,也就是来读取,现在就是会把头的方向进行改变,但是整体是不会变的 if (keyCode == KeyEvent.VK_LEFT) { //如果等于左边的话 fx = "L"; } else if (keyCode == KeyEvent.VK_RIGHT) { fx = "R"; } else if (keyCode == KeyEvent.VK_UP) { fx = "U"; } else if (keyCode == KeyEvent.VK_DOWN) { fx = "D"; } } //再写一个定时器,用来监听时间,帧 @Override public void actionPerformed(ActionEvent e) { //就是就要开始让小蛇动起来了 //先判断他是不是开始游戏了,并且没有失败的话 if (isStart && !isFail) { //如果开始了,并且是右移的 //然后对于其他的,就使用循环就行了,这里是需要让从后面往前面的,如果是前面往后面的话,由于0和1不是同一个,所以会被直接吞并 for (int i = len - 1; i > 0; i--) { //这里要把Y也加上来,这个是一个整体,上下左右都是会直接跟随的 snakeX[i] = snakeX[i - 1]; snakeY[i] = snakeY[i - 1]; } //在这里继续判断是朝那边 if (fx.equals("R")) { //对于头部来说,那就是往前移动25.右移,y是不动的 snakeX[0] = snakeX[0] + 25; //解决蛇出边界的情况 if (snakeX[0] > 800) { snakeX[0] = 25; } } else if (fx.equals("L")) { snakeX[0] = snakeX[0] - 25; if (snakeX[0] < 25) { snakeX[0] = 800; } } else if (fx.equals("U")) { snakeY[0] = snakeY[0] - 25; if (snakeY[0] < 75) { snakeY[0] = 650; } } else if (fx.equals("D")) { snakeY[0] = snakeY[0] + 25; if (snakeY[0] > 650) { snakeY[0] = 75; } } //这里就需要吃食物了 if (snakeY[0] == foody && snakeX[0] == foodx) { //如果和食物重合的话,那就是需要把长度加一 len++; //把分数也更新一下 score = score + 10; //并且重新刷新一个食物位置 foodx = 25 + 25 * rand.nextInt(24); foody = 75 + 25 * rand.nextInt(24); } //这里就需要来判断游戏是否失败了 for (int i = 1; i < len; i++) { if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) { //把游戏变成失败 isFail = true; } } if ((snakeX[0]<25 || snakeX[0]>850)||(snakeY[0]<75 || snakeY[0]>650 ) ){ isFail = true; } //然后刷新 repaint(); } //并且让监听器启动 timer.start(); } //下面两个方法用不到,就不管就行了 @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } }
import javax.imageio.ImageIO; import javax.swing.*; import java.net.URL; //用来存放外部数据的图片 public class Data { //头部的上下左右 public static URL upUrl = Data.class.getResource("/statics/up.png"); public static URL downUrl = Data.class.getResource("/statics/down.png"); public static URL leftUrl = Data.class.getResource("/statics/left.png"); public static URL rightUrl = Data.class.getResource("/statics/right.png"); public static ImageIcon up = new ImageIcon(upUrl); public static ImageIcon down = new ImageIcon(downUrl); public static ImageIcon left = new ImageIcon(leftUrl); public static ImageIcon right = new ImageIcon(rightUrl); //身体的 public static URL bodyUrl = Data.class.getResource("/statics/body.png"); public static ImageIcon body = new ImageIcon(bodyUrl); //食物的 public static URL foodUrl = Data.class.getResource("/statics/food.png"); public static ImageIcon food = new ImageIcon(foodUrl); }
package start; import javax.swing.*; public class tanchishe { public static void main(String[] args) { JFrame frame=new JFrame("贪吃蛇"); //设置窗口大小 frame.setBounds(10,10,900,750); frame.setResizable(false); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //把这个画板通过创建对象的方法导入进去 frame.add(new GamePanel()); frame.setVisible(true); } }