2020-09-16QT写一个简单的元胞自动机(6)

目录


  1. QTimer介绍
  2. QTimer使用
  3. 车辆运动算法
  4. 最终模型展示

1. QTimer介绍


QTimer类为计时器提供了高级编程接口。要使用它,需要创建一个QTimer,将其timeout()信号连接到适当的插槽函数,并调用start()。从那时起,它将以恒定的间隔发出timeout()信号,槽函数每收到一次信号就会执行一次。


2. QTimer使用

2.1 单次触发的计时器

QTimer可以弄个单次触发的计时器


使用静态cheng
//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发出一次信号
}

计时器的启动和暂停放在开始和暂停按钮的槽函数中


image.png

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数组也更新一下

4. 最终模型展示

1

2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。