1
votes

I am writing a game. By tick timer should work the this slot.

void game_process::animate_cell(MainWindow* m, const std::string& s, double x,double y, size_t i, size_t j, const std::string& step)
{ 
    painter.begin(m);
    std::string ss("C:\\Users\\Vardan\\GAmes_lines\\res\\red_" + step + ".png");
    ss += s;
    const char* p = ss.c_str();    
    QImage image(p);
    RECT temp = cal

    culate_cell_rect(i, j);
    QRectF target(x, y, image.width(), image.height());
    painter.drawImage(target, image);
    painter.end();
    m->update(x + temp.x0, y + temp.y0, 60, 60);
}
, that's it,

QTimer * timer = new QTimer (this); connect (timer, SIGNAL (timeout ()), this, SLOT (render_cell (MainWindow * m, const std :: string & s, double x, double y, size_t i, size_t j, const std :: string & step))); timer-> start ();

But as you can see the slot more parameters than the signal, and hence signals and slots mechanism does not work. What to do? Here cod

#include <QDesktopWidget>
#include <QResizeEvent>
#include <QDebug>
#include <QTimer>
#include <QTime> 
#include <phonon/MediaObject>
#include <phonon/MediaSource>
#include <phonon/AudioOutput>
#include <utility>
#include <cassert>

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
    QImage image("C:\\Users\\Vardan\\GAmes_lines\\res\\back_3.png");
    m_width = 1000;
    m_height = 800;
    m_game_width = image.width();
    m_game_height = image.height();
    setFixedSize(m_width, m_height);
    m_click_coords.first = 0;
    m_click_coords.second = 0;
    m_timer_tick = false;
    m_timer_id = 0;        
    setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
    m_area_x0_coordinate = (this->width() - image.width())/2;
    m_area_y0_coordinate = (this->height() - image.height())/2;
    m_r = new game_process(m_area_x0_coordinate, m_area_y0_coordinate, image.width()/*+30*/, image.height()/*+30*/, 57);
    m_status = false;     
    Phonon::MediaObject *mediaobject = new Phonon::MediaObject;
    QString filename("C://Users//Vardan//GAmes_lines//music//Casino Ambiance Music.wav");
    mediaobject->setCurrentSource(filename);
    Phonon::AudioOutput *audio = new Phonon::AudioOutput;
    Phonon::createPath(mediaobject,audio);
    mediaobject->play();
    QPixmap pixmap("C:\\Users\\Vardan\\GAmes_lines\\res\\background.png");    
    QPalette palette;    
    palette.setBrush(/*this->backgroundRole()*/QPalette::Background, QBrush(pixmap));
    this->setPalette(palette);

}
MainWindow::MainWindow(std::string& str, QWidget *parent):
    QWidget(parent)
{

}

double MainWindow::get_mouse_click_absolute_x_coordinate() const
{
    return m_area_x0_coordinate;
}

double MainWindow::get_mouse_click_absolute_y_coordinate() const
{
    return m_area_y0_coordinate;
}

void MainWindow::set_mouse_click_absolute_x_coordinate(double x)
{
    m_area_x0_coordinate = x;
}

void MainWindow::set_mouse_click_absolute_y_coordinate(double y)
{
    m_area_y0_coordinate = y;
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    if(m_status == false)
    {
        m_r->game_loop(this);
    }
    else
    {   
        game_process::RECT temp = m_r->calculate_cell_rect(m_click_coords.first, m_click_coords.second);
        int x = m_area_x0_coordinate + temp.x0;
        int y = m_area_y0_coordinate + temp.y0;
        std::pair<double, double> p;
/////////////////////////////////////////////////////////
        start_timer();
//////////////////////////////////////////////////////////
        for(int i = 2; i < 8; ++i)
        {
            char buf[sizeof(int)];
            itoa(i, buf, 10);
            std::string s(buf);            
            m_r->erase_frame(this, x, y);
            while(m_timer_tick == false){}
            p = m_r->draw_frame(this, m_click_coords.first, m_click_coords.second, s.c_str());
            m_timer_tick = false;
        }
        end_timer();            
        m_status = false;
    }        
}

