java实现贪吃蛇小游戏
前言
本文主要是记录一下我自己之前学习java的时候写的一个java中GUI小程序,代码可能比较简陋,但对于初学者小白学习应该够用了。很多初学者觉得GUI没必要学习,但是做一点GUI小项目练手更能了解java的面向对象思想。因我的水平有限,若有不足之处请评论留言,谢谢。
开发环境
本程序是在jdk1.8和idea环境开发的,因为我的电脑分辨率是2.5K,因此显示大小可能与你们下载不同,窗口大小需要根据自身修改!
项目结构图
因为是我写这篇随笔2年前的代码所以多多少少不太规范,我也懒得重构。
Snake类代码
package snake;
import com.google.gson.Gson;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Writer;
/**
* @author Tireless
*/
public class Snake {
public static void main(String[] args) {
//利用JFrame创建窗体
JFrame frame = new JFrame();
Container conn = frame.getContentPane();
conn.setLayout(null);
//黑色画布大小及坐标
SnakePanel panel = new SnakePanel();
panel.setBounds(0, 0, 900, 730);
JButton btnSave = new JButton("保存");
//按钮大小及坐标
btnSave.setBounds(300, 680, 100, 30);
JButton btnLoad = new JButton("加载存档");
btnLoad.setBounds(500, 680, 100, 30);
conn.add(panel);
conn.add(btnLoad);
conn.add(btnSave);
//窗体坐标大小
frame.setBounds(200, 200, 900, 760);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
btnSave.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SnakeInfo si = new SnakeInfo();
si.setDirection(panel.direction);
si.setSnakex(panel.snakex);
si.setSnakey(panel.snakey);
si.setLen(panel.len);
si.setFoodx(panel.foodx);
si.setFoody(panel.foody);
si.setScore(panel.score);
// 序列化对象
Gson gson = new Gson();
String snakeStr = gson.toJson(si);
try (Writer writer = new FileWriter("a.txt")) {
writer.write(snakeStr);
writer.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
/*
* 调用接口定义Save按钮方法,用于响应按下后保存游戏数据
* */
btnLoad.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
InputStream is = new FileInputStream("a.txt");
int ia = is.available();
byte[] bytes = new byte[ia];
is.read(bytes);
String snakeStr = new String(bytes);
Gson gson = new Gson();
SnakeInfo si = gson.fromJson(snakeStr, SnakeInfo.class);
panel.direction = si.getDirection();
panel.snakey = si.getSnakey();
panel.snakex = si.getSnakex();
panel.score = si.getScore();
panel.len = si.getLen();
panel.foody = si.getFoody();
panel.foodx = si.getFoodx();
is.close();
panel.repaint();
panel.setFocusable(true);
panel.addKeyListener(panel);
panel.requestFocus();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
}
}
SnaleInfo代码
package snake;
/**
* @author Tireless
*/
public class SnakeInfo {
private int len;
private int score;
private int[] snakex;
private int[] snakey;
private int foodx;
private int foody;
private String direction;
/**
* 以下是get set获取方法
*/
public void setLen(int len) {
this.len = len;
}
public void setScore(int score) {
this.score = score;
}
public void setSnakex(int[] snakex) {
this.snakex = snakex;
}
public void setSnakey(int[] snakey) {
this.snakey = snakey;
}
public void setFoodx(int foodx) {
this.foodx = foodx;
}
public void setFoody(int foody) {
this.foody = foody;
}
public void setDirection(String direction) {
this.direction = direction;
}
public int getLen() {
return len;
}
public int getScore() {
return score;
}
public int[] getSnakex() {
return snakex;
}
public int[] getSnakey() {
return snakey;
}
public int getFoodx() {
return foodx;
}
public int getFoody() {
return foody;
}
public String getDirection() {
return direction;
}
}
SnakePanel代码
package snake;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.*;
import java.awt.*;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Random;
/**
* @author Tireless
*/
public class SnakePanel extends JPanel implements KeyListener, ActionListener {
ImageIcon up = new ImageIcon("up.png");
ImageIcon down = new ImageIcon("down.png");
ImageIcon food = new ImageIcon("food.png");
ImageIcon left = new ImageIcon("left.png");
ImageIcon body = new ImageIcon("body.png");
ImageIcon right = new ImageIcon("right.png");
ImageIcon title = new ImageIcon("title.jpg");//导入素材
/*
定义变量
*/
//蛇身坐标
int[] snakex = new int[700];
int[] snakey = new int[700];
int len = 3;//蛇身长度
int score = 0;//得分
boolean isStarted = false;//用于判断是否游戏开始
boolean isFailed = false;//判断是否撞到自身
String direction = "R";//U上 D下 L左 R右 初始时蛇头方向
Timer timer = new Timer(100, this);//定义计时器用于监测刷新
Random random = new Random();//创建随机数
int foodx = random.nextInt(34) * 25 + 25;
int foody = random.nextInt(24) * 25 + 75;// 食物坐标
public SnakePanel() {
this.setFocusable(true);
this.addKeyListener(this);
init();
timer.start();
}//用于初始化
@Override
public void paint(Graphics g) {
this.setBackground(Color.BLACK);
title.paintIcon(this, g, 25, 11);
g.fillRect(25, 75, 850, 600);//定义画板
if (direction.equals("R")) {
right.paintIcon(this, g, snakex[0], snakey[0]);
} else if (direction.equals("U")) {
up.paintIcon(this, g, snakex[0], snakey[0]);
} else if (direction.equals("D")) {
down.paintIcon(this, g, snakex[0], snakey[0]);
} else if (direction.equals("L")) {
left.paintIcon(this, g, snakex[0], snakey[0]);
}//判断方向调用图片
for (int i = 0; i < len; i++) {
body.paintIcon(this, g, snakex[i], snakey[i]);
} //蛇身长度
if (!isStarted) {
g.setColor(Color.WHITE);
g.setFont(new Font("宋体", Font.BOLD, 30));
g.drawString("按下空格键 开始/暂停 游戏", 300, 400);
}
if (isFailed) {
g.setColor(Color.WHITE);
g.setFont(new Font("宋体", Font.BOLD, 30));
g.drawString("游戏结束,请重新按下空格加载游戏", 200, 400);
}
//绘制食物坐标
food.paintIcon(this, g, foodx, foody);
g.setColor(Color.WHITE);
g.setFont(new Font("宋体", Font.BOLD, 20));
g.drawString("长度:" + len, 760, 37);
g.drawString("分数:" + score, 760, 57);
}//游戏显示文字
public void init() {
len = 3;
score = 0;
isFailed = false;
isStarted = false;
direction = "R";
snakex[0] = 100;
snakex[1] = 75;
snakex[2] = 50;
snakey[0] = 100;
snakey[1] = 100;
snakey[2] = 100;
}//蛇身坐标位置
@Override
public void keyTyped(KeyEvent e) {
}
//监听按键进行判断方向
@Override
public void keyPressed(KeyEvent e) {
int Keycode = e.getKeyCode();
if (Keycode == KeyEvent.VK_SPACE) {
if (isFailed) {
init();
} else {
isStarted = !isStarted;
}
} else if (Keycode == KeyEvent.VK_UP && !direction.equals("D")) {
direction = "U";
} else if (Keycode == KeyEvent.VK_DOWN && !direction.equals("U")) {
direction = "D";
} else if (Keycode == KeyEvent.VK_RIGHT && !direction.equals("L")) {
direction = "R";
} else if (Keycode == KeyEvent.VK_LEFT && !direction.equals("R")) {
direction = "L";
}
repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
if (isStarted && !isFailed) {
for (int i = len; i > 0; i--) {
snakex[i] = snakex[i - 1];
snakey[i] = snakey[i - 1];
}//蛇身与蛇头位置关联
switch (direction) {
case "R":
snakex[0] = snakex[0] + 25;
if (snakex[0] > 850) {
snakex[0] = 25;
}
break;
case "L":
snakex[0] = snakex[0] - 25;
if (snakex[0] < 25) {
snakex[0] = 850;
}
break;
case "D":
snakey[0] = snakey[0] + 25;
if (snakey[0] > 650) {
snakey[0] = 75;
}
break;
case "U":
snakey[0] = snakey[0] - 25;
if (snakey[0] < 75) {
snakey[0] = 650;
}
break;
default:
break;
}
if (snakex[0] == foodx && snakey[0] == foody) {
playSound();
len++;
score = score + 2;
foodx = random.nextInt(34) * 25 + 25;
foody = random.nextInt(24) * 25 + 75;
}//蛇吃到食物后蛇身加长并且食物在其他处随机出现
for (int i = 1; i < len; i++) {
//判断是否蛇头撞到蛇身
if (snakex[0] == snakex[i] && snakey[0] == snakey[i]) {
isFailed = true;
}
}
}
repaint();
}
// 吃到物体音频
private void playSound() {
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("beep.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
} catch (Exception e) {
e.printStackTrace();
}
}//用于吃到食物后声音播放
}
运行效果
游戏开始
游戏中
游戏失败
资源下载
项目完整源代码已经在我的码云分享了有需要的请自行下载:https://gitee.com/jingzhaoghost/snake