문제

In my game, I'd like to fire rockets from a rocket launcher. The player holds a rocket launcher as a child item. The rockets must be parentless. I'm trying to position the rocket so that its back lines up with the back of the rocket launcher (the player is facing north in the screenshots) and centered horizontally within it:

correct

Instead, what I'm getting is:

incorrect

The rotation is also incorrect (run the example and move the mouse cursor around to see what I mean). Where am I going wrong in my code?

#include <QtWidgets>

QPointF moveBy(const QPointF &pos, qreal rotation, float distance)
{
    return pos - QTransform().rotate(rotation).map(QPointF(0, distance));
}

float directionTo(const QPointF &source, const QPointF &target) {
    QPointF toTarget(target.x() - source.x(), target.y() - source.y());
    float facingTarget = qRadiansToDegrees(atan2(toTarget.y(), toTarget.x())) + 90.0f;
    facingTarget = fmod(facingTarget, 360.0f);
    if(facingTarget < 0)
        facingTarget += 360.0f;
    return facingTarget;
}

class Controller : public QObject
{
public:
    Controller(QGraphicsScene *scene) :
        mScene(scene)
    {
        mPlayer = scene->addRect(0, 0, 25, 25, QPen(Qt::blue));
        mPlayer->setTransformOriginPoint(mPlayer->boundingRect().width() / 2, mPlayer->boundingRect().height() / 2);

        mRocketLauncher = scene->addRect(0, 0, 16, 40, QPen(Qt::green));
        mRocketLauncher->setParentItem(mPlayer);
        mRocketLauncher->setPos(mPlayer->boundingRect().width() * 0.9 - mRocketLauncher->boundingRect().width() / 2,
            -mRocketLauncher->boundingRect().height() * 0.3);

        mRocket = scene->addRect(0, 0, 16, 20, QPen(Qt::red));
        scene->installEventFilter(this);

        QGraphicsTextItem *playerText = scene->addText("Player");
        playerText->setPos(0, 100);
        playerText->setDefaultTextColor(Qt::blue);
        QGraphicsTextItem *rocketLauncherText = scene->addText("Rocket launcher");
        rocketLauncherText->setPos(0, 120);
        rocketLauncherText->setDefaultTextColor(Qt::green);
        QGraphicsTextItem *rocketText = scene->addText("Rocket");
        rocketText->setPos(0, 140);
        rocketText->setDefaultTextColor(Qt::red);
    }

    bool eventFilter(QObject *, QEvent *event) {
        if (event->type() == QEvent::GraphicsSceneMouseMove) {
            const QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
            mPlayer->setRotation(directionTo(mPlayer->sceneBoundingRect().center(), mouseEvent->scenePos()));

            qreal rocketX = mRocketLauncher->sceneBoundingRect().center().x() - mRocket->boundingRect().width() / 2;
            QPointF rocketPos(rocketX, 0);
            rocketPos = moveBy(rocketPos, mPlayer->rotation(), mRocketLauncher->boundingRect().height() - mRocket->boundingRect().height());
            mRocket->setPos(rocketPos);
            mRocket->setRotation(mPlayer->rotation());

            return true;
        }
        return false;
    }
private:
    QGraphicsScene *mScene;
    QGraphicsRectItem *mPlayer;
    QGraphicsRectItem *mRocketLauncher;
    QGraphicsRectItem *mRocket;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QGraphicsView view;
    view.setMouseTracking(true);
    QGraphicsScene *scene = new QGraphicsScene;
    view.setScene(scene);

    Controller controller(scene);

    view.resize(300, 300);
    view.show();

    return app.exec();
}
도움이 되었습니까?

해결책

The idea is to:

  1. set rotation of both items;
  2. get positions of bottom left corner of launcher and rocket in global (scene) coordinates;
  3. shift rocket to make positinos equal.

Code:

mPlayer->setRotation(directionTo(mPlayer->sceneBoundingRect().center(), 
                                 mouseEvent->scenePos()));
mRocket->setRotation(mPlayer->rotation());
QPointF launcherPos = mRocketLauncher->mapToScene(
  mRocketLauncher->boundingRect().bottomLeft());
QPointF currentRocketPos = mRocket->mapToScene(
  mRocket->boundingRect().bottomLeft());
mRocket->setPos(mRocket->pos() - currentRocketPos + launcherPos);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top