01.入门篇-体验AI编程

1 体验AI编程

1.1 案例需求

需求:利用AI开发一款贪吃蛇小游戏

1.2 描述信息

你是一个经验丰富的Java工程师。
请利用Java的GUI开发一个像素风格的贪吃蛇游戏,要求:
- 用方向键控制蛇的移动方向
- 蛇头和蛇身体采用不同颜色
- 每当蛇吃到苹果则蛇身长度加1,积分加1
- 顶部显示用户当前得分
- 蛇头碰到墙壁或自己身体则游戏结束
- 游戏结束后可以退出游戏或重新开始游戏
项目基础包为com.itheima,请设计合理的项目结构,不要把所有代码写在一个包。要给出每一个类及类中详细完整的代码。

1.3 项目结构

com.itheima
├── SnakeGame.java                // 主类:启动程序
├── controller
│   └── GameController.java       // 控制游戏逻辑(方向、更新、碰撞等)
├── model
│   ├── Direction.java            // 枚举:方向
│   ├── GameStatus.java           // 枚举:游戏状态
│   ├── Point.java                // 自定义坐标点(避免与 java.awt.Point 冲突)
│   └── Snake.java                // 蛇的数据模型
├── view
│   └── GamePanel.java            // 游戏主面板(绘制 + 键盘监听)
└── util
    └── Constants.java            // 常量配置(格子大小、速度、颜色等)

com.itheima/SnakeGame.java

package com.itheima;

import javax.swing.*;

public class SnakeGame {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("像素贪吃蛇 - by Itheima");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setResizable(false);
            frame.add(new com.itheima.view.GamePanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

com.itheima/model/Direction.java

package com.itheima.model;

public enum Direction {
    UP, DOWN, LEFT, RIGHT
}

com.itheima/model/GameStatus.java

package com.itheima.model;

public enum GameStatus {
    RUNNING, GAME_OVER
}

com.itheima/model/Point.java

package com.itheima.model;

public class Point {
    public final int x;
    public final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Point point = (Point) obj;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Integer.hashCode(x) * 31 + Integer.hashCode(y);
    }
}

com.itheima/model/Snake.java

package com.itheima.model;

import java.util.*;

public class Snake {
    private final LinkedList<Point> body;
    private Direction direction;

    public Snake() {
        body = new LinkedList<>();
        // 初始长度为3
        body.add(new Point(10, 10));
        body.add(new Point(9, 10));
        body.add(new Point(8, 10));
        direction = Direction.RIGHT;
    }

    public void move(Point newHead, boolean grow) {
        body.addFirst(newHead);
        if (!grow) {
            body.removeLast();
        }
    }

    public Point getHead() {
        return body.getFirst();
    }

    public List<Point> getBody() {
        return new ArrayList<>(body);
    }

    public Direction getDirection() {
        return direction;
    }

    public void setDirection(Direction direction) {
        this.direction = direction;
    }

    public boolean contains(Point p) {
        return body.contains(p);
    }

    public int getLength() {
        return body.size();
    }
}

com.itheima/util/Constants.java

package com.itheima.util;

import java.awt.Color;

public class Constants {
    public static final int GRID_SIZE = 20;          // 每个格子像素大小
    public static final int ROWS = 20;               // 行数
    public static final int COLS = 20;               // 列数
    public static final int DELAY = 150;             // 游戏刷新间隔(毫秒)

    public static final Color SNAKE_HEAD_COLOR = Color.GREEN;
    public static final Color SNAKE_BODY_COLOR = Color.CYAN;
    public static final Color APPLE_COLOR = Color.RED;
    public static final Color BACKGROUND_COLOR = Color.BLACK;
    public static final Color TEXT_COLOR = Color.WHITE;
}

com.itheima/controller/GameController.java

package com.itheima.controller;

import com.itheima.model.*;
import com.itheima.util.Constants;

import java.util.Random;

public class GameController {
    private Snake snake;
    private Point apple;
    private int score;
    private GameStatus status;
    private final Random random = new Random();

    public GameController() {
        reset();
    }

    public void reset() {
        snake = new Snake();
        score = 0;
        status = GameStatus.RUNNING;
        generateApple();
    }

    public void update() {
        if (status != GameStatus.RUNNING) return;

        Point head = snake.getHead();
        Point newHead = getNextHead(head);

        // 检查是否撞墙
        if (newHead.x < 0 || newHead.x >= Constants.COLS ||
                newHead.y < 0 || newHead.y >= Constants.ROWS) {
            status = GameStatus.GAME_OVER;
            return;
        }

        // 检查是否撞自己
        if (snake.contains(newHead)) {
            status = GameStatus.GAME_OVER;
            return;
        }

        boolean ateApple = newHead.equals(apple);
        snake.move(newHead, ateApple);

        if (ateApple) {
            score++;
            generateApple();
        }
    }

    private Point getNextHead(Point head) {
        int x = head.x;
        int y = head.y;
        switch (snake.getDirection()) {
            case UP:    y--; break;
            case DOWN:  y++; break;
            case LEFT:  x--; break;
            case RIGHT: x++; break;
        }
        return new Point(x, y);
    }

    private void generateApple() {
        while (true) {
            int x = random.nextInt(Constants.COLS);
            int y = random.nextInt(Constants.ROWS);
            Point candidate = new Point(x, y);
            if (!snake.contains(candidate)) {
                apple = candidate;
                break;
            }
        }
    }

    public Snake getSnake() {
        return snake;
    }

    public Point getApple() {
        return apple;
    }

    public int getScore() {
        return score;
    }

    public GameStatus getStatus() {
        return status;
    }

