Ответы пользователя по тегу Разработка игр
  • Как рассчитать "плавный" угол поворота спрайта (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
    Ответ написан
    Комментировать
  • Как узнать координаты точек (вершин)?

    @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;
    }
    Ответ написан