Swing贪吃蛇游戏(一):基本功能实现_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Swing贪吃蛇游戏(一):基本功能实现

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

 2013/7/25 15:42:52  MouseLearnJava  程序员俱乐部  我要评论(0)
  • 摘要:本文将提供一个Swing版本的贪吃蛇游戏,游戏包括最基本的功能:1.用Timer来管理贪吃蛇线程。2.实现按钮,键盘的事件响应。3.随机产生食物。4.游戏结束的判断:蛇头触碰到蛇身或者蛇头触碰到边界。5.实现游戏过程中的暂停以及贪吃蛇运行速度调整。6.……程序界面如下:左边是贪吃蛇运行的范围,右边暂时只有分数信息,当蛇吃到食物的时候分数加10.暂停,调整蛇体运行速度界面如下:主要的代码如下:packagemy.games.snake.model;importjava.awt.Color
  • 标签:功能 实现 游戏 贪吃蛇 Swing

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

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


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



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



主要的代码如下:



class="java">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,有需要的朋友可以下载。

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

(二)添加随机障碍物。
(三)添加游戏进度的存储和读取
(四)完成游戏排行榜
... ...
  • 大小: 20.3 KB
  • 大小: 23 KB
  • 大小: 20.3 KB
  • MySnakeGame.7z (14 KB)
  • 下载次数: 1
  • 查看图片附件
发表评论
用户名: 匿名