parent
dfc3823072
commit
84f19cd434
@ -0,0 +1,258 @@
|
||||
package tanchishe;
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class SnakeGame extends JFrame {
|
||||
|
||||
// 主界面
|
||||
private JPanel mainPanel;
|
||||
private JButton startButton;
|
||||
private JComboBox<String> difficultyComboBox;
|
||||
private JComboBox<String> modeComboBox;
|
||||
|
||||
// 游戏界面
|
||||
private GamePanel gamePanel;
|
||||
|
||||
public SnakeGame() {
|
||||
setTitle("贪吃蛇游戏");
|
||||
setSize(600, 600);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
// 初始化主界面
|
||||
initMainPanel();
|
||||
add(mainPanel);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
private void initMainPanel() {
|
||||
mainPanel = new JPanel();
|
||||
mainPanel.setLayout(new GridLayout(3, 1));
|
||||
|
||||
// 难度选择
|
||||
JPanel difficultyPanel = new JPanel();
|
||||
difficultyPanel.add(new JLabel("选择难度:"));
|
||||
String[] difficulties = {"简单", "困难", "地狱"};
|
||||
difficultyComboBox = new JComboBox<>(difficulties);
|
||||
difficultyPanel.add(difficultyComboBox);
|
||||
mainPanel.add(difficultyPanel);
|
||||
|
||||
// 模式选择
|
||||
JPanel modePanel = new JPanel();
|
||||
modePanel.add(new JLabel("选择模式:"));
|
||||
String[] modes = {"穿墙模式", "撞墙模式"};
|
||||
modeComboBox = new JComboBox<>(modes);
|
||||
modePanel.add(modeComboBox);
|
||||
mainPanel.add(modePanel);
|
||||
|
||||
// 开始按钮
|
||||
startButton = new JButton("开始游戏");
|
||||
startButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// 获取用户选择的难度和模式
|
||||
String difficulty = (String) difficultyComboBox.getSelectedItem();
|
||||
String mode = (String) modeComboBox.getSelectedItem();
|
||||
|
||||
// 切换到游戏界面
|
||||
mainPanel.setVisible(false);
|
||||
gamePanel = new GamePanel(difficulty, mode);
|
||||
add(gamePanel);
|
||||
gamePanel.setVisible(true);
|
||||
gamePanel.requestFocus(); // 让游戏面板获取焦点,以便接收键盘事件
|
||||
}
|
||||
});
|
||||
mainPanel.add(startButton);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SnakeGame();
|
||||
}
|
||||
}
|
||||
|
||||
class GamePanel extends JPanel implements KeyListener, Runnable {
|
||||
private static final int WIDTH = 600;
|
||||
private static final int HEIGHT = 600;
|
||||
private static final int UNIT_SIZE = 20;
|
||||
private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);
|
||||
|
||||
private final List<Point> snake = new ArrayList<>();
|
||||
private Point food;
|
||||
private int direction = KeyEvent.VK_RIGHT; // 初始方向向右
|
||||
private boolean running = false;
|
||||
private int score = 0;
|
||||
private int delay; // 控制蛇的移动速度
|
||||
private boolean wallCollision; // 是否开启撞墙模式
|
||||
|
||||
public GamePanel(String difficulty, String mode) {
|
||||
setPreferredSize(new Dimension(WIDTH, HEIGHT));
|
||||
setBackground(Color.BLACK);
|
||||
setFocusable(true);
|
||||
addKeyListener(this);
|
||||
|
||||
// 根据难度设置蛇的移动速度
|
||||
switch (difficulty) {
|
||||
case "简单":
|
||||
delay = 150;
|
||||
break;
|
||||
case "困难":
|
||||
delay = 100;
|
||||
break;
|
||||
case "地狱":
|
||||
delay = 50;
|
||||
break;
|
||||
}
|
||||
|
||||
// 根据模式设置是否开启撞墙模式
|
||||
wallCollision = mode.equals("撞墙模式");
|
||||
|
||||
startGame();
|
||||
}
|
||||
|
||||
public void startGame() {
|
||||
snake.clear();
|
||||
snake.add(new Point(WIDTH / 2, HEIGHT / 2)); // 初始化蛇的起始位置
|
||||
generateFood();
|
||||
running = true;
|
||||
new Thread(this).start();
|
||||
}
|
||||
|
||||
public void generateFood() {
|
||||
Random random = new Random();
|
||||
int x = random.nextInt(WIDTH / UNIT_SIZE) * UNIT_SIZE;
|
||||
int y = random.nextInt(HEIGHT / UNIT_SIZE) * UNIT_SIZE;
|
||||
food = new Point(x, y);
|
||||
|
||||
// 确保食物不会生成在蛇的身体上
|
||||
while (snake.contains(food)) {
|
||||
x = random.nextInt(WIDTH / UNIT_SIZE) * UNIT_SIZE;
|
||||
y = random.nextInt(HEIGHT / UNIT_SIZE) * UNIT_SIZE;
|
||||
food = new Point(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void move() {
|
||||
Point head = snake.get(0);
|
||||
Point newHead = new Point(head);
|
||||
|
||||
switch (direction) {
|
||||
case KeyEvent.VK_UP:
|
||||
newHead.y -= UNIT_SIZE;
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:
|
||||
newHead.y += UNIT_SIZE;
|
||||
break;
|
||||
case KeyEvent.VK_LEFT:
|
||||
newHead.x -= UNIT_SIZE;
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:
|
||||
newHead.x += UNIT_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
// 穿墙模式:蛇穿过边界从另一侧出现
|
||||
if (!wallCollision) {
|
||||
if (newHead.x < 0) newHead.x = WIDTH - UNIT_SIZE;
|
||||
if (newHead.x >= WIDTH) newHead.x = 0;
|
||||
if (newHead.y < 0) newHead.y = HEIGHT - UNIT_SIZE;
|
||||
if (newHead.y >= HEIGHT) newHead.y = 0;
|
||||
}
|
||||
|
||||
// 检查是否撞墙(撞墙模式下)
|
||||
if (wallCollision && (newHead.x < 0 || newHead.x >= WIDTH || newHead.y < 0 || newHead.y >= HEIGHT)) {
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否撞到自己
|
||||
if (snake.contains(newHead)) {
|
||||
running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
snake.add(0, newHead);
|
||||
|
||||
// 检查是否吃到食物
|
||||
if (newHead.equals(food)) {
|
||||
score++;
|
||||
generateFood();
|
||||
} else {
|
||||
snake.remove(snake.size() - 1); // 如果没有吃到食物,移除蛇尾
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g) {
|
||||
super.paintComponent(g);
|
||||
draw(g);
|
||||
}
|
||||
|
||||
public void draw(Graphics g) {
|
||||
if (running) {
|
||||
// 绘制食物
|
||||
g.setColor(Color.RED);
|
||||
g.fillRect(food.x, food.y, UNIT_SIZE, UNIT_SIZE);
|
||||
|
||||
// 绘制蛇
|
||||
for (Point p : snake) {
|
||||
g.setColor(Color.GREEN);
|
||||
g.fillRect(p.x, p.y, UNIT_SIZE, UNIT_SIZE);
|
||||
}
|
||||
|
||||
// 绘制分数
|
||||
g.setColor(Color.WHITE);
|
||||
g.setFont(new Font("Arial", Font.BOLD, 20));
|
||||
g.drawString("Score: " + score, 10, 20);
|
||||
} else {
|
||||
gameOver(g);
|
||||
}
|
||||
}
|
||||
|
||||
public void gameOver(Graphics g) {
|
||||
// 游戏结束界面
|
||||
g.setColor(Color.RED);
|
||||
g.setFont(new Font("Arial", Font.BOLD, 40));
|
||||
g.drawString("Game Over", WIDTH / 2 - 100, HEIGHT / 2);
|
||||
g.setFont(new Font("Arial", Font.BOLD, 20));
|
||||
g.drawString("Final Score: " + score, WIDTH / 2 - 80, HEIGHT / 2 + 40);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (running) {
|
||||
move();
|
||||
repaint();
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
int key = e.getKeyCode();
|
||||
|
||||
// 防止蛇反向移动
|
||||
if ((key == KeyEvent.VK_LEFT && direction != KeyEvent.VK_RIGHT) ||
|
||||
(key == KeyEvent.VK_RIGHT && direction != KeyEvent.VK_LEFT) ||
|
||||
(key == KeyEvent.VK_UP && direction != KeyEvent.VK_DOWN) ||
|
||||
(key == KeyEvent.VK_DOWN && direction != KeyEvent.VK_UP)) {
|
||||
direction = key;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {}
|
||||
}
|
Loading…
Reference in new issue