没想到发的第一篇关于java的博客会是这个,写作业用来练手,顺道就搬上来了。

代码肯定不最优的,欢迎大家一起来探讨~

先搬个效果图~

java 教程 贪吃蛇 java贪吃蛇思路_Game

然后结构~

java 教程 贪吃蛇 java贪吃蛇思路_游戏_02

        一共分成4个部分,Define包下有蛇,食物和成绩数据的类,主要包括他们的初始化和像蛇的移动之类的东西;SetWindow包里是主函数的入口,包括窗口和面板的建立过程代码;RunPanel是游戏面板 ,大部分内容都在这个类里,最后是Resource包,包括图片的导入加载。

思路分析~

1、框架搭建,这是我一开始搞的,后面直接代码里小修改,做一件事总是要先规划规划怎么做

java 教程 贪吃蛇 java贪吃蛇思路_java 教程 贪吃蛇_03

2、构建流程,当然,实际写代码时候我可没整这玩意,脑子里知道该做什么就好

java 教程 贪吃蛇 java贪吃蛇思路_java_04

之后就是源码~

窗体(游戏界面)MainScene:

package Game.SetWindow;

import Game.RunPanel;
import javax.swing.*;

public class MainScene extends JPanel{
    //
    public static void main(String[] args) {
        //定义类
        InterFace initwindow = new InterFace();
        //建立基础界面
        initwindow.InitWindow();
        //建立游戏面板
        initwindow.add(new RunPanel());
    }
    //内部类
    static class InterFace extends JFrame {
        //界面初始化函数
        public void InitWindow() {
            setTitle("贪吃蛇游戏           ——Woodenman杜");    //标题
            setBounds(0, 0, 820, 820);      //界面大小设定
            setResizable(false);    //设定大小不可改变
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     //设定界面可关闭
            setLocationRelativeTo(null);    //设置屏幕中央打开
            setVisible(true);   //界面显示
        }
    }
}

 图片加载A_LoadImg:

加了个A就是单纯为了让它排到最前面,其实在Game包下建个类导入可能更好看一点

package Resource;

import java.awt.*;

public class A_LoadImg {
    //游戏标题
    public static Image logo = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Logo.jpg"));
    public static Image gamename = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Gname.jpg"));
    //四个方向的蛇头
    public static Image upsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/UpSnake.jpg"));
    public static Image downsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/DownSnake.jpg"));
    public static Image rightsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/RightSnake.jpg"));
    public static Image leftsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/LeftSnake.jpg"));
    //蛇身
    public static Image body = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Body.jpg"));
    //食物
    public static Image food = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Food.jpg"));
}

蛇对象Snake:

package Game.Define;

public class Snake {
    public int length; //蛇长
    public int x[] = new int[60];    //蛇的x坐标
    public int y[] = new int[60];    //蛇的y坐标
    public char dir;    //蛇的移动方向
    //游戏状态
        // 0未开始
        // 1结束
        // 2暂停
        // 3进行中
        // 5选择等级
        // 6通关
    public byte over;

    public Snake() {
        init();
    }
    //蛇的初始化
    public void init(){
        length = 4;
        dir = 'R';
        over = 0;
        x[0] = 30+125; y[0] = 140+100;
        x[1] = 30+100; y[1] = 140+100;
        x[2] = 30+75; y[2] = 140+100;
        x[3] = 30+50; y[3] = 140+100;
    }

    //蛇的移动和边界检测
    public void go(){
        //蛇身移动
        for(int i = length-1; i > 0; i--){
            x[i] = x[i-1];
            y[i] = y[i-1];
        }
        //蛇头移动
        if(dir == 'L')
        {
            x[0] -= 25;
            if(x[0] < 30) over = 1;
        }
        else if(dir == 'R')
        {
            x[0] += 25;
            if(x[0] > 755) over = 1;
        }
        else if(dir == 'U')
        {
            y[0] -= 25;
            if(y[0] < 140) over = 1;
        }
        else if(dir == 'D')
        {
            y[0] += 25;
            if(y[0] > 740) over = 1;
        }
    }

}

食物Food:

package Game.Define;

import java.util.Random;

public class Food {
    //食物坐标
    public int x;
    public int y;
    //随机数
    Random random = new Random();
    //构造体
    public Food() {
        init();
    }
    //建立新的食物点
    public void set(){
        x = 30 + 25*random.nextInt(30);
        y = 140 + 25*random.nextInt(25);
    }
    //食物点初始化
    public void init(){
        x = 30 + 175;
        y = 140 + 175;
    }
}

 成绩数据Score:

