Commit 3d520afa authored by Ian Wadham's avatar Ian Wadham

Add documentation and comments, clean up, tidy up and reorganise the code a little.

svn path=/branches/work/kgoldrunner-qgv/; revision=1298064
parent ad6dcbf7
......@@ -15,6 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************/
// TODO - Border tiles, display tiles.
// TODO - Add attributes to theme: HasBorderTiles, HasDisplayTiles.
#include <KGameRenderer>
#include <KgThemeProvider>
#include <KgThemeSelector>
......@@ -23,30 +26,55 @@
#include <QDebug>
#include <QString>
#include "kgrglobals.h"
#include "kgrthemetypes.h"
#include "kgrrenderer.h"
#include "kgrglobals.h"
KGrRenderer::KGrRenderer (QWidget * view)
#include <cmath>
KGrRenderer::KGrRenderer (QObject * parent)
:
QObject (view)
QObject (parent)
{
qDebug() << "KGrRenderer called";
m_setProvider = new KgThemeProvider("Theme", this); // Saved config.
m_actorsProvider = new KgThemeProvider("", this); // Do not save.
// Set up two theme providers: for the Set and the Actors.
m_setProvider = new KgThemeProvider("Theme", this); // Save config.
m_actorsProvider = new KgThemeProvider("", this); // Do not save.
// Find SVG files for the Set, i.e. tiles and backgrounds.
const QMetaObject * setThemeClass = & KGrSetTheme::staticMetaObject;
m_setProvider->discoverThemes ("appdata", QLatin1String ("themes"),
QLatin1String ("egypt"), setThemeClass);
m_themeSelector = new KgThemeSelector (m_setProvider,
KgThemeSelector::DefaultBehavior,
0); // No parent: modeless dialog.
// Find SVG files for the Actors, i.e. hero and enemies.
const QMetaObject * actorsThemeClass = & KGrActorsTheme::staticMetaObject;
m_actorsProvider->discoverThemes ("appdata", QLatin1String ("themes"),
QLatin1String ("egypt"), actorsThemeClass);
// Set up a dialog for selecting themes.
m_themeSelector = new KgThemeSelector (m_setProvider,
KgThemeSelector::DefaultBehavior,
0); // No parent: modeless dialog.
m_setRenderer = new KGameRenderer (m_setProvider);
// Set up the renderer for the Set, i.e. tiles and backgrounds.
m_setRenderer = new KGameRenderer (m_setProvider);
m_setRenderer->setParent (this);
m_setRenderer->setFrameSuffix ("_%1");
m_setRenderer->setFrameBaseIndex (1);
initPixmapKeys();
// Set up the renderer for the Actors, i.e. hero and enemies.
m_actorsRenderer = new KGameRenderer (m_actorsProvider);
m_actorsRenderer->setParent (this);
m_actorsRenderer->setFrameSuffix ("_%1");
m_actorsRenderer->setFrameBaseIndex (1);
// Match the Actors SVG theme to the Set theme, whenever the theme changes.
connect (m_setProvider, SIGNAL(currentThemeChanged(const KgTheme*)),
this, SLOT(currentThemeChanged(const KgTheme*)));
// Match the starting SVG theme for the Actors to the one for the Set.
currentThemeChanged (m_setProvider->currentTheme());
}
KGrRenderer::~KGrRenderer()
......@@ -54,8 +82,28 @@ KGrRenderer::~KGrRenderer()
delete m_themeSelector;
}
void KGrRenderer::currentThemeChanged (const KgTheme* currentSetTheme)
{
// Start of game or change of theme: initialise the counts of pixmap keys.
initPixmapKeys();
// Make the Actors theme (hero, etc.) match the Set theme (bricks, etc.).
qDebug() << "KGrRenderer::currentThemeChanged()" << currentSetTheme->name();
foreach (const KgTheme * actorsTheme, m_actorsProvider->themes()) {
qDebug() << "KGrRenderer::currentThemeChanged() Actors" << actorsTheme->customData("Set") << currentSetTheme->customData("Set");
if (actorsTheme->customData("Set") ==
currentSetTheme->customData("Set")) {
m_actorsProvider->setCurrentTheme (actorsTheme);
qDebug() << "actorsTheme" << actorsTheme->customData("Set")
<< actorsTheme->customData("Actors");
return;
}
}
}
void KGrRenderer::selectTheme()
{
// Show the theme-selection dialog.
m_themeSelector->showAsDialog (i18n("Theme Selector"));
}
......@@ -69,53 +117,105 @@ KGrRenderer::PixmapSpec KGrRenderer::keyTable [] = {
{LADDER, Set, "ladder", "-%1", 0, -2},
{NUGGET, Set, "gold", "-%1", 0, -2},
{BAR, Set, "bar", "-%1", 0, -2},
{BACKDROP, Set, "background", "%1", 0, -2},
{FREE, Set, "", "", -1, -2} // Must be last entry.
};
void KGrRenderer::initPixmapKeys()
{
// Set all pixmaps in keyTable[] as "not counted yet" (frameCount -2).
int index = 0;
while (true) {
// Start of game or change of theme: pixmap keys not counted yet.
while (keyTable[index].picType != FREE) {
keyTable[index].frameCount = -2;
if (keyTable[index].picType == FREE) {
break; // End of table: all done.
}
index++;
}
}
QString KGrRenderer::getPixmapKey (const char picType)
{
// TODO - Backgrounds, border tiles, display tiles.
// TODO - Add attributes to theme: HasBorderTiles, HasDisplayTiles.
QString pixmapKey = "";
int index = findKeyTableIndex (picType);
int frameCount = (index < 0) ? -1 : keyTable[index].frameCount;
if (frameCount > -1) {
pixmapKey = keyTable[index].picKey; // No suffix.
if (frameCount > 0) {
// Pick a random frame number and add it as a suffix.
// Note: We are not worried about having a good seed for this.
pixmapKey = pixmapKey + QString(keyTable[index].frameSuffix);
pixmapKey = pixmapKey.arg (keyTable[index].frameBaseIndex +
(rand() % frameCount));
}
}
qDebug() << "picType" << picType << "pixmapKey" << pixmapKey;
return pixmapKey;
}
QString KGrRenderer::getBackgroundKey (const int level)
{
QString pixmapKey = "";
int index = findKeyTableIndex (BACKDROP);
int frameCount = (index < 0) ? -1 : keyTable[index].frameCount;
if (frameCount > -1) {
pixmapKey = keyTable[index].picKey;
if (frameCount > 0) {
// Cycle through available backgrounds as the game-level increases.
pixmapKey = pixmapKey + QString(keyTable[index].frameSuffix);
pixmapKey = pixmapKey.arg (level % frameCount);
}
}
qDebug() << "picType" << BACKDROP << "pixmapKey" << pixmapKey;
return pixmapKey;
}
int KGrRenderer::findKeyTableIndex (const char picType)
{
int index = 0;
while (true) {
if (keyTable[index].picType == FREE) {
break; // Pixmap key not found.
index = -1; // Pixmap key not found.
break;
}
else if (keyTable[index].picType == picType) {
if (keyTable[index].frameCount == -2) {
// TODO - Find and count the SVG elements.
// TODO - Must check for key with no suffix first.
// Use picKey + frameSuffix and start at frameBaseIndex.
}
else if (keyTable[index].frameCount == -1) {
break; // Element missing from theme.
}
else if (keyTable[index].frameCount == 0) {
pixmapKey = keyTable[index].picKey; // No suffix.
}
else {
// TODO Pick a random frame number and add a suffix.
keyTable[index].frameCount = countFrames (index);
}
break;
}
index++;
}
return pixmapKey;
return index;
}
int KGrRenderer::countFrames (const int index)
{
int count = -1;
int frame = keyTable[index].frameBaseIndex;
KGameRenderer * r = (keyTable[index].picSource == Set) ? m_setRenderer :
m_actorsRenderer;
if (r->spriteExists (keyTable[index].picKey)) {
count++;
}
qDebug() << "KGrRenderer::countFrames 1" << keyTable[index].picKey << count;
if ((count == 0) && (QString(keyTable[index].picKey) != QString("brick"))) {
return count;
}
if (frame < 0) {
return count; // This element cannot have more than one frame.
}
count = 0;
QString pixmapKey = QString(keyTable[index].picKey) +
QString(keyTable[index].frameSuffix);
while (r->spriteExists (pixmapKey.arg (frame))) {
qDebug() << "KGrRenderer::countFrames found" << pixmapKey.arg (frame);
count++;
frame++;
}
qDebug() << "KGrRenderer::countFrames 2" << keyTable[index].picKey << count;
return count;
}
#include "kgrrenderer.moc"
......@@ -18,42 +18,122 @@
#ifndef KGRRENDERER_H
#define KGRRENDERER_H
#include <QObject>
#include <QString>
#include <KGameRenderer>
class KgThemeProvider;
class KgThemeSelector;
class KGameRenderer;
class QWidget;
/* @short A class to assist theme-handling and rendering in KGoldrunner.
*
* KGoldrunner has two SVG files for each theme: one to hold the Actors (hero
* and enemies) and one to hold the Set (bricks, ladders, background, etc.).
*
* The files are marked with the keywords "Actors" and "Set" in each theme's
* .desktop file, rather than the usual "Filename" keyword. There are two
* KgThemeProvider objects and two KGameRenderer objects, each with its own
* set of SVG files and KgTheme objects.
*
* There is one KgThemeSelector object, which selects the "Set" theme and uses
* the "Set" KgThemeProvider. Its currentThemeChanged signal is connected to a
* currentThemeChanged slot in KGrRenderer, which finds the KgTheme for the
* corresponding "Actors" theme and SVG file.
*
* KGoldrunner also has several different usages of the KGameRenderer concepts
* of "frameSuffix" and "frameBaseIndex". For animation frames (hero, enemies
* and dug bricks), it always has frameSuffix = "_%1" and frameBaseIndex = 1, so
* animation will be handled normally by KGameRenderer.
*
* Depending on the theme and the artist's choices, backgrounds and tiles can
* have one or more variants, to add variety to the look of brick walls, etc.
* The suffixes used can be "-%1" or just "%1" and the frameBaseIndex = 0, or
* there can be just one variant, with no suffix. The keyTable structure and the
* getPixmapKey() and getBackgroundKey() methods of KGrRenderer provide ways to
* go from KGoldrunner's internal tile-types to SVG element names that can be
* used as pixmap keys in KGameRenderer.
*/
class KGrRenderer : public QObject
{
Q_OBJECT
public:
KGrRenderer (QWidget * view);
KGrRenderer (QObject * parent);
virtual ~KGrRenderer();
/*
* Get a pointer to the KGameRenderer for "Set" graphics (bricks, etc.).
*/
KGameRenderer * getSetRenderer() { return m_setRenderer; }
/*
* Get a pointer to the KGameRenderer for "Actors" graphics (hero, etc.).
*/
KGameRenderer * getActorsRenderer() { return m_actorsRenderer; }
/*
* Get the SVG element name for a KGoldrunner tile type. If the theme has
* more than one tile of that type (e.g. BRICK), make a random selection.
*
* @param picType The internal KGoldrunner type of a tile or background.
*/
QString getPixmapKey (const char picType);
/*
* Get the SVG element name for a KGoldrunner background. If the theme has
* more than one background, cycle though the choices as the KGoldrunner
* game's level changes.
*
* @param level The current level in a KGoldrunner game.
*/
QString getBackgroundKey (const int level);
public slots:
/*
* Show the theme-selector dialog. When the theme changes, KGrRenderer uses
* a signal and slot to keep the "Set" and "Actors" parts of the theme and
* SVG files in synch.
*/
void selectTheme();
private slots:
// Keep the "Set" and "Actors" parts of a KGoldrunner theme in synch as
// the theme-selection changes.
void currentThemeChanged(const KgTheme * currentSetTheme);
private:
enum PicSrc {Actors, Set};
enum PicSrc {Actors, Set};
// Structure of table-row to specify a tile or pixmap type in a theme.
struct PixmapSpec {
const char picType;
const PicSrc picSource;
const char * picKey;
const char * frameSuffix;
const int frameBaseIndex;
int frameCount;
const char picType; // KGoldrunner's internal type.
const PicSrc picSource; // Actors or Set?
const char * picKey; // Prefix of SVG element name.
const char * frameSuffix; // Format of suffix or "" if none.
const int frameBaseIndex; // Lowest value of suffix or -1 if none.
int frameCount; // Number of variants available.
// -2 = not yet counted, -1 = element
// not found, 0 = only one variant with
// no suffix, >0 = number of variants.
};
static PixmapSpec keyTable [];
KgThemeProvider * m_setProvider; // Provider for Set themes.
KgThemeProvider * m_actorsProvider; // Provider for Actors themes.
KgThemeSelector * m_themeSelector; // Selector (dialog) for themes.
KGameRenderer * m_setRenderer; // Renderer for Set SVG files.
KGameRenderer * m_actorsRenderer; // Renderer for Actors SVG files.
static PixmapSpec keyTable []; // Table of tile/background specs.
// Set the frame counts to -2 at startup and when the theme changes.
void initPixmapKeys();
KgThemeProvider * m_setProvider;
KgThemeProvider * m_actorsProvider;
KgThemeSelector * m_themeSelector;
KGameRenderer * m_setRenderer;
KGameRenderer * m_actorsRenderer;
// Find a tile type or background in the table of tiles and backgrounds.
int findKeyTableIndex (const char picType);
// Count the number of variants of a tile or background.
int countFrames (const int index);
};
#endif // KGRRENDERER_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment