Swing贪吃蛇游戏(一):基本功能实现

本文将提供一个Swing版本的贪吃蛇游戏,游戏包括最基本的功能:

1. 用Timer来管理贪吃蛇线程。
2. 实现按钮,键盘的事件响应。
3. 随机产生食物。
4. 游戏结束的判断:蛇头触碰到蛇身或者蛇头触碰到边界。
5. 实现游戏过程中的暂停以及贪吃蛇运行速度调整。
6. … …


程序界面如下:左边是贪吃蛇运行的范围,右边暂时只有分数信息,当蛇吃到食物的时候分数加10.

[img]http://dl2.iteye.com/upload/attachment/0087/3921/af342211-d283-3363-9d90-7f22e53804dd.jpg[/img]

暂停,调整蛇体运行速度界面如下:

[img]http://dl2.iteye.com/upload/attachment/0087/3919/98c451aa-554c-3297-87ba-092b51af86d9.jpg[/img]

主要的代码如下:

[img]http://dl2.iteye.com/upload/attachment/0087/3917/cbb14deb-6058-32e5-acbc-fb7714bc6ea0.jpg[/img]

package my.games.snake.model;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import my.games.snake.contants.SnakeGameConstant;

/**
*
* 贪吃蛇游戏用到的格子类
*
* @author Eric
*
*/
public class Grid implements Serializable {

private static final long serialVersionUID = 5105993927776028563L;

private int x; // x location

private int y; // y location

private Color color; // color for square

public Grid() {
}

public Grid(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}

/**
* Draw Grid
*
* @param g2
*/
public void draw(Graphics2D g2) {
int clientX = SnakeGameConstant.SNAKE_GAME_PANEL_LEFT + x
* SnakeGameConstant.GRID_SIZE;
int clientY = SnakeGameConstant.SNAKE_GAME_PANEL_TOP + y
* SnakeGameConstant.GRID_SIZE;
Rectangle2D.Double rect = new Rectangle2D.Double(clientX, clientY,
SnakeGameConstant.GRID_SIZE, SnakeGameConstant.GRID_SIZE);
g2.setPaint(color);
g2.fill(rect);
g2.setPaint(Color.BLACK);
g2.draw(rect);
}

/**
* @return the color
*/
public Color getColor() {
return color;
}

/**
* @param color
* the color to set
*/
public void setColor(Color color) {
this.color = color;
}

/**
* @return the x
*/
public int getX() {
return x;
}

/**
* @param x
* the x to set
*/
public void setX(int x) {
this.x = x;
}

/**
* @return the y
*/
public int getY() {
return y;
}

/**
* @param y
* the y to set
*/
public void setY(int y) {
this.y = y;
}

}


package my.games.snake.model;

import java.awt.Graphics2D;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

import my.games.snake.contants.SnakeGameConstant;
import my.games.snake.enums.Direction;

public class Snake implements Serializable {

private static final long serialVersionUID = -1064622816984550631L;

private List<Grid> list = null;

private Direction direction = Direction.RIGHT;

public Snake() {
this.list = new LinkedList<Grid>();
}

public void changeDirection(Direction direction) {
if (direction.isUpDirection()) {
if (!this.direction.isUpDirection()
&& !this.direction.isDownDirection()) {
this.direction = direction;
}
} else if (direction.isRightDirection()) {
if (!this.direction.isRightDirection()
&& !this.direction.isLeftDirection()) {
this.direction = direction;
}
} else if (direction.isDownDirection()) {
if (!this.direction.isUpDirection()
&& !this.direction.isDownDirection()) {
this.direction = direction;
}
} else if (direction.isLeftDirection()) {
if (!this.direction.isRightDirection()
&& !this.direction.isLeftDirection()) {
this.direction = direction;
}
}
}

public void draw(Graphics2D g2) {
for (Grid grid : list) {
grid.draw(g2);
}
}

/**
* @return the list
*/
public List<Grid> getList() {
return list;
}

/**
* @param list
* the list to set
*/
public void setList(List<Grid> list) {
this.list = list;
}

/**
* @return the direction
*/
public Direction getDirection() {
return direction;
}

/**
* @param direction
* the direction to set
*/
public void setDirection(Direction direction) {
this.direction = direction;
}

public void move() {
Grid currentHead = list.get(0);
int headX = currentHead.getX();
int headY = currentHead.getY();
currentHead.setColor(SnakeGameConstant.SNAKE_BODY_COLOR);

if (direction.isDownDirection()) {
list.add(0, new Grid(headX, headY + 1,
SnakeGameConstant.SNAKE_HEADER_COLOR));
list.remove(list.size() - 1);
} else if (direction.isUpDirection()) {
list.add(0, new Grid(headX, headY - 1,
SnakeGameConstant.SNAKE_HEADER_COLOR));
list.remove(list.size() - 1);
} else if (direction.isRightDirection()) {
list.add(0, new Grid(headX + 1, headY,
SnakeGameConstant.SNAKE_HEADER_COLOR));
list.remove(list.size() - 1);
} else if (direction.isLeftDirection()) {
list.add(0, new Grid(headX - 1, headY,
SnakeGameConstant.SNAKE_HEADER_COLOR));
list.remove(list.size() - 1);
}

}

}


