- 浏览: 203143 次
- 性别:
- 来自: 湖南
文章分类
最新评论
对大多数人来说,要想自己编写出《贪吃蛇》游戏的程序代码,是有较大难度的。可是,很多初学者一直梦想和追求着自己亲手编写出一个《贪吃蛇》的游戏程序。为了帮助大家实现心愿,向大家讲解和展示了传智播客版《贪吃蛇游戏》的每一行代码的编写过程。
贪吃蛇游戏开发学习包括15小节,依次为:
01_游戏功能演示与说明
02_游戏中的面向对象分析与设计
03_使用传智播客提供的API类组装贪吃蛇游戏
04_编写贪吃蛇游戏中的各个类的主体框架性代码
05_编写Controler类与实现蛇移动的事件监听
06_编写对各个类进行测试的程序代码
07_蛇的数据结构设计与移动显示
08_测试与修正蛇的移动与显示问题
09_排除蛇的相反方向与无效方向的按键问题
10_编写与测试表示食物的类
11_完成蛇吃食物的相关代码
12_为游戏增加作为障碍物的石头
13_为蛇增加吃到石头而死掉的功能
14_解决食物与石头蛇身重叠的问题
15_为蛇增加吃到蛇身而死掉的功能
窗体界面如下
游戏入口:
游戏的显示界面:
工具类:
实物类:
游戏监听器:
控制器:
贪吃蛇游戏开发学习包括15小节,依次为:
01_游戏功能演示与说明
02_游戏中的面向对象分析与设计
03_使用传智播客提供的API类组装贪吃蛇游戏
04_编写贪吃蛇游戏中的各个类的主体框架性代码
05_编写Controler类与实现蛇移动的事件监听
06_编写对各个类进行测试的程序代码
07_蛇的数据结构设计与移动显示
08_测试与修正蛇的移动与显示问题
09_排除蛇的相反方向与无效方向的按键问题
10_编写与测试表示食物的类
11_完成蛇吃食物的相关代码
12_为游戏增加作为障碍物的石头
13_为蛇增加吃到石头而死掉的功能
14_解决食物与石头蛇身重叠的问题
15_为蛇增加吃到蛇身而死掉的功能
窗体界面如下
游戏入口:
package cn.itcast.snake.game; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import javax.swing.JColorChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.border.EtchedBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import cn.itcast.snake.controller.Controller; import cn.itcast.snake.entities.Food; import cn.itcast.snake.entities.Ground; import cn.itcast.snake.entities.Snake; import cn.itcast.snake.listener.GameListener; import cn.itcast.snake.util.Global; import cn.itcast.snake.view.GamePanel; /** * 主界面, 实现了 GameListener 接口 * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class MainFrame extends JFrame implements GameListener { /** * */ private static final long serialVersionUID = 1L; /** * Launch the application * * @param args */ public static void main(String args[]) { try { MainFrame frame = new MainFrame(new Controller(new Snake(), new Food(), new Ground(), new GamePanel(), new JLabel())); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } private final GameOptionPanel optionPanel; private final GamePanel gamePanel; private final Snake snake; private final Ground ground; private final Food food; private final JLabel infoLabel; private final Controller controller; /** * Create the frame */ public MainFrame(Controller c) { super(); this.controller = c; this.setTitle("贪吃蛇"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); this.setResizable(false); int left = 10; optionPanel = new GameOptionPanel(); /** =======* */ gamePanel = c.getGamePanel(); snake = c.getSnake(); ground = c.getGround(); food = c.getFood(); infoLabel = c.getGameInfoLabel() == null ? new JLabel() : c .getGameInfoLabel(); c.setGameInfoLabel(infoLabel); optionPanel.getButton_griddingColor().addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { Color griddingColor = JColorChooser.showDialog( MainFrame.this, "请选择网格的颜色", Color.LIGHT_GRAY); if (griddingColor != null) ground.setGriddingColor(griddingColor); } }); optionPanel.getButton_backgroundColor().addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { Color backgroundColor = JColorChooser .showDialog(MainFrame.this, "请选择背景的颜色", new Color(0xcfcfcf)); if (backgroundColor != null) gamePanel.setBackgroundColor(backgroundColor); } }); optionPanel.getButton_foodColor().addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { Color foodColor = JColorChooser.showDialog( MainFrame.this, "请选择食物的颜色", Color.DARK_GRAY); if (foodColor != null) food.setColor(foodColor); } }); optionPanel.getButton_headColor().addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { Color headColor = JColorChooser .showDialog(MainFrame.this, "请选择蛇头的颜色", new Color(0xFF4500)); if (headColor != null) snake.setHeadColor(headColor); } }); optionPanel.getButton_bodyColor().addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { Color bodyColor = JColorChooser.showDialog( MainFrame.this, "请选择蛇身体的颜色", Color.DARK_GRAY); if (bodyColor != null) snake.setBodyColor(bodyColor); } }); this.addFocusListener(new FocusAdapter() { public void focusLost(FocusEvent arg0) { controller.pauseGame(); if (optionPanel.getPauseButton().isEnabled()) optionPanel.getPauseButton().setText("继续游戏"); } }); gamePanel.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent arg0) { // controller.continueGame(); } public void focusLost(FocusEvent arg0) { controller.pauseGame(); if (optionPanel.getPauseButton().isEnabled()) optionPanel.getPauseButton().setText("继续游戏"); } }); optionPanel.getRadioButton_map2().addChangeListener( new ChangeListener() { public void stateChanged(ChangeEvent e) { controller.setMap(optionPanel.getRadioButton_map2() .isSelected() ? 2 : 1); } }); optionPanel.getNewGameButton().addActionListener(new ActionListener() { /** * 开始游戏的按钮 */ public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub if (controller.isPlaying()) { return; } controller.newGame(); } }); optionPanel.getStopGameButton().addActionListener(new ActionListener() { /** * 停止游戏的按钮 */ public void actionPerformed(ActionEvent e) { controller.stopGame(); } }); optionPanel.getPauseButton().setEnabled(false); optionPanel.getStopGameButton().setEnabled(false); optionPanel.getPauseButton().addActionListener(new ActionListener() { /** * 暂停/继续游戏的按钮 */ public void actionPerformed(ActionEvent e) { if (controller.isPausingGame()) { controller.continueGame(); } else { controller.pauseGame(); } if (controller.isPausingGame()) optionPanel.getPauseButton().setText("继续游戏"); else optionPanel.getPauseButton().setText("暂停游戏"); } }); optionPanel.getCheckBox_drawGridding().addChangeListener( new ChangeListener() { public void stateChanged(ChangeEvent arg0) { optionPanel.getButton_griddingColor().setVisible( optionPanel.getCheckBox_drawGridding() .isSelected()); ground.setDrawGridding(optionPanel .getCheckBox_drawGridding().isSelected()); } }); optionPanel.getButton_default().addActionListener(new ActionListener() { /** * 恢复默认设置的按钮 */ public void actionPerformed(ActionEvent e) { gamePanel .setBackgroundColor(GamePanel.DEFAULT_BACKGROUND_COLOR); optionPanel.getCheckBox_drawGridding().setSelected(false); ground.setGriddingColor(Ground.DEFAULT_GRIDDING_COLOR); snake.setHeadColor(Snake.DEFAULT_HEAD_COLOR); snake.setBodyColor(Snake.DEFAULT_BODY_COLOR); optionPanel.getRadioButton_map1().setSelected(true); } }); /** ******************* */ infoLabel.setBounds(10, 0, infoLabel.getSize().width - 10, infoLabel .getSize().height); gamePanel.setBounds(0, infoLabel.getSize().height, gamePanel.getSize().width, gamePanel.getSize().height); /** * subPanel */ JPanel subPanel = new JPanel(); subPanel.setLayout(null); subPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); subPanel.setFocusable(false); subPanel.setSize(gamePanel.getSize().width + 1, infoLabel.getSize().height + gamePanel.getSize().height + 1); subPanel.setBounds(left, 5, subPanel.getSize().width, subPanel .getSize().height); subPanel.add(infoLabel); subPanel.add(gamePanel); optionPanel.setBounds(left, subPanel.getSize().height + 10, optionPanel .getSize().width, optionPanel.getSize().height); /** * 说明 */ JPanel infoPanel = new JPanel(); infoPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); infoPanel.setLayout(null); infoPanel.setBounds(left + optionPanel.getSize().width + 5, subPanel .getSize().height + 10, gamePanel.getSize().width - optionPanel.getSize().width - 5 + 1, optionPanel.getSize().height); final JLabel infoTitleLable = new JLabel(); infoTitleLable.setFont(new Font("宋体", Font.PLAIN, 12)); infoTitleLable.setText(Global.TITLE_LABEL_TEXT); infoTitleLable.setBounds(10, 5, infoPanel.getSize().width - 10, 20); final JTextArea infoTextArea = new JTextArea(); infoTextArea.setFont(new Font("宋体", Font.PLAIN, 12)); infoTextArea.setText(Global.INFO_LABEL_TEXT); infoTextArea.setFocusable(false); infoTextArea.setBackground(this.getBackground()); infoTextArea.setBounds(10, 25, infoPanel.getSize().width - 20, infoPanel.getSize().height - 50); infoPanel.add(infoTitleLable); infoPanel.add(infoTextArea); optionPanel.getCheckBox_drawGridding().setFocusable(false); optionPanel.getRadioButton_map1().setFocusable(false); optionPanel.getRadioButton_map2().setFocusable(false); this .setSize( subPanel.getSize().width > optionPanel.getSize().width ? gamePanel .getSize().width + 2 * left + 8 : optionPanel.getSize().width + 2 * left + 8, subPanel.getSize().height + 20/* 边框 */ + optionPanel.getSize().height + 30); /* 让窗口居中 */ this.setLocation(this.getToolkit().getScreenSize().width / 2 - this.getWidth() / 2, this.getToolkit().getScreenSize().height / 2 - this.getHeight() / 2); /* 添加监听器 */ gamePanel.addKeyListener(controller); this.addKeyListener(controller); controller.addGameListener(this); this.getContentPane().add(subPanel); this.getContentPane().add(optionPanel); this.getContentPane().add(infoPanel); } public void gameOver() { // TODO Auto-generated method stub optionPanel.getPauseButton().setEnabled(false); optionPanel.getStopGameButton().setEnabled(false); optionPanel.getNewGameButton().setEnabled(true); optionPanel.getPauseButton().setText("暂停/继续"); } public void gameStart() { // TODO Auto-generated method stub optionPanel.getPauseButton().setEnabled(true); optionPanel.getNewGameButton().setEnabled(false); optionPanel.getStopGameButton().setEnabled(true); } public void gameContinue() { // TODO Auto-generated method stub optionPanel.getPauseButton().setText("暂停游戏"); } public void gamePause() { // TODO Auto-generated method stub optionPanel.getPauseButton().setText("继续游戏"); } }
package cn.itcast.snake.game; import java.awt.Font; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSeparator; import javax.swing.SwingConstants; import javax.swing.border.EtchedBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * 游戏的设置项面板 * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class GameOptionPanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private ButtonGroup buttonGroup = new ButtonGroup(); private ImageIcon czbkIcon = new ImageIcon(GameOptionPanel.class .getResource("czbk.png")); private JFrame frame; private final JButton newGameButton = new JButton(); private final JButton stopGameButton = new JButton(); private final JButton pauseButton = new JButton(); private final JCheckBox checkBox_drawGridding = new JCheckBox(); private final JRadioButton radioButton_map1; private final JRadioButton radioButton_map2; private final JButton button_griddingColor; private final JButton button_backgroundColor; private final JButton button_foodColor; private final JButton button_headColor; private final JButton button_bodyColor; private final JButton button_default; /** * Create the panel */ public GameOptionPanel() { super(); setSize(450, 185); setLayout(null); setBorder(new EtchedBorder(EtchedBorder.LOWERED)); setFocusable(false); final JSeparator separator = new JSeparator(); separator.setBounds(140, 55, 156, 50); add(separator); button_griddingColor = new JButton(); button_griddingColor.setBounds(85, 10, 60, 23); separator.add(button_griddingColor); button_griddingColor.setFont(new Font("宋体", Font.PLAIN, 12)); button_griddingColor.setFocusable(false); button_griddingColor.setText("颜色"); button_griddingColor.setVisible(false); checkBox_drawGridding.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent arg0) { button_griddingColor.setVisible(checkBox_drawGridding .isSelected()); } }); checkBox_drawGridding.setBounds(5, 10, 78, 23); separator.add(checkBox_drawGridding); checkBox_drawGridding.setText("显示网格"); checkBox_drawGridding.setFont(new Font("宋体", Font.PLAIN, 12)); final JSeparator separator_6 = new JSeparator(); separator_6.setBounds(10, 55, 119, 33); add(separator_6); button_backgroundColor = new JButton(); button_backgroundColor.setBounds(5, 10, 110, 23); separator_6.add(button_backgroundColor); button_backgroundColor.setFont(new Font("宋体", Font.PLAIN, 12)); button_backgroundColor.setFocusable(false); button_backgroundColor.setText("设置背景颜色"); final JSeparator separator_4 = new JSeparator(); separator_4.setBounds(10, 135, 286, 39); add(separator_4); button_foodColor = new JButton(); button_foodColor.setBounds(5, 10, 111, 23); separator_4.add(button_foodColor); button_foodColor.setFont(new Font("宋体", Font.PLAIN, 12)); button_foodColor.setFocusable(false); button_foodColor.setText("设置食物颜色"); radioButton_map1 = new JRadioButton(); radioButton_map1.setFont(new Font("宋体", Font.PLAIN, 12)); radioButton_map1.setSelected(true); buttonGroup.add(radioButton_map1); radioButton_map1.setText("地图1"); radioButton_map1.setBounds(135, 10, 63, 23); separator_4.add(radioButton_map1); radioButton_map2 = new JRadioButton(); radioButton_map2.setFont(new Font("宋体", Font.PLAIN, 12)); buttonGroup.add(radioButton_map2); radioButton_map2.setText("地图2"); radioButton_map2.setBounds(198, 10, 63, 23); separator_4.add(radioButton_map2); final JSeparator separator_1 = new JSeparator(); separator_1.setBounds(10, 95, 286, 39); add(separator_1); button_headColor = new JButton(); button_headColor.setBounds(5, 10, 110, 23); separator_1.add(button_headColor); button_headColor.setFont(new Font("宋体", Font.PLAIN, 12)); button_headColor.setFocusable(false); button_headColor.setText("设置蛇头颜色"); button_bodyColor = new JButton(); button_bodyColor.setBounds(135, 10, 113, 23); separator_1.add(button_bodyColor); button_bodyColor.setFont(new Font("宋体", Font.PLAIN, 12)); button_bodyColor.setFocusable(false); button_bodyColor.setText("设置蛇身颜色"); final JSeparator separator_2 = new JSeparator(); separator_2.setOrientation(SwingConstants.VERTICAL); separator_2.setBounds(302, 10, 140, 165); add(separator_2); final JSeparator separator_5 = new JSeparator(); separator_5.setBounds(10, 70, 125, 95); separator_2.add(separator_5); stopGameButton.setText("停止游戏"); stopGameButton.setBounds(11, 10, 101, 23); separator_5.add(stopGameButton); stopGameButton.setFont(new Font("宋体", Font.PLAIN, 12)); stopGameButton.setFocusable(false); pauseButton.setBounds(10, 40, 101, 23); separator_5.add(pauseButton); pauseButton.setText("暂停/继续"); pauseButton.setFont(new Font("宋体", Font.PLAIN, 12)); pauseButton.setFocusable(false); newGameButton.setFont(new Font("宋体", Font.PLAIN, 12)); newGameButton.setBounds(11, 70, 101, 23); separator_5.add(newGameButton); newGameButton.setFocusable(false); newGameButton.setText("开始新游戏"); final JLabel label_logo = new JLabel(czbkIcon); label_logo.setBounds(10, 10, 125, 50); separator_2.add(label_logo); final JSeparator separator_3 = new JSeparator(); separator_3.setBounds(10, 20, 286, 34); add(separator_3); final JLabel label_2 = new JLabel(); label_2.setFont(new Font("宋体", Font.PLAIN, 12)); label_2.setText("选项:"); label_2.setBounds(10, 10, 60, 15); separator_3.add(label_2); button_default = new JButton(); button_default.setText("恢复默认设置"); button_default.setFont(new Font("宋体", Font.PLAIN, 12)); button_default.setBounds(139, 6, 137, 23); button_default.setFocusable(false); separator_3.add(button_default); } public JFrame getFrame() { return frame; } public void setFrame(JFrame frame) { this.frame = frame; } public JCheckBox getCheckBox_drawGridding() { return checkBox_drawGridding; } public ImageIcon getCzbkIcon() { return czbkIcon; } public void setCzbkIcon(ImageIcon czbkIcon) { this.czbkIcon = czbkIcon; } public JButton getNewGameButton() { return newGameButton; } public JButton getPauseButton() { return pauseButton; } public JButton getStopGameButton() { return stopGameButton; } public JButton getButton_griddingColor() { return button_griddingColor; } public JButton getButton_backgroundColor() { return button_backgroundColor; } public JButton getButton_foodColor() { return button_foodColor; } public JButton getButton_headColor() { return button_headColor; } public JButton getButton_bodyColor() { return button_bodyColor; } public JRadioButton getRadioButton_map2() { return radioButton_map2; } public JRadioButton getRadioButton_map1() { return radioButton_map1; } public JButton getButton_default() { return button_default; } public ButtonGroup getButtonGroup() { return buttonGroup; } public void setButtonGroup(ButtonGroup buttonGroup) { this.buttonGroup = buttonGroup; } }
游戏的显示界面:
package cn.itcast.snake.view; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import javax.swing.JPanel; import javax.swing.border.EtchedBorder; import cn.itcast.snake.entities.Food; import cn.itcast.snake.entities.Ground; import cn.itcast.snake.entities.Snake; import cn.itcast.snake.util.Global; /** * 游戏的显示界面<BR> * 可以用 setBackgroundColor() 设置游戏的背景色 * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class GamePanel extends JPanel { /** * */ private static final long serialVersionUID = 1L; private Image oimg; private Graphics og; public static final Color DEFAULT_BACKGROUND_COLOR = new Color(0xcfcfcf); /** * 背景颜色 */ private Color backgroundColor = DEFAULT_BACKGROUND_COLOR; public GamePanel() { /* 设置大小和布局 */ this.setSize(Global.WIDTH * Global.CELL_WIDTH, Global.HEIGHT * Global.CELL_HEIGHT); this.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); this.setFocusable(true); } /** * 重新显示 Ground, Shape * * @param ground * @param snake */ public synchronized void redisplay(Ground ground, Snake snake, Food food) { /* 重新显示 */ if (og == null) { oimg = createImage(getSize().width, getSize().height); if (oimg != null) og = oimg.getGraphics(); } if (og != null) { og.setColor(backgroundColor); og.fillRect(0, 0, Global.WIDTH * Global.CELL_WIDTH, Global.HEIGHT * Global.CELL_HEIGHT); if (ground != null) ground.drawMe(og); snake.drawMe(og); if (food != null) food.drawMe(og); this.paint(this.getGraphics()); } } @Override public void paint(Graphics g) { g.drawImage(oimg, 0, 0, this); } /** * 得到当前的背景颜色 * * @return */ public Color getBackgroundColor() { return backgroundColor; } /** * 设置当前的背景颜色 * * @param backgroundColor */ public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } }
工具类:
package cn.itcast.snake.util; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * * 工具类<BR> * <BR> * 此类中存放了其他类中用到的一些常量<BR> * 并且支持配置文件<BR> * 配置文件的路径为游戏运行的目录, 文件名为 snake.ini<BR> * <BR> * 配置文件的写法请参见字段的注释<BR> * <BR> * 配置文件中设置项可以只写需要配置的, 没有写的设置项默认为缺省值<BR> * 各配置项的缺省值请参见字段的注释<BR> * <BR> * 每个配置项都有设置值范围, 超出范围(无效)的设置值将不起作用<BR> * 设置值的范围请参见字段的注释<BR> * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class Global { private static Properties properties = new Properties(); /** * 配置文件的路径(默认为当前目录下的 snake.ini文件) */ private static String CONFIG_FILE = "snake.ini"; /** * 一个格子的宽度, 单位:像素 <BR> * 对应的配置文件中的关键字为: cell_width, 或用 cell_size指定<BR> * 范围1 至 100<BR> * 缺省值为 23 */ public static final int CELL_WIDTH; /** * 一个格子的高度, 单位:像素 <BR> * 对应的配置文件中的关键字为: cell_width, 或用 cell_size指定<BR> * 范围1 至 100<BR> * 缺省值为 23 */ public static final int CELL_HEIGHT; /** * 用格子表示的宽度, (宽度为多少个格子) 单位:格 <BR> * 对应的配置文件中的关键字为: width<BR> * 范围10 至 80<BR> * 缺省值为 30 */ public static final int WIDTH; /** * 用格子表示的高度, (高度为多少个格子), 单位:格)<BR> * 对应的配置文件中的关键字为: height<BR> * 范围10 至 60<BR> * 缺省值为20 */ public static final int HEIGHT; /** * 显示的像素宽度 (格子宽度度 * 每一格的宽度) */ public static final int CANVAS_WIDTH; /** * 显示的像素高度 (格子高度 * 每一格的高度) */ public static final int CANVAS_HEIGHT; /** * 蛇的初始长度, 对应的配置文件中的关键字为: init_length<BR> * 范围2 至 最大宽度<BR> * (单位:格) 缺省值为 2 */ public static final int INIT_LENGTH; /** * 蛇的初始速度 (单位: 毫秒/格)<BR> * 对应的配置文件中的关键字为: speed<BR> * 范围10 至 无限大<BR> * 缺省值为 200 */ public static final int SPEED; /** * 蛇每次加速或减速的幅度 (单位: 毫秒/格)<BR> * 对应的配置文件的关键字为: speed_step<BR> * 范围1 至 无限大<BR> * 缺省值为 25 */ public static final int SPEED_STEP; public static final String TITLE_LABEL_TEXT; public static final String INFO_LABEL_TEXT; /** * 默认的构造器, 私有的, 不能生成这个类的实例 */ private Global() { } /** * 初始化常量 */ static { InputStream inputStream = null; try { inputStream = new FileInputStream(CONFIG_FILE); properties.load(inputStream); } catch (Exception e) { System.out.println("没有配置文件"); } finally { try { if (inputStream != null) inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } Integer temp = null; /* 没有设置或设置的无效时要有一个默认值 */ WIDTH = (temp = getIntValue("width")) != null && temp <= 80 && temp >= 10 ? temp : 35; HEIGHT = (temp = getIntValue("height")) != null && temp <= 60 && temp >= 10 ? temp : 20; INIT_LENGTH = (temp = getIntValue("init_length")) != null && temp > 1 && temp < WIDTH ? temp : 2; SPEED = (temp = getIntValue("speed")) != null && temp >= 10 ? temp : 200; SPEED_STEP = (temp = getIntValue("speed_step")) != null && temp >= 1 ? temp : 25; int defaultCellSize = (temp = getIntValue("cell_size")) != null && temp > 0 && temp <= 100 ? temp : 20; CELL_WIDTH = (temp = getIntValue("cell_width")) != null && temp > 0 && temp <= 100 ? temp : defaultCellSize; CELL_HEIGHT = (temp = getIntValue("cell_height")) != null && temp > 0 && temp <= 100 ? temp : defaultCellSize; CANVAS_WIDTH = WIDTH * CELL_WIDTH; CANVAS_HEIGHT = HEIGHT * CELL_HEIGHT; String tempStr = null; TITLE_LABEL_TEXT = (tempStr = getValue("title")) == null ? "说明:" : tempStr; INFO_LABEL_TEXT = (tempStr = getValue("info")) == null ? "方向键控制方向, 回车键暂停/继续\nPAGE UP, PAGE DOWN 加速或减速\n\n更多请看 www.itcast.cn " : tempStr; } /** * 要考虑多种情况<BR> * 1. 没有这个key和value<BR> * 2 有key 没有 value */ private static Integer getIntValue(String key) { if (key == null) throw new RuntimeException("key 不能为空"); try { return new Integer(properties.getProperty(key)); } catch (NumberFormatException e) { return null; } } private static String getValue(String key) { try { return new String(properties.getProperty(key).getBytes("iso8859-1")); } catch (Exception e) { return null; } } }
实物类:
package cn.itcast.snake.entities; import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; import cn.itcast.snake.listener.SnakeListener; import cn.itcast.snake.util.Global; /** * * 蛇<BR> * move()方法默认支持走到边以后从另一边出现<BR> * <BR> * 可以用setHeadColor(), 和 setBodyColor() 方法更改蛇头或蛇身体的颜色<BR> * <BR> * 也可以通过覆盖 drawHead(Graphics, int, int, int, int) 方法 改变蛇头的显示方式 和覆盖 * drawBody(Graphics, int, int, int, int) 方法 改变蛇身体的显示方式<BR> * <BR> * 用内部类MoveDriver 驱动蛇定时移动<BR> * begin() 方法内部开启一个新的线程驱动蛇定时移动, 调用这个方法的时候要注意<BR> * * 蛇的身体的初始长度必须大于等于2 * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class Snake { /** * 方向上 */ public static final int UP = 1; /** * 方向下 */ public static final int DOWN = -1; /** * 方向左 */ public static final int LEFT = 2; /** * 方向右 */ public static final int RIGHT = -2; /* 蛇(多个节点) */ private LinkedList<Point> body = new LinkedList<Point>(); /* 上一次的移动方向 */ private int oldDirection; /* 下一步的方向(有效方向) */ private int newDirection; /* 临时存放蛇头的坐标 */ private Point head; /* 临时存放蛇尾巴的坐标 */ private Point tail; /* 移动速度 */ private int speed; /* 生命, 是否活着 */ private boolean live; /* 是否暂停 */ private boolean pause; private Set<SnakeListener> listeners = new HashSet<SnakeListener>(); public static final Color DEFAULT_HEAD_COLOR = new Color(0xcc0033); /* 蛇头的颜色 */ private Color headColor = DEFAULT_HEAD_COLOR; public static final Color DEFAULT_BODY_COLOR = new Color(0xcc0033); /* 蛇身体的颜色 */ private Color bodyColor = DEFAULT_BODY_COLOR; /** * 移动一步, 会忽略相反方向 */ public void move() { /* 忽略相反方向 */ if (oldDirection + newDirection != 0) oldDirection = newDirection; /* 把蛇尾巴拿出来重新设置坐标作为新蛇头 */ /* getLocation 将返回一个新的Point */ /* tail把尾巴坐标保存下来, 吃到食物时再加上 */ tail = (head = takeTail()).getLocation(); /* 根据蛇头的坐标再 上下左右 */ head.setLocation(getHead()); /* 根据方向让蛇移动 */ switch (oldDirection) { case UP: head.y--; /* 到边上了可以从另一边出现 */ if (head.y < 0) head.y = Global.HEIGHT - 1; break; case DOWN: head.y++; /* 到边上了可以从另一边出现 */ if (head.y == Global.HEIGHT) head.y = 0; break; case LEFT: head.x--; /* 到边上了可以从另一边出现 */ if (head.x < 0) head.x = Global.WIDTH - 1; break; case RIGHT: head.x++; /* 到边上了可以从另一边出现 */ if (head.x == Global.WIDTH) head.x = 0; break; } /* 添加到头上去 */ body.addFirst(head); } /** * 一个内部类, 驱动蛇定时移动 * * @author 汤阳光 * */ private class SnakeDriver implements Runnable { public void run() { // TODO Auto-generated method stub while (live) { if (!pause) { move(); /* 触发 ControllerListener 的状态改变事件 */ for (SnakeListener l : listeners) l.snakeMoved(); } try { Thread.sleep(speed); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 在尾巴上增加一个节点 */ public void eatFood() { /* 把上一次移动拿掉的节点再加上 */ body.addLast(tail.getLocation()); /* 触发SnakeListener 的 snakeEatFood 事件 */ for (SnakeListener l : listeners) l.snakeEatFood(); } /** * 改变方向 * * @param direction */ public void changeDirection(int direction) { this.newDirection = direction; } /** * 得到蛇头节点 * * @return */ public Point getHead() { /* 自己约定哪个是蛇头 */ return body.getFirst(); } /** * 拿掉蛇尾巴节点 * * @return */ public Point takeTail() { /* 去掉蛇尾巴 */ return body.removeLast(); } /** * 得到蛇的长度 * * @return */ public int getLength() { return body.size(); } /** * 让蛇开始运动<BR> * 开启一个新的线程 */ public void begin() { new Thread(new SnakeDriver()).start(); } /** * 让蛇复活, 并开始运动<BR> * 将调用 begin() 方法 */ public void reNew() { init(); begin(); } /** * 初始化蛇的信息<BR> * 长度, 位置, 方向, 速度, 生命和暂停状态 */ public void init() { body.clear(); /* 初始化位置在中间 */ int x = Global.WIDTH / 2 - Global.INIT_LENGTH / 2; int y = Global.HEIGHT / 2; for (int i = 0; i < Global.INIT_LENGTH; i++) this.body.addFirst(new Point(x++, y)); /* 设置默认方向为向右 */ oldDirection = newDirection = RIGHT; /* 初始化速度 */ speed = Global.SPEED; /* 初始化生命和暂停状态 */ live = true; pause = false; } /** * 是否吃到自己的身体<BR> * * @return 蛇头的坐标是否和自己的身体的某一个坐标重合 */ public boolean isEatBody() { /* 要把蛇头排除, body.get(0) 是蛇头 */ for (int i = 1; i < body.size(); i++) if (getHead().equals(body.get(i))) return true; return false; } /** * 画自己<BR> * 将调用 drawHead(Graphics, int, int, int, int) 方法 和 drawBody(Graphics, int, * int, int, int) 方法 * * @param g */ public void drawMe(Graphics g) { for (Point p : body) { /* 画蛇身体 */ g.setColor(bodyColor); drawBody(g, p.x * Global.CELL_WIDTH, p.y * Global.CELL_HEIGHT, Global.CELL_WIDTH, Global.CELL_HEIGHT); } /* 画蛇头 */ g.setColor(headColor); drawHead(g, getHead().x * Global.CELL_WIDTH, getHead().y * Global.CELL_HEIGHT, Global.CELL_WIDTH, Global.CELL_HEIGHT); } /** * 画蛇头, 可以覆盖这个方法改变蛇头的显示 * * @param g * @param x * 像素坐标 x * @param y * 像素坐标 y * @param width * 宽度(单位:像素) * @param height * 高度(单位:像素) */ public void drawHead(Graphics g, int x, int y, int width, int height) { g.fill3DRect(x, y, width, height, true); } /** * 画蛇的一节身体, 可以覆盖这个方法改变蛇的身体节点的显示 * * @param g * @param x * 像素坐标 x * @param y * 像素坐标 y * @param width * 宽度(单位:像素) * @param height * 高度(单位:像素) */ public void drawBody(Graphics g, int x, int y, int width, int height) { g.fill3DRect(x, y, width, height, true); } /** * 得到蛇头的颜色 * * @return */ public Color getHeadColor() { return headColor; } /** * 设置蛇头的颜色 * * @param headColor */ public void setHeadColor(Color headColor) { this.headColor = headColor; } /** * 得到蛇身体的颜色 * * @return */ public Color getBodyColor() { return bodyColor; } /** * 设置蛇身体的颜色 * * @param bodyColor */ public void setBodyColor(Color bodyColor) { this.bodyColor = bodyColor; } /** * 添加监听器 * * @param l */ public synchronized void addSnakeListener(SnakeListener l) { if (l == null) return; this.listeners.add(l); } /** * 移除监听器 * * @param l */ public synchronized void removeSnakeListener(SnakeListener l) { if (l == null) return; this.listeners.remove(l); } /** * 加速, 幅度为 Global 中设置的 SPEED_STEP <BR> * 在有效的速度范围之内(增加后速度大于 0毫秒/格) */ public void speedUp() { if (speed > Global.SPEED_STEP) speed -= Global.SPEED_STEP; } /** * 减速, 幅度为 Global 中设置的 SPEED_STEP */ public void speedDown() { speed += Global.SPEED_STEP; } /** * 得到蛇的移动速度 * * @return */ public int getSpeed() { return speed; } /** * 设置蛇的移动速度 * * @param speed */ public void setSpeed(int speed) { this.speed = speed; } /** * 蛇是否死掉了 * * @return */ public boolean isLive() { return live; } /** * 设置蛇是否死掉 * * @param live */ public void setLive(boolean live) { this.live = live; } /** * 设置蛇死掉 */ public void dead() { this.live = false; } /** * 是否是暂停状态 * * @return */ public boolean isPause() { return pause; } /** * 设置暂停状态 * * @param pause */ public void setPause(boolean pause) { this.pause = pause; } /** * 更改暂停状态<BR> * 若是暂停状态, 则继续移动<BR> * 若正在移动, 则暂停 */ public void changePause() { pause = !pause; } }
package cn.itcast.snake.entities; import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.util.Random; import cn.itcast.snake.util.Global; /** * * 食物, 有x , y 坐标 和 颜色等属性<BR> * 可以用setColor() 改变食物的颜色<BR> * 也可以通过覆盖 drawFood(Graphics, int, int, int, int) 方法 改变食物的显示方式<BR> * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class Food extends Point { /** * */ private static final long serialVersionUID = 1L; /* 食物的颜色 */ private Color color = new Color(0xcc0033); private Random random = new Random(); /** * 默认的构造器, 产生(0,0)的坐标 */ public Food() { super(); } public Point getNew() { Point p = new Point(); p.x = random.nextInt(Global.WIDTH); p.y = random.nextInt(Global.HEIGHT); return p; } /** * 初始化坐标和指定坐标相同的构造器 * * @param x * @param y */ public Food(Point p) { super(p); } /** * 蛇是否吃到了食物 * * @param p * @return */ public boolean isSnakeEatFood(Snake snake) { return this.equals(snake.getHead()); } /** * 画自己, 将调用 drawFood(Graphics, int, int, int, int) 方法 * * @param g */ public void drawMe(Graphics g) { g.setColor(color); drawFood(g, x * Global.CELL_WIDTH, y * Global.CELL_HEIGHT, Global.CELL_WIDTH, Global.CELL_HEIGHT); } /** * 画食物, 可以覆盖这个方法改变食物的显示 * * @param g * @param x * 像素坐标 x * @param y * 像素坐标 y * @param width * 宽度(单位:像素) * @param height * 高度(单位:像素) */ public void drawFood(Graphics g, int x, int y, int width, int height) { g.fill3DRect(x, y, width, height, true); } /** * 得到食物的颜色 * * @return */ public Color getColor() { return color; } /** * 设置食物的颜色 * * @param color */ public void setColor(Color color) { this.color = color; } }
package cn.itcast.snake.entities; import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.util.Random; import cn.itcast.snake.util.Global; /** * 可以叫做地形, 或地面<BR> * <BR> * 可以通过setRockColor(), setGriddingColor()方法更改石头或网格的颜色<BR> * 通过setDrawGridding() 方法设置是否画网格<BR> * <BR> * 可以覆盖 drawRock(Graphics, int, int, int, int) 方法以改变石头的显示方式<BR> * <BR> * 可以通过覆盖genernateRocks() 方法改变石头产生的布局<BR> * 覆盖此方法时, 请使用addRock(int,int) 方法在指定的坐标添加石头<BR> * <BR> * 这个类提供了两种石头的布局<BR> * 默认是使用第一种, 即一圈石头<BR> * 如果想使用第二种, 则应该使用如下代码:<BR> * <code><BR> Ground ground = new Ground();<BR> // 清空石头<BR> ground.init();<BR> // 使用提供的第二种石头的布局 <BR> ground.generateRocks2();<BR> </code> <BR> * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class Ground { /* 存放石头的二维数组 */ private boolean rocks[][] = new boolean[Global.WIDTH][Global.HEIGHT]; /* 存放getFreePoint()方法生成的不是石头的随机的坐标 */ private Point freePoint = new Point(); public static final Color DEFAULT_ROCK_COLOR = new Color(0x666666); /* 石头的颜色 */ private Color rockColor = DEFAULT_ROCK_COLOR; public static final Color DEFAULT_GRIDDING_COLOR = Color.LIGHT_GRAY; /* 网格的颜色 */ private Color griddingColor = DEFAULT_GRIDDING_COLOR; private Random random = new Random(); /* 是否画网格的开关 */ private boolean drawGridding = false; /** * 默认的构造器, 将调用 init()方法和 generateRocks() 方法 */ public Ground() { init(); } /** * 初始化地面(清空石头) */ public void clear() { for (int x = 0; x < Global.WIDTH; x++) for (int y = 0; y < Global.HEIGHT; y++) rocks[x][y] = false; } public void init() { clear(); generateRocks(); } /** * 产生石头, 可以覆盖这个方法改变石头在地面上的布局 */ public void generateRocks() { for (int x = 0; x < Global.WIDTH; x++) rocks[x][0] = rocks[x][Global.HEIGHT - 1] = true; for (int y = 0; y < Global.HEIGHT; y++) rocks[0][y] = rocks[Global.WIDTH - 1][y] = true; } /** * 提供的第二种默认的石头布局<BR> * 用这个可以测试蛇从另一边出现<BR> * 使用时先调用init()方法清空石头, 再调用这个方法产生石头布局<BR> * 详细使用请参见类介绍 */ public void generateRocks2() { for (int y = 0; y < 6; y++) { rocks[0][y] = true; rocks[Global.WIDTH - 1][y] = true; rocks[0][Global.HEIGHT - 1 - y] = true; rocks[Global.WIDTH - 1][Global.HEIGHT - 1 - y] = true; } for (int y = 6; y < Global.HEIGHT - 6; y++) { rocks[6][y] = true; rocks[Global.WIDTH - 7][y] = true; } } /** * 添加一块石头到指定格子坐标 * * @param x * 格子坐标 x * @param y * 格子坐标 y */ public void addRock(int x, int y) { rocks[x][y] = true; } /** * 蛇是否吃到了石头 * * @param p * @return */ public boolean isSnakeEatRock(Snake snake) { return rocks[snake.getHead().x][snake.getHead().y]; } /** * 随机生成一个不是石头的坐标, 用于丢食物 * * @return */ public Point getFreePoint() { do { freePoint.x = random.nextInt(Global.WIDTH); freePoint.y = random.nextInt(Global.HEIGHT); } while (rocks[freePoint.x][freePoint.y]); return freePoint; } /** * 得到石头的颜色 * * @return */ public Color getRockColor() { return rockColor; } /** * 设置石头的颜色 * * @param rockColor */ public void setRockColor(Color rockColor) { this.rockColor = rockColor; } /** * 画自己, 将调用drawRock(Graphics, int, int, int, int) 方法 和 * drawGridding(Graphics, int, int, int, int) 方法 * * @param g */ public void drawMe(Graphics g) { for (int x = 0; x < Global.WIDTH; x++) for (int y = 0; y < Global.HEIGHT; y++) { /* 画石头 */ if (rocks[x][y]) { g.setColor(rockColor); drawRock(g, x * Global.CELL_WIDTH, y * Global.CELL_HEIGHT, Global.CELL_WIDTH, Global.CELL_HEIGHT); } else if (drawGridding) { /* 画网格(如果允许) */ g.setColor(griddingColor); drawGridding(g, x * Global.CELL_WIDTH, y * Global.CELL_HEIGHT, Global.CELL_WIDTH, Global.CELL_HEIGHT); } } } /** * 画一块石头, 可以覆盖这个方法改变石头的显示 * * @param g * @param x * 像素坐标 x * @param y * 像素坐标 y * @param width * 宽度(单位:像素) * @param height * 高度(单位:像素) */ public void drawRock(Graphics g, int x, int y, int width, int height) { g.fill3DRect(x, y, width, height, true); } /** * 画网格, 可以覆盖这个方法改变网格的显示 * * @param g * @param x * 像素坐标 x * @param y * 像素坐标 y * @param width * 宽度(单位:像素) * @param height * 高度(单位:像素) */ public void drawGridding(Graphics g, int x, int y, int width, int height) { g.drawRect(x, y, width, height); } /** * 得到网格的颜色 * * @return */ public Color getGriddingColor() { return griddingColor; } /** * 设置网格的颜色 * * @param griddingColor */ public void setGriddingColor(Color griddingColor) { this.griddingColor = griddingColor; } /** * 是否画网格 * * @return */ public boolean isDrawGridding() { return drawGridding; } /** * 设置是否画网格 * * @param drawGridding */ public void setDrawGridding(boolean drawGridding) { this.drawGridding = drawGridding; } }
游戏监听器:
package cn.itcast.snake.listener; /** * * 游戏监听器 * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public interface GameListener { /** * 游戏开始了 */ void gameStart(); /** * 游戏结束了 */ void gameOver(); /** * 游戏暂停了 */ void gamePause(); /** * 游戏继续 */ void gameContinue(); }
package cn.itcast.snake.listener; /** * * 蛇的监听器 * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public interface SnakeListener { /** * 蛇移动事件 */ void snakeMoved(); /** * 蛇吃到食物事件 */ void snakeEatFood(); }
控制器:
package cn.itcast.snake.controller; import java.awt.Font; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.HashSet; import java.util.Set; import javax.swing.JLabel; import cn.itcast.snake.entities.Food; import cn.itcast.snake.entities.Ground; import cn.itcast.snake.entities.Snake; import cn.itcast.snake.listener.GameListener; import cn.itcast.snake.listener.SnakeListener; import cn.itcast.snake.util.Global; import cn.itcast.snake.view.GamePanel; /** * 控制器<BR> * 控制Ground, Snake, Food<BR> * 负责游戏的逻辑<BR> * 处理按键事件<BR> * <BR> * 实现了SnakeListener接口, 可以处理Snake 触发的事件<BR> * 方法 snakeEatFood() 处理蛇吃到食物后触发的 snakeEatFood事件 但什么也没做<BR> * <BR> * * @version 1.0, 01/01/08 * * @author 汤阳光 * */ public class Controller extends KeyAdapter implements SnakeListener { /* 地形 */ private Ground ground; /* 蛇 */ private Snake snake; /* 食物 */ private Food food; /* 显示 */ private GamePanel gamePanel; /* 提示信息 */ private JLabel gameInfoLabel; private boolean playing; private int map; /* 控制器监听器 */ private Set<GameListener> listeners = new HashSet<GameListener>(); /** * 处理按键事件<BR> * 接受按键, 根据按键不同, 发出不同的指令<BR> * UP: 改变蛇的移动方向为向上<BR> * DOWN: 改变蛇的移动方向为向下<BR> * LEFT: 改变蛇的移动方向为向左 <BR> * RIGHT: 改变蛇的移动方向为向右<BR> * SPACE: 暂停/继续<BR> * PAGE UP: 加快蛇的移动速度<BR> * PAGE DOWN: 减慢蛇的移动速度<BR> * Y: 重新开始游戏 */ public void keyPressed(KeyEvent e) { if (e.getKeyCode() != KeyEvent.VK_Y && !playing) return; // TODO Auto-generated method stub /* 根据按键不同, 让蛇改变不同的方向 */ switch (e.getKeyCode()) { /* 方向键 上 */ case KeyEvent.VK_UP: if (snake.isPause()) { snake.changePause(); for (GameListener l : listeners) l.gameContinue(); } snake.changeDirection(Snake.UP); break; /* 方向键 下 */ case KeyEvent.VK_DOWN: if (snake.isPause()) { snake.changePause(); for (GameListener l : listeners) l.gameContinue(); } snake.changeDirection(Snake.DOWN); break; /* 方向键 左 */ case KeyEvent.VK_LEFT: if (snake.isPause()) { snake.changePause(); for (GameListener l : listeners) l.gameContinue(); } snake.changeDirection(Snake.LEFT); break; /* 方向键 右 */ case KeyEvent.VK_RIGHT: if (snake.isPause()) { snake.changePause(); for (GameListener l : listeners) l.gameContinue(); } snake.changeDirection(Snake.RIGHT); break; /* 回车或空格 (暂停) */ case KeyEvent.VK_ENTER: case KeyEvent.VK_SPACE: snake.changePause(); /* === */ for (GameListener l : listeners) if (snake.isPause()) l.gamePause(); else l.gameContinue(); break; /* PAGE_UP 加速 */ case KeyEvent.VK_PAGE_UP: snake.speedUp(); break; /* PAGE_DOWN 减速 */ case KeyEvent.VK_PAGE_DOWN: snake.speedDown(); break; /* 字母键 Y (重新开始游戏) */ case KeyEvent.VK_Y: if (!isPlaying()) newGame(); break; } /* 重新显示 */ if (gamePanel != null) gamePanel.redisplay(ground, snake, food); /* 更新提示 */ if (gameInfoLabel != null) gameInfoLabel.setText(getNewInfo()); } /** * 处理Snake 触发的 snakeMoved 事件<BR> */ public void snakeMoved() { /* 判断是否吃到食物 */ if (food != null && food.isSnakeEatFood(snake)) { /* 吃到食物后, 蛇增加身体, 再重新丢一个食物 */ snake.eatFood(); food.setLocation(ground == null ? food.getNew() : ground .getFreePoint()); }/* 如果吃到食物, 就肯定不会吃到石头 */ else if (ground != null && ground.isSnakeEatRock(snake)) { /* 如果吃到的是石头, 或吃到自己的身体, 就让蛇死掉 */ stopGame(); } if (snake.isEatBody()) stopGame(); if (gamePanel != null) gamePanel.redisplay(ground, snake, food); /* 更新提示 */ if (gameInfoLabel != null) gameInfoLabel.setText(getNewInfo()); } /** * 开始一个新游戏 */ public void newGame() { if (ground != null) { switch (map) { case 2: ground.clear(); ground.generateRocks2(); break; default: ground.init(); break; } } playing = true; snake.reNew(); for (GameListener l : listeners) l.gameStart(); } /** * 结束游戏 */ public void stopGame() { if (playing) { playing = false; snake.dead(); for (GameListener l : listeners) l.gameOver(); } } /** * 暂停游戏 */ public void pauseGame() { snake.setPause(true); for (GameListener l : listeners) l.gamePause(); } /** * 继续游戏 */ public void continueGame() { snake.setPause(false); for (GameListener l : listeners) l.gameContinue(); } /** * 接受Snake,Food,Ground 的构造器<BR> * * @param snake * @param food * @param ground */ public Controller(Snake snake, Food food, Ground ground, GamePanel gamePanel) { this.snake = snake; this.food = food; this.ground = ground; this.gamePanel = gamePanel; /* 先丢一个食物 */ if (ground != null && food != null) food.setLocation(ground.getFreePoint()); /* 注册监听器 */ this.snake.addSnakeListener(this); } /** * 多接受一个显示提示信息的JLabel * * @param snake * @param food * @param ground * @param gameInfoLabel */ public Controller(Snake snake, Food food, Ground ground, GamePanel gamePanel, JLabel gameInfoLabel) { this(snake, food, ground, gamePanel); this.setGameInfoLabel(gameInfoLabel); if (gameInfoLabel != null) gameInfoLabel.setText(getNewInfo()); } /** * 得到最新的提示信息 * * @return 蛇的最新信息 */ public String getNewInfo() { if (!snake.isLive()) return " ";// " 提示: 按 Y 开始新游戏"; else return new StringBuffer().append("提示: ").append("速度 ").append( snake.getSpeed()).toString() + " 毫秒/格"; } /** * 添加监听器 * * @param l */ public synchronized void addGameListener(GameListener l) { if (l != null) this.listeners.add(l); } /** * 移除监听器 * * @param l */ public synchronized void removeGameListener(GameListener l) { if (l != null) this.listeners.remove(l); } /** * 得到蛇的引用 * * @return */ public Snake getSnake() { return this.snake; } /** * 得到食物的引用 * * @return */ public Food getFood() { return this.food; } /** * 得到地形的引用 * * @return */ public Ground getGround() { return this.ground; } /** * 处理蛇吃到食物后触发的 snakeEatFood事件, 但什么也没做<BR> * 可以覆盖这个方法增加功能, 例如, 增加记分功能 */ public void snakeEatFood() { // TODO Auto-generated method stub System.out.println("吃到食物!"); } public GamePanel getGamePanel() { return gamePanel; } /** * 设置GamePanel * * @param gamePanel */ public void setGamePanel(GamePanel gamePanel) { this.gamePanel = gamePanel; } public JLabel getGameInfoLabel() { return gameInfoLabel; } public void setGameInfoLabel(JLabel gameInfoLabel) { this.gameInfoLabel = gameInfoLabel; this.gameInfoLabel.setSize(Global.WIDTH * Global.CELL_WIDTH, 20); this.gameInfoLabel.setFont(new Font("宋体", Font.PLAIN, 12)); gameInfoLabel.setText(this.getNewInfo()); } public void setGround(Ground ground) { this.ground = ground; } public void setSnake(Snake snake) { this.snake = snake; } public void setFood(Food food) { this.food = food; } public int getMap() { return map; } public void setMap(int map) { this.map = map; } public boolean isPlaying() { return playing; } public void setPlaying(boolean playing) { this.playing = playing; } public boolean isPausingGame() { // TODO Auto-generated method stub return snake.isPause(); } }
发表评论
-
java版 纸牌
2012-05-30 15:43 854java 纸牌游戏,有连翻一张或三张两种玩法,程序在部分点击区 ... -
java版 推箱子
2012-01-12 17:24 1488java版 推箱子源码 import javax.swin ... -
java 基础加强
2011-01-07 14:17 753java基础 jdk1.5 新特征 ... -
网络五子棋
2011-01-05 15:50 1039最近空限,完成之前未完成的网络五子棋,它是面向TCP协 ... -
java图片处理:文字图像水印 缩放补白
2010-12-28 11:40 1158package com.util; import j ... -
Java2D绘制五星红旗
2010-12-27 09:17 1151/** 使用Java2D绘制五星红旗 五星 ... -
网络编程
2010-12-21 14:16 1228网络编程 网络编程的基础知识 网络协议与TCP/IP 计算 ... -
IO/输入输出
2010-12-21 14:14 1428IO/输入输出 File类 它是 ... -
银行业务调度系统
2010-08-19 18:34 1322模拟实现银行业务调度系统逻辑,具体需求如下: 银行内有6 ... -
交通灯管理系统
2010-08-18 13:16 1289模拟实现十字路口的交通灯管理系统逻辑,具体需求如下: 异 ... -
蜘蛛牌
2010-08-15 00:17 1859蜘蛛牌在朴克牌游戏当中是比较有趣的游戏,特别是闯关成功 ... -
j2se版俄罗斯方块
2009-10-21 21:22 14541.图形界面 import java.awt.*; ... -
豆子吃妖精
2009-10-19 21:30 765本程序是运用了图形化画版和多程技术,只支持固定运行轨迹, ... -
连连看
2009-10-09 20:54 1011java不易开发大型游戏,但任一语言都有是相通,本程序运 ... -
Globle Get 多线程下载系统
2009-10-07 21:41 1084GlobalGet”是实现HTTP协议和FTP协议的多线程下载 ... -
控制台五子棋
2009-08-17 20:15 912<p>这是一个控制台的五子棋,它的妙处是它算法侦听 ...
相关推荐
java 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zip java 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zip java 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava ...
【贪吃蛇游戏源代码】是一个适合初学者深入理解Java编程的项目,它结合了基本的编程概念和游戏逻辑,让学习者在实践中提升技能。贪吃蛇游戏是一款经典的计算机游戏,玩家通过控制蛇的移动,使其吃到食物,每吃一颗...
最新单片机仿真 8x8点阵做的贪吃蛇游戏最新单片机仿真 8x8点阵做的贪吃蛇游戏最新单片机仿真 8x8点阵做的贪吃蛇游戏最新单片机仿真 8x8点阵做的贪吃蛇游戏最新单片机仿真 8x8点阵做的贪吃蛇游戏最新单片机仿真 8x8...
贪吃蛇游戏是一款经典的计算机游戏,它源自早期的诺基亚手机,并且在全球范围内广受欢迎。这个Java版本的贪吃蛇游戏源码是为那些希望深入理解游戏开发和Java GUI编程,特别是AWT(Abstract Window Toolkit)和Swing...
嵌入式ARM的贪吃蛇游戏课程设计 嵌入式ARM的贪吃蛇游戏课程设计是基于ARM架构的贪吃蛇游戏设计实践项目。该项目的目的是设计和实现一个基于ARM的贪吃蛇游戏机,使用飞利浦公司的LPC2124芯片板作为平台。 该项目的...
根据提供的文件信息,内容涉及到LabVIEW这一图形化编程语言,以及利用该语言开发的贪吃蛇游戏。为了生成相关知识点,我们可以从LabVIEW的基本概念出发,讲述其在游戏开发中的应用,并尝试将文档中的片段整理为有意义...