一、使用知識
Jframe
GUI
雙向鏈表
線程
二、使用工具
IntelliJ IDEA
jdk 1.8
三、開發過程
3.1素材准備
首先在開發之前應該准備一些素材,已備用,我主要找了一個圖片以及一段優雅的音樂。
在這里插入圖片描述
3.2 開發過程
3.2.1 創建項目
首先進入idea首頁 open一個你想放項目的文件夾
在這里插入圖片描述
進入之后右鍵文件名 new 一個新的Directory——Snake
在這里插入圖片描述
把准備好的素材復制到文件中
在這里插入圖片描述
繼續創建目錄 src/Sanke
在這里插入圖片描述
選中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();
}
}
在這里插入圖片描述
繼續創建新的文件 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();
}
}
運行樣式
在這里插入圖片描述
設置背景圖片 背景音樂
在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();
}
}
呈現
在這里插入圖片描述
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(colspan, rowspan, 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();//創建蛇
1
並在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(colspan, 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();
1
2
3
4
5
@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.colhead.col && n.rowhead.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();
}
}
在這里插入圖片描述
到這里這個小游戲就全部做完了,當然也可以在其基礎上增加其他功能
也可以把這個小游戲打成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