package my.games.snake.ui;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import my.games.snake.contants.SnakeGameConstant;
import my.games.snake.enums.GameState;

public class SnakeGameFrame extends JFrame {

private static final long serialVersionUID = 998014032682506026L;

private SnakeGamePanel panel;

private Container contentPane;

private JMenuItem startMI = new JMenuItem("Start");

private JMenuItem pauseMI = new JMenuItem("Pause");

private JMenu speedMenu = new JMenu("Speed");

private JMenuItem exitMI = new JMenuItem("Exit");

private JMenuItem aboutMI = new JMenuItem("About");

private JRadioButtonMenuItem speedMI1 = new JRadioButtonMenuItem("Speed1",
true);

private JRadioButtonMenuItem speedMI2 = new JRadioButtonMenuItem("Speed2",
false);

private JRadioButtonMenuItem speedMI3 = new JRadioButtonMenuItem("Speed3",
false);

private JRadioButtonMenuItem speedMI4 = new JRadioButtonMenuItem("Speed4",
false);

private JRadioButtonMenuItem speedMI5 = new JRadioButtonMenuItem("Speed5",
false);

public int speedFlag = 1;

public SnakeGameFrame() {
setTitle(SnakeGameConstant.SNAKE_GAME);
setSize(SnakeGameConstant.SNAKE_GAME_FRAME_WIDTH,
SnakeGameConstant.SNAKE_GAME_FRAME_HEIGHT);
setResizable(false);

JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);

JMenu setMenu = new JMenu("Set");
JMenu helpMenu = new JMenu("Help");

setMenu.setMnemonic('s');
setMenu.setMnemonic('H');

menuBar.add(setMenu);
menuBar.add(helpMenu);

setMenu.add(startMI);
setMenu.add(pauseMI);
setMenu.addSeparator();

setMenu.addSeparator();
setMenu.add(speedMenu);
setMenu.addSeparator();
setMenu.add(exitMI);

ButtonGroup group = new ButtonGroup();
group.add(speedMI1);
group.add(speedMI2);
group.add(speedMI3);
group.add(speedMI4);
group.add(speedMI5);

speedMenu.add(speedMI1);
speedMenu.add(speedMI2);
speedMenu.add(speedMI3);
speedMenu.add(speedMI4);
speedMenu.add(speedMI5);

startMI.addActionListener(new StartAction());
pauseMI.addActionListener(new PauseAction());
exitMI.addActionListener(new ExitAction());
speedMI1.addActionListener(new SpeedAction());
speedMI2.addActionListener(new SpeedAction());
speedMI3.addActionListener(new SpeedAction());
speedMI4.addActionListener(new SpeedAction());
speedMI5.addActionListener(new SpeedAction());

helpMenu.add(aboutMI);
aboutMI.addActionListener(new AboutAction());

contentPane = getContentPane();
panel = new SnakeGamePanel(this);
contentPane.add(panel);

startMI.setEnabled(true);
pauseMI.setEnabled(false);

// 设置游戏状态是初始化状态
panel.setGameState(GameState.INITIALIZE);
}

private class StartAction implements ActionListener {
public void actionPerformed(ActionEvent event) {
startMI.setEnabled(false);
pauseMI.setEnabled(true);
panel.setGameState(GameState.RUN);
panel.getTimer().start();
}
}

private class PauseAction implements ActionListener {
public void actionPerformed(ActionEvent event) {
pauseMI.setEnabled(false);
startMI.setEnabled(true);
panel.setGameState(GameState.PAUSE);
if (panel.getTimer().isRunning()) {
panel.getTimer().stop();
}

}
}

