QT:即使在 static_cast 之后也无法在主窗口中设置对象的位置
QT: cannot set position of an object in mainwindow even after static_cast
我正在制作一个小游戏,我希望游戏中的敌人能够同时自动移动和产生子弹。
到目前为止,我的敌人可以自动移动并自动生成子弹,但问题是
my bullet cannot follow the enemy's movement and spawn at the different
start point of the enemy.
更具体地说,
I want to catch the very position of the enemy every time the enemy spawn bullet. However, I cannot setPos my bullet dynamically.
现在,我分别设计了敌人移动函数(enemyMove())和生成子弹函数(MakeBall())。我在 mainwindow 构造函数中为每个函数设置了不同的计时器,以便每次 window 时自动调用该函数。
到目前为止我的尝试和想法:
- 我的敌人是 class 敌人的对象,但我有静态施法
这个对象在主 window 构造函数中指向 QGraphicsPixmapItem,所以我
认为它应该能够使用敌人作为 QGraphicsPixmapItem。
但是,当我尝试在我的 MakeBall() 中做 enemy->x() 之类的事情时
函数,编译器强行结束。
- 我将敌人的位置作为参数发送给 MakeBall 函数,这样
子弹可以在敌人的位置设置Pos。然而,
编译器说这是对非常量的无效初始化
从类型 'int'.
的右值引用类型 'int&'
- 我将 QGraphicsPixmapItem *enemy 作为参数发送给 MakeBall 函数
并使用 enemy->x() 来捕捉它的位置,然而,它最终甚至没有
产生任何子弹,这意味着从未调用 MakeBall 函数
成功。
任何分享或建议将不胜感激。非常非常感谢。
主要window.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;
}
主要window.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());
}
enemy.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
一般来说,您希望避免将 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;
然后您可以创建小部件,这些小部件将使用模型将元素绘制到它们的位置。
我正在制作一个小游戏,我希望游戏中的敌人能够同时自动移动和产生子弹。
到目前为止,我的敌人可以自动移动并自动生成子弹,但问题是
my bullet cannot follow the enemy's movement and spawn at the different start point of the enemy.
更具体地说,
I want to catch the very position of the enemy every time the enemy spawn bullet. However, I cannot setPos my bullet dynamically.
现在,我分别设计了敌人移动函数(enemyMove())和生成子弹函数(MakeBall())。我在 mainwindow 构造函数中为每个函数设置了不同的计时器,以便每次 window 时自动调用该函数。
到目前为止我的尝试和想法:
- 我的敌人是 class 敌人的对象,但我有静态施法 这个对象在主 window 构造函数中指向 QGraphicsPixmapItem,所以我 认为它应该能够使用敌人作为 QGraphicsPixmapItem。 但是,当我尝试在我的 MakeBall() 中做 enemy->x() 之类的事情时 函数,编译器强行结束。
- 我将敌人的位置作为参数发送给 MakeBall 函数,这样 子弹可以在敌人的位置设置Pos。然而, 编译器说这是对非常量的无效初始化 从类型 'int'. 的右值引用类型 'int&'
- 我将 QGraphicsPixmapItem *enemy 作为参数发送给 MakeBall 函数 并使用 enemy->x() 来捕捉它的位置,然而,它最终甚至没有 产生任何子弹,这意味着从未调用 MakeBall 函数 成功。
任何分享或建议将不胜感激。非常非常感谢。
主要window.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;
}
主要window.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());
}
enemy.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
一般来说,您希望避免将 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;
然后您可以创建小部件,这些小部件将使用模型将元素绘制到它们的位置。