【问题标题】:QT: cannot set position of an object in mainwindow even after static_castQT:即使在 static_cast 之后也无法在主窗口中设置对象的位置
【发布时间】:2018-06-06 01:02:26
【问题描述】:

我正在制作一个小游戏,我希望游戏中的敌人同时移动并自动生成子弹。

到目前为止,我的敌人可以自动移动并产生子弹,但问题是

我的子弹无法跟随敌人的移动并在不同的地方生成 敌人的起点。

具体来说,

每次敌人产生子弹时,我都想抓住敌人的位置。但是,我不能动态设置我的子弹位置。

现在,我分别设计了移动敌人的函数(enemyMove())和生成子弹的函数(MakeBall())。我在我的主窗口构造函数中为每个函数设置了一个不同的计时器,以便在每个时间窗口自动调用该函数。

到目前为止我的尝试和想法:

  • 我的敌人是 Enemy 类的对象,但我使用了静态施法 这个对象到主窗口构造函数中的 QGraphicsPixmapItem ,所以我 认为它应该能够将敌人用作 QGraphicsPixmapItem。 但是,当我尝试在 MakeBall() 中执行诸如 enemy->x() 之类的事情时 函数,编译器强行结束。
  • 我将敌人的位置作为参数发送给 MakeBall 函数,这样 子弹可以在敌人的位置设置Pos。然而, 编译器说这是非常量的无效初始化 从“int”类型的右值引用“int&”类型。
  • 我将 QGraphicsPixmapItem *enemy 作为参数发送给 MakeBall 函数 并使用enemy->x() 来捕捉它的位置,然而,它最终甚至没有 产生任何子弹,这意味着 MakeBall 函数从未被调用 成功。

任何分享或建议都将不胜感激。非常感谢。

主窗口.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent):
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    enemyMoveTimer(new QTimer),
    balldrop(new QTimer),
    makeballtimer(new QTimer)
{ 
    ui->setupUi(this);
    //scene
    scene = new QGraphicsScene(0, 0, 1050, 600);
    //view
    view = new QGraphicsView;
    view ->setScene(scene);
    setCentralWidget(view);

    //enemy
    Enemy * enemy = new Enemy();
    enemy->setPixmap(QPixmap(QPixmap(":/img/ghost.gif").scaled(100,100)));
    enemy->setPos(0,0);
    scene->addItem(static_cast<QGraphicsPixmapItem*>(enemy));

    enemyMoveTimer->start(100);
    enemy->connect(enemyMoveTimer, SIGNAL(timeout()), enemy, SLOT(enemyMove()));

    //enemy's bullet
    makeballtimer->start(1000);
    //int & x=enemy->x();
    //connect(makeballtimer, SIGNAL(timeout()), this, SLOT(MakeBall(int & x)));
    connect(makeballtimer, SIGNAL(timeout()), this, SLOT(MakeBall(QGraphicsPixmapItem * enemy)));

}


void MainWindow::MakeBall(QGraphicsPixmapItem * enemy)
{
    EnemyBullet * ball = new EnemyBullet();
    ball->setPixmap(QPixmap(":/img/yellowblankball.png").scaled(50, 30));

    ball->setPos(enemy->x()+50, 100);//the problem is here

    balldrop->start(100);
    ball->connect(balldrop, SIGNAL(timeout()), ball, SLOT(fall()));
    scene->addItem(static_cast<QGraphicsPixmapItem*>(ball));
}

MainWindow::~MainWindow()
{
    delete ui;
}

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QTimer>
#include <QKeyEvent>
#include <QtGui>

#include "enemy.h"
#include "ball.h"
#include "enemybullet.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    //virtual void MakeBall(int &x);
    virtual void MakeBall( QGraphicsPixmapItem * enemy);
    //virtual void MakeBall();

private:
    Ui::MainWindow *ui;
    QGraphicsScene *scene;
    QTimer *enemyMoveTimer;
    QTimer *balldrop;
    QTimer *makeballtimer;
    QGraphicsItem *enemy;

    QGraphicsView * view;

};

