使用的IDE eclipse
JDK版本 1.6
辅助类 Coordinate.java
package com.nn.util; /** *坐标点 */ public class Coordinate { public int x; public int y; public Coordinate(int newX, int newY) { x = newX; y = newY; } public boolean equals(Coordinate other) { if (x == other.x && y == other.y) { return true; } return false; } @Override public String toString() { return "Coordinate: [" + x + "," + y + "]"; } }
接口 Direction
package com.nn.entity; public interface Direction { public class Dir{ public static final int UP = 1; public static final int DOWN = 2; public static final int LEFT = 3; public static final int RIGHT = 4; } }
实体类 Snake.java
package com.nn.entity; import java.util.ArrayList; import com.nn.entity.Direction.Dir; import com.nn.util.Coordinate; public class Snake{ //小方块x坐标 private int x; //小方块y坐标 private int y; //宽度 public static final int TILE_W = 10; //高度 public static final int TILE_H = 10; //下一个方向 private int mNextDirection = Dir.RIGHT; //游戏是否结束 private boolean isEnd; //存放贪吃蛇 private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>(); //存放豆子 private ArrayList<Coordinate> mAppleList = new ArrayList<Coordinate>(); public Snake() { initNewGame(); } //初始化新游戏 public void initNewGame() { //初始化蛇身 mSnakeTrail.add(new Coordinate(5, 7)); mSnakeTrail.add(new Coordinate(6, 7)); mSnakeTrail.add(new Coordinate(7, 7)); mSnakeTrail.add(new Coordinate(8, 7)); mSnakeTrail.add(new Coordinate(9, 7)); mSnakeTrail.add(new Coordinate(10, 7)); //初始化豆子 mAppleList.add(new Coordinate(20,3)); //设置初始状态为false isEnd = false; } public ArrayList<Coordinate> getmSnakeTrail() { return mSnakeTrail; } public ArrayList<Coordinate> getmAppleList() { return mAppleList; } public boolean isEnd() { return isEnd; } public int getmNextDirection() { return mNextDirection; } public void setEnd(boolean isEnd) { this.isEnd = isEnd; } }
frame类 继承JFrame SnakeFrame.java
package com.nn.ui; import java.awt.Dimension; import java.awt.Toolkit; import javax.swing.JFrame; /** *游戏界面 */ public class SnakeFrame extends JFrame{ private static final long serialVersionUID = 1L; //宽度 private static final int width = 530; //高度 private static final int height = 450; //高度偏移量 private static final int offset = 15; public SnakeFrame(){ init(); } /** * 初始化游戏界面 */ private void init() { this.setTitle("Java版贪吃蛇_1.0"); //frame的高度 宽度 this.setSize(width, height); //窗口居中显示 Toolkit toolkit = Toolkit.getDefaultToolkit(); Dimension screen = toolkit.getScreenSize(); int w = screen.width; int h = screen.height; //计算左上角坐标点的x y值 this.setLocation((w-this.getWidth())/2, (h-this.getHeight())/2-offset); //设置默认关闭的操作 this.setDefaultCloseOperation(EXIT_ON_CLOSE); //设置窗口大小不可改变 this.setResizable(false); //设置可见性 this.setVisible(true); this.setLayout(null); } }
panel j继承JPanel SnakePanel.java
package com.nn.ui; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import javax.swing.JButton; import javax.swing.JPanel; import com.nn.control.PlayControl; import com.nn.entity.Snake; import com.nn.util.Coordinate; public class SnakePanel extends JPanel{ private static final long serialVersionUID = 1L; //panel的宽度 private static final int width = 400; //panel的高度 private static final int height = 400; //坐标点x private static final int x = 10; //坐标点y private static final int y = 10; //方块尺寸 private static final int SIZE = 10; //是否开启网格 private boolean isOpen = false; private Snake snake; //开启作弊 private JButton girdButton; private JButton aboutButton; //暂停 继续按钮 private JButton PauseButton; //重新开始游戏 private JButton StartButton; public Snake getSnake() { return snake; } private ArrayList<Coordinate> mSnakeTrail = null; private ArrayList<Coordinate> mAppleList = null; public SnakePanel() { snake = new Snake(); this.setLayout(null); StartButton = new JButton("重新开始"); StartButton.setLocation(420,100); StartButton.setSize(90,26); this.add(StartButton); PauseButton = new JButton("暂停游戏"); PauseButton.setLocation(420, 150); PauseButton.setSize(90,26); this.add(PauseButton); girdButton = new JButton("开启网格"); girdButton.setLocation(420, 200); girdButton.setSize(90,26); this.add(girdButton); aboutButton = new JButton("关于游戏"); aboutButton.setLocation(420, 250); aboutButton.setSize(90,26); this.add(aboutButton); girdButton.addActionListener(new GirdActionListener()); aboutButton.addActionListener(new AboutActionListerner()); } class GirdActionListener implements ActionListener{ int i = 1; public void actionPerformed(ActionEvent e) { if(i%2==1) { girdButton.setText("关闭网格"); isOpen = false; i++; } else if(i%2==0){ girdButton.setText("开启网格"); isOpen = true; i++; } } } class AboutActionListerner implements ActionListener{ public void actionPerformed(ActionEvent e) { } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); creatGameWindow(g); if(snake.isEnd()) { paintWords(g); } //将焦点定在Jpanel上 this.requestFocus(); } /** * 安装玩家控制器 * @param control */ public void setGameControl(PlayControl control){ this.addKeyListener(control); } private void creatGameWindow(Graphics g) { g.setColor(Color.BLACK); g.drawRect(x, y, width, height); g.setColor(Color.WHITE); g.fillRect(x+1, y+1, width-1, height-1); g.setColor(Color.GRAY); /***************test******************/ paintLine(g); /***************test******************/ mSnakeTrail = snake.getmSnakeTrail(); mAppleList = snake.getmAppleList(); if(mSnakeTrail==null) { return; } g.setColor(Color.BLACK); for(int i=0;i<mSnakeTrail.size();i++){ g.fillRect(this.x+mSnakeTrail.get(i).x*SIZE, this.y+mSnakeTrail.get(i).y*SIZE, Snake.TILE_W, Snake.TILE_H); } //画豆子 g.fillRect(this.x+mAppleList.get(0).x*SIZE, this.y+mAppleList.get(0).y*SIZE, Snake.TILE_W, Snake.TILE_H); } //画网格 private void paintLine(Graphics g) { for(int i = 1;i < 40;i++) { g.drawLine(this.x, i*10+this.y, 400+this.x, i*10+this.y); } for(int i = 1;i < 40;i++) { g.drawLine(i*10+this.x,this.y,i*10+this.x,400+this.y); } } //结束提示 private void paintWords(Graphics g){ Font font = new Font("宋体", Font.BOLD, 64); g.setFont(font); g.setColor(Color.RED); g.drawString("游戏结束",60,220); } }
最关键的类 控制类 PlayControl.java
package com.nn.control; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import java.util.Random; import com.nn.entity.Direction.Dir; import com.nn.ui.SnakePanel; import com.nn.util.Coordinate; public class PlayControl implements KeyListener{ private SnakePanel panel; //蛇头在list中索引 private int headIndex; /** * 贪吃蛇列表 */ ArrayList<Coordinate> mSnakeTrail; /* * 豆子列表 */ private ArrayList<Coordinate> mAppleList; //新产生的豆子 Coordinate newCoordinate; private int mNextDirection; //是否绘制出结束提示 private boolean isDraw = false; private Random random = new Random(); public PlayControl(SnakePanel panel) { this.panel = panel; mSnakeTrail = panel.getSnake().getmSnakeTrail(); mAppleList = panel.getSnake().getmAppleList(); mNextDirection = panel.getSnake().getmNextDirection(); headIndex = mSnakeTrail.size()-1; Thread thread = new Thread(runnable); thread.start(); } //响应键盘按下事件 public void keyPressed(KeyEvent e) { if(isDraw){ return; } switch (e.getKeyCode()) { case KeyEvent.VK_UP: if(mNextDirection!=Dir.DOWN) { mNextDirection = Dir.UP; //moveUp(); } break; case KeyEvent.VK_DOWN: if(mNextDirection!=Dir.UP) { mNextDirection = Dir.DOWN; //moveDown(); } break; case KeyEvent.VK_LEFT: if(mNextDirection!=Dir.RIGHT) { mNextDirection = Dir.LEFT; //moveLeft(); } break; case KeyEvent.VK_RIGHT: if(mNextDirection!=Dir.LEFT) { mNextDirection = Dir.RIGHT; //moveRight(); } break; } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } //向上移动 private void moveUp() { if(!isEndGame()){ //每移动一次 先在头部加一块 list增加一个元素 mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x, mSnakeTrail.get(headIndex).y-1)); //如果判断吃到豆子 if(isEat()){ //吃到豆子的处理 afterEatApple(); } //否则 移除第一个元素 else { mSnakeTrail.remove(0); } //重新绘制 panel.repaint(); } } //向下移动 private void moveDown() { if(!isEndGame()){ mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x, mSnakeTrail.get(headIndex).y+1)); if(isEat()){ afterEatApple(); } else { mSnakeTrail.remove(0); } panel.repaint(); } } //向左移动 private void moveLeft() { if(!isEndGame()){ mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x-1, mSnakeTrail.get(headIndex).y)); if(isEat()) { afterEatApple(); } else { mSnakeTrail.remove(0); } panel.repaint(); } } //向右移动 private void moveRight() { if(!isEndGame()){ mSnakeTrail.add(new Coordinate(mSnakeTrail.get(headIndex).x+1, mSnakeTrail.get(headIndex).y)); if(isEat()) { afterEatApple(); } else { mSnakeTrail.remove(0); } panel.repaint(); } } //增加一个坐标点到存放蛇的list 添加到list的末尾 private void afterEatApple(){ //每增加一个 索引值加1 重新开始游戏时要回复初始值 headIndex++; mAppleList.add(new Coordinate(random.nextInt(40), random.nextInt(40))); mAppleList.remove(0); newCoordinate = mAppleList.get(0); //System.out.println("蛇身长度:"+mSnakeTrail.size()); } //判断蛇是否吃到豆子 private boolean isEat() { return mSnakeTrail.get(mSnakeTrail.size()-1).equals(mAppleList.get(0)); } //判断是否到边界或者碰到自己的身体 private boolean isEndGame(){ int x = mSnakeTrail.get(headIndex).x; int y = mSnakeTrail.get(headIndex).y; if(touchBody()||x<0||x>39||y<0||y>39){ afterEndGame(); return true; } return false; } //碰到自己身体 private boolean touchBody(){ for(int i =0;i<mSnakeTrail.size()-1;i++) { if(mSnakeTrail.get(headIndex).equals(mSnakeTrail.get(i))){ return true; } } return false; } //游戏结束处理 private void afterEndGame() { mSnakeTrail.remove(headIndex); panel.getSnake().setEnd(true); panel.repaint(); this.isDraw = true; } Runnable runnable = new Runnable() { public void run() { moveRight(); while(!isEndGame()) { if(mNextDirection==Dir.UP) moveUp(); else if(mNextDirection==Dir.DOWN) moveDown(); else if(mNextDirection==Dir.LEFT) moveLeft(); else if(mNextDirection==Dir.RIGHT) moveRight(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }; }
最后是测试类 SnakeTest.java
package com.nn.main; import com.nn.control.PlayControl; import com.nn.ui.SnakeFrame; import com.nn.ui.SnakePanel; /** *启动游戏 * */ public class SnakeTest { public static void main(String[] args) { SnakeFrame frame = new SnakeFrame(); SnakePanel panel = new SnakePanel(); PlayControl playControl = new PlayControl(panel); panel.setGameControl(playControl); //setContentPane()把panel设置为JFrame的内容面板 frame.setContentPane(panel); } }
大致说下思路,panel面板增加控制器获得游戏控制权,控制器根据输入在列表中更新蛇身所在位置的坐标,并通知panel重绘,直至游戏结束,鼠标监听事件return。当然程序有不恰当的地方,比如说控制层和业务层混杂在了一起,代码中存在硬编码,代码的复用性不高,只是个练习的小程序,还有很多不完善的地方。
时间: 2024-10-05 04:37:32