    public void setDirection(Direction dir) {
        if (status != GameStatus.RUNNING) return;

        Direction current = snake.getDirection();
        // 防止反向移动(如正在右,不能直接左)
        if ((current == Direction.LEFT && dir == Direction.RIGHT) ||
                (current == Direction.RIGHT && dir == Direction.LEFT) ||
                (current == Direction.UP && dir == Direction.DOWN) ||
                (current == Direction.DOWN && dir == Direction.UP)) {
            return;
        }
        snake.setDirection(dir);
    }
}

com.itheima/view/GamePanel.java

package com.itheima.view;

import com.itheima.controller.GameController;
import com.itheima.model.Direction;
import com.itheima.model.GameStatus;
import com.itheima.model.Point;
import com.itheima.model.Snake;
import com.itheima.util.Constants;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

public class GamePanel extends JPanel implements ActionListener {
    private final GameController controller;
    private final Timer timer;

    public GamePanel() {
        this.controller = new GameController();
        setPreferredSize(new Dimension(
                Constants.COLS * Constants.GRID_SIZE,
                Constants.ROWS * Constants.GRID_SIZE + 30)); // +30 给分数留空间
        setBackground(Constants.BACKGROUND_COLOR);
        setFocusable(true);

        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_UP:    controller.setDirection(Direction.UP); break;
                    case KeyEvent.VK_DOWN:  controller.setDirection(Direction.DOWN); break;
                    case KeyEvent.VK_LEFT:  controller.setDirection(Direction.LEFT); break;
                    case KeyEvent.VK_RIGHT: controller.setDirection(Direction.RIGHT); break;
                    case KeyEvent.VK_R:
                        if (controller.getStatus() == GameStatus.GAME_OVER) {
                            controller.reset();
                        }
                        break;
                    case KeyEvent.VK_ESCAPE:
                        System.exit(0);
                        break;
                }
            }
        });

        timer = new Timer(Constants.DELAY, this);
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawScore(g);
        if (controller.getStatus() == GameStatus.GAME_OVER) {
            drawGameOver(g);
            return;
        }
        drawSnake(g);
        drawApple(g);
    }

    private void drawScore(Graphics g) {
        // 设置中文字体
        Font font = new Font("SimHei", Font.BOLD, 16); // 确保使用支持中文的字体
        g.setFont(font);

        // 获取分数字符串
        String scoreText = "得分: " + controller.getScore();

        // 假设 this 是你的 JComponent 或 JPanel 子类实例
        int frameWidth = this.getWidth(); // 获取组件宽度

        // 设置分数行背景颜色为黄色
        g.setColor(Color.YELLOW);

        // 计算需要填充的矩形区域的高度
        FontMetrics fm = g.getFontMetrics();
        int textHeight = fm.getHeight();

        // 填充背景色,宽度设置为整个组件的宽度
        g.fillRect(0, 0, frameWidth, textHeight); // 使用组件宽度作为背景宽度

        // 重置颜色为文本颜色
        g.setColor(Color.BLACK);

        // 绘制文本
        int textX = 10; // 文本起始点x坐标,可以根据需求调整
        int textY = textHeight - fm.getDescent(); // 文本基线y坐标
        g.drawString(scoreText, textX, textY);
    }

    private void drawSnake(Graphics g) {
        Snake snake = controller.getSnake();
        boolean isFirst = true;
        for (Point p : snake.getBody()) {
            if (isFirst) {
                g.setColor(Constants.SNAKE_HEAD_COLOR);
                isFirst = false;
            } else {
                g.setColor(Constants.SNAKE_BODY_COLOR);
            }
            g.fillRect(p.x * Constants.GRID_SIZE, p.y * Constants.GRID_SIZE + 30,
                    Constants.GRID_SIZE, Constants.GRID_SIZE);
        }
    }

    private void drawApple(Graphics g) {
        g.setColor(Constants.APPLE_COLOR);
        Point apple = controller.getApple();
        g.fillRect(apple.x * Constants.GRID_SIZE, apple.y * Constants.GRID_SIZE + 30,
                Constants.GRID_SIZE, Constants.GRID_SIZE);
    }


    private void drawGameOver(Graphics g) {
        // 使用中文字体
        Font titleFont = new Font("SimHei", Font.BOLD, 24);
        Font hintFont = new Font("SimHei", Font.PLAIN, 16);

        g.setColor(Color.RED);
        g.setFont(titleFont);
        String msg = "游戏结束!得分: " + controller.getScore();
        FontMetrics fm = g.getFontMetrics();
        int x = (getWidth() - fm.stringWidth(msg)) / 2;
        int y = (getHeight() - 30) / 2;
        g.drawString(msg, x, y);

        g.setFont(hintFont);
        String hint = "按 R 重新开始,ESC 退出";
        fm = g.getFontMetrics();
        x = (getWidth() - fm.stringWidth(hint)) / 2;
        y += 30;
        g.drawString(hint, x, y);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        controller.update();
        repaint();
    }
}

1.4 AI时代程序开发的变化

 人工时代:

  1.有思路       知道下一步做什么,有编程思维

  2.会输入       会自己写代码实现思路,需要熟练使用API

  3.能看懂       能看懂代码,甄别错误,看懂异常信息

 AI 时代: 驾驭智能工具的能力  (1).培养编程思维、(2).甄别代码的能力

  1.会思考       有一定的编程思维,询问AI获取解决思路

  2.会提问       知道如何询问AI(写好提示词)

  3.能看懂       能看懂AI生成的代码,甄别错误

———————————————————————————————————————————————————————————————————————————

                                                                                                                         无敌小马爱学习

posted on 2025-11-18 16:38  马俊南  阅读(11)  评论(0)    收藏  举报