Javaworkers团队最终项目总结

小组成员

  1. 20145205武钰
  2. 20145222黄亚奇
  3. 20145235李涛
  4. 20145103冯文华

团队项目总结

案例提出及工程用时

本次项目由十一到十六周共计6周时间

在结合我们自身能力以及去图书馆查找相关的java项目书籍后,我们小组决定选择贪吃蛇这一项目课题,

在明确课题后,查阅了相关资料进行下一步的工作。

设计思路

贪吃蛇游戏设计与实现,我们认为主要分为以下二个模块:

游戏界面模块和游戏控制模块。

游戏界面模块:

因为我们这个项目是一个基于界面进行表达的小游戏,所以界面是我们首先要解决的设计部分,在有了界面的情况下才可以进一步定义其中的蛇和食物。

游戏控制模块:
因为本身就是一个考验操作性的小游戏,所以在控制方面的设计决定了游戏的可玩性。

项目实现情况

我们小组的项目贪吃蛇小游戏,已经完成了功能的实现,可以在界面中控制蛇进行不断吃在屏幕中随机出现的食物,获得分数,而且随着游戏时间的增加和和分数的增加,蛇的运行速度会越来越快。

窗口视图

设计的界面如下图

图一:正常游戏下

Android贪吃蛇项目报告 贪吃蛇项目总结_Android贪吃蛇项目报告

图二:咬到自己的身体

Android贪吃蛇项目报告 贪吃蛇项目总结_随机数_02

图三:撞到墙壁

Android贪吃蛇项目报告 贪吃蛇项目总结_键盘输入_03

项目测试

界面设计

创建界面时需要import java.awt.* ,import javax.swing.* 两个包

在设计界面时,定义了一个主函数,以下是显示界面的名称部分

package javaworkers;
import java.awt.*;
import javax.swing.*;

 @SuppressWarnings("serial")//注释处的所有警告都忽视

public class MainClass  {

    ControlSnake control;


    Toolkit kit;//所有实际应用的抽象窗口工具包的父类

 

    Dimension dimen;//压缩了有整数精确度的组件

 

    public static void main(String[] args) {

        new MainClass("javaworkers");//显示界面名称

    }

贪吃蛇的具体实现

JPanel类用于为小内容提供简单窗口,界面呈现需要

ActionListener为对象提供添加动作的方法

Random,用48bit的种子产生伪随机序列,应用到食物的随机生成

规定一个屏幕范围中的二维矩阵,在其中使用坐标定义蛇和食物,以下是部分代码

public MainClass(String s) {

        super(s);

        control = new ControlSnake();//新的ControlSnake类

        control.setFocusable(true);

        kit = Toolkit.getDefaultToolkit();

        dimen = kit.getScreenSize();//获取屏幕尺寸

        add(control);//添加control

        setLayout(new BorderLayout());

        setLocation(dimen.width / 3, dimen.height / 3);// 挪位置,dimen.width/3,dimen.height/3

        setSize(FWIDTH, FHEIGHT);//定格操作窗口大小

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setResizable(false);

        setVisible(true);

    }

    public static final int FWIDTH = 315;

    public static final int FHEIGHT = 380;

}

蛇的坐标:x,y

食物坐标:fx,fy

分别定义参数snakeBody和speed,来初始化蛇的初始长度和速度

蛇的初始长度和初始速度都可以通过修改对应参数的初始值进行调节

下面是设计蛇时的部分代码

