Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

mouse pos() returns wrong position



  • Hello !,
    So whenever i press right click, my character moves towards that position and its all working just fine till i get to the land
    check this video :
    https://streamable.com/cjo0d

    you can see when i print character current position and the positioning of the mouse ( when i press right click ) it gives me wrong coordinates ( from the mouse ) and i don't know why... Sea and Land are two different items ( classes ), both are QPixmap so maybe it has to do something with that ?
    Here is the main class code:

    Game.h:

    #ifndef GAME_H
    #define GAME_H
    #include "player.h"
    #include "button.h"
    #include "sea.h"
    #include "land.h"
    
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include <QObject>
    #include <QMouseEvent>
    #include <QGraphicsSceneMouseEvent>
    #include <QGraphicsScene>
    #include <QWidget>
    #include <QKeyEvent>
    
    class Game: public QGraphicsView{
        Q_OBJECT
    public:
        // this class stuff
        static QString in_room;
        Game(QWidget *parent=NULL);
        QGraphicsScene *scene;
        void menu();
        void createMap();
        void createPlayer();
        QPixmap darkenImage(QString image, float num);
    
        // other class stuff
        Player *player;
        Button *startButton;
        Button *quitButton;
        Land *land;
        Sea *sea;
    
        // static stuff
        int curr_pos_in_menu;
        void changeColorOfButton();
    
    public slots:
        void start();
        void mousePressEvent(QMouseEvent *event);
    };
    
    #endif // GAME_H
    

    Game.cpp:

    #include "game.h"
    #include "player.h"
    #include "button.h"
    
    #include <QGraphicsRectItem>
    #include <QGraphicsScene>
    #include <QDebug>
    #include <QApplication>
    #include <QTimer>
    #include <QFont>
    #include <QMessageBox>
    #include <fstream>
    #include <cmath>
    #include <QRect>
    #include <QDesktopWidget>
    #include <QtMath>
    
    QString Game::in_room = "menu";
    
    Game::Game(QWidget *parent)
    {
        scene = new QGraphicsScene();
        scene->setSceneRect(0,0,350,300);
        setFixedSize(350,300);
        setScene(scene);
        setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        setBackgroundBrush(QBrush(QImage("red")));
        show();
        menu();
    }
    
    void Game::menu()
    {
        QGraphicsTextItem *title = new QGraphicsTextItem("NIGHTLESS");
        title->setPos(10,30);
        title->setFont(QFont("comic sans",40,70));
        scene->addItem(title);
    
        qDebug() << width();
        startButton = new Button("START", 200, 50);
        startButton->setPos(width()/2-startButton->rect().width()/2,125);
        connect(startButton,SIGNAL(clicked()),this,SLOT(start()));
        scene->addItem(startButton);
    
        quitButton = new Button("QUIT", 200, 50);
        quitButton->setPos(width()/2-quitButton->rect().width()/2,200);
        connect(quitButton,SIGNAL(clicked()),this,SLOT(close()));
        scene->addItem(quitButton);
    
    }
    
    void Game::createMap()
    {
        land = new Land;
        land->setPos(0,0);
        scene->addItem(land);
    
        sea = new Sea;
        sea->setPos(0,0);
        scene->addItem(sea);
    }
    
    void Game::createPlayer()
    {
        player = new Player;
        player->setFlag(QGraphicsItem::ItemIsFocusable);
        player->setFocus();
        centerOn(player);
        scene->addItem(player);
    }
    
    QPixmap Game::darkenImage(QString file_name, float num)
    {
        QImage tmp( file_name );
    
        for(int i=0;i<tmp.height();i++)
        {
            for(int k=0;k<tmp.width();k++)
            {
                QColor color( tmp.pixel( k, i ) );   // changed this from pixelColor() to ensure alpha is copied
                if ( tmp.pixel(k,i) !=  0)    // modify only the pixels with non-zero alpha
                {
                    color.setRgb(color.red()*num,color.blue()*num,color.green()*num);
                    tmp.setPixelColor(k,i,color);
                }
            }
        }
    
        // Now, convert the image to a pixmap and set it on the graphics object
        QPixmap t = QPixmap::fromImage( tmp );
        return t;
    }
    
    void Game::start()
    {
        scene->clear();
        in_room = "world";
        // semi-transparent background
        /*
        QRect rec = QApplication::desktop()->screenGeometry();
        int height = rec.height();
        int width = rec.width();
        */
    
        setSceneRect(0,0,7097,7298);
        setFixedSize(1000,800);
        //setBackgroundBrush(QBrush(QImage(":/Images/Grass.png")));
        //showFullScreen();
    
        createMap();
        createPlayer();
    }
    
    void Game::mousePressEvent(QMouseEvent *event)
    {
        if(event->buttons() == Qt::RightButton && in_room!="menu"){
    
            QLineF ln(event->pos(),player->pos());
            int angle = -1 * ln.angle() + 460;
    
            int tmp = angle + 80;
            if(tmp>360)
                tmp-=360;
    
            if(angle > 360)
                angle += -360;
    
            player->setPlayerRotation(angle,tmp);
    
            QPointF t(event->pos());
            player->setDestination(event->pos());
    
        }
    }
    

    In the Land and Sea class i just setPixmap to the image, put them into the scene,set position and that is it.

    And i have one more question, how do i make a player stop when he reaches his destination ? i was thinking about making an QGraphicsRectItem whenever i press a right button and then checking if player has collided with that item and when he does he stops and then that item gets deleted or is there a better and easier way to do that, cause comparing mouse pos() and player pos() is not working.

    Any kind of help or advice is appreciated !!!


  • Lifetime Qt Champion

    Hi,

    For the "collision" checking, you can take a look at the colliding mice example.



  • @SGaist
    Hi thanks for the reply, i know how to do the collision thingy i just don't know if its worth doing it like that



  • @FlyDoodle
    Hi,
    for collision detection you can use shape() method. The shape is used for many things, including collision detection, hit tests, and for the QGraphicsScene::items() functions.
    https://doc.qt.io/archives/qt-4.8/qgraphicsitem.html#shape
    For better conversion between view coordinates and scene coordinates you can use mapToScene(QPoint) method. This method returns the viewport coordinate point mapped to scene coordinates. See more:
    https://doc.qt.io/archives/qt-4.8/qgraphicsview.html#mapToScene
    Lastly, you can see my repo. I did simple game which use collision detecion. It may help you:

    bool Hero::onCollisionEnter(QString collider)
    {
        //Calculate a type of collision
        int sumOfCollision = 0;
        QList<QGraphicsItem*> colliderList = collidingItems();
        for(int idx = 0; idx < colliderList.size(); ++idx)
        {
            if(collider == "Background")
            {
                //QGraphicsItem *item = qgraphicsitem_cast<BlueBackground*>(colliderList[idx]);
                if(qgraphicsitem_cast<BlueBackground*>(colliderList[idx]))
                {
                    sumOfCollision += 1;
                }
                //Brick | Evil1 | Bullet |
                else if(qgraphicsitem_cast<Brick*>(colliderList[idx]) ||
                        qgraphicsitem_cast<Ground*>(colliderList[idx]) ||
                        qgraphicsitem_cast<Evil1*>(colliderList[idx]) ||
                        qgraphicsitem_cast<Bullet*>(colliderList[idx])
                        )
                {
                    sumOfCollision += 1;
                }
            }
        }
        if(sumOfCollision == 1)
        {
            return true;
        }
        return false;
    }
    

    Link to this repo: https://github.com/Przemekkkth/Qt-C-SimpleGame



  • @Bondrusiek
    Hello !
    I tried using mapToScene before and i realized that when i was creating a QLine item between the player and the mouse position i forgot to use it and now it's working all fine.
    About that colliding thingy i will take a look, thank you !
    I have taken a look at your game and it's amazing, but i couldn't find how you did that player movement ? i tried looking for it and i found keyPressedEvent functions but there were no == Qt::key_W stuff and so on for movement, only for space.

    Tho i have one more question, how do i put waves (image) around my island in the game as the background. I want to make it so that for example 60 x 60 pixels waves fill the background ( or the item that is around the island ). Doing setBackgroundBrush(QBrush(QImage("path"))); will set the background the way i want it to, but the problem is when the player is moving and he gets near the water, he has to stop. I want to check if he is near the water using collision.I have class Land and class Sea and they are both QGraphicsPixmapItems and i could just check if the player has collided with the Sea class but the problem comes when i want the sea to be moving, and i would do that using 2 pictures and changing between them but changing pictures takes time especially if the image is that big and that's not optimal...



  • @FlyDoodle , I used GetAsyncKeyState() (https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate) to control my hero. This function monitore the status of the keyboard keys used by the function of the WinAPI.
    When you want to collide one object with another object, Objects must be QGraphicsItem or descendant. You can creater bigger geometry for shape() than bouncingRect() for detect collision and next:

        QList<QGraphicsItem*> colliderList = collidingItems();
        for(int idx = 0; idx < colliderList.size(); ++idx)
        {
                if(qgraphicsitem_cast<Land*>(colliderList[idx]))
               {
                   //collide with Land
               }
               else if(qgraphicsitem_cast<Sea*>(colliderList[idx]))
               {
                   //collide with Sea
               }
    


  • @Bondrusiek
    Oh i see, I'll check that out !
    And thank you for the code, everything is working fine now !



  • @FlyDoodle why not use QML?




Log in to reply