Spielfeld erstellen

Alles rund um die Programmierung mit Qt
Antworten
Kudi
Beiträge: 6
Registriert: 27. Januar 2007 23:33

Spielfeld erstellen

Beitrag von Kudi »

Hallo
Ich würde gerne wissen wie man am Sinnvollsten ein Spielfeld (Schach, TicTacToe,...) erstellt.
Mach ich das mit Buttons oder ganz anders?
Lg Kudi

P.S. Mit der Suche habe ich leider nichts gefunden.
gerome69
Beiträge: 188
Registriert: 28. April 2006 22:50
Wohnort: Berlin
Kontaktdaten:

Re: Spielfeld erstellen

Beitrag von gerome69 »

Kudi hat geschrieben: Ich würde gerne wissen wie man am Sinnvollsten ein Spielfeld (Schach, TicTacToe,...) erstellt.
Mach ich das mit Buttons oder ganz anders?
Lg Kudi
Das Spielfeld als Datenstruktur könntest du in einem zweidimensionalen Array ablegen.
Zeichen würde ich das Schachfeld in der Implementierung der paint-Methode durch eine Bitmap für den Hintergrund, auf die du dann einfach deine Spielfiguren (zB als png abgelegt) draufzeichnest.
Wo ein Benutzer hingeklickt hat, bekommst du durch Auswertung des QMouseEvent .

G.
Tarek
Beiträge: 46
Registriert: 3. Oktober 2005 14:29
Kontaktdaten:

Beitrag von Tarek »

Mit den vorhandenen Widgets wirst du da nicht weit kommen sondern du wirst wohl oder übel das meiste selbst schreiben müssen. Also am Besten eine neue Klasse von QWidget ableiten und dann die nötigen Ereignisbehandlungsroutinen überschreiben. D.h. du zeichnest z.B. im paintEvent() deines Widgets das Schachbrett und die Figuren und im mouseMoveEvent() implementierst du das Verschieben der Figuren mit der Maus.

Oder du könntest auch jede Figur in ein eigens Widget packen, was vielleicht sogar eleganter wäre, also es gibt da 1000 Möglichkeiten...

Es kann übrigens auch nicht schaden mal im Quelltext existierender Qt4-Spiele herumzuschnüffeln, z.B. hier: KCheckers
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Alles selber neu schreiben halte ich für zu viel Aufwand. Da gehts deutlich leichter mit dem GraphicsView-Framework. Das Schachbrett (oder auch, falls notwendig, jedes einzelne Schachfeld) von QGraphicsItem ableiten, dann die Figuren (ebenfalls von QGraphicsItem abgeleitet) auf die entsprechende Position setzen (mit dem Schachbrett/Feld als parentItem), QGraphicsItem reagiert schon auf MouseOver, Drag'n'Drop ist auch schnell implementiert (schau dir da die Examples an).

Grüße
Franz
Kudi
Beiträge: 6
Registriert: 27. Januar 2007 23:33

Beitrag von Kudi »

QGraphicsItem gibt es aber nicht bei der Version 4.0.1 oder?
Würde gerne diese Version behalten.
Kudi
Beiträge: 6
Registriert: 27. Januar 2007 23:33

Beitrag von Kudi »

Kudi hat geschrieben:QGraphicsItem gibt es aber nicht bei der Version 4.0.1 oder?
Würde gerne diese Version behalten.
Niemand eine andere Idee wie es sinnvoll wäre?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Kudi hat geschrieben:
Kudi hat geschrieben:QGraphicsItem gibt es aber nicht bei der Version 4.0.1 oder?
Würde gerne diese Version behalten.
Niemand eine andere Idee wie es sinnvoll wäre?
Wenn du in deinem Qt4 den Qt3-Support hast, kannst du Q3Canvas verwenden:
http://doc.trolltech.com/4.0/q3canvas.html

Warum willst du denn nicht updaten? Der einzige Grund für mich wäre eine kommerzielle Version...

Grüße
Fanz
Kudi
Beiträge: 6
Registriert: 27. Januar 2007 23:33