int snakeBody;

    //控制蛇的长度

    int speed;

 

    public ControlSnake()

    {

        snakeBody = 1;//蛇的初始长度

 

        str = "上下左右方向键控制 P键暂停...";

        str1 = "现在的长度为:" + snakeBody;

        key = true;

        flag = 1;

 

        speed = 200;//速度初始值,修改初始

        rand = new Random();//创造一个新的随机数产生器

        list = new ArrayList<Point>();//创造一个初始容量为10的数列

        listBody = new ArrayList<Point>();

        x = 5;

        y = 5;

        list.add(new Point(x, y));//在坐标空间中创建并初始化一个新的点

        listBody.add(list.get(0));//list.get(0),返回在list列中0位置的元素

食物的生成使用Random,用48bit的种子产生伪随机序列生成随机数,之后反馈到食物坐标
fx,fy上,实现食物的随机生成,食物的部分代码如下:

fx = rand.nextInt(30) * 10 + 5;// rand.nextInt(30),返回一个在0——30内的随机数

        fy = rand.nextInt(30) * 10 + 5;// 2

控制蛇时,需要将键盘输入转换为对应的整形键码,之后使用
键盘输入时,使用抽象类KeyAdapter()将键盘输入反馈到界面中,控制蛇的运行方向和游戏暂停

addKeyListener(new KeyAdapter()

        {

        //KeyAdapter(),用于接收键盘传来的事件的抽象类

            public void keyPressed(KeyEvent e)

            {

                //KeyEvent,使键盘输入转化成对应对象
                //getKeyCode(),将键盘输入转化成对应的整形键码
                if (e.getKeyCode() == 37) {//左

                    dx = -10;

                    dy = 0;

                } else if (e.getKeyCode() == 38) {//上

                    dx = 0;

                    dy = -10;

                } else if (e.getKeyCode() == 39) {//右

                    dx = 10;

                    dy = 0;

                } else if (e.getKeyCode() == 40) {//下

                    dx = 0;

                    dy = 10;

                } else if (e.getKeyCode() == 80) {//暂停

                    if (flag % 2 == 1) {

                        time.stop();

                    }

                    if (flag % 2 == 0) {

                        time.start();

                    }

                    flag++;

                }

            }

        });

在设计游戏时,为了增加游戏可玩性,游戏中蛇的速度会随着吃到食物的增加而变快,速度上限为100,速度增加函数是一个开口向下的抛物线,所以说游戏会越玩难度越大。

if (x == fx && y == fy) {//即“蛇吃到果实”

            speed = (int) (speed * 0.8);// 速度增加参数

            if (speed < 200) {

                speed = 100;

            }

完整代码如下
主函数代码

package javaworkers;
import java.awt.*;
import javax.swing.*;

 @SuppressWarnings("serial")//注释处的所有警告都忽视

public class MainClass extends JFrame {

    ControlSnake control;


    Toolkit kit;//所有实际应用的抽象窗口工具包的父类

 

    Dimension dimen;//压缩了有整数精确度的组件

 

    public static void main(String[] args) {

        new MainClass("javaworkers");//显示界面名称

    }

 

    public MainClass(String s) {

        super(s);

        control = new ControlSnake();//新的ControlSnake类

        control.setFocusable(true);

        kit = Toolkit.getDefaultToolkit();

        dimen = kit.getScreenSize();//获取屏幕尺寸

 

        add(control);//添加control

        setLayout(new BorderLayout());

        setLocation(dimen.width / 3, dimen.height / 3);// 挪位置,dimen.width/3,dimen.height/3

        setSize(FWIDTH, FHEIGHT);//定格操作窗口大小

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setResizable(false);

        setVisible(true);

    }

 

    public static final int FWIDTH = 315;

 

    public static final int FHEIGHT = 380;

}

实现贪吃蛇的代码

package javaworkers;

import java.util.*;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.Timer;

import java.util.Random;

 

@SuppressWarnings("serial")

public class ControlSnake extends JPanel implements ActionListener {

    //JPanel类用于为小内容提供简单窗口,ActionListener为对象提供添加动作的方法

    Random rand;

    //Random,用48bit的种子产生伪随机序列

    ArrayList<Point> list, listBody;

    //ArrayList<Point>,类似于二维数组,声明了两个泛型对象

    String str, str1;

   

    static boolean key;

   

    int x, y, dx, dy, fx, fy, flag;

 

    int snakeBody;

    //控制蛇的长度

    int speed;

 

    public ControlSnake()

    {

        snakeBody = 1;//蛇的初始长度

 

        str = "上下左右方向键控制 P键暂停...";

        str1 = "现在的长度为:" + snakeBody;

        key = true;

        flag = 1;

 

        speed = 200;//速度初始值

        rand = new Random();//创造一个新的随机数产生器

        list = new ArrayList<Point>();//创造一个初始容量为10的数列

        listBody = new ArrayList<Point>();

 

        x = 5;

        y = 5;

        list.add(new Point(x, y));//在坐标空间中创建并初始化一个新的点

        listBody.add(list.get(0));//list.get(0),返回在list列中0位置的元素

 

        dx = 10;

        dy = 0;

 

        fx = rand.nextInt(30) * 10 + 5;// rand.nextInt(30),返回一个在0——30内的随机数

        fy = rand.nextInt(30) * 10 + 5;// 2

 

        setBackground(Color.WHITE);//为窗口添加背景色

        setSize(new Dimension(318, 380));//重新定义窗口的高和宽

 

        final Timer time = new Timer(speed, this);

        time.start();

        //timer类,在指定时间间隔触发一个或多个 ActionEvent

        addKeyListener(new KeyAdapter()

        {

        //KeyAdapter(),用于接收键盘传来的事件的抽象类

            public void keyPressed(KeyEvent e)

            {

                //KeyEvent,使键盘输入转化成对应对象

                if (e.getKeyCode() == 37) {//getKeyCode(),将键盘输入转化成对应的整形键码

                    dx = -10;

                    dy = 0;

                } else if (e.getKeyCode() == 38) {

                    dx = 0;

                    dy = -10;

                } else if (e.getKeyCode() == 39) {

                    dx = 10;

                    dy = 0;

                } else if (e.getKeyCode() == 40) {

                    dx = 0;

                    dy = 10;

                } else if (e.getKeyCode() == 80) {

                    if (flag % 2 == 1) {

                        time.stop();

                    }

                    if (flag % 2 == 0) {

                        time.start();

                    }

                    flag++;

                }

            }

        });

 

    }

    public void paint(Graphics g) {//Graphics,所有环境算法基础类,允许应用在已有组件上进行绘制

        g.setColor(Color.WHITE);

        g.fillRect(0, 0, 400, 400);//指定一个以setColor返回值为底色的长方形,具体参数为x,y

        g.setColor(Color.DARK_GRAY);

        g.drawLine(3, 3, 305, 3);//在点(3,3)和(305,3)之间用当前色填充一条线

        g.drawLine(3, 3, 3, 305);

        g.drawLine(305, 3, 305, 305);

        g.drawLine(3, 305, 305, 305);

        g.setColor(Color.PINK);

 

        for (int i = 0; i < listBody.size(); i++) {//listBody.size(),返回当前list的元素个数

            g.fillRect(listBody.get(i).x, listBody.get(i).y, 9, 9);

        }//控制蛇的长度

        g.fillRect(x, y, 9, 9);//蛇的长度最大为9

        g.setColor(Color.ORANGE);

        g.fillRect(fx, fy, 9, 9);//随机显示果实

 

        g.setColor(Color.DARK_GRAY);

        str1 = "现在的长度为:" + snakeBody;

        g.drawString(str, 10, 320);//在图形化界面中显示字符串

        g.drawString(str1, 10, 335);

    }

 

    public void actionPerformed(ActionEvent e) {

        x += dx;

        y += dy;

        if (makeOut() == false) {//见最后的函数,用于排除超出图形界面的不合法输出

            JOptionPane.showMessageDialog(null, "重新开始......");

            //跳出对话框,显示“重新开始”

            speed = 200;//重新定义蛇的速度和长度

 

            snakeBody = 1;

 

            x = 5;

            y = 5;

 

            list.clear();//清空数列

            list.add(new Point(x, y));//加入新元素

            listBody.clear();

            listBody.add(list.get(0));

 

            dx = 10;

            dy = 0;

 

        }

        addPoint(x, y);

        if (x == fx && y == fy) {//即“蛇吃到果实”

            speed = (int) (speed * 0.8);// 速度增加参数

            if (speed < 200) {

                speed = 100;

            }

            fx = rand.nextInt(30) * 10 + 5;// 2

            fy = rand.nextInt(30) * 10 + 5;// 2

            snakeBody++;// 2

        } // 2

        repaint();//重新进行

    }

 

    public void addPoint(int xx, int yy) {

        // 动态的记录最新发生的50步以内的移动过的坐标

        // 并画出最新的snakeBody

        if (list.size() < 100) {// 蛇身长度最长为100

            list.add(new Point(xx, yy));

        } else {

            list.remove(0);

            list.add(new Point(xx, yy));

        }

        if (snakeBody == 1) {

            listBody.remove(0);

            listBody.add(0, list.get(list.size() - 1));

        } else {

            listBody.clear();

            if (list.size() < snakeBody) {

                for (int i = list.size() - 1; i > 0; i--) {

                    listBody.add(list.get(i));

                }

            } else {

                for (int i = list.size() - 1; listBody.size() < snakeBody; i--) {

                    listBody.add(list.get(i));

                }

            }

        }

    }

 

    public boolean makeOut() {

        if ((x < 3 || y < 3) || (x > 305 || y > 305)) {

            return false;

        }

        for (int i = 0; i < listBody.size() - 1; i++) {

            for (int j = i + 1; j < listBody.size(); j++) {

                if (listBody.get(i).equals(listBody.get(j))) {

                    return false;

                }

            }

        }

        return true;

    }

}

项目实现中的问题与解决

对于项目的实现开始时,我们想到了一些问题,见第四周项目报告,连接如下:

  • Javaworkers团队第四周项目总结 然后我们在优化的过程中解决了如上问题。
    但是对于我们来说最困难的是对于未学习知识的应用,就像在使用界面设计包import java.awt.* ,import javax.swing.* 时,开始的时候并不会,然后再网上找有关的例子,和查阅API
    文档,然后尝试的去修改代码,一步一步的试错学习得到了结果。

项目的展望与改进

贪吃蛇作为一个经典游戏,对于改进方面我认为可以穿墙吃食物,并不是非要碰到墙就死,还可以进行关卡设置,在规定时间内吃到目标数量的食物就算过关,加大难度的话就是在一定时间内没有吃到食物,就自动扣一分并且重新生成新的食物。以及在其中放置障碍物,或是有毒的食物,通过颜色进行区别,因为一段时间就会刷新食物,所以并不是每个食物都要吃,避免吃到有毒的食物会进行加分。

团队成员成绩分配

姓名

任务

分配分数

20145205武钰

项目框架设计、代码模块构思及后期代码优化

30分

20145222黄亚奇

项目bug测试以及协作代码优化

23分

20145235李涛

项目资料寻找以及协作代码编写

25分

20145103冯文华

项目推送以及博客写作以及协作代码优化

22分

总结

经过长达五周的项目制作,从初步想法到翻阅资料,从具体构思到编写代码,从项目测试到写作代码优化,这样一步步走来,不仅锻炼了我们小组成员的动手协作能力,还让我们能对java这门课程有了进一步的了解,大大激发了我们的学习热情。虽然不是所有的代码是我们小组成员亲自编写,但对于不懂的我们通过到图书馆三楼翻阅相关书籍资料、结合自己以前的学习总结博客、向学长学姐请教等途径我们终于完成了贪吃蛇游戏的项目制作。不过还是有些地方由于时间关系我们未能进行优化,例如改进使蛇能穿墙吃食物、控制蛇的速度等,但我们相信通过这次小组合作制作项目,我们小组会不断成长,越学越好!