#endif // MAINWINDOW_H

enemybullet.cpp

#include "enemybullet.h"
#include <QTimer>
#include <QGraphicsScene>
#include <QList>

EnemyBullet::EnemyBullet()
{

}

void EnemyBullet::fall()
{
    setPos(x(), y() +10 );
}

enemybullet.h

#ifndef ENEMYBULLET_H
#define ENEMYBULLET_H

#include <QObject>
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>

class EnemyBullet: public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT

public:
    EnemyBullet();

public slots:
    void fall();
};


#endif// ENEMYBULLET_H

enemy.cpp (修剪到本质。它实际上可以从左到右和从右到左重复移动。所以我们无法计算产生子弹的具体时间,因为每个位置都会一次又一次地重新访问。 )

#include "enemy.h"
#include "enemybullet.h"
#include <QDebug>

Enemy::Enemy()
{

}

void Enemy::enemyMove()
{
      setPos(x() + 10,y());
}

敌人.h

#ifndef ENEMY_H
#define ENEMY_H

#include <QObject>
#include <QGraphicsPixmapItem>
#include <QTimer>


class Enemy:  public QObject,public QGraphicsPixmapItem
{
    Q_OBJECT

public:
    Enemy();

public slots:
    void enemyMove();
};

#endif // ENEMY_H

【问题讨论】:

    标签: c++ qt casting pass-by-reference qgraphicspixmapitem


    【解决方案1】:

    通常,您希望避免将 UI 代码与数据结构混合,这样可以更容易扩展,因此在您的情况下,我真的建议创建仅包含数据和 UI 的支持数据类。

    但是,您的问题是您正在混合信号和插槽 - 您正在将 QTimer::timeout() 信号连接到您的插槽,该插槽采用 QGraphicsPixmapItem * 类型的参数。虽然这个编译我认为至少在调试模式下你会收到消息说信号和插槽不兼容。最好使用这样的现代连接样式:

     connect(makeballtimer, &QTimer::timeout, this, &MainWindow::MakeBall);
    

    因为这个符号在编译时已经失败了。

    我对您的建议是:创建模型类(或结构,这完全取决于您),它只保存与每个元素关联的数据;例如:

    struct Enemy {
        QPoint position;
    };
    
    struct BulletModel {
        std::shared_ptr<Enemy> enemy;
        QPoint position;
    };
    

    然后你的敌人列表将被存储为std::shared_ptr 的向量,以确保他们的生命周期得到管理:

    std::vector<std::shared_ptr<Enemy>> m_enemies;
    

    然后你可以创建敌人和子弹:

    auto enemy = std::make_shared<EnemyModel>();
    auto bullet = std::make_shared<BulletModel>();
    bullet->enemy = enemy;
    

    然后您可以创建将使用模型将元素绘制到其位置的小部件。

    【讨论】:

    • 感谢分享,但我仍然很困惑将这些代码放在哪里。如果我将 QPoint 位置放到新创建的结构中。我怎样才能得到敌人的位置?而且,我不明白为什么使用自动来创建我的敌人和子弹,自动确定时间窗口???
    • 你能指定把 std::vector<:shared_ptr>> m_enemies; 放在哪里吗?抱歉>
    • 在我们深入探讨之前,您介意告诉我您为什么选择 C++ 吗?如果您想坚持使用 Qt,您可能会更喜欢 Unity 或 QML 之类的东西。 QML 也是硬件加速的,它的语法更加友好。
    • 嗯,实际上因为这是我在学校的一项作业。需要使用 c++ qt 执行此操作。我以前学过Unity,但我还没有听说过QML,也许我以后应该学习一下。但现在,我别无选择,只能赚我的分数>
    • 好吧,除非你真的想学习如何正确地解决我指出的问题。主要问题是 QTimer 发出没有参数的信号,但您的方法需要 QGraphicsPixmapItem 类型的参数。最简单的解决方案是将指向 Enemy 的指针存储为类变量(类似于场景和视图),然后删除函数 MakeBall 的参数。这应该能让你继续前进。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 2011-01-27
    • 2013-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多