private class SpeedAction implements ActionListener {
public void actionPerformed(ActionEvent event) {
Object speed = event.getSource();
if (speed == speedMI1) {
speedFlag = 1;
} else if (speed == speedMI2) {
speedFlag = 2;
} else if (speed == speedMI3) {
speedFlag = 3;
} else if (speed == speedMI4) {
speedFlag = 4;
} else if (speed == speedMI5) {
speedFlag = 5;
}

panel.getTimer().setDelay(1000 - 200 * (speedFlag - 1));
}
}

private class ExitAction implements ActionListener {
public void actionPerformed(ActionEvent event) {
int result = JOptionPane.showConfirmDialog(SnakeGameFrame.this,
SnakeGameConstant.QUIT_GAME, SnakeGameConstant.SNAKE_GAME,
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
}

private class AboutAction implements ActionListener {
public void actionPerformed(ActionEvent event) {
String string = SnakeGameConstant.KEYBOARDS_DESCRIPTION;
JOptionPane.showMessageDialog(SnakeGameFrame.this, string);
}
}

}


package my.games.snake.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
import my.games.snake.contants.SnakeGameConstant;
import my.games.snake.enums.Direction;
import my.games.snake.enums.GameState;
import my.games.snake.model.Grid;
import my.games.snake.model.Snake;

public class SnakeGamePanel extends JPanel {

private static final long serialVersionUID = -4173775119881265176L;

private int flag[][] = new int[SnakeGameConstant.GRID_COLUMN_NUMBER][SnakeGameConstant.GRID_ROW_NUMBER];// 在一个20*30的界面中,设置每个方块的flag

private Color color[][] = new Color[SnakeGameConstant.GRID_COLUMN_NUMBER][SnakeGameConstant.GRID_ROW_NUMBER];// 在一个20*30的界面中,设置每个方块的颜色

private Snake snake;

private Grid food;

public TimerAction timerAction;

private int score;

private SnakeGameFrame frame;

private Timer timer;

private Grid grid;

private GameState gameState = GameState.INITIALIZE;

//private GameOverType gameOverType = GameOverType.TOUCH_EDGE;

private boolean needToGenerateFood = false;

public SnakeGamePanel(SnakeGameFrame frame) {
for (int i = SnakeGameConstant.LEFT; i <= SnakeGameConstant.RIGHT; i++) {
for (int j = SnakeGameConstant.UP; j <= SnakeGameConstant.DOWN; j++) {
flag[i][j] = 0;
}
}
addKeyListener(new KeyHandler());
setFocusable(true);
init();

timerAction = new TimerAction();
timer = new Timer(1000, timerAction);
score = 0;
this.frame = frame;
grid = new Grid();
}

private void init() {
initSnake();
initFood();
}

private void initSnake() {
snake = new Snake();
List<Grid> list = new LinkedList<Grid>();
list.add(new Grid(4, 1, SnakeGameConstant.SNAKE_BODY_COLOR));
list.add(0, new Grid(5, 1, SnakeGameConstant.SNAKE_HEADER_COLOR));
snake.setList(list);
}

private void initFood() {
food = new Grid();
needToGenerateFood = true;
this.generateFoodByRandom();
}

public void setGameState(GameState state) {
gameState = state;
}

private void judgeGameOver() {
if (isSnakeHeadTouchEdge() || isSnakeHeadTouchBody()) {
gameState = GameState.OVER;
int result = JOptionPane.showConfirmDialog(frame,
SnakeGameConstant.GAME_OVER, SnakeGameConstant.SNAKE_GAME,
JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
for (int i = SnakeGameConstant.LEFT; i <= SnakeGameConstant.RIGHT; i++) {
for (int j = SnakeGameConstant.UP; j <= SnakeGameConstant.DOWN; j++) {
flag[i][j] = 0;
}
}

gameState = GameState.RUN;
score = 0;
init();
timer.start();
} else {
System.exit(0);
}
}
}

public void drawGameFrame(Graphics2D g2) {

}

public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;

g2.draw(new Rectangle2D.Double(SnakeGameConstant.SNAKE_GAME_PANEL_LEFT,
SnakeGameConstant.SNAKE_GAME_PANEL_TOP,
SnakeGameConstant.SNAKE_GAME_PANEL_RIGHT,
SnakeGameConstant.SNAKEGAME_PANEL_BOTTOM));

if (gameState.isInitializedState()) {
return;
}

draw(g2);
drawScore(g);
}

private void draw(Graphics2D g2) {
drawSnake(g2);
drawFood(g2);
for (int i = SnakeGameConstant.LEFT; i <= SnakeGameConstant.RIGHT; i++) {
for (int j = SnakeGameConstant.UP; j <= SnakeGameConstant.DOWN; j++) {
if (flag[i][j] == 1) {
grid.setX(i);
grid.setY(j);
grid.setColor(color[i][j]);
grid.draw(g2);
}
}
}
}

private void drawScore(Graphics g) {
g.drawString("Score: " + score,
SnakeGameConstant.SNAKE_GAME_PANEL_RIGHT + 20, 200);
}

private void drawSnake(Graphics2D g2) {
snake.draw(g2);
}

private void drawFood(Graphics2D g2) {
food.draw(g2);
}

private class KeyHandler implements KeyListener {
public void keyPressed(KeyEvent event) {
if (!gameState.isRunState()) {
return;
}
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_LEFT:
snake.changeDirection(Direction.LEFT);
break;

case KeyEvent.VK_RIGHT:
snake.changeDirection(Direction.RIGHT);
break;

case KeyEvent.VK_UP:
snake.changeDirection(Direction.UP);
break;

case KeyEvent.VK_DOWN:
snake.changeDirection(Direction.DOWN);
break;
default:
break;
}
repaint();
}

public void keyReleased(KeyEvent event) {
}

public void keyTyped(KeyEvent event) {
}
}

