交通信号灯模拟
问题描述:
模拟实现十字路口的交通灯管理系统逻辑
1.随机生成按照各个路线行驶的车辆(车辆数据可以是每次随机产生,也可以采用随机产生,保存到文 件,下次运行程序从文件中加载到程序)。例如:
由北向驶往南向的车辆----直行
由西向驶往南向的车辆----右转
由东向驶往南向的车辆----左转
2.信号灯忽略黄灯,只考虑红灯和绿灯。
3.应考虑左转车辆受信号灯控制,右转车辆不受信号灯控制。
4.具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑:南北车辆与东西车辆交替放行,同方向车辆等待应先放行直行车辆,后放行左转车辆。
5.每辆车通过路口的时间为1秒。
6.随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
7.运行结果展现方式:
①基本版:不实现图形界面,只考虑系统逻辑实现,可通过log方式展现程序运行结果。
②中级版:采用图形界面,但图形界面上只有信号灯,没有车运行,只是根据车的数据,模拟信号灯的变化。
③高级版:采用图形界面,图形界面有地图(单路口或多路口)和运行的车辆,以及信号灯的变化。
8.所有的车辆数据和运行数据采用文件存储
9.特殊需求:当某个方向来一辆救护车或消防车,设计策略,优先处理该方向的通行。
需求分析:
交通灯模拟系统的主要功能就是对交通灯的控制。
(1)用户可以对红绿灯进行初始化。
(2)用户可以随时选择模拟或停止。
(3)用户可以退出系统。
用户用例分析:用户可以通过点击按钮实现相应的功能,时间单位是毫秒。 用例图如下:
系统的设计
系统主要是一个主类,主类里的 MyCanvas 类为 Canvas 类的扩展,重写了 paint 方法; init 方法实现的是系统的逻辑控制,其中有两个 ActionListener,一个是小车的(CAR_timer),一个是红绿灯的(timer),这两个 ActionListener 可以让小车和红绿灯每隔一段时间进行状态刷新。
系统结构图
界面的设计
开始界面:通过重写 Canvas 类里的 paint 实现,背景颜色为白色。 下方有四个按钮,对应的功能如下:
Start:界面的初始化,点击 Start,画面上的灯亮起,同时小车出现。
Simulate:开始进行模拟,点击 Simulate,画面的灯开始闪烁,小车开始移动。
Stop:停止模拟,点击 Stop,灯停止闪烁,小车停止移动。
Exit:退出系统,点击 Exit,系统退出,界面消失。
实现的关键代码
两个时间监听器的代码:
//灯的时间监听器,每隔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 表示由东向西行驶
测试数据与运行结果
开始界面
初始化界面
CURRENT_STATE=0
CURRENT_STATE=1
CURRENT_STATE=2
CURRENT_STATE=3
总结:
在该系统中设置了两个监听器来实现灯的状态转换和小车的移动,这个事件也可以使用多线程的方式来解决,但是因为设计的是每次只允许一个方向的车通过,因此只需要设置事件监听器进行刷新即可。图形化界面使用的是 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();
}
}