知识屋:更实用的电脑技术知识网站
所在位置:首页 > 科技

Java简单实现贪吃蛇经典小游戏(附源代码)

发表时间:2022-03-26来源:网络

在我们学习java的时候,为了提高我们的兴趣,我们经常会使用所学到的知识去做一些小游戏,这篇blog就介绍了一个经典而且好理解的小游戏-贪吃蛇。

一、使用知识

JframeGUI双向链表线程

二、使用工具

IntelliJ IDEAjdk 1.8

三、开发过程

3.1素材准备

首先在开发之前应该准备一些素材,已备用,我主要找了一个图片以及一段优雅的音乐。

进入之后右键文件名 new 一个新的Directory——Snake把准备好的素材复制到文件中选中src Mark Directory as — Souces 把src添加为根目录

3.2.2 页面设计

创建java Class 文件 Snake - new - java class SnakeName 接下来的时候会对这个SnakeName.java里面的代码不停完善
首先设置窗口格式package Sanke; import javax.swing.*; /** * @author Swyee **/ public class SnakeGame extends JFrame { SnakeGame(){ this.setBounds(100, 50, 700, 500);//设置窗口大小 this.setLayout(null);//更改layout 以便添加组件 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的状态 this.setResizable(false);//窗口不可以改变大小 this.setVisible(true);//设置焦点状态为true } public static void main(String[] args) { new SnakeGame(); } } 继续创建新的文件 SnakeGridpackage Sanke; import java.awt.*; /** * @author Swyee **/ public class SnakeGrid extends Panel { SnakeGrid(){ this.setBounds(0, 0, 700, 400); this.setBackground(Color.black);设置背景颜色 } } 将页面引用到SnakeGame.java中package Sanke; import javax.swing.*; /** * @author Swyee **/ public class SnakeGame extends JFrame { SnakeGrid snakeGrid= new SnakeGrid(); SnakeGame(){ this.setBounds(100, 50, 700, 500);//设置窗口大小 this.setLayout(null);//更改layout 以便添加组件 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的状态 this.setResizable(false);//窗口不可以改变大小 this.add(snakeGrid); this.setVisible(true);//设置焦点状态为true } public static void main(String[] args) { new SnakeGame(); } }

运行样式

设置背景图片 背景音乐
在SnakeGrid.java中增加Music方法 设置画笔 绘图package Sanke; import java.applet.Applet; import java.applet.AudioClip; import java.awt.*; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.JPanel; /** * @author Swyee **/ public class SnakeGrid extends JPanel { ImageIcon image = new ImageIcon("Snake/sky.jpg");//图片文件地址 File f= new File("Snake/music.wav");//音乐文件地址 SnakeGrid(){ this.setBounds(0, 0, 700, 400); this.setBackground(Color.black); } /** * 设置画笔 * @param g */ @Override public void paint(Graphics g) { super.paint(g); image.paintIcon(this, g, 0, 0); //设置背景图片 } //读取音乐文件 void Music(){ try { URI uri = f.toURI(); URL url = uri.toURL(); AudioClip aau= Applet.newAudioClip(url); aau.loop(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

在SnakeName中调用

package Sanke; import javax.swing.*; /** * @author Swyee **/ public class SnakeGame extends JFrame { SnakeGrid snakeGrid= new SnakeGrid(); SnakeGame(){ this.setBounds(100, 50, 700, 500);//设置窗口大小 this.setLayout(null);//更改layout 以便添加组件 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的状态 this.setResizable(false);//窗口不可以改变大小 this.add(snakeGrid); //设置焦点 snakeGrid.setFocusable(true); snakeGrid.re(); snakeGrid.Music();//调用打开音乐的方法 this.setVisible(true);//设置焦点状态为true } public static void main(String[] args) { new SnakeGame(); } }

呈现

3.23 画蛇

蛇的身体将会有双向链表组成,双向链表能记录一个节点的上一个节点和下一个节点。蛇的移动其实就是节点的变化,从而达到一种移动的视觉。

新建java Snake 创建节点package Sanke; import java.awt.Graphics; public class Snake { public static final int span=20;//间距 public static final String up="u"; public static final String down="d"; public static final String left="l"; public static final String right="r"; class Node{ int row; int col; String dir;//方向 Node next; Node pre; Node(int row,int col,String dir){ this.row = row; this.col = col; this.dir = dir; } public void draw(Graphics g) { g.fillOval(col*span, row*span, span,span); } } } 画蛇

在snake里面增加draw()方法

/* 把蛇画出来 */ public void draw(Graphics g) { g.setColor(Color.yellow); for(Node n=head;n!=null;n=n.next){ n.draw(g); g.setColor(Color.green); } }

在SnakeGrid.java中创建蛇

Snake snake = new Snake();//创建蛇

并在paint中调用snake.draw(g);

/** * 设置画笔 * @param g */ @Override public void paint(Graphics g) { super.paint(g); image.paintIcon(this, g, 0, 0); //设置背景图片 snake.draw(g); }控制蛇的移动

在snake中增加键盘调用的方法:

/* 调用键盘的上下左右键 head.dir记录现在操作的是什么按钮,从而更改蛇的状态 向上移送时,下键失效,其他四个方向也是如此判断 */ public void keyboard(KeyEvent e) { switch(e.getKeyCode()){ case KeyEvent.VK_UP: if(head.dir.equals(down)){ break; } head.dir=up; break; case KeyEvent.VK_DOWN: if(head.dir.equals(up)){ break; } head.dir=down; break; case KeyEvent.VK_LEFT: if(head.dir.equals(right)){ break; } head.dir=left; break; case KeyEvent.VK_RIGHT: if(head.dir.equals(left)){ break; } head.dir=right; break; default: break; } }

增加头部的方法

/* 增加头部 不管移动哪个方向都是在相应位置增加一个节点 */ public void addHead(){ Node node = null; switch (head.dir){ case "l": node = new Node(head.row,head.col-1,head.dir); break; case "r": node = new Node(head.row,head.col+1,head.dir); break; case "u": node = new Node(head.row-1,head.col,head.dir); break; case "d": node = new Node(head.row+1,head.col,head.dir); break; default: break; } node.next=head; head.pre=node; head=node; }

删除尾部的方法

/* 删除尾部 删除最后一个节点 */ public void deleteTail(){ tail.pre.next=null; tail=tail.pre; }

增加move的方法

/* 增加move方法 一增一减,实现蛇的移动 */ public void move() { addHead(); deleteTail(); }

在SnakeGrid中创建一个线程类,用来执行蛇的移动方法

class SnakeThread extends Thread{ @Override public void run() { while (true){ try { Thread.sleep(300);//沉睡300ms 用来控制蛇的移动速度 } catch (InterruptedException e) { e.printStackTrace(); } repaint();//每次沉睡完之后都执行一下repaint()方法,重新绘画 } }

print方法中调用remove 在SnakeGrid()创建键盘监听事件:

package Sanke; import java.applet.Applet; import java.applet.AudioClip; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.JPanel; /** * @author Swyee **/ public class SnakeGrid extends JPanel { Snake snake = new Snake();//创建蛇 ImageIcon image = new ImageIcon("Snake/sky.jpg");//图片文件地址 File f= new File("Snake/music.wav");//音乐文件地址 SnakeThread snakeThread = new SnakeThread(); SnakeGrid(){ this.setBounds(0, 0, 700, 400); this.setBackground(Color.black); snakeThread.start(); this.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { snake.keyboard(e); } }); } /** * 设置画笔 * @param g */ @Override public void paint(Graphics g) { super.paint(g); image.paintIcon(this, g, 0, 0); //设置背景图片 snake.move();//蛇移动 snake.draw(g); } //读取音乐文件 void Music(){ try { URI uri = f.toURI(); URL url = uri.toURL(); AudioClip aau= Applet.newAudioClip(url); aau.loop(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } class SnakeThread extends Thread{ @Override public void run() { while (true){ try { Thread.sleep(300);//沉睡300ms 用来控制蛇的移动速度 } catch (InterruptedException e) { e.printStackTrace(); } repaint();//每次沉睡完之后都执行一下repaint()方法,重新绘画 } } } }

执行main方法可以看到可以通过键盘进行控制移动了

3.24创建蛇的食物

增加食物的实例 以及画食物的方法 反映食物坐标的方法 新建Food.java

package Sanke; import java.awt.*; public class Food { int row; int col; Food(){ row = 10;//创建食物的大小 col =10; } public void repearShow(){ row = (int)(Math.random()*18);//生成随机数 乘以食物的大小可以得到坐标 col = (int)(Math.random()*32); } public void draw(Graphics g) {//把食物画出来 g.setColor(Color.red); g.fillRect(col*20, row*20, 20, 20);//表示坐标 } public Rectangle getCoordinates(){ return new Rectangle(col*20,row*20,20,20);//获得食物的坐标 } }

修改Snake.java 增加判断蛇头位置的方法,修改午无参构造方法,改为有参构造,把food添加进来 修改move方法

package Sanke; import java.awt.*; import java.awt.event.KeyEvent; /** * @author Swyee */ public class Snake { public static final int span=20;//间距 public static final String up="u"; public static final String down="d"; public static final String left="l"; public static final String right="r"; Node body;//蛇的身体 Node head;//蛇的头部 Node tail;//蛇的头部 Food food; Snake(Food food){ body = new Node(5,20,left); head = body; tail = body; this.food=food; } class Node{ int row; int col; String dir;//方向 Node next; Node pre; Node(int row,int col,String dir){ this.row = row; this.col = col; this.dir = dir; } public void draw(Graphics g) { g.fillOval(col*span, row*span, span,span);//坐标 } } /* 把蛇画出来 */ public void draw(Graphics g) { g.setColor(Color.yellow); for(Node n=head;n!=null;n=n.next){ n.draw(g); g.setColor(Color.green); } } /* 调用键盘的上下左右键 head.dir记录现在操作的是什么按钮,从而更改蛇的状态 向上移送时,下键失效,其他四个方向也是如此判断 */ public void keyboard(KeyEvent e) { switch(e.getKeyCode()){ case KeyEvent.VK_UP: if(head.dir.equals(down)){ break; } head.dir=up; break; case KeyEvent.VK_DOWN: if(head.dir.equals(up)){ break; } head.dir=down; break; case KeyEvent.VK_LEFT: if(head.dir.equals(right)){ break; } head.dir=left; break; case KeyEvent.VK_RIGHT: if(head.dir.equals(left)){ break; } head.dir=right; break; default: break; } } /* 增加头部 */ public void addHead(){ Node node = null; switch (head.dir){ case "l": node = new Node(head.row,head.col-1,head.dir); break; case "r": node = new Node(head.row,head.col+1,head.dir); break; case "u": node = new Node(head.row-1,head.col,head.dir); break; case "d": node = new Node(head.row+1,head.col,head.dir); break; default: break; } node.next=head; head.pre=node; head=node; } /* 删除尾部 */ public void deleteTail(){ tail.pre.next=null; tail=tail.pre; } /* 增加move方法 */ public void move() { addHead(); if(this.getSnakeRectangle().intersects(food.getCoordinates())){//当蛇头与食物重合的时候 蛇吃食物 食物刷新,不再删除尾巴,达到一种蛇增长的要求 food.repearShow(); }else{ deleteTail(); } } public Rectangle getSnakeRectangle(){//获取蛇头的坐标 return new Rectangle(head.col*span,head.row*span,span,span); } }

在修改snakegrid.java 贪吃蛇的功能就基本实现了

Food food = new Food(); Snake snake = new Snake(food);//创建蛇 ImageIcon image = new ImageIcon("Snake/sky.jpg");//图片文件地址 File f= new File("Snake/music.wav");//音乐文件地址 SnakeThread snakeThread = new SnakeThread();


@Override public void paint(Graphics g) { super.paint(g); image.paintIcon(this, g, 0, 0); //设置背景图片 snake.move();//蛇移动 snake.draw(g); food.draw(g); }

3.2.5增加蛇的存活状态

在Snake中增加蛇的存活状态,每一次移动都判断下是否存活,修改SnakeGrid的线程,执行时进行判断是否存活

public void DeadOrLive(){//超出边框范围 蛇头撞到身体 游戏结束 if(head.rowrows-1 || head.colcols){ islive=false; } for(Node n=head.next;n!=null;n=n.next){ if(n.col==head.col && n.row==head.row){ islive=false; } } }


public void move() { addHead(); if(this.getSnakeRectangle().intersects(food.getCoordinates())){//当蛇头与食物重合的时候 蛇吃食物 食物刷新,不再删除尾巴,达到一种蛇增长的要求 food.repearShow(); }else{ deleteTail(); } DeadOrLive();//每移动一步都要判断一下是否存活 }


class SnakeThread extends Thread{ boolean flag = true; @Override public void run() { while (Snake.islive && flag) { try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (Snake.islive ) { repaint(); } } if (!flag == false) { JOptionPane.showMessageDialog(SnakeGrid.this, "游戏结束"); } }

3.2.6 增加按钮

最后的时候,给这个小游戏增加几个按钮,用来实现暂停开始
新建Button.javapackage Sanke; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Button extends JPanel{ public static boolean isMove=true;//表示运行状态 SnakeGrid snakeGrid; Button(SnakeGrid snakeGrid){ this.snakeGrid=snakeGrid; this.setBounds(0, 400, 700, 100); JButton jb1 = new JButton("暂停游戏"); JButton jb2 = new JButton("继续游戏"); JButton jb3 = new JButton("重新游戏"); this.add(jb1); this.add(jb2); this.add(jb3); jb1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { isMove=false; } }); jb2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { isMove=true; snakeGrid.setFocusable(true); snakeGrid.re(); } }); jb3.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) {//重新创建蛇等 重新开始游戏 snakeGrid.snakeThread.stopThread(); Food food = new Food(); snakeGrid.food=food; snakeGrid.snake=new Snake(food); Snake.islive=true; isMove=true; SnakeGrid.SnakeThread st = snakeGrid.new SnakeThread(); snakeGrid.snakeThread=st; st.start(); snakeGrid.setFocusable(true); snakeGrid.re(); } }); } }

再修改SnakeGrid中的thread

package Sanke; import java.applet.Applet; import java.applet.AudioClip; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.JPanel; /** * @author Swyee **/ public class SnakeGrid extends JPanel { Food food = new Food(); Snake snake = new Snake(food);//创建蛇 ImageIcon image = new ImageIcon("Snake/sky.jpg");//图片文件地址 File f= new File("Snake/music.wav");//音乐文件地址 SnakeThread snakeThread = new SnakeThread(); SnakeGrid(){ this.setBounds(0, 0, 700, 400); this.setBackground(Color.black); snakeThread.start(); this.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { snake.keyboard(e); } }); } /** * 设置画笔 * @param g */ @Override public void paint(Graphics g) { super.paint(g); image.paintIcon(this, g, 0, 0); //设置背景图片 snake.move();//蛇移动 snake.draw(g); food.draw(g); } //读取音乐文件 void Music(){ try { URI uri = f.toURI(); URL url = uri.toURL(); AudioClip aau= Applet.newAudioClip(url); aau.loop(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } class SnakeThread extends Thread{ boolean flag = true; @Override public void run() { while(Snake.islive &&flag){ try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(Snake.islive&& Button.isMove){ repaint(); } } if(!flag==false){ JOptionPane.showMessageDialog(SnakeGrid.this, "游戏结束"); } } public void stopThread(){ flag=false; } } }

在主页面中把按钮添加上去

package Sanke; import javax.swing.*; /** * @author Swyee **/ public class SnakeGame extends JFrame { SnakeGrid snakeGrid= new SnakeGrid(); Button button = new Button(snakeGrid); SnakeGame(){ this.setBounds(100, 50, 700, 500);//设置窗口大小 this.setLayout(null);//更改layout 以便添加组件 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口的状态 this.setResizable(false);//窗口不可以改变大小 this.add(snakeGrid); this.add(button); //设置焦点 snakeGrid.setFocusable(true); snakeGrid.re(); snakeGrid.Music();//调用打开音乐的方法 this.setVisible(true);//设置焦点状态为true } public static void main(String[] args) { new SnakeGame(); } }

到这里这个小游戏就全部做完了,当然也可以在其基础上增加其他功能

也可以把这个小游戏打成jar包的形式进行运行,将打好的jar包和资源文件放在同一个目录下,即可正常运行访问

四、打jar包

idea打jar包方式命令行运行jar包方式

源码

最后附上源码链接:

链接: https://pan.baidu.com/s/1iUmSUnvpi_YKUNsPs3ugIQ
提取码: zxsk作者:swyee
链接:https://blog.csdn.net/qq_44433261/article/details/107598788?utm_medium=distribute.pc_feed.none-task-blog-personrec_tag-8.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-personrec_tag-8.nonecase&request_id=5f28e5fb8c9fb674c6722510
来源:CSDN博客
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