2015-10-29 35 views
0

我正在用qt 5.0.1創建一個簡單的遊戲。這就像Warblade。 我有創造敵人的波浪問題。產生敵人的海浪C++

int k; 
int pos = 100; 
for (k = 0; k < 5; k++) 
{ 
    pos = 100; 
    for (int i = 0; i < 9; i++) 
    { 
     player->spawn_in_pos(pos); 
     pos += 100; 
    } 
    //QThread::sleep(2); 
} 

當我使用睡眠()函數,我只是遊戲無法運行。它正在等待循環完成,然後顯示。

我還面臨着第二個選項:

QTimer * timer = new QTimer(); 
QObject::connect(timer, SIGNAL(timeout()), player, SLOT(spawn_in_pos(pos))); 
timer->start(450); 

但它看起來像SLOT無法得到的位置。

編輯: 我只是做了@ddriver說的,這對我很有幫助。 現在我得到一些'laggy'風格的敵人運動。

enter image description here

EDIT2:

我移動我的敵人下來是這樣的:

setPos(x(),y()+1); 

與計時器:

// connect 
QTimer * timer = new QTimer(this); 
connect(timer,SIGNAL(timeout()),this,SLOT(move())); 
// start the timer 
timer->start(10); 

看起來很流暢運動,但大概+1像素下降,10個計時器減少:((

+3

您無法將值傳遞給連接方法內的插槽。我建議你閱讀關於信號和插槽的內容:http://doc.qt.io/qt-5/signalsandslots.html –

+1

你是否希望通過詢問關於每一步的問題來製作整個遊戲?看起來你正在超越自己。我建議你拿起一本關於遊戲編程的書,並在你開始製作遊戲之前研究這個主題。你的方法非常天真,從根本上說是錯誤的。一種尺寸並不適合所有人,僅僅因爲計時器是產生敵方波的好方案並不意味着你應該爲每個遊戲對象使用專用計時器。這不是遊戲的工作原理。同時,堅持一個問題,這個問題是關於產生敵人,而不是敵人的運動。 – dtech

回答

0

調用睡眠會阻止線程處理任何事情,這不是您想要做的事情。

Using C++ 11,您可以使用QTimer用這樣的lambda函數: -

int pos = 100; 
int nextWaveTime = 2000; // 2 seconds per wave 
for (k = 0; k < 5; k++) // 5 waves of enemies 
{  
    for (int i = 0; i < 9; i++) // 9 enemies per wave 
    { 
     QTimer * timer = new QTimer(); 
     timer->setSingleShot(true); 

     pos = pos + (100*i); // set the pos, which is captured by value, in the lambda function 

     QObject::connect(timer, QTimer::timeout, [=](){ 
      player->spawn_in_pos(pos); 
      timer->deleteLater(); // must cleanup the timer 
     }); 

     timer->start(450 + (k*nextWaveTime)); 
    } 
} 
1

我不知道你想達到什麼樣的,但在你的第二個選擇,你不能得到的位置,因爲超時不會發送它。 信號超時(無效),您的插槽需要一個參數。我想你對信號/插槽機制缺乏一些基本的瞭解。 Qt文檔是非常簡潔: http://doc.qt.io/qt-5/signalsandslots.html

如果你只是想創建一個遊戲無中生有,在這裏你可以找到一個小教程,如何編寫遊戲在QT: https://www.youtube.com/watch?v=8ntEQpg7gck

0

爲了爲了傳遞帶有Qt中的信號和時隙的參數,信號參數必須與時隙的參數(或自Qt 5以來的函數)匹配。

解決此問題的一種方法是在TheDarkKnight的答案中使用lambda。

我建議使用封裝 - 你可以創建一個Spawner對象,專用於產生敵人並保持內部位置。通過這種方式,產卵者將管理該位置,並且您可以擁有像Spawner::createWave()插槽這樣的無參數插槽,因爲該位置是內部的。然後設置計時器並將其連接到createWave(),然後設置好。

此外,硬編碼這樣的東西是非常糟糕的主意,你真的需要更多的靈活性,選擇改變敵人和波數,波浪時間以及屏幕寬度,以便你的遊戲可以改變這些東西因爲它變得更難。

class Spawner : public QObject { 
    Q_OBJECT 
public: 
    Spawner(int wCount = 5, int eCount = 9, int time = 2000, int sWidth = 1000) 
     : waveCount(wCount), enemyCount(eCount), currentWave(0), screenWidth(sWidth) { 
     timer.setInterval(time); 
     connect(&timer, SIGNAL(timeout()), this, SLOT(createWave())); 
    } 
    void set(int wCount, int eCount, int time) { 
     timer.setInterval(time); 
     waveCount = wCount; 
     enemyCount = eCount; 
    } 
    void changeWidth(int w) { screenWidth = w; } 
public slots: 
    void start() { timer.start(); } 
    void stop() { 
     timer.stop(); 
     currentWave = 0; 
    }  
private slots: 
    void createWave() { 
     int pos = screenWidth/(enemyCount + 1); 
     int step = pos; 
     for (int i = 0; i < enemyCount; ++i) { 
      Game::spawnEnemyAt(pos); 
      pos += step; 
     } 
     if (++currentWave >= waveCount) stop(); 
    } 
private: 
    QTimer timer; 
    int waveCount, enemyCount, currentWave, screenWidth; 
}; 

創建Spawner對象和遊戲新臺階連接到start() - 這將跨越均勻地分佈在遊戲畫面的敵人給定數量的波浪,當你完成盪漾開,你調整產卵設置和啓動新的水平。

隨着遊戲變得越來越不像測試,更像真實的遊戲 - 隨着難度的增加,產卵和攻擊模式的變化等等,這種封裝將會在以後派上用場。因此,從一開始就實施它是一個好主意,並且建立在良好而靈活的設計之上,而不是回頭和改變周圍的東西,這可能會破壞其他代碼。如果沒有好的設計並且稍後進行設計更改,你真的不想開始。因此需要封裝功能和責任,只需連接各個部分,而不是在一堆意大利麪代碼的基礎上構建。在這一思路中,我注意到你使用的是player->spawn_in_pos(pos);--這是一個糟糕的設計的例子,因爲產卵應該是Game類的職責,而不是Player類。一個好的設計不僅靈活,而且乾淨。該物體只負責產生敵人的波浪,其可見接口限於start()stop()set()

編輯:

class Game : public QObject { 
    Q_OBJECT 
public: 
    Game() { 
     if (!scene) scene = new QGraphicsScene(this); 
     connect(this, SIGNAL(newLevel()), &spawner, SLOT(start())); 
    } 
    static void spawnEnemyAt(int x = 0) { 
     scene->addItem(new Enemy(x, 0)); 
     qDebug() << "enemy created"; 
    } 
public slots: 
    void newGame() { 
     // initialize game 
     emit newLevel(); // begin spawning 
    } 
    void onLevelEnd() { 
     // spawner.set(new level settings); 
     emit newLevel(); 
    } 
    void onGameEnded() { 
     // ... 
    } 
signals: 
    void newLevel(); 
private: 
    Spawner spawner; 
    static QGraphicsScene * scene; 
}; 

// in game.cpp 
QGraphicsScene * Game::scene = nullptr; 

如果你不希望使用靜態成員,可以使spawnEnemyAt()scene實例成員,但隨後你將不得不通過Game實例的Spawner在構造函數,因此你可以參考產卵者操作的遊戲並使用game->spawnEnemyAt()代替。這樣你就可以用自己的專用場景創建多個遊戲。或者讓遊戲中的親生父親參與遊戲,並將產卵者的parent()投射到Game *以訪問有點冒險的遊戲實例,但通過重用父代來保存額外的成員。