Beitrag von Kudi »

Ich habe jetzt mal probiert etwas mit QGraphicsItem zu machen.
Folgender Code ist größtenteils von den Examples kopiert und ich weiß, dass dieser nicht "sauber" ist. Das Spiel ist mein erstes Programm mit Qt (nach den Tutorials).

Teile aus mainwindow.cpp

Code: Alles auswählen

CMainWindow::CMainWindow(CGame *pGame, QApplication *pApp)
{
 m_pGame=pGame;
 m_pApp=pApp;
 
 QWidget *w = new QWidget;
 setCentralWidget(w);

 QWidget *topFiller = new QWidget;
 topFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

 m_pInfoLabel = new QLabel(tr("<i>Choose a menu option, or right-click to invoke a context menu</i>"));
 m_pInfoLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
 m_pInfoLabel->setAlignment(Qt::AlignCenter);

 QWidget *bottomFiller = new QWidget;
 bottomFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

 CreateBoard();

 QVBoxLayout *vbox = new QVBoxLayout;
 vbox->setMargin(5);
 vbox->addWidget(topFiller);
 vbox->addWidget(m_pInfoLabel);
 vbox->addWidget(bottomFiller);
 w->setLayout(vbox);

 CreateActions();
 CreateMenus();

 statusBar()->showMessage(tr("A context menu is available by right-clicking"));
 statusBar()->setSizeGripEnabled(false);
 statusBar()->setFixedHeight(20);
 
 setWindowTitle(tr("TicTacToe"));
 setFixedSize(390,430);
}

void CMainWindow::CreateBoard()
{
 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

 QGraphicsScene scene(-200, -200, 400, 400);

 for (int i = 0; i < 10; ++i) 
 {
  CBoardItem *item = new CBoardItem;
  item->setPos(::sin((i * 6.28) / 10.0) * 150, ::cos((i * 6.28) / 10.0) * 150);

  scene.addItem(item);
 }
 
 QGraphicsView view(&scene);
 view.setRenderHint(QPainter::Antialiasing);
 view.setBackgroundBrush(QColor(230, 200, 167));
 view.show();
}
boarditem.cpp

Code: Alles auswählen

#include <QtGui>
#include "boarditem.hpp"

CBoardItem::CBoardItem() : color(qrand() % 256, qrand() % 256, qrand() % 256)
{
}

void CBoardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
 Q_UNUSED(option);
 Q_UNUSED(widget);
 painter->setPen(Qt::NoPen);
 painter->setBrush(Qt::darkGray);
 painter->drawEllipse(-12, -12, 30, 30);
 painter->setPen(QPen(Qt::black, 1));
 painter->setBrush(QBrush(color));
 painter->drawEllipse(-15, -15, 30, 30);
}

QRectF CBoardItem::boundingRect() const
{
 return QRectF(-15.5, -15.5, 34, 34);
}
Ich kann das Programm zwar kompilieren und fehlerfrei ausführen, jedoch werden die erstellten items nicht angezeigt. Ich nehme an, dass ich die Methode paint irgendwo aufrufen muss und dort ein widget übergeben muss. Doch wie genau mach ich das (Aufruf im Konstruktor von CBoardItem?)
Lg Kudi
Dateianhänge
TicTacToe.rar
Quellcode des Programms
(2.75 KiB) 222-mal heruntergeladen
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Du musst paint() nicht aufrufen nur eine an deine Umgebung angepasste Version implementieren (hast du ja gemacht).
Aber view wird nach Verlassen der Methode CreateBoard() wieder zerstört. Deklariere bitte view und scene (evtl. gleich als Zeiger) als Member deiner MainWindow. Dann bleibt das Spielfeld auch sichtbar nach dem Verlassen der Methode.

Grüße
Franz
Kudi
Beiträge: 6
Registriert: 27. Januar 2007 23:33

Beitrag von Kudi »

Aber wie zeig ich die Scene jetzt an?
Gibt es eine Möglichkeit die Scene auf ein Widget zu legen?

Hier mal wie ich mir das vorstellen würde (funktioniert natürlich nicht)

