交通信号灯模拟

问题描述:

模拟实现十字路口的交通灯管理系统逻辑

1.随机生成按照各个路线行驶的车辆(车辆数据可以是每次随机产生,也可以采用随机产生,保存到文 件,下次运行程序从文件中加载到程序)。例如:
由北向驶往南向的车辆----直行
由西向驶往南向的车辆----右转
由东向驶往南向的车辆----左转

2.信号灯忽略黄灯,只考虑红灯和绿灯。

3.应考虑左转车辆受信号灯控制,右转车辆不受信号灯控制。

4.具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑:南北车辆与东西车辆交替放行,同方向车辆等待应先放行直行车辆,后放行左转车辆。

5.每辆车通过路口的时间为1秒。

6.随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。

7.运行结果展现方式:
①基本版:不实现图形界面,只考虑系统逻辑实现,可通过log方式展现程序运行结果。
②中级版:采用图形界面,但图形界面上只有信号灯,没有车运行,只是根据车的数据,模拟信号灯的变化。
③高级版:采用图形界面,图形界面有地图(单路口或多路口)和运行的车辆,以及信号灯的变化。

8.所有的车辆数据和运行数据采用文件存储

9.特殊需求:当某个方向来一辆救护车或消防车,设计策略,优先处理该方向的通行。

需求分析:

交通灯模拟系统的主要功能就是对交通灯的控制。

(1)用户可以对红绿灯进行初始化。
(2)用户可以随时选择模拟或停止。
(3)用户可以退出系统。

用户用例分析:用户可以通过点击按钮实现相应的功能,时间单位是毫秒。 用例图如下:

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_java

系统的设计

系统主要是一个主类,主类里的 MyCanvas 类为 Canvas 类的扩展,重写了 paint 方法; init 方法实现的是系统的逻辑控制,其中有两个 ActionListener,一个是小车的(CAR_timer),一个是红绿灯的(timer),这两个 ActionListener 可以让小车和红绿灯每隔一段时间进行状态刷新。

系统结构图

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_ide_02

界面的设计

开始界面:通过重写 Canvas 类里的 paint 实现,背景颜色为白色。 下方有四个按钮,对应的功能如下:

Start:界面的初始化,点击 Start,画面上的灯亮起,同时小车出现。
Simulate:开始进行模拟,点击 Simulate,画面的灯开始闪烁,小车开始移动。 
Stop:停止模拟,点击 Stop,灯停止闪烁,小车停止移动。 
Exit:退出系统,点击 Exit,系统退出,界面消失。

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_ide_03

实现的关键代码

两个时间监听器的代码:

//灯的时间监听器,每隔1000ms更新灯的状态
ActionListener LIGHT_task = new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        LayerY = 500;
        LayerX = 100;
        CURRENT_STATE = STATE % 4;
        drawArea.repaint();
        STATE += 1;
    }
};
//小车的时间监听器,每隔20ms更新小车的状态
ActionListener CAR_task = new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        LayerY += SPEED;
        LayerX -= SPEED;
        drawArea.repaint();
    }
};

LayerY、LayerX 分别为小车南北和东西的位置,SPEED 为小车行驶的速度。每次绿灯亮起,小车从初始位置出发。系统只模拟了直行的小车,左转和右转的小车没有绘制。

STATE 每次加一。使用 Canvas 里的 repaint 方法更新灯和小车的状态,其中灯每隔 1000ms 更新一次,小车每隔 20ms 更新一次。 CURRENT_STATE 为交通灯目前的状态:

0 表示由南向北行驶
1 表示由北向南行驶
2 表示由西向东行驶
3 表示由东向西行驶
测试数据与运行结果

开始界面

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_开发语言_04

初始化界面

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_ide_05

CURRENT_STATE=0

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_监听器_06

CURRENT_STATE=1

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_ide_07

CURRENT_STATE=2

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_JAVA 十字路口 红绿灯 小程序_08

CURRENT_STATE=3

JAVA 十字路口 红绿灯 小程序 java红绿灯模拟_监听器_09

总结:

在该系统中设置了两个监听器来实现灯的状态转换和小车的移动,这个事件也可以使用多线程的方式来解决,但是因为设计的是每次只允许一个方向的车通过,因此只需要设置事件监听器进行刷新即可。图形化界面使用的是 java.awt 来进行绘制,java.awt 绘制相对来说比较简单。也可以使用 JavaFX 来进行绘制,但是要在 JavaFX 里面使用多线程的话,要注意的是,JavaFX 是不允许除了主线程以外的线程去刷新 UI 的,个人不建议使用 JavaFX 来开发该系统。

附源码如下:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TrafficLight {
    private int STATE = 0;
    private int CURRENT_STATE = 5;  //四种状态, 0:由南向北 1:由北向南 2:由西向东 3:由东向西
    private int LINE_1 = 110;
    private int LINE_2 = 460;

    private int SPEED = 10;     //小车的速度
    private int LayerX = 500;   //小车位置
    private int LayerY = 100;   //小车位置

    private Frame frame = new Frame("Traffic Light");
    private final int TABALE_WIDTH = 600;   //画布宽度
    private final int TABALE_HEIGHT = 600;  //画布高度
    private final int REC_WIDTH = 150;      //灯板宽度
    private final int REC_HEIGHT = 50;      //灯板高度
    private final int C_SIZE = 30;          //灯的直径

    Button start = new Button("Start");
    Button simulate = new Button("Simulate");
    Button stop = new Button("Stop");
    Button exit = new Button("Exit");

    private Timer timer;    //灯变化的时间监听器
    private Timer CAR_timer;    //小车移动的时间监听器

    private class MyCanvas extends Canvas {
        @Override
        public void paint(Graphics g){
            //绘制线条
            g.drawLine(150, 0, 150, 600);
            g.drawLine(300, 50, 300, 550);
            g.drawLine(450, 0, 450, 600);
            g.drawLine(0, 150, 600, 150);
            g.drawLine(50, 300, 550, 300);
            g.drawLine(0, 450, 600, 450);
            //绘制黑色矩形框
            g.fillRect(150, 100, REC_WIDTH, REC_HEIGHT);
            g.fillRect(300, 450, REC_WIDTH, REC_HEIGHT);
            g.fillRect(100, 300, REC_HEIGHT, REC_WIDTH);
            g.fillRect(450, 150, REC_HEIGHT, REC_WIDTH);
            //小车移动超过UI界面的范围时,小车位置重新回到初始位置
            if (LayerY > 500 || LayerX < 0){
                LayerY = 0;
                LayerX = 500;
            }
            //灯的状态,0:由南向北行驶 1:由北向南行驶 2:由西向东行驶 3:由东向西行驶
            if (CURRENT_STATE == 0){
                g.fillOval(225, LayerX, 20, 20);//小车,这里只设置一辆直行的小车
                g.setColor(Color.GREEN);//绿灯
                //第一组灯
                g.fillOval(160, LINE_1, C_SIZE, C_SIZE); // light 1
                g.fillOval(210, LINE_1, C_SIZE, C_SIZE); // light 2
                g.fillOval(260, LINE_1, C_SIZE, C_SIZE); // light 3
                //四、七、十
                g.fillOval(LINE_2, 160, C_SIZE, C_SIZE); // light 4
                g.fillOval(405, LINE_2, C_SIZE, C_SIZE); // light 7
                g.fillOval(LINE_1, 405, C_SIZE, C_SIZE); // light 10

                g.setColor(Color.RED);//红灯
                //第二组灯
                g.fillOval(LINE_2, 210, C_SIZE, C_SIZE); // light 5
                g.fillOval(LINE_2, 260, C_SIZE, C_SIZE); // light 6
                //第三组灯
                g.fillOval(360, LINE_2, C_SIZE, C_SIZE); // light 8
                g.fillOval(310, LINE_2, C_SIZE, C_SIZE); // light 9

                //第四组灯
                g.fillOval(LINE_1, 360, C_SIZE, C_SIZE); // light 11
                g.fillOval(LINE_1, 310, C_SIZE, C_SIZE); // light 12

            }
            if (CURRENT_STATE == 1){
                g.fillOval(375, LayerY, 20, 20);//小车,这里只设置一辆直行的小车
                g.setColor(Color.GREEN);
                //第三组灯
                g.fillOval(310, LINE_2, C_SIZE, C_SIZE); // light 9
                g.fillOval(360, LINE_2, C_SIZE, C_SIZE); // light 8
                g.fillOval(405, LINE_2, C_SIZE, C_SIZE); // light 7

                g.fillOval(160, LINE_1, C_SIZE, C_SIZE); // light 1
                g.fillOval(LINE_2, 160, C_SIZE, C_SIZE); // light 4
                g.fillOval(LINE_1, 405, C_SIZE, C_SIZE); // light 10

                g.setColor(Color.RED);
                //第一组灯
                g.fillOval(210, LINE_1, C_SIZE, C_SIZE); // light 2
                g.fillOval(260, LINE_1, C_SIZE, C_SIZE); // light 3
                //第二组灯
                g.fillOval(LINE_2, 210, C_SIZE, C_SIZE); // light 5
                g.fillOval(LINE_2, 260, C_SIZE, C_SIZE); // light 6
                //第四组灯
                g.fillOval(LINE_1, 360, C_SIZE, C_SIZE); // light 11
                g.fillOval(LINE_1, 310, C_SIZE, C_SIZE); // light 12
            }
            if (CURRENT_STATE == 2){
                g.fillOval(LayerY, 225, 20, 20);//小车,这里只设置一辆直行的小车
                g.setColor(Color.GREEN);
                //第二组灯
                g.fillOval(LINE_2, 160, C_SIZE, C_SIZE); // light 4
                g.fillOval(LINE_2, 210, C_SIZE, C_SIZE); // light 5
                g.fillOval(LINE_2, 260, C_SIZE, C_SIZE); // light 6

                g.fillOval(160, LINE_1, C_SIZE, C_SIZE); // light 1
                g.fillOval(405, LINE_2, C_SIZE, C_SIZE); // light 7
                g.fillOval(LINE_1, 405, C_SIZE, C_SIZE); // light 10

                g.setColor(Color.RED);
                //第一组灯
                g.fillOval(210, LINE_1, C_SIZE, C_SIZE); // light 2
                g.fillOval(260, LINE_1, C_SIZE, C_SIZE); // light 3
                //第三组灯
                g.fillOval(360, LINE_2, C_SIZE, C_SIZE); // light 8
                g.fillOval(310, LINE_2, C_SIZE, C_SIZE); // light 9
                //第四组灯
                g.fillOval(LINE_1, 360, C_SIZE, C_SIZE); // light 11
                g.fillOval(LINE_1, 310, C_SIZE, C_SIZE); // light 12
            }
            if (CURRENT_STATE == 3){
                g.fillOval(LayerX, 375, 20, 20);//小车,这里只设置一辆直行的小车
                g.setColor(Color.GREEN);
                //第四组灯
                g.fillOval(LINE_1, 310, C_SIZE, C_SIZE); // light 12
                g.fillOval(LINE_1, 360, C_SIZE, C_SIZE); // light 11
                g.fillOval(LINE_1, 405, C_SIZE, C_SIZE); // light 10

                g.fillOval(160, LINE_1, C_SIZE, C_SIZE); // light 1
                g.fillOval(LINE_2, 160, C_SIZE, C_SIZE); // light 4
                g.fillOval(405, LINE_2, C_SIZE, C_SIZE); // light 7

                g.setColor(Color.RED);
                //第一组灯
                g.fillOval(210, LINE_1, C_SIZE, C_SIZE); // light 2
                g.fillOval(260, LINE_1, C_SIZE, C_SIZE); // light 3
                //第二组灯
                g.fillOval(LINE_2, 210, C_SIZE, C_SIZE); // light 5
                g.fillOval(LINE_2, 260, C_SIZE, C_SIZE); // light 6
                //第三组灯
                g.fillOval(360, LINE_2, C_SIZE, C_SIZE); // light 8
                g.fillOval(310, LINE_2, C_SIZE, C_SIZE); // light 9
            }
        }
    }
    MyCanvas drawArea = new MyCanvas();
    public void init() {
        //灯的时间监听器,每隔1000ms更新灯的状态
        ActionListener LIGHT_task = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                LayerY = 500;
                LayerX = 100;
                CURRENT_STATE = STATE % 4;
                drawArea.repaint();
                STATE += 1;
            }
        };
        //小车的时间监听器,每隔20ms更新小车的状态
        ActionListener CAR_task = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                LayerY += SPEED;
                LayerX -= SPEED;
                drawArea.repaint();
            }
        };
        //Start按键响应事件
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                CURRENT_STATE = 0;
                drawArea.repaint();
            }
        });
        //Simulate按键响应事件
        simulate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timer = new Timer(1000, LIGHT_task);//1000ms执行一次LIGHT_task任务
                timer.start();
                CAR_timer = new Timer(20, CAR_task);//20ms执行一次CAR_task任务
                CAR_timer.start();
                drawArea.repaint();
            }
        });
        //Stop按键响应事件
        stop.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timer.stop();       //红绿灯停止闪烁
                CAR_timer.stop();   //小车停止移动
                drawArea.repaint();
            }
        });
        //Exit按键响应事件
        exit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(1);
            }
        });
        Panel panel = new Panel();
        panel.add(start);
        panel.add(simulate);
        panel.add(stop);
        panel.add(exit);
        frame.add(panel, BorderLayout.SOUTH);
        drawArea.setPreferredSize(new Dimension(TABALE_WIDTH, TABALE_HEIGHT));
        frame.add(drawArea);
        frame.pack();
        frame.setVisible(true);
        frame.setResizable(false);
    }
    public static void main(String[] args) {
        new TrafficLight().init();
    }
}