贪吃蛇-JavaGUI实现
开发的大体思路
1.定义数据
2.画上面板(将数据进行初始化赋值)
3.监听事件
键盘监听
事件监听
游戏主界面代码
<details>
<summary>点击查看代码</summary>
```
package com.Tang.gui.snake;
import javax.swing.*;
//游戏主界面
public class StartGame {
public static void main(String[] args) {
JFrame frame = new JFrame();
//正常的游戏界面都在面板上
frame.add(new GamePanel());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setBounds(10,10,900,720);
frame.setResizable(false);//窗口大小不可变
frame.setVisible(true);
}
}
蛇头蛇身图片数据代码
package com.Tang.gui.snake;
import javax.swing.*;
import java.net.URL;
public class Data {
//相对路径 tx.jpj
//绝对路径 / 相对于当前项目
//广告栏
public static URL headerURL = Data.class.getResource("statics/header.png");
public static ImageIcon header = new ImageIcon(headerURL);
//身体
public static URL bodyURL = Data.class.getResource("statics/body.png");
public static ImageIcon body = new ImageIcon(bodyURL);
//蛇头
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 foodURL = Data.class.getResource("statics/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
}
游戏面板代码
package com.Tang.gui.snake;
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;
//游戏的面板
//ActionListener接口主要用于计时器的监听
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//绘制面板,游戏中的所有东西都是用画笔来画
//定义蛇的数据结构
int length;
int[] snakeX = new int[600];
int[] snakeY = new int[500];
String fx;//蛇头的方向
//定义积分
int score;
//定义食物的坐标
int foodx;
int foody;
Random random = new Random();
//定时器以毫秒为单位1s = 1000ms
Timer timer = new Timer(100,this);//100毫秒执行一次,为小蛇移动的速度
//初始游戏状态
boolean isStart = false;//游戏初始默认为停止
//失败状态
boolean isFail = false;//初始默认不是失败的
public GamePanel() {
init();
//获取焦点和键盘监听事件
this.setFocusable(true);//获得焦点事件,就是当前运行进程为游戏窗口
foodx = 25 + 25*random.nextInt(34);//游戏界面宽度为850,蛇一节身体宽度为25(左边界的起始位置也为25),所以在横向上可以有850/25=34个位置可以产生食物
foody = 75 + 25*random.nextInt(24);//75为上边界的起始位置,游戏界面高度为600,蛇一节身体宽度为25,所以在纵向上可以有600/25=24个位置可以产生食物
this.addKeyListener(this);//获得键盘监听事件
timer.start();//游戏一开始定时器就启动
}
//初始化方法
public void init(){
length = 3;//初始化蛇长(加上蛇头)一共三节
snakeX[0] = 100; snakeY[0] = 100;//初始蛇脑袋的位置
snakeX[1] = 75; snakeY[1] = 100;//初始蛇第一节身体的位置
snakeX[2] = 50; snakeY[2] = 100;//初始蛇第二节身体的位置
fx = "R";//初始方法向右
score = 0;//初始成绩为零
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏
//绘制静态面板
//面板背景颜色为白色
this.setBackground(Color.white);
//将游戏头部广告栏画上去
Data.header.paintIcon(this,g,25,11);
//默认的游戏界面
g.fillRect(25,75,850,600);
//将成绩给画上去
g.setColor(Color.white);//画笔颜色
g.setFont(new Font("微软雅黑",Font.BOLD,18));//设置字体
g.drawString("长度:"+ length ,750,35);
g.drawString("分数:"+ score ,750,60);
//将食物画入游戏界面中
Data.food.paintIcon(this,g,foodx,foody);
//将小蛇的初始状态放入游戏界面中
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]);//将蛇头画入游戏界面指定位置
}
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//若果游戏没有开始这显示按下空格开始游戏字体
if(isStart == false){
g.setColor(Color.white);//设置画笔颜色
g.setFont(new Font("微软雅黑",Font.BOLD,40));//设置字体
g.drawString("按下空格键开始游戏",300,400);//设置画笔画下的文字,以及文字画入游戏界面的位置
}
//如果游戏失败则显示游戏结束,按下空格重新开始游戏字体
if(isFail){
g.setColor(Color.RED);//设置画笔颜色
g.setFont(new Font("微软雅黑",Font.BOLD,40));//设置字体
g.drawString("游戏结束,按下空格重新开始",300,400);//设置画笔画下的文字,以及文字画入游戏界面的位置
}
}
//键盘监听事件
@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_UP){//当按下上键小蛇的头转向上
fx = "U";
}else if(keyCode == KeyEvent.VK_DOWN){//当按下下键小蛇的头转向下
fx = "D";
}else if(keyCode == KeyEvent.VK_LEFT){//当按下左键小蛇的头转向左
fx = "L";
}else if(keyCode == KeyEvent.VK_RIGHT){//当按下右键小蛇的头转向右
fx = "R";
}
}
//事件的监听,需要通过固定事件来刷新,1s=10次
@Override
public void actionPerformed(ActionEvent e) {
if(isStart && isFail == false){//如果游戏是开始状态并且没有失败,就让小蛇动起来
if(snakeX[0] == foodx && snakeY[0] == foody){//蛇头碰到食物后
length ++;//蛇身长度加一
//没吃到一个食物分数加一
score ++;
//再次随机生成食物
foodx = 25 + 25*random.nextInt(34);//游戏界面宽度为850,蛇一节身体宽度为25(左边界的起始位置也为25),所以在横向上可以有850/25=34个位置可以产生食物
foody = 75 + 25*random.nextInt(24);//75为上边界的起始位置,游戏界面高度为600,蛇一节身体宽度为25,所以在纵向上可以有600/25=24个位置可以产生食物
}
for (int i = length-1; i >0 ; i--) {//让蛇的后一节移动到前一节位置
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
if(fx.equals("R")){//如果此时蛇头向右
snakeX[0] += 25;//蛇头向右引领方向,蛇身大小为25
//边界判断
if(snakeX[0] > 850){//碰到游戏界面的右边界时
snakeX[0] = 25;//回到最左侧边界
}
}else if(fx.equals("L")){//如果此时蛇头向左
snakeX[0] -= 25;
//边界判断
if(snakeX[0] < 25){//碰到游戏界面的左边界时
snakeX[0] = 850;//回到最右侧边界
}
}else if(fx.equals("U")){//如果此时蛇头向上
snakeY[0] -= 25;
//边界判断
if(snakeY[0] < 75){//碰到游戏界面的上边界时
snakeY[0] = 650;//回到最下侧边界
}
}else if(fx.equals("D")){//如果此时蛇头向下
snakeY[0] += 25;
//边界判断
if(snakeY[0] > 650){//碰到游戏界面的下边界时
snakeY[0] = 75;//回到最上侧边界
}
}
//蛇头撞到自己则游戏失败
for (int i = 1; i < length; i++) {
if(snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){//如果蛇身与蛇头相遇则游戏失败
isFail = true;//游戏失败
}
}
repaint();//重画页面
}
timer.start();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
运行结果图
起初界面
运行中界面
失败界面