J a v a贪吃蛇报告 Revised final draft November 26, 2020
《Java高级编程》课程报告
第xx小组:贪吃蛇游戏项目
小组成员及分工
一、实验环境
操作系统:Windows 7
编程环境:Eclipse、JDK
二、实验内容与完成情况
(主要介绍项目总体功能分析与说明。)
贪吃蛇小游戏的JAVA程序是利用上↑、下↓、左←、右→方向键来改变蛇的运动方向,按空键暂停游戏,按enter键重新开始。长按某个方向键后,蛇的运动速度会加快,在随机的地方产生食物,吃到食物就变成新的蛇体,碰到壁或自身则游戏结束,否则正常进行游戏。以不同的速度和不同方向吃到食物所获得的分数也不相同。
窗口功能说明:设计了三个窗口,分别是游戏主窗口,主菜单窗口,模式选择窗口。菜单栏分别为:游戏菜单(重新开始)和帮助菜单以及返回(返回主菜单)。其中,按返回菜单按钮后会显示主菜单,其包括游戏开始、设置、退出游戏三项按钮选择;如果按
“设置”按钮会进入“模式选择”窗口。而模式选择窗口菜单包括了初级、中级、高级、返回按钮。
1、功能1(主菜单窗口)
(1)主菜单窗口主要是提供“游戏开始”、“设置”和“退出”按钮。“游戏开始”按钮按下后会进入“游戏主窗口”开始游戏;“设置”按钮是调用
“模式选择”窗口对游戏贪吃蛇的速度进行设置;“退出”按钮按下则会
直接退出游戏。
(2)功能1实现的流程图
实现的效果图如下:
(3)功能1(主菜单窗口)代码:
package Swing;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class setMenu extends JFrame {
private int speed1 = 200;
public static int speed = 200;
// static int speed = 20;
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
setMenu frame = new setMenu(speed);
frame.SsetMenu(frame);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public setMenu(int speed2){
speed1=speed2;
(speed2);
}
public void SsetMenu(final setMenu frame) {
setTitle("主菜单");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 250, 350);
contentPane = new JPanel();
contentPane.setBackground(new Color(102, 204, 102));
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
//按钮:游戏开始
JButton NewGameButton = new JButton("");
NewGameButton.setIcon(new ImageIcon("img/gamebegin.png"));
NewGameButton.setBounds(53, 52, 123, 40);
NewGameButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Game gs = new Game(speed1);
frame.dispose();
}
});
contentPane.add(NewGameButton);
//按钮:游戏设置
JButton setButton = new JButton("");
setButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
model frame1 = new model();
frame1.Mmodel(frame1);
frame1.setVisible(true);
frame.dispose();
}
});
//按钮图片设置
setButton.setIcon(new ImageIcon("img/set.png"));
setButton.setBounds(53, 128, 123, 45);
contentPane.add(setButton);
//按钮:游戏推出
JButton exitButton= new JButton("");
exitButton.setIcon(new ImageIcon("img/exit.png"));
exitButton.setBounds(53, 206, 123, 40);
exitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
contentPane.add(exitButton);
}
}
2、功能2(模式选择窗口)
(1)功能2的文字描述:
“模式选择”窗口菜单包括了初级、中级、高级、返回按钮。其中当选择按下初级、中级、高级按钮后,会弹出一个“游戏难度“窗口,并提示设置成功:**,并按下”确定“按钮后窗口关闭同时模式选择成功,按下”返回“按钮返回主菜单窗口。
(2)功能2(模式选择窗口)实现的流程图
实现的效果图如下:
(3)功能2(模式选择窗口)代码:
package Swing;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class setMenu extends JFrame {
private int speed1 = 200;
public static int speed = 200;
// static int speed = 20;
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
setMenu frame = new setMenu(speed);
frame.SsetMenu(frame);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public setMenu(int speed2){
speed1=speed2;
System.out.println(speed2);
}
public void SsetMenu(final setMenu frame) {
setTitle("主菜单");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 250, 350);
contentPane = new JPanel();
contentPane.setBackground(new Color(102, 204, 102));
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
//按钮:游戏开始
JButton NewGameButton = new JButton("");
NewGameButton.setIcon(new ImageIcon("img/gamebegin.png"));
NewGameButton.setBounds(53, 52, 123, 40);
NewGameButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Game gs = new Game(speed1);
frame.dispose();
}
});
contentPane.add(NewGameButton);
//按钮:游戏设置
JButton setButton = new JButton("");
setButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
model frame1 = new model();
frame1.Mmodel(frame1);
frame1.setVisible(true);
frame.dispose();
}
});
//按钮图片设置
setButton.setIcon(new ImageIcon("img/set.png"));
setButton.setBounds(53, 128, 123, 45);
contentPane.add(setButton);
//按钮:游戏推出
JButton exitButton= new JButton("");
exitButton.setIcon(new ImageIcon("img/exit.png"));
exitButton.setBounds(53, 206, 123, 40);
exitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
contentPane.add(exitButton);
}
}
3、功能3(贪吃蛇游戏窗口)
(1)能3(贪吃蛇游戏窗口)文字描述:
贪吃蛇游戏窗口界面包括蛇体与食物游戏区域,正上方有即时计分框(记录目前所得的分数),左上角有三个下拉菜单选项包括“菜单”下拉菜单,“帮助”菜单,“返回”菜单。点击“菜单”菜单会出现下拉的“重新开始”选项同时也可以按下Enter键重新开始游戏;点击“帮助”菜单会出现“游戏说明”选项,点击进入后出现游戏帮助信息;点击“返回”菜单则直接返回主菜单选择窗口。
贪吃蛇游戏窗口大小是固定的目的是确定并设置当蛇体碰触到边框后提示游戏失败的出框,在规定的窗口范围内蛇体可以通过按上↑、下↓、左←、右→方向键控制其运动方向;在吃到界面区域中出现的食物后蛇体会变长,而以不同的速度和运动长度(UP和DOWN 是偶数,RIGHT和LEFT是奇数)所得到的分数也不一样。按空键游戏暂停,按Enter键游戏重新开始。
(2)功能3现的流程图:
(3)功能3(贪吃蛇游戏窗口)代码: package Swing;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
//Main Class
public class Game extends KeyAdapter implements ImageObserver { //初始速度
int speed_all = 200;
BufferedImage bgImage=null;
JFrame mainFrame;
JPanel jPanel;
// Canvas paintCanvas;
JLabel labelScore;// 计分牌
SnakeModel snakeModel = null;// 蛇
public static final int DEFAULT_WIDTH = 500;
public static final int DEFAULT_HEIGHT = 400;
public static final int nodeWidth = 10;
public static final int nodeHeight = 10;
private JMenuBar menuBar;
private JMenu menu;
private JMenuItem menuItem;
private JMenuBar menuBar_1;
private JMenu mnNewMenu;
private JMenu mnNewMenu_1;
private JMenuItem mntmNewMenuItem;
private JMenuItem mntmNewMenuItem_1;
private JMenu mnNewMenu_2;
// GreedSnake():初始化游戏界面
public Game(int speed_gs) {
speed_all=speed_gs;
("Game:"+speed_all);
// 设置界面元素
mainFrame = new JFrame("贪吃蛇游戏");
Container cp = mainFrame.getContentPane();
aoao(mainFrame);
jPanel = new JPanel();
jPanel.setPreferredSize(new Dimension(DEFAULT_WIDTH-10, DEFAULT_HEIGHT-10 ));//500*390
// paintCanvas.setSize(DEFAULT_WIDTH + 20, DEFAULT_HEIGHT + 20);
jPanel.addKeyListener(this);
cp.add(jPanel, BorderLayout.CENTER);
// cp.add(paintCanvas, BorderLayout.CENTER);
JPanel panelButtom = new JPanel();
panelButtom.setLayout(new BorderLayout());
cp.add(panelButtom, BorderLayout.SOUTH);
//score
labelScore = new JLabel("所得分数为:", JLabel.CENTER);
mainFrame.getContentPane().add(labelScore, BorderLayout.NORTH);
mainFrame.addKeyListener(this);
mainFrame.pack();
mainFrame.setResizable(false);// 设置窗口大小不能变化
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
begin();
}
// keyPressed():按键检测及菜单设置
public void aoao(final JFrame mainFrame){
mainFrame.setJMenuBar(menuBar);
menuBar_1 = new JMenuBar();
mainFrame.setJMenuBar(menuBar_1);
mnNewMenu = new JMenu("菜单");
menuBar_1.add(mnNewMenu);
mntmNewMenuItem = new JMenuItem("重新开始");
mntmNewMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Game gs = new Game(speed_all);
mainFrame.dispose();
}
});
mnNewMenu.add(mntmNewMenuItem);
mnNewMenu_1 = new JMenu("帮助");
mnNewMenu_1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
snakeModel.changePauseState();
}
});
menuBar_1.add(mnNewMenu_1);
mntmNewMenuItem_1 = new JMenuItem("游戏说明");
mntmNewMenuItem_1.addActionListener(new ActionListener() {
//游戏说明响应时间
public void actionPerformed(ActionEvent arg0) {
JOptionPane.showMessageDialog(null, "按→ ← ↑ ↓ 控制方向,空格键暂停,Enter键重新开始", "游戏帮助", https://www.doczj.com/doc/133754866.html,RMATION_MESSAGE);
}
});
mnNewMenu_1.add(mntmNewMenuItem_1);
mnNewMenu_2 = new JMenu("返回");
mnNewMenu_2.addMouseListener(new MouseAdapter()
{//连接主菜单
@Override
public void mouseClicked(MouseEvent arg0) {
setMenu frame123 = new setMenu(speed_all);
frame123.SsetMenu(frame123);
frame123.setVisible(true);
mainFrame.dispose();
//("123456");
}
});
menuBar_1.add(mnNewMenu_2);
}
//键盘响应时间设置
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (snakeModel.running)
switch (keyCode) {
case KeyEvent.VK_UP:
snakeModel.changeDirection(SnakeModel.UP);
break;
case KeyEvent.VK_DOWN:
snakeModel.changeDirection(SnakeModel.DOWN);
break;
case KeyEvent.VK_LEFT:
snakeModel.changeDirection(SnakeModel.LEFT);
break;
case KeyEvent.VK_RIGHT:
snakeModel.changeDirection(SnakeModel.RIGHT);
break;
case KeyEvent.VK_ADD:
case KeyEvent.VK_PAGE_UP:
snakeModel.speedUp();// 加速
break;
case KeyEvent.VK_SUBTRACT:
case KeyEvent.VK_PAGE_DOWN:
snakeModel.speedDown();// 减速
break;
case KeyEvent.VK_SPACE:
case KeyEvent.VK_P:
snakeModel.changePauseState();// 暂停或继续
break;
default:
}
// 重新开始
if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_ENTER) { snakeModel.running = false;
begin();
}
}
// repaint():绘制游戏界面(包括蛇和食物)
void repaint() {
Graphics g = jPanel.getGraphics();
//draw background
//g.drawImage(image, 210, 210, this);
//g.setColor(Color.LIGHT_GRAY);
try{
bgImage = ImageIO.read(new File("img/1.jpg"));
//将缓冲图片绘制到窗体中
}
catch(IOException e)
{
e.printStackTrace();
}
g.drawImage(bgImage, 0, 0, this);
// g.fillRect(10, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT);
// draw the snake
g.setColor(Color.BLACK);
LinkedList na = snakeModel.nodeArray;
Iterator it = na.iterator();
while (it.hasNext()) {
Node n = (Node) it.next();
drawNode(g, n);
}
// draw the food
g.setColor(Color.RED);
Node n = snakeModel.food;
drawNode(g, n);
updateScore();
}
// drawNode():绘画某一结点(蛇身或食物)
private void drawNode(Graphics g, Node n) {
g.fillRect(n.x * nodeWidth, n.y * nodeHeight, nodeWidth - 1, nodeHeight -
1);
}
// updateScore():改变计分牌
public void updateScore() {
String s = "所得分数为: " + snakeModel.score;
labelScore.setText(s);
}
// begin():游戏开始,放置贪吃蛇
void begin() {
if (snakeModel == null || !snakeModel.running) {
snakeModel = new SnakeModel(this, DEFAULT_WIDTH / nodeWidth, DEFAULT_HEIGHT / nodeHeight,speed_all);
(new Thread(snakeModel)).start();
}
}
// main():主函数
public static void main(String[] args) {
Game gs = new Game(200);
}
@Override
public boolean imageUpdate(Image arg0, int arg1, int arg2, int arg3,
int arg4, int arg5) {
// TODO Auto-generated method stub
return false;
}
}
// Node:结点类
class Node {
int x;
int y;
Node(int x, int y) {
this.x = x;
this.y = y;
}
}
// SnakeModel:贪吃蛇模型
class SnakeModel implements Runnable {
Game gs;
boolean[][] matrix;// 界面数据保存在数组里
LinkedList nodeArray = new LinkedList();
Node food;
int maxX;// 最大宽度
int maxY;// 最大长度
int direction = 2;// 方向
boolean running = false;
int timeInterval = 200;// 间隔时间(速度)
double speedChangeRate = 0.75;// 速度改变程度
boolean paused = false;// 游戏状态
int score = 0;
int countMove = 0;
// UP和DOWN是偶数,RIGHT和LEFT是奇数
public static final int UP = 2;
public static final int DOWN = 4;
public static final int LEFT = 1;
public static final int RIGHT = 3;
// GreedModel():初始化界面
public SnakeModel(Game gs, int maxX, int maxY,int speed_snake) { timeInterval = speed_snake;//速度
this.gs = gs;
this.maxX = maxX;
this.maxY = maxY;
matrix = new boolean[maxX][];
for (int i = 0; i < maxX; ++i) {
matrix[i] = new boolean[maxY];
Arrays.fill(matrix[i], false);// 没有蛇和食物的地区置false }
// 初始化贪吃蛇
int initArrayLength = maxX > 20 10 : maxX / 2;//蛇头位置,长度 //(initArrayLength);
for (int i = 0; i < initArrayLength; ++i) {
int x = maxX / 2 + i;
// (x);
int y = maxY / 2;
// (y);
nodeArray.addLast(new Node(x, y));
matrix[x][y] = true;// 蛇身处置true
}
food = createFood();
matrix[food.x][food.y] = true;// 食物处置true
}
// changeDirection():改变运动方向
public void changeDirection(int newDirection) {
if (direction % 2 != newDirection % 2) {// 检查方向冲突
direction = newDirection;
}
}
// moveOn():贪吃蛇运动函数
public boolean moveOn() {
Node n = (Node) nodeArray.getFirst();//获取蛇头的位置
int x = n.x;
int y = n.y;
// (x);
//(y);
switch (direction) {
case UP:
y--;
break;
case DOWN:
y++;
break;
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
}
if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) {
//("asd");
if (matrix[x][y]) {// 吃到食物或者撞到身体
if (x == food.x && y == food.y) {// 吃到食物
("eat");
nodeArray.addFirst(food);// 在头部加上一结点
// 计分规则与移动长度和速度有关
int scoreGet = (10000 - 200 * countMove) / timeInterval; score += scoreGet > 0 scoreGet : 10;
countMove = 0;
food = createFood();
matrix[food.x][food.y] = true;
return true;
} else
return false;// 撞到身体
} else {// 什么都没有碰到
nodeArray.addFirst(new Node(x, y));// 加上头部
matrix[x][y] = true;
n = (Node) nodeArray.removeLast();// 去掉尾部
matrix[n.x][n.y] = false;
countMove++;
return true;
}
}
return false;// 越界(撞到墙壁)
}
// run():贪吃蛇运动线程
public void run() {
running = true;
while (running) {
try {
Thread.sleep(timeInterval);
} catch (Exception e) {
break;
}
if (!paused) {
if (moveOn()) {// 未结束
gs.repaint();
} else {// 游戏结束
JOptionPane.showMessageDialog(null, "GAME OVER", "Game Over", https://www.doczj.com/doc/133754866.html,RMATION_MESSAGE);
break;
}
}
}
running = false;
}
// createFood():生成食物及放置地点
private Node createFood() {
int x = 0;
int y = 0;
do {
Random r = new Random();
x = r.nextInt(maxX);
y = r.nextInt(maxY);
} while (matrix[x][y]);
return new Node(x, y);
}
// speedUp():加快蛇运动速度
public void speedUp() {
timeInterval *= speedChangeRate;
}
// speedDown():放慢蛇运动速度
public void speedDown() {
timeInterval /= speedChangeRate;
}
// changePauseState(): 改变游戏状态(暂停或继续)
public void changePauseState() {
paused = !paused;
}
}
三、功能测试
对系统的所有功能模块进行测试并截图显示,并对出现的问题(及其现象)和解决办法予以记录。
游戏主界面:
点击“菜单”菜单出现“重新开始”下拉菜单,点击后游戏重新开始
点击“帮助”菜单出现“游戏说明”下拉菜单
当蛇碰到边界或者碰到自身蛇体,游戏结束。
主菜单窗口:
模式选择窗口:
对出现的问题(及其现象)和解决办法予以记录:
1、开始在程序编写时没规定游戏主窗口的大小,当用鼠标拉大窗口后,出现了蛇在移动时没碰触到边界就出现游戏失败的弹出框即游戏结束。经过查看程序和在网上找资料了解到是由于没有对主窗口设定一定的窗口大小导致的。解决办法为:public static final int DEFAULT_WIDTH = 500; public static final int DEFAULT_HEIGHT =
400; ………jPanel.setPreferredSize(new Dimension(DEFAULT_WIDTH-10,
DEFAULT_HEIGHT-10 ));//490*390
2、在蛇的运行线程过程中,当蛇撞到墙或自己的身体时,程序出错。发现是因为我们只做了简单的抛出异常操作,使程序运行后效果不出来,经过老师在上课时教的用try-catch去捕捉异常,将抛出一个Exception类的异常对象。
try{
Thread.sleep(timeInterval);}
catch(Exceptione)
{break;}
3、通过在网上查找资料参考学习到Swing中弹出对话框
JOptionPane.showMessageDialog实现显示出信息、提出问题、警告、用户输入参数等功能并显示一个带有OK 按钮的模态对话框。JOptionPane类其中封装了很多的方法,很方便。在这些模式对话框中使用了showMessageDialog()显示信息对话框以及showOptionDialog()显示选择性的对话框等。
四、项目总结
每个小组成员单独完成,内容包括项目分析、开发和团队合作过程中的经验和教训,如:遇到的困难及解决方法、主要技术的使用等。
设计程序采用什么编程语言并不是最重要的,关键是要有一个清晰的思路和一个完整的软件流程图,所有要先把设计原理与思路搞清楚,再把流程图画出来。在编码过程中使用不了解的函数还可以查资料或翻书来了解功能和执行语法。在设计程序时,不能妄想一次就将整个程序设计好,“反复修改,不断改进”不仅提高代码感,也培养做事细心的习惯,温故和矫正中发现问题,更好的完善程序。还有要养成养成注释程序的习惯,一个程序的完美与否不仅是实现功能,还是能清晰快速地明白编写者的思路,这样使资料的保存和交流方便。
五、个人课程总结报告
在基于原来的Java学习上了解了更细致的Java学习和编程思路,老师的讲解很细致,原来学习Java没想过功能语法上,在课堂学习中渐渐更加深对各函数语法的理解有助于日后在编码时更准确的应用这些工具。在学习的过程中也发现Java的语言功能远不止目前所学到的这些,课堂之后自己还要继续去发掘,不会的东西还有太多,需要不断去了解积累更新,Java的编程才能更得心应手。