private class TimerAction implements ActionListener, Serializable {

private static final long serialVersionUID = 749074368549207272L;

public void actionPerformed(ActionEvent e) {
if (!gameState.isRunState()) {
return;
}

generateFoodByRandom();
snake.move();
eatFood();
judgeGameOver();

repaint();
}
}

private boolean isFoodAvailable(int x, int y) {
for (Grid grid : snake.getList()) {
if (x == grid.getX() && y == grid.getY()) {
return false;
}
}
return true;
}

private void generateFoodByRandom() {

if (needToGenerateFood) {
Random r = new Random();
int randomX = r.nextInt(SnakeGameConstant.GRID_COLUMN_NUMBER);
int randomY = r.nextInt(SnakeGameConstant.GRID_ROW_NUMBER);

if (isFoodAvailable(randomX, randomX)) {
food = new Grid(randomX, randomY, SnakeGameConstant.FOOD_COLOR);

needToGenerateFood = false;
} else {
generateFoodByRandom();
}
}
}

private boolean isSnakeHeadTouchEdge() {
Grid head = this.snake.getList().get(0);
if ((head.getX() >= SnakeGameConstant.GRID_COLUMN_NUMBER)
|| (head.getX() < 0)) {
//this.gameOverType = GameOverType.TOUCH_EDGE;
return true;
}
if ((head.getY() >= SnakeGameConstant.GRID_ROW_NUMBER)
|| (head.getY() < 0)) {
//this.gameOverType = GameOverType.TOUCH_EDGE;
return true;
}

return false;
}

private boolean isSnakeHeadTouchBody() {
Grid head = this.snake.getList().get(0);
int length = snake.getList().size();

for (int i = 1; i < length; i++) {
if (head.getX() == snake.getList().get(i).getX()
&& head.getY() == snake.getList().get(i).getY()) {
//this.gameOverType = GameOverType.TOUCH_BODY;
return true;
}
}

return false;
}

private boolean isFoodTouched() {
Grid head = snake.getList().get(0);
return head.getX() == food.getX() && head.getY() == food.getY();
}

private void eatFood() {
if (isFoodTouched()) {
Grid tail = snake.getList().get(snake.getList().size() - 1);
snake.getList().add(tail);
this.needToGenerateFood = true;
this.score += 10;

}
}

/**
* @return the timer
*/
public Timer getTimer() {
return timer;
}

/**
* @param timer
* the timer to set
*/
public void setTimer(Timer timer) {
this.timer = timer;
}

}


完整的代码,请参考附件MySnakeGame.7z,有需要的朋友可以下载。

后续的博文将添加如下功能:

(二)添加随机障碍物。
(三)添加游戏进度的存储和读取
(四)完成游戏排行榜
... ...
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值