package Game.Define;
public class Score{
    public int result;  //游戏得分
    public int grade;   //游戏难度
    public int PeopleGrade;     //人工设定的游戏难度
    //构造函数
    public Score() {
        init();
    }
    //数据初始化
    public void init(){
        result = 0;
        PeopleGrade = 0;
        grade = 1;
    }
    //等级判定
    public int graded(int length){
        return (length - 4) / 5 + 1;
    }

    //帧率判定(蛇的移动速度)
    public int speed(int length){ return 250 - (length - 4) * 5; }
}

最后就是重头戏——游戏面板:

        稍微说一下吧,首先对象需要画出来->画笔,键盘操控->键盘监听,实质是高帧率刷新->定时器

结构上:

首先所有的定义,定时器对象,内容对象等等

然后定时器,包括:游戏状态检测,是暂停了,选难度,还是游戏进行中;有没有吃到食物的判定;蛇是否碰到自身;界面刷新

之后键盘监听,顾名思义,就是所有会用到的按键识别,包括游戏状态、游戏难度、游戏操控的读入

最后画笔,包括基础背景界面,游戏界面的对象,各种内容提示的绘制

package Game;

import Game.Define.Food;
import Game.Define.Score;
import Game.Define.Snake;
import Resource.A_LoadImg;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class RunPanel extends JPanel implements ActionListener , KeyListener {
    //构造函数
    public RunPanel() {
        //定时器启动
        timer.start();
        //键盘监听
        this.setFocusable(true);
        this.addKeyListener(this);
    }
    //定义
    Snake snake = new Snake(); //snake
    Food food = new Food(); //food
    Score score = new Score();  //计分
    int delay = 250;
    boolean ans = false;
    Timer timer = new Timer(250,this);  //定时器
//定时器
    @Override
    public void actionPerformed(ActionEvent e) {
        //是否为进行状态
        if(snake.over == 3)  snake.go();
        if(score.PeopleGrade != 0){
            delay = 250 - score.PeopleGrade*25;
            score.grade = score.PeopleGrade;
            timer.setDelay(delay);
        }
        //增长检测
        if(snake.x[0] == food.x && snake.y[0]== food.y){
            snake.length++; //长度更新
            if(snake.length == 54) { snake.over = 6; } //通关判定
            food.set(); //食物点更新
            score.result += 1;  //得分更新

            //非人工选定难度状态下更新数据
            if(score.PeopleGrade == 0)
            {
                delay = score.speed(snake.length) > 30 ? score.speed(snake.length) : 25;    //帧率更新
                score.grade = score.graded(snake.length); //等级更新
                timer.setDelay(delay);
            }
        }
        //碰撞检测
                for(int i = 1; i < snake.length; i++){
                    if(snake.y[0] == snake.y[i] && snake.x[0] == snake.x[i]) snake.over = 1;
                }
        //界面刷新
        repaint();
        timer.start();
    }
//键盘监听
    @Override
    public void keyPressed(KeyEvent e) {
        //进入游戏状态
        if(e.getKeyCode() == KeyEvent.VK_ENTER){
            if(snake.over == 0) {
                snake.over = 3; //初始到进行
                //snake.init();
            }
            else if(snake.over == 1 || snake.over == 2){
                snake.over = 0; //结束到初始
            }
            else if(snake.over == 3) snake.over = 0;   //重置到初始状态
        }
        else if(e.getKeyCode() == KeyEvent.VK_SPACE){
            //暂停或者进行状态转换
            if(snake.over == 2) snake.over = 3;
            else if(snake.over == 3) snake.over = 2;
        }
        else if(e.getKeyCode() == KeyEvent.VK_G && snake.over == 0){
            snake.over = 5;
            ans = true;
        }
        //难度控制
        else if(e.getKeyCode() == KeyEvent.VK_1 && ans ){ score.PeopleGrade = 1; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_2 && ans ){ score.PeopleGrade = 2; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_2 && ans ){ score.PeopleGrade = 2; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_3 && ans ){ score.PeopleGrade = 3; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_4 && ans ){ score.PeopleGrade = 4; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_5 && ans ){ score.PeopleGrade = 5; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_6 && ans ){ score.PeopleGrade = 6; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_7 && ans ){ score.PeopleGrade = 7; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_8 && ans ){ score.PeopleGrade = 8; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_9 && ans ){ score.PeopleGrade = 9; snake.over = 3; ans = false; }
        //方向控制
        else if(e.getKeyCode() == KeyEvent.VK_DOWN){
            if(snake.dir == 'U') snake.over = 1; else snake.dir = 'D';
        }else if(e.getKeyCode() == KeyEvent.VK_UP){
            if(snake.dir == 'D') snake.over = 1; else snake.dir = 'U';
        }else if(e.getKeyCode() == KeyEvent.VK_LEFT){
            if(snake.dir == 'R') snake.over = 1; else snake.dir = 'L';
        }else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
            if(snake.dir == 'L') snake.over = 1; else snake.dir = 'R';
        }
    }