bool MainWindow::delay(int ms)
{
    QTime dieTime = QTime::currentTime().addMSecs(ms);
    while( QTime::currentTime() < dieTime )
    return true;
}

void MainWindow::mousePressEvent (QMouseEvent* e)
{
    qDebug() << "Local:" << e->pos().x();
    qDebug() << "Local:" << e->pos().y();    
    std::pair<double, double> p = m_r->calculate_index_of_the_coordinates(e->pos().x(), e->pos().y(), m_width, m_height);
    if(m_area_x0_coordinate <= e->pos().x() && m_area_y0_coordinate <= e->pos().y()
            && m_area_x0_coordinate + m_game_width >= e->pos().x() && m_area_y0_coordinate + m_game_height >= e->pos().y() )
    {        
        m_status = true;
        m_click_coords.first = p.first;
        m_click_coords.second = p.second;        
        game_process::RECT coords = m_r->calculate_cell_rect(p.first, p.second);                
        Figure* f = m_r->detect_figure_by_index(p.first, p.second);         
        m_r->delete_cluster(this, f);            
    }
    game_process::RECT r;
    qDebug() << "Local:" << p.first;
    qDebug() << "Local:" << p.second;
}

void MainWindow::timerEvent(QTimerEvent *event)
{
    m_timer_tick = true;
} 

void MainWindow::start_timer()
{
    m_timer_id = startTimer(1000 / 30);
}

void MainWindow::end_timer()
{
    killTimer(m_timer_id);
}

bool MainWindow::event(QEvent *e)
{
    switch (e->type())
    {
        case QEvent::WindowActivate:
        case QEvent::WindowDeactivate:
          return true;
    }
    return QWidget::event(e);

}

I noticed that the timer does not start from paintEvent, and I need what he started with paintEvent. What to do?

I adjusted the code following your advice.

#include "mainwindow.h"
#include "game_process.h"

