• На чём писать клиентское приложение с GUI?

    QtWidgets - быстро
    QtQuick - красиво
    PyQt - молодежно
    Ответ написан
    1 комментарий
  • Как реализовать чат на вебсокетах?

    Ответ написан
    Комментировать
  • Как написать чат на websocket'ax (javascript)?

    C++Qt + PHP + WorkerMan: Чат на WebSocket'ах
    Ответ написан
    Комментировать
  • Как создать QML тип?

    @wxmaper Автор вопроса
    Такс, вот с этим разобрался:
    Model {
        anode: Anode {
        }
    }


    Нужно было дополнительно объявить типы через макрос QML_DECLARE_TYPE:
    QML_DECLARE_TYPE(Model)
    QML_DECLARE_TYPE(Anode)


    Но с этим ошибка по прежнему сохраняется...
    Model {
        Anode {
        }
    }


    Похоже нужен еще какой-то магический макрос :)

    Upd.
    Очень хитрый Qt! Залез в QQuickItem и подглядел что там у него есть... А есть у него задействованный макрос Q_CLASSINFO.
    В общем проблема решилась добавлением макроса таким образом:
    class Model : public QObject
    {
        Q_OBJECT
    
        Q_PROPERTY(Anode* anode READ anode WRITE setAnode NOTIFY anodeChanged)
    
        Q_PROPERTY(QObject* item WRITE addItem)
        Q_CLASSINFO("DefaultProperty", "item")
    
    public:
        explicit Model(QObject *parent = Q_NULLPTR);
    
    public slots:
        void addItem(QObject* item);
    }


    При создании объекта Anode вызывается метод Model::addItem. А там уже можно объекту Anode установить в качестве родителя объект Model.
    Ответ написан
    Комментировать
  • Есть ли алгоритм для наиболее быстрого нахождения включает ли одна фигура другую?

    Это можно сделать через 2 проекции: на оси 0x и 0y для каждой фигуры. В итоге получаем 4 отрезка. Сравниваем координаты двух отрезков на одной прямой, если обе проекции первой фигуры "поглощают" проекции второй, то значит фигура 2 находится внутри фигуры 1.

    Примерный алгоритм
    struct Plane {
        int px1 = 0;
        int px2 = 0;
        int py1 = 0;
        int py2 = 0;
    };
    
    Plane getPlane(const QPolygon &shape) {
        Plane plane;
        plane.px1 = shape.at(0).x();
        plane.px2 = plane.px1;
        plane.py1 = shape.at(0).y();
        plane.py2 = plane.py1;
    
        foreach (const QPoint &point, shape) {
            if(point.x() < plane.px1) plane.px1 = point.x();
            if(point.x() > plane.px2) plane.px2 = point.x();
            if(point.y() < plane.py1) plane.py1 = point.y();
            if(point.y() > plane.py2) plane.py2 = point.y();
        }
    
        return plane;
    }
    
    void test()
    {
        QPolygon shapeA;
        shapeA.append(QPoint(100,100));
        shapeA.append(QPoint(120,90));
        shapeA.append(QPoint(150,110));
        shapeA.append(QPoint(150,130));
        shapeA.append(QPoint(120,140));
        shapeA.append(QPoint(90,130));
    
        QPolygon shapeB;
        shapeB.append(QPoint(100,120));
        shapeB.append(QPoint(110,110));
        shapeB.append(QPoint(140,120));
        shapeB.append(QPoint(120,130));
        shapeB.append(QPoint(100,190));
    
        Plane planeA = getPlane(shapeA);
        Plane planeB = getPlane(shapeB);
    
        if(planeA.px1 < planeB.px1
                && planeA.px2 > planeB.px2
                && planeA.py1 < planeB.py1
                && planeA.py2 > planeB.py2) {
            qDebug() << "Фигура B в фигуре A!";
        }
        else if(planeA.px1 > planeB.px1
                && planeA.px2 < planeB.px2
                && planeA.py1 > planeB.py1
                && planeA.py2 < planeB.py2) {
            qDebug() << "Фигура A в фигуре В!";
        }
        else {
            /* nothing */
        };
    }



    Можно его дополнить условиями на обнаружение неполных вхождений. Алгоритм очень легкий, но у него есть минус: он работает только с выпуклыми фигурами. Если фигура будет в форме подковы и в середине этой подковы будет другая фигура, алгоритм решит что фигуры лежат друг в друге.

    Вот реализация с подробным описанием www.gamedev.ru/code/articles/?id=4195
    Ответ написан
    Комментировать
  • Как рассчитать "плавный" угол поворота спрайта (2D)?

    @wxmaper Автор вопроса
    Вот что получилось:

    bool QTDTower::rotateTo(QTDUnit *unit, qint64 time)
    {
        // если обновление произошло слишком быстро, 
        // пропускаем ход
        qint64 elapsed = time - m_lastTime;
        if(!elapsed)
            return false;
    
        m_lastTime = time;
    
        QPointF unitCenterPos = unit->centerPos();
        QPointF thisCenterPos = centerPos();
        QPointF diff = unitCenterPos - thisCenterPos;
    
        // новый угол поворота
        qreal angle = qAtan2(diff.y(), diff.x()) * (180/M_PI);
    
        // скорость поворота
        qreal delta = m_rotationSpeed * elapsed/1000.0f;
    
        // выгодное направление поворота
        qint8 disp = 1;
        if(angle > rotation())
            if(angle - rotation() > 180) disp = -1;
            else disp = 1;
        else
            if(rotation() > angle)
                if(rotation() - angle > 180) disp = 1;
                else disp = -1;
        
        qreal newRotation = rotation() + delta * disp;
    
        // предотвращаем "переповорот" (сглаживание) 
        if((newRotation < 0 && newRotation < angle)
                || (newRotation > 0 && newRotation > angle))
            newRotation = angle;
    
        // фиксируем диапазон
        if(newRotation > 180) newRotation = (360 - newRotation) * -1;
        else if(newRotation < -180) newRotation = (360 + newRotation);
    
        // рассчитываем оставшийся угол поворота
        qreal adiff = newRotation - angle;
        if (adiff < 0) adiff += 360;
        if (adiff > 180) adiff = -(360 - adiff);
        
        // поворачиваем
        setRotation(newRotation);
        
        // если оставшийся угол удовлетворяет углу атаки 
        // (например от 0 до 20 градусов), то можно стрелять
        return qAbs(adiff) < m_attackAngle;
    }
    Ответ написан
    Комментировать
  • Как рассчитать позицию отрисовки тайла на изометрической сетке?

    @wxmaper Автор вопроса
    В общем получилось вот что:
    property var mapObjects: [
            { "row": 4, "col": 2, "wsize": 1, "hsize": 1, "wpos": 0, "hpos": 0,
                "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 },
            { "row": 4, "col": 2, "wsize": 2, "hsize": 2, "wpos": 1, "hpos": 1,
                "source": "qrc:/tiles/001-001-00.png", "width": 2079, "height": 3249 }, // tree
            { "row": 4, "col": 3, "wsize": 2, "hsize": 2, "wpos": 1, "hpos": 1,
                "source": "qrc:/tiles/001-002-00.png", "width": 1100, "height": 823 }, // tree
            { "row": 4, "col": 2, "wsize": 1, "hsize": 1, "wpos": 1, "hpos": 1,
                "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 }, 
            { "row": 4, "col": 3, "wsize": 1, "hsize": 1, "wpos": 1, "hpos": 0,
                "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 },
            { "row": 4, "col": 3, "wsize": 1, "hsize": 1, "wpos": 1, "hpos": 1,
                "source": "qrc:/tiles/002-000-00.png", "width": 500, "height": 373 },
        ]
    
    function createMapObjects() {
        mapObjects.map(function(tileInfo) {
            // нормализация размера создаваемого тайла
            var tile_w = tileWidth * tileInfo.wsize / cellDivider
            var tile_h = tileWidth/tileInfo.width * tileInfo.height * tileInfo.hsize / cellDivider
    
            // левая верхняя координата описывающего клетку прямоугольника
            var tile_sx = (map.width/2 + tileInfo.col*tileWidth/2 - tileInfo.row*tileWidth/2 - tileWidth/2)
            var tile_sy = (tileInfo.row*tileHeight/2 + tileInfo.col*tileHeight/2) - tile_h
    
            // координата создаваемого тайла
            var tile_x = tile_sx + tileWidth/cellDivider * tileInfo.wsize/cellDivider
                    + (tileWidth/cellDivider * tileInfo.wsize/cellDivider * tileInfo.wpos) * (cellDivider - tileInfo.wsize)
                    - (tileHeight/cellDivider * tileInfo.hsize * tileInfo.hpos)
    
            var tile_y = tile_sy + tileHeight/cellDivider * tileInfo.hsize/cellDivider
                    + (tileHeight/cellDivider * tileInfo.hsize/cellDivider * tileInfo.hpos) * (cellDivider - tileInfo.hsize)
                    + (tileHeight/cellDivider * tileInfo.wsize/cellDivider * tileInfo.wpos) * (cellDivider - tileInfo.wsize)
        })
    }


    Формулы дикие и, как выяснилось, подходят только для cellDivider = 2 ;-(
    уверен, можно сделать проще и правильнее :D

    2cff51d94cac4f358074b1df04ea80ed.png
    Ответ написан
    Комментировать
  • Как правильно передать void в функцию (C++/Qt)?

    @wxmaper Автор вопроса
    Короче сделал так:

    bool call(QWidget *qo, QMetaMethod metaMethod, QGenericReturnArgument *returnArgument)
    {
        /* ... */
        return metaMethod.invoke(qo, *returnArgument);
    }
    
    void somefunction()
    {
        void *vlayout;
        QGenericReturnArgument returnArgument(metaMethod.typeName(), &vlayout);
    
        if( call(qo, metaMethod, &returnArgument) ) {
            QLayout *layout = reinterpret_cast<QLayout*>(vlayout); 
            /* ... */
        }
    }

    работает.
    Ответ написан
    Комментировать
  • Как правильно собрать приложение Qt с динамической библиотекой?

    @wxmaper Автор вопроса
    Разобрался. Оказывается все решается в два щелчка: в исходники библиотеки нужно было добавить __declspec(dllexport) перед расшаренными функциями/классами.
    Ответ написан
    Комментировать
  • Как отсортировать объекты в массиве?

    @wxmaper Автор вопроса
    Все, разобрался, вместо Arrays нужно использовать Collections
    Ответ написан
    Комментировать
  • Как создать сигнал в классе javascript?

    @wxmaper Автор вопроса
    Всё оказалось намного проще чем я себе представлял =)
    function TTCache(){}
    
    TTCache.prototype = {
        check : function() {
            /* ... */
            this.onReady()
        },
        onReady : function(){}
    }
    
    myfunction() {
      var ttcache = new TTCache();
    
      ttcache.onReady = function {
        /* продолжаем работать */
      }
    
      ttcache.check();
    }
    Ответ написан
    Комментировать
  • Как узнать координаты точек (вершин)?

    @wxmaper Автор вопроса
    Включил мозг и разобрался =) грубо говоря, найти эти точки можно так:
    // псевдокод
    frontPoint.x = cos ( body->rotation * PI / 180 ) * body->centerX() + body->width() / 2;
    frontPoint.y = sin ( body->rotation * PI / 180 ) * body->centerY() + body->height() / 2;
    rearPoint.x = cos ( body->rotation * PI / 180 ) * body->centerX() - body->width() / 2;
    rearPoint.y = sin ( body->rotation * PI / 180 ) * body->centerY() - body->height() / 2;


    Если учесть все "опасные" углы, то получится так:
    // реализация на Qt
    qint16 angle = qRound(body->rotation());
    qint16 newFrontY, newRearY, newFrontX, newRearX;
    
    if(angle == 0 || qAbs(angle) == 180) {
        newFrontY = qFloor((newY - body->height()/2.1) / mCellSize);
        newRearY =  qFloor((newY + body->height()/2.1) / mCellSize);
    }
    else {
        newFrontY = qAbs(qSin(angle * PI_DIFF_180) * newY - body->height()/2.1) / mCellSize;
        newRearY = qAbs(qSin(angle * PI_DIFF_180) * newY + body->height()/2.1) / mCellSize;
    }
    
    if(qAbs(angle) == 90 || qAbs(angle) == 270) {
        newFrontX = qFloor((newX - body->width()/2.1) / mCellSize);
        newRearX = qFloor((newX + body->width()/2.1) / mCellSize);
    }
    else {
        newFrontX = qAbs(qCos(angle * PI_DIFF_180) * newX - body->width()/2.1) / mCellSize;
        newRearX = qAbs(qCos(angle * PI_DIFF_180) * newX + body->width()/2.1) / mCellSize;
    }
    Ответ написан
  • Как организовать удаление скрытых компонентов в Qt QML?

    @wxmaper Автор вопроса
    Решение вопроса: www.cyberforum.ru/qt/thread1328440.html
    Ответ написан
    Комментировать
  • Как в QML отобразить список без скролла?

    @wxmaper Автор вопроса
    ListView {
        ...
        ListView {
            interactive: false
        ...
        }
    }
    Ответ написан
    Комментировать
  • QML, Android. XMLHttpRequest работает только с включенным wifi, почему?

    @wxmaper Автор вопроса
    Разобрался в чем была проблема! =[ Для сборки проекта я использовал Qt 5.4.0 beta. Скачал версию 5.3.2 - там все работает и в 3g и в wifi! 2 дня сидел тупил (( столько времени потратил...
    Ответ написан
    Комментировать
  • Клиент-клиент приложения. Как они работают?

    Не знаю как правильно объяснить, но utorrent работает через сервер (трекер), адрес которого записывается в самом torrent-файле. Трекеров может быть несколько, именно через них происходит обнаружение клиентов друг другом, а дальше между ними устанавливается обычное соединение, типа сокета что-ли
    Ответ написан
    Комментировать
  • Как сделать подвал сайта статичным?

    сверстай примерно так:

    < div style="display: table;height:100%">
    < div style="display:table-row">
    < div style="display:table-cell">ШАПКА< / div>
    < / div>

    < div style="display:table-row">
    < div style="display:table-cell">ТЕЛО< / div>
    < / div>

    < div style="display:table-row; height:1px">
    < div style="display:table-cell">ПОДВАЛ< / div>
    < / div>
    < / div>

    Кстати, зачем индекс отрицательный? Не надо так, потому футер и не видно!
    Ответ написан