//绘画方法重写
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //设置基础界面的颜色
        setBackground(Color.orange);
        //载入游戏标题图片
        g.drawImage(A_LoadImg.logo,30,20,160,120,this);
        g.drawImage(A_LoadImg.gamename, 190,20,420,120,this);
        //画出游戏区域
        g.setColor(Color.DARK_GRAY);
        g.fillRect(30,140,750,625);
        g.setColor(Color.GREEN);
        g.drawRect(30,140,750,625);
        //计分区域
        g.setColor(Color.WHITE);
        g.setFont(new Font("隶书",Font.BOLD,25));
        g.drawString("长度" + snake.length,620,50);
        g.setColor(Color.WHITE);
        g.setFont(new Font("隶书",Font.BOLD,25));
        g.drawString("得分" + score.result, 620,90);
        g.setColor(Color.WHITE);
        g.setFont(new Font("隶书",Font.BOLD,25));
        g.drawString("游戏等级" + score.grade,620 ,130);
        //绘制蛇
        switch(snake.dir)
        {
            case 'L':
                g.drawImage(A_LoadImg.leftsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
            case 'R':
                g.drawImage(A_LoadImg.rightsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
            case 'U':
                g.drawImage(A_LoadImg.upsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
            case 'D':
                g.drawImage(A_LoadImg.downsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
        }
        for (int i = 1; i < snake.length; i++) {
            g.drawImage(A_LoadImg.body, snake.x[i], snake.y[i],25,25,this);
        }
        //绘制食物
        g.drawImage(A_LoadImg.food, food.x, food.y, 25,25,this);

        //游戏状态判断
        // 0未开始 1结束 2暂停 3进行中 5选择等级 6通关
        if(snake.over == 0){
            //刷新界面
            repaint();
            //初始化
            snake.init();
            food.init();
            score.init();
            //显示设置
            g.setColor(Color.WHITE);
            g.setFont(new Font("华文彩云",Font.BOLD,70));
            g.drawString("欢迎来到贪吃蛇游戏",70,400);
            g.setColor(Color.CYAN);
            g.setFont(new Font("楷书",Font.BOLD,30));
            g.drawString("Enter       开始/重置游戏",250,480);
            g.drawString("Space     暂停/继续游戏",250,530);
            g.drawString("g              选择游戏等级",250,580);
            g.drawString("箭头控制小蛇移动,长度54就~通关",200,670);

        }
        if(snake.over == 1){
            g.setColor(Color.RED);
            g.setFont(new Font("隶书",Font.BOLD,70));
            g.drawString("Game Over!", 200,400);
        }
        else if(snake.over == 2){
            g.setColor(Color.WHITE);
            g.setFont(new Font("隶书",Font.BOLD,50));
            g.drawString("游戏暂停,按下空格继续游戏",70,400);
        }
        if(snake.over == 5){
            g.setColor(Color.orange);
            g.setFont(new Font("隶书",Font.BOLD,50));
            g.drawString("请选择游戏难度(1-9)",150,400);

        }
        if(snake.over == 6){
            g.setColor(Color.red);
            g.setFont(new Font("隶书",Font.BOLD,50));
            g.drawString("恭喜你,游戏胜利!!!",150,400);
        }
        //repaint();
    }


    @Override public void keyTyped(KeyEvent e) {}     @Override public void keyReleased(KeyEvent e) {}
}

 我只是把这个类分开放了,代码原封不动。

  这个的核心就是画笔(画图片),键盘监听,定时器,这三个搞定了也就写出来了,定时器用的是swing下的,util的我写一半卡住了,键盘监听写一半也卡住了...........所以,继续学习哈哈