#include <QPixmap>
#include <QPainter>
#include <QPalette>
#include <QDesktopWidget>
#include <QResizeEvent>
#include <QDebug>
#include <QTimer>
#include <QTime> 
#include <phonon/MediaObject>
#include <phonon/MediaSource>
#include <phonon/AudioOutput>
#include <utility>
#include <cassert>

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent)
{
    QImage image("C:\\Users\\Vardan\\GAmes_lines\\res\\back_3.png");
    m_width = 1000;
    m_height = 800;
    m_game_width = image.width();
    m_game_height = image.height();
    setFixedSize(m_width, m_height);
    m_click_coords.first = 0;
    m_click_coords.second = 0;
    m_next_cell = 0;
    m_frame_count = 2;
    m_timer_tick = false;
    m_timer_id = 0;
    m_matrix_size = 0;
    m_timer_flag = false;
    setWindowFlags( Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
    m_area_x0_coordinate = (this->width() - image.width())/2;
    m_area_y0_coordinate = (this->height() - image.height())/2;
    m_r = new game_process(m_area_x0_coordinate, m_area_y0_coordinate, image.width()/*+30*/, image.height()/*+30*/, 57);
    m_status = false;     
    Phonon::MediaObject *mediaobject = new Phonon::MediaObject;
    QString filename("C://Users//Vardan//GAmes_lines//music//Casino Ambiance Music.wav");
    mediaobject->setCurrentSource(filename);
    Phonon::AudioOutput *audio = new Phonon::AudioOutput;
    Phonon::createPath(mediaobject,audio);
    mediaobject->play();
    QPixmap pixmap("C:\\Users\\Vardan\\GAmes_lines\\res\\background.png");    
    QPalette palette;    
    palette.setBrush(/*this->backgroundRole()*/QPalette::Background, QBrush(pixmap));
    this->setPalette(palette);
}

MainWindow::~MainWindow()
{

}

MainWindow::MainWindow(std::string& str, QWidget *parent):
    QWidget(parent)
{

}

double MainWindow::get_mouse_click_absolute_x_coordinate() const
{
    return m_area_x0_coordinate;
}

double MainWindow::get_mouse_click_absolute_y_coordinate() const
{
    return m_area_y0_coordinate;
}

void MainWindow::set_mouse_click_absolute_x_coordinate(double x)
{
    m_area_x0_coordinate = x;
}

void MainWindow::set_mouse_click_absolute_y_coordinate(double y)
{
    m_area_y0_coordinate = y;
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    static int  ind = 0;
    if(m_status == false && m_timer_tick != true)
    {
        m_r->game_loop(this);
    }
    else
    {
        std::pair<double, double> p;
        int x = 0;
        int y = 0;

        static int s = m_r->get_close_map_size();
        static std::vector<std::pair<int, int> > v = m_r->get_close_map_indexes();
        if(m_frame_count >= 7)
        {
            m_frame_count = 2;            
            ++m_next_cell;
            if(m_next_cell <= v.size())
            {
                game_process::RECT temp = m_r->calculate_cell_rect(v[m_next_cell].second, v[m_next_cell].first);
                x = m_area_x0_coordinate + temp.x0;
                y = m_area_y0_coordinate + temp.y0;
                m_x = x;
                m_y = y;
            }
        }
        if(m_next_cell == 0)
        {
            game_process::RECT temp = m_r->calculate_cell_rect(v[m_next_cell].second, v[m_next_cell].first);
            x = m_area_x0_coordinate + temp.x0;
            y = m_area_y0_coordinate + temp.y0;
            m_x = x;
            m_y = y;
        }
        if(m_frame_count < 7 && m_next_cell < v.size())
        {
            char buf[sizeof(int)];
            itoa(m_frame_count, buf, 10);
            std::string s(buf);
            m_r->erase_frame(this, x, y);
            p = m_r->draw_frame(this, v[m_next_cell].second, v[m_next_cell].first, s.c_str());
            m_timer_tick = false;            
            c = true;
        }        
        if(c == false && m_next_cell > v.size() - 1)
        {
            end_timer();
            qDebug()<<"m_x = " << m_x;
            qDebug()<<"m_y = " << m_y;
            qDebug()<<"m_frame_count + 1 = " << m_frame_count + 1;
            qDebug()<<"v.size() = " << v.size();
            m_r->repaint_cells(this);
        }
        m_status = false;
    }    
}

void MainWindow::mousePressEvent (QMouseEvent* e)
{    
    qDebug() << "Local:" << e->pos().x();
    qDebug() << "Local:" << e->pos().y();    
    std::pair<double, double> p = m_r->calculate_index_of_the_coordinates(e->pos().x(), e->pos().y(), m_width, m_height);
    if(m_area_x0_coordinate <= e->pos().x() && m_area_y0_coordinate <= e->pos().y()
            && m_area_x0_coordinate + m_game_width >= e->pos().x() && m_area_y0_coordinate + m_game_height >= e->pos().y() )
    {
        start_timer();
        m_status = true;
        m_click_coords.first = p.first;
        m_click_coords.second = p.second;        
        game_process::RECT coords = m_r->calculate_cell_rect(p.first, p.second);                
        Figure* f = m_r->detect_figure_by_index(p.first, p.second);                 
        m_r->delete_cluster(this, f);
        //this->update(m_area_x0_coordinate + coords.x0, m_area_y0_coordinate + coords.y0, 57, 57);
    }
    game_process::RECT r;
    qDebug() << "Local:" << p.first;
    qDebug() << "Local:" << p.second;
}

void MainWindow::timerEvent(QTimerEvent *event)
{
    if(event->timerId() == m_timer_id)
    {        
        m_timer_tick = true;
        ++m_frame_count;
        if(m_x >=0 && m_y >=0)
        {
            qDebug()<<"m_x  "<<m_x <<"m_y  "<<m_y<<"time |||||| Passed";
            this->update(m_x, m_y, 60, 60);
        }
    }
    else
    {
        QWidget::timerEvent(event);
    }
}

void MainWindow::start_timer()
{
    m_timer_id = startTimer(50);
}

void MainWindow::end_timer()
{    
       killTimer(m_timer_id);     
}

bool MainWindow::event(QEvent *e)
{
    switch (e->type())
    {
        case QEvent::WindowActivate:
        case QEvent::WindowDeactivate:
          return true;
    }
    return QWidget::event(e);

}

Here's the code repaint_cells()

void game_process::repaint_cells(MainWindow* m)
{
    Figure* f = 0;    
    for(int i = 0; i < 8; ++i)
    {        
        for(int j = 0; j < 8; ++j)
        {
            if(m_close_list[j][i] == -1)
            {
                f = create_new_figure(j, i);
                m_figures.push_back(f);
                assert(f != 0);
                draw_figure(m, f, i, j);
                m_close_list[j][i] = 0;                
            }
        }
     }
}

enter link description here

For two days I can not understand why only one ball is drawn. Тhe remaining balls are not drawn.

2
The question comes down to: which class has access to all the information that render_cell needs? With that information you can create a new slot for that class, that then calls render_cell with all the needed parameters. You could also, instead of receiving the information as parameters query whatever class has the necessary information from within render_cell and keep your render_cell slot.Daniel Christiany
The timerEvent is an event, so you need to let the event loop process it. From what I see in your source code, you are busy waiting for the timer to fire. That is not how it works. The timerEvent is doing all the time scheduling for you. All you need to do is to call update() in timerEvent, which will cause updating the screen. To see an example of how this works, you can have a look at my game here, which uses timerEvent itself. The important file for you is Pexeso3D / src / game / CPexesoScene.cpp at the very bottom.jcxz
Also, in your delay function you are missing semicolon, which means that your while will process only on iteration (probably not what you want, but this may be just a typo). However, you should stop using delay functions like this, because they heavily load CPU. Instead consider implementing some type of state machine in your timerEvent or using singleShot QTimer.jcxz

2 Answers

0
votes

I see from your code snippet that you are passing a pointer to MainWindow to your render_cell() function, which I assume is some kind of widget or class derived from QObject.

In that case you could override the timerEvent(), which is defined for each QObject class and implement your game loop here. This way the parameters of your render_cell() could be be member variables of MainWindow, or your entire game_process class could be embedded in MainWindow.

Also, I think this approach is a little faster than using signals, which might be important for code that has to render something 30-60 times per second and update a bunch of other things.

For documentation see http://qt-project.org/doc/qt-4.8/qobject.html#timerEvent

In pseudo code, you could implement your game like this:

class MainWindow : public QWidget
{
  private:
    game_process *game;
    int timer_id;

  public:
    MainWindow(void)
      : QWidget(0),
        game(0),
        timer_id(0)
    {
      game = new game_process;
    }

    void startGame(void)
    {
      timer_id = startTimer(1000 / 30);   // 30 fps
    }

    void endGame(void)
    {
      killTimer(timer_id);
    }

  protected:
    virtual void timerEvent(QTimerEvent *event)
    {
       // update AI
       // update network
       // render game
       game->render_cell(/* params */);
    }

};
5
votes

You have two main approaches:

  1. Simply define another slot with no parameters that will call game_process::render_cell(), then connect to the new slot.

  2. If you're using Qt 5, use a lambda. See here for examples. It would look something like this: connect(timer, &QTimer::timeout, [=](){/*call the function here*/});

I recommend #2.