Code: Alles auswählen

CMainWindow::CMainWindow(CGame *pGame, QApplication *pApp)
{
 m_pGame=pGame;
 m_pApp=pApp;
 
 QWidget *w = new QWidget;
 setCentralWidget(w);

 QWidget *topFiller = new QWidget;
 topFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

 m_pInfoLabel = new QLabel(tr("<i>Choose a menu option, or right-click to invoke a context menu</i>"));
 m_pInfoLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
 m_pInfoLabel->setAlignment(Qt::AlignCenter);

 QWidget *bottomFiller = new QWidget;
 bottomFiller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);


//Testweiße in den Konstruktor gegeben

 qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));

 QGraphicsScene scene(-200, -200, 400, 400);

 for (int i = 0; i < 10; ++i) 
 {
  CBoardItem *item = new CBoardItem;
  item->setPos(::sin((i * 6.28) / 10.0) * 150, ::cos((i * 6.28) / 10.0) * 150);

  scene.addItem(item);
 }
 
 QGraphicsView view(&scene);
 view.setRenderHint(QPainter::Antialiasing);
 view.setBackgroundBrush(QColor(230, 200, 167));
 //view.show();
//----------------------------------

 QVBoxLayout *vbox = new QVBoxLayout;
 vbox->setMargin(5);
 vbox->addWidget(topFiller);
 vbox->addWidget(m_pInfoLabel);
 vbox->addWidget(bottomFiller);
 vbox->addWidget(&view); //Gibt es eine Möglichkeit das in dieser Art zu machen?
 w->setLayout(vbox);

 CreateActions();
 CreateMenus();

 statusBar()->showMessage(tr("A context menu is available by right-clicking"));
 statusBar()->setSizeGripEnabled(false);
 statusBar()->setFixedHeight(20);
 
 setWindowTitle(tr("TicTacToe"));
 setFixedSize(390,430);
}
Bitte die Zeile vbox->addWidget(&view); beachten.

Lg Kudi
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Das was ich gesagt habe seh ich noch nicht ;)

Code: Alles auswählen

// mainapp.hpp

class CMainApp {
  private:
    ...
    QGraphicsScene* scene;
    QGraphicsView* view;
    ...
};

// mainapp.cpp
void CMainApp::CreateBoard()
{
  ...
  scene = new QGraphicsScene;
  ...
  // items hinzufügen
  ...
  view = new QGraphicsView( scene );
  view->setblablabla...
  ...
  view->show();
}
QGraphicsView erbt von QFrame (steht in der Doku), deshalb kannst du es so auch anzeigen. Wenn du ein separates Spielfeld bevorzugst belass es bei dieser Methode. Ansonsten kannst du view natürlich auch im MainWindow in das Layout packen (oder gleich als CentralWidget setzen).
Wichtig ist nur dass du unbedingt view + scene als member deiner Klasse definierst.

Grüße
Franz
Kudi
Beiträge: 6
Registriert: 27. Januar 2007 23:33

Beitrag von Kudi »

Ok ich kann es jetzt kompilieren aber es sind dann 2 Fenster (siehe Anhang).
Ich hätte das jetzt aber gerne wo momentan das infolabel ist.
Lg Kudi
Dateianhänge
Unbenannt-2.jpg
Unbenannt-2.jpg (41.73 KiB) 7731 mal betrachtet
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Du hast nach dem Aufruf von CreateBoard() einen von NULL verschiedenen Zeiger auf ein QGraphicsView. Du weißt wie man Widgets zu einem Layout hinzufügt (vorausgesetzt du hast das verstanden was du per Copy&Paste aus dem Example in dein Projekt eingefügt hast).
Der nächste Schritt ist dermaßen simpel dass du sicher selbst drauf kommst.

Wenn nicht lies dir bitte (und am besten nicht nur in diesem Fall) die Basic-Tutorials (Assistant->index->suche nach "Tutorial") durch, dann bist du gewappnet für den alltäglichen Kampf gegen die qt4-Unwissenheit ;)

Grüße
Franz
Antworten