2008年9月2日 星期二

qt -canvas - 物件之間的碰撞

現在要開始研究如何讓canvasitem之間的物件碰撞時,會觸發碰撞的訊息~

非常好~在QT中就內建了這一個函數!

bool QCanvasItem::collidesWith ( const QCanvasItem * other ) const [pure virtual]

這一個透過上一篇文章的例子做一些修改,可以知道這一個可以正確運作無誤~

void contentsMousePressEvent(QMouseEvent *e)
{
  r->move(e->pos().x(), e->pos().y());
  if (r->collidesWith(p))
    t->setText("Collision");
  else
    t->setText("That is ok!");
}

當我按滑鼠時,程式會判斷三角型與正方型是否有碰撞~

基本上應該是要讓程式自己去偵測兩物是否有碰撞,而不是我去按滑鼠後,才去偵測~

目前我知道設定完setAdvancePeriod後,時間到後會自動呼叫advance(),
基本上偵測的function應該是要放在advance()裡面~
但是,void QCanvas::advance () [virtual slot]是父類別的function,而時間到的時候呼叫的是父類別的advance(),那麼應該如何修改,才會讓它呼叫子類別另外定義的advance哩~這是我目前需要解決的問題~明天試試看,先新建一個類別繼承QCanvas,然後,重新定義advance()試試看~有點累了~回家睡覺吧~

[2008.09.3 更新]
在今天早上研究到現在總算成功的讓每30毫秒就去判斷一次物件是否有碰撞到~
話不多說~直接把程式碼貼上來吧~我覺得我的方法還蠻笨的,沒有用到物件導向的精神~
我想當我上過這一個學期的物件導向後,應該會有更深入的認知吧~

說明主要的精神:
現在有兩個類別myqcanvas、View這兩個類別,而在main.cpp設定myqcanvas的velocity後,每30ms會呼叫advance()一次。因此我另外改寫了myqcanvas的advance,這裡有用到virtual function的觀念,請參考c++ - virtual function
本來View、myqcanvas是兩個獨立的類別,但是,為了要讓View中的兩個圖形可以在myqcanvas的advance()判斷是否有碰撞,因此,在View中設定了三個回傳指標的public function。並在myqcanvas設定一個function可以設定這三個物件的指標。
本來每30豪秒會呼叫QCanvas::advance(),但是,因為,它是virtual function,所以,當我重新宣告一個advnace()時,就算是QCanvas指標指到MyQcanvas的物件,當透過QCanvas指標呼叫advance()時,就會是呼叫我新增的advance()了,而不是QCanvas的advance()~因此,完成了這一個碰撞的目標了~
myqcanvas.h

#ifndef MYQCANVAS_H
#define MYQCANVAS_H

#include <qcanvas.h>

class MyQCanvas:public QCanvas
{
Q_OBJECT
  public:
    MyQCanvas(int w=0,int h=0);
    void setAddress(QCanvasPolygon*,QCanvasRectangle*,QCanvasText*); // 新增的部分,設定這三個物件的指標
  protected:
    void advance(); // 修改父類別的virtual function

  private:
    QCanvasPolygon *my_p; // 新增的變數,用來記錄多角形的指標
    QCanvasRectangle *my_r; // 新增的變數,用來記錄方形的指標
    QCanvasText *my_t; // 新增的變數,用來記錄文字的指標
};

#endif // MYQCANVAS_H

myqcanvas.cpp

#include "myqcanvas.h"

MyQCanvas::MyQCanvas(int w,int h):QCanvas(w,h)
{
  // do nothing
}

void MyQCanvas::advance() // 新增的部分
{
  if (my_r->collidesWith(my_p)) // 判斷是否有發生碰撞
    my_t->setText("Collision");
  else
    my_t->setText("There is no Collision!");

  QCanvas::advance(); // 衍生類別呼叫基底類別的advance function
}

void MyQCanvas::setAddress(QCanvasPolygon* p,QCanvasRectangle* r,QCanvasText* t)
{
  my_p = p;
  my_r = r;
  my_t = t;
}

view.h

#ifndef VIEW_H
#define VIEW_H

#include <qcanvas.h>

class View:public QCanvasView
{
Q_OBJECT
  public:
    View(QCanvas& canvas);
    QCanvasPolygon* getPolygon() const; // 新增的function,用來傳回多角形的指標
    QCanvasRectangle* getRectangle() const; // 新增的function,用來傳回方形的指標
    QCanvasText* getText() const; // 新增的function,用來傳回文字的指標

  protected:
    void contentsMousePressEvent(QMouseEvent *e);

  private:
    QCanvasPolygon *p;
    QCanvasRectangle *r;
    QCanvasText *t;
};

#endif // VIEW_H

view.cpp

#include <qfont.h>
#include <qimage.h>

#include "view.h"

View::View(QCanvas &canvas):QCanvasView(&canvas)
{
  canvas.setBackgroundPixmap(QPixmap("logo.jpg"));
  canvas.resize(370,300);
  setFixedSize(sizeHint());

  p = new QCanvasPolygon(&canvas);
  QPointArray a;
  a.setPoints(3,50,100,200,200,50,200);
  p->setPoints(a);
  p->setBrush(Qt::blue);
  p->setZ(10);
  p->show();

  r = new QCanvasRectangle(100,100,50,100,&canvas);
  r->setVelocity(0.5,0);
  r->setBrush(Qt::red);
  r->setZ(10);
  r->show();

  t = new QCanvasText("What will you",&canvas);
  t->setFont(QFont("Helvetica",12,QFont::Bold));
  t->setColor(Qt::blue);
  t->setZ(20);
  t->setTextFlags(AlignBottom);
  t->move(5,20);
  t->show();
}

void View::contentsMousePressEvent(QMouseEvent *e)
{
  r->move(e->pos().x(),e->pos().y());
}

QCanvasPolygon* View::getPolygon() const
{
  return p;
}

QCanvasRectangle* View::getRectangle() const
{
  return r;
}

QCanvasText* View::getText() const
{
  return t;
}

main.cpp

#include <qapplication.h>

#include "view.h"
#include "myqcanvas.h"

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

  MyQCanvas canvas(0,0);

  View c(canvas);
  canvas.setAddress(c.getPolygon(),c.getRectangle(),c.getText()); // 新增的部分
  canvas.setAdvancePeriod(30);
  canvas.setDoubleBuffering(true);

  app.setMainWidget(&c);
  c.show();

  return app.exec();
}


參考資料:回傳指標資料範例

沒有留言: