目录
- QTimer介绍
- QTimer使用
- 车辆运动算法
- 最终模型展示
1. QTimer介绍
QTimer类为计时器提供了高级编程接口。要使用它,需要创建一个QTimer,将其timeout()信号连接到适当的插槽函数,并调用start()。从那时起,它将以恒定的间隔发出timeout()信号,槽函数每收到一次信号就会执行一次。
2. QTimer使用
2.1 单次触发的计时器
QTimer可以弄个单次触发的计时器
//Example:
QApplication app(argc, argv);
QTimer::singleShot(600000, &app, SLOT(quit()));
...
return app.exec();
2.2 按设置好的时间间隔触发的计时器
QTimer *timer = new QTimer(this); //设置父对象this,挂接到对象树上,这样程序结束时会自动释放空间
connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));//将Qtimer定时发出的信号和槽函数连接起来,
//一旦收到timeout信号,就执行槽函数
timer->start(1000);//启动计时器,并设置信号发出间隔1000ms
注:如果有多个计时器,通过TimerID来引用,这儿不说了
2.3 用计时器来更新场景
// .h定义计时器
QTimer *timer; //定义计时器
//.cpp 计时器在构造函数中设置
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer= new QTimer(this); // 在类的构造函数中初始化timer
connect(timer,&QTimer::timeout, this, &Widget::on_updateScene_timeout);
//connect(发出信号的是谁,谁的哪种信号,谁接受信号,谁的什么函数接受信号)
//on_updateScene_timeout是我自定义的槽函数
timer->setInterval(100); //设置,每间隔100ms发出一次信号
}
计时器的启动和暂停放在开始和暂停按钮的槽函数中
3. 车辆运动算法
sceneUpdate()函数需要考虑两点:1更新顺序的问题,2如何更新
3.1更新顺序我们可以随机选取车辆更新,需要使用到洗牌算法
C++有个random_shuffle就可以随机打乱,但qt用不了
#include <algorithm>
#include <vector>
#include <ctime>
......
srand((unsigned int)time(NULL));
vector<int> v;
for(int i = 0 ; i < 10;i++)
{
v.push_back(i);
}
random_shuffle(v.begin(), v.end());//顺序打乱
洗牌算法实现
void Widget::sceneUpdate()
{
// 1选择,2 算法更新
//洗牌算法,决定谁先更新,0-numV随机排序再依次更新
QVector<int> orderContainer;
for (int i=0;i<numV;i++) {
orderContainer.append(i); //初始化序列容器
}
//费雪耶兹置乱算法
for(int i=numV-1; i>0; i--)
{
int rand=QRandomGenerator::global()->bounded(0,i+1); //[0,i] 内生成随机整数
if(rand==i) continue;
orderContainer.swapItemsAt(i,rand); //QVector用来交换两个位置元素的算法
}
qDebug()<<orderContainer;//测试使用
}
3.2 车辆更新
考虑车辆最大速度为5,使用NS模型
对车辆进行更新
#define speedMax 5 //车辆最大速度,单位元胞
话不多说,对于车辆的更新直接上代码
int speedA =(veContainer[order]->speed+1);
int desiredSpeed = (speedA > speedMax) ? speedMax:speedA;
int speedLast; //定义最终速度,用来放最后得到的速度
//用desiredSpeed查看空间,也就是用此速度会不会遇到障碍
int x= veContainer[order]->pos.x();
int i = desiredSpeed;// 使用i来进行车辆运动遇障判断
while(i!=0)//每往车前判断一格,就i自减,直到i为0
{
if(x==sL) x=0; //过了右侧边界,从左侧继续判断
if(scene[++x][sW/2]==1) break;//一旦有障碍,就跳出此循环
i--;
}
if(i!=0){//上面的循环,不正常退出
speedLast=desiredSpeed -i;
}
else{
speedLast=desiredSpeed;
}
// 确认速度后进行车辆的更新,包括(原来元胞的占有去掉,车辆对象的信息更新,占据新的元胞)
//定义一个NotShowOccupied函数,和showOccupied差不多,只是赋值由1变为0
notShowOccupied(veContainer[order]->pos.x());
veContainer[order]->speed=speedLast;
int pos = veContainer[order]->pos.x()+speedLast; //原位置加速度得到现在的位置
int posLast = (pos >= sL)? (pos-sL) : pos; //考虑右边界,得到车辆最终速度
veContainer[order]->pos.setX(posLast); //使用QPoint的方法来设置x坐标
showOccupied(posLast);//scene数组也更新一下