欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-03 13:48:34
文章目录一、使用知识二、使用工具三、开发过程3.1素材准备3.2 开发过程3.2.1 创建项目3.2.2 页面设计3.23 画蛇在我们学习java的时候,为了提高我们的兴趣,我们经常会使用所学到的知识去做一些小游戏,这篇blog就介绍了一个经典而且好理解的小游戏-贪吃蛇。一、使用知识JframeGUI双向链表线程二、使用工具IntelliJ IDEAjdk 1.8三、开发过程3.1素材准备首先在开发之前应该准备一些素材,已备用,我主要找了一个图片以及一段优雅的音乐。3.2...


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

一、使用知识

  • Jframe
  • GUI
  • 双向链表
  • 线程

二、使用工具

  • IntelliJ IDEA
  • jdk 1.8

三、开发过程

3.1素材准备

首先在开发之前应该准备一些素材,已备用,我主要找了一个图片以及一段优雅的音乐。
荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)

3.2 开发过程

3.2.1 创建项目
  • 首先进入idea首页 open一个你想放项目的文件夹
    荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)
  • 进入之后右键文件名 new 一个新的Directory——Snake

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

  • 把准备好的素材复制到文件中
    荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)
  • 继续创建目录 src/Sanke
    荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)
  • 选中src Mark Directory as — Souces 把src添加为根目录
    荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)
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();
    }

}

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

  • 继续创建新的文件 SnakeGrid
package 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();
    }

}

运行样式
荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)

  • 设置背景图片 背景音乐
    在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.requestFocus();
        snakeGrid.Music();//调用打开音乐的方法
        this.setVisible(true);//设置焦点状态为true
    }
    public static void main(String[] args) {
        new SnakeGame();
    }

}

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

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.row<0 || head.row>rows-1 || head.col<0 ||head.col>cols){
			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.java
package 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.requestFocus();
			}
		});
         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.requestFocus();
 			}
 		});

   }
}

再修改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.requestFocus();
        snakeGrid.Music();//调用打开音乐的方法
        this.setVisible(true);//设置焦点状态为true
    }
    public static void main(String[] args) {
        new SnakeGame();
    }

}

荐
                                                        Java经典小游戏——贪吃蛇简单实现(附源码)
到这里这个小游戏就全部做完了,当然也可以在其基础上增加其他功能

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

四 打jar包

idea打jar包方式:
https://blog.csdn.net/qq_44433261/article/details/107433540
命令行运行jar包方式:
https://blog.csdn.net/qq_44433261/article/details/107433355

源码

最后附上源码链接:
链接: https://pan.baidu.com/s/1iUmSUnvpi_YKUNsPs3ugIQ 提取码: zxsk

本文地址:https://blog.csdn.net/qq_44433261/article/details/107598788