Development/Tutorials/Games/Highscores: Difference between revisions

From KDE TechBase
m (Correct include path)
(Mark for updating)
 
(9 intermediate revisions by 3 users not shown)
Line 11: Line 11:
reading={{class|KScoreDialog}}
reading={{class|KScoreDialog}}
}}
}}
{{Review|Port to KF5}}


==Abstract==
==Abstract==
Line 25: Line 27:
==Displaying Scores==
==Displaying Scores==
To display the high score table, it's as simple as two lines of code.  
To display the high score table, it's as simple as two lines of code.  
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KScoreDialog>
#include <KScoreDialog>


void showHighscores()
void showHighscores()
Line 33: Line 35:
   ksdialog.exec();
   ksdialog.exec();
}
}
</code>
</syntaxhighlight>
This will display the highscore table showing, by default, the 'Name' and 'Score' columns.
This will display the highscore table showing, by default, the 'Name' and 'Score' columns.


In order to comply with the kdegames standards, you should use a {{class|KStandardGameAction}} to launch this function. This will set up the icons and toolbars correctly. See the [[Development/Tutorials/Games/KStandardGameAction|KStandardGameAction tutorial]] for more information on this.
In order to comply with the kdegames standards, you should use a {{class|KStandardGameAction}} to launch this function. This will set up the icons and toolbars correctly. See the [[Development/Tutorials/Games/KStandardGameAction|KStandardGameAction tutorial]] for more information on this.
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KStandardGameAction>
#include <KStandardGameAction>
void setupActions()
void setupActions()
{
{
Line 46: Line 48:
   setupGUI();
   setupGUI();
}
}
</code>
</syntaxhighlight>


==Adding Scores==
==Adding Scores==
===Simplest way to add a score===
===Simplest way to add a score===
The simplest way to add a new score to the table is as follows:
The simplest way to add a new score to the table is as follows:
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KScoreDialog>
#include <KScoreDialog>


void newHighscore(int playersScore)
void newHighscore(int playersScore)
Line 60: Line 62:
   ksdialog.exec();
   ksdialog.exec();
}
}
</code>
</syntaxhighlight>
This will add the score <tt>playersScore</tt> to the high score table and then launch the dialog. If it is the first score to be entered on the table, a blank line-edit will be provided for the player to enter their name, otherwise the line-edit will still be provided but the player's name will be automatically filled in.
This will add the score <tt>playersScore</tt> to the high score table and then launch the dialog. If it is the first score to be entered on the table, a blank line-edit will be provided for the player to enter their name, otherwise the line-edit will still be provided but the player's name will be automatically filled in.


However, you will notice that the dialog is shown every time, even if the player didn't manage to get onto the table. If you only want to show the table if the player achieved a high score, place an <tt>if()</tt> command around the <tt>KScoreDialog::addScore()</tt> call:
However, you will notice that the dialog is shown every time, even if the player didn't manage to get onto the table. If you only want to show the table if the player achieved a high score, place an <tt>if()</tt> command around the <tt>KScoreDialog::addScore()</tt> call:
<code cppqt>
<syntaxhighlight lang="cpp-qt">
if(ksdialog.addScore(playersScore))
if(ksdialog.addScore(playersScore))
   ksdialog.exec();
   ksdialog.exec();
</code>
</syntaxhighlight>


===Passing name by code===
===Passing name by code===
If you want to suggest a name programatically you can do so by using the <tt>KScoreDialog::FieldInfo</tt> type. It's easy to use, for example:
If you want to suggest a name programatically you can do so by using the <tt>KScoreDialog::FieldInfo</tt> type. It's easy to use, for example:
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KScoreDialog>
#include <KScoreDialog>


Line 84: Line 86:
   ksdialog.addScore(scoreInfo);
   ksdialog.addScore(scoreInfo);
}
}
</code>
</syntaxhighlight>


And in this same way you can display other default fields by passing them to the <tt>KScoreDialog</tt> constructor and adding the information to your <tt>KScoreDialog::FieldInfo</tt>. For example, to display the level the player got to:
And in this same way you can display other default fields by passing them to the <tt>KScoreDialog</tt> constructor and adding the information to your <tt>KScoreDialog::FieldInfo</tt>. For example, to display the level the player got to:
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KScoreDialog>
#include <KScoreDialog>


void newHighscore(int score, const QString& name, int level)
void newHighscore(int score, const QString& name, int level)
Line 102: Line 104:
   ksdialog.addScore(scoreInfo);
   ksdialog.addScore(scoreInfo);
}
}
</code>
</syntaxhighlight>
===Custom fields===
===Custom fields===
Since there are only a set number of standatd fields it is possible to add you own custom fields. For example you may want to put the number of moves the player made on the table. This is done through the <tt>KScoreDialog::addField()</tt> function.
Since there are only a set number of standard fields it is possible to add your own custom fields. For example you may want to put the number of moves the player made to the table. This is done through the <tt>KScoreDialog::addField()</tt> function.
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KScoreDialog>
#include <KScoreDialog>


void newHighscore(int score, const QString& name, int numMoves)
void newHighscore(int score, const QString& name, int numMoves)
Line 122: Line 124:
   ksdialog.addScore(scoreInfo);
   ksdialog.addScore(scoreInfo);
}
}
</code>
</syntaxhighlight>
The first argument to <tt>KScoreDialog::addField()</tt> must be from <tt>KScoreDialog::Custom1</tt> to <tt>KScoreDialog::Custom5</tt>, the second is the text that will appear on the high score table at the head of the column (and must therefore be i18n'd) and the last argument is a unique identifier for the field. After that, it is added to your <tt>KScoreDialog::FieldInfo</tt> in the same way as before.
The first argument to <tt>KScoreDialog::addField()</tt> must be from <tt>KScoreDialog::Custom1</tt> to <tt>KScoreDialog::Custom5</tt>, the second is the text that will appear on the high score table at the head of the column (and must therefore be i18n'd) and the last argument is a unique identifier for the field. After that, it is added to your <tt>KScoreDialog::FieldInfo</tt> in the same way as before.


==Grouping Scores==
==Grouping Scores==
Your game may have different levels of difficulty and so you don't want to put the scores for the 'Hard' level on the same table as the 'Easy' table. Grouping scores is easy to achieve using the <tt>KScoreDialog::setConfigGroup()</tt> function:
Your game may have different levels of difficulty and so you don't want to put the scores for the 'Hard' level on the same table as the 'Easy' table. Grouping scores is easy to achieve using the <tt>KScoreDialog::setConfigGroup()</tt> function:
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KScoreDialog>
#include <KScoreDialog>


void newHighscore(int playersScore, const QString& difficulty)
void newHighscore(int playersScore)
{
{
   KScoreDialog ksdialog(KScoreDialog::Name, this);
   KScoreDialog ksdialog(KScoreDialog::Name, this);
   ksdialog.setConfigGroup(difficulty);
   ksdialog.setConfigGroup(I18N_NOOP("Easy"));
   ksdialog.addScore(playersScore);
   ksdialog.addScore(playersScore);
   ksdialog.exec();
   ksdialog.exec();
}
}
</code>
</syntaxhighlight>
Each group will show up as a tab on the high score table dialog. If you don't specify a group, the score will be added to the generic 'High Score' tab.
Each group will show up as a tab on the high score table dialog. If you don't specify a group, the score will be added to the generic 'High Score' tab.
A very important point to remember is to pass the untranslated group name through <tt>I18N_NOOP()</tt> otherwise the group name will not be translated properly and will cause bugs.


==Advanced Features==
==Advanced Features==
Line 144: Line 148:
In some special cases you won't want to display a score as such but rather just the time the player took to complete the level.
In some special cases you won't want to display a score as such but rather just the time the player took to complete the level.


While you're not going to display the 'Score' field in your table you must always submit a value to 'Score' field since it is used for sorting the scores. In fact, the 'Score' field is always present in a <tt>KScoreDialog</tt> object even if you didn't pass it to the constructor. However, ity is possible to hide the 'Score' field (and in fact any field) from display using the <tt>KScoreDialog::hideField()</tt> function. It takes a Field flag from the same set that the constructor takes.
While you're not going to display the 'Score' field in your table you must always submit a value to 'Score' field since it is used for sorting the scores. In fact, the 'Score' field is always present in a <tt>KScoreDialog</tt> object even if you didn't pass it to the constructor. However, it is possible to hide the 'Score' field (and in fact any field) from display using the <tt>KScoreDialog::hideField()</tt> function. It takes a Field flag from the same set that the constructor takes.
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KDE/KScoreDialog>
#include <KScoreDialog>


// timeString is a nicely formatted string
// timeString is a nicely formatted string
Line 162: Line 166:
   ksdialog.exec();
   ksdialog.exec();
}
}
</code>
</syntaxhighlight>


[[Category:C++]]
[[Category:C++]]
[[Category:KDEGames]]

Latest revision as of 14:23, 31 May 2019

High Scores
Tutorial Series   KDE Games
Previous   Introduction to KDE4 programming, KStandardGameAction Tutorial
What's Next  
Further Reading   KScoreDialog
Warning
This page needs a review and probably holds information that needs to be fixed.

Parts to be reviewed:

Port to KF5

Abstract

This tutorial will explain how to use the high score system built into kdegames in your application.

Dialog in KMines

KScoreDialog

The high score system is provided through the KScoreDialog class. It is intended to be a lightweight solution and offers the following abilities:

  1. Grouping of scores (for different difficulty levels etc.)
  2. Standard fields: Name, Level, Date, Time, Score
  3. Custom fields (e.g. number of moves)

Displaying Scores

To display the high score table, it's as simple as two lines of code.

#include <KScoreDialog>

void showHighscores()
{
  KScoreDialog ksdialog(KScoreDialog::Name, this);
  ksdialog.exec();
}

This will display the highscore table showing, by default, the 'Name' and 'Score' columns.

In order to comply with the kdegames standards, you should use a KStandardGameAction to launch this function. This will set up the icons and toolbars correctly. See the KStandardGameAction tutorial for more information on this.

#include <KStandardGameAction>
void setupActions()
{
  KStandardGameAction::highscores(this, 
                       SLOT(showHighscores()), 
                       actionCollection());
  setupGUI();
}

Adding Scores

Simplest way to add a score

The simplest way to add a new score to the table is as follows:

#include <KScoreDialog>

void newHighscore(int playersScore)
{
  KScoreDialog ksdialog(KScoreDialog::Name, this);
  ksdialog.addScore(playersScore);
  ksdialog.exec();
}

This will add the score playersScore to the high score table and then launch the dialog. If it is the first score to be entered on the table, a blank line-edit will be provided for the player to enter their name, otherwise the line-edit will still be provided but the player's name will be automatically filled in.

However, you will notice that the dialog is shown every time, even if the player didn't manage to get onto the table. If you only want to show the table if the player achieved a high score, place an if() command around the KScoreDialog::addScore() call:

if(ksdialog.addScore(playersScore))
  ksdialog.exec();

Passing name by code

If you want to suggest a name programatically you can do so by using the KScoreDialog::FieldInfo type. It's easy to use, for example:

#include <KScoreDialog>

void newHighscore(int score, const QString& name)
{
  KScoreDialog ksdialog(KScoreDialog::Name, this);
  
  KScoreDialog::FieldInfo scoreInfo;
  scoreInfo[KScoreDialog::Name] = name;
  scoreInfo[KScoreDialog::Score].setNum(score);
  
  ksdialog.addScore(scoreInfo);
}

And in this same way you can display other default fields by passing them to the KScoreDialog constructor and adding the information to your KScoreDialog::FieldInfo. For example, to display the level the player got to:

#include <KScoreDialog>

void newHighscore(int score, const QString& name, int level)
{
  KScoreDialog ksdialog(KScoreDialog::Name |
                        KScoreDialog::Level, this);
  
  KScoreDialog::FieldInfo scoreInfo;
  scoreInfo[KScoreDialog::Name] = name;
  scoreInfo[KScoreDialog::Score].setNum(score);
  scoreInfo[KScoreDialog::Level].setNum(level);
  
  ksdialog.addScore(scoreInfo);
}

Custom fields

Since there are only a set number of standard fields it is possible to add your own custom fields. For example you may want to put the number of moves the player made to the table. This is done through the KScoreDialog::addField() function.

#include <KScoreDialog>

void newHighscore(int score, const QString& name, int numMoves)
{
  KScoreDialog ksdialog(KScoreDialog::Name, this);
  
  KScoreDialog::FieldInfo scoreInfo;
  scoreInfo[KScoreDialog::Name] = "Matt";
  scoreInfo[KScoreDialog::Score].setNum(playersScore);
  
  ksdialog.addField(KScoreDialog::Custom1, 
                    i18n("Num of Moves"), "moves");
  scoreInfo[KScoreDialog::Custom1].setNum(numMoves);
  
  ksdialog.addScore(scoreInfo);
}

The first argument to KScoreDialog::addField() must be from KScoreDialog::Custom1 to KScoreDialog::Custom5, the second is the text that will appear on the high score table at the head of the column (and must therefore be i18n'd) and the last argument is a unique identifier for the field. After that, it is added to your KScoreDialog::FieldInfo in the same way as before.

Grouping Scores

Your game may have different levels of difficulty and so you don't want to put the scores for the 'Hard' level on the same table as the 'Easy' table. Grouping scores is easy to achieve using the KScoreDialog::setConfigGroup() function:

#include <KScoreDialog>

void newHighscore(int playersScore)
{
  KScoreDialog ksdialog(KScoreDialog::Name, this);
  ksdialog.setConfigGroup(I18N_NOOP("Easy"));
  ksdialog.addScore(playersScore);
  ksdialog.exec();
}

Each group will show up as a tab on the high score table dialog. If you don't specify a group, the score will be added to the generic 'High Score' tab.

A very important point to remember is to pass the untranslated group name through I18N_NOOP() otherwise the group name will not be translated properly and will cause bugs.

Advanced Features

Hiding Fields

In some special cases you won't want to display a score as such but rather just the time the player took to complete the level.

While you're not going to display the 'Score' field in your table you must always submit a value to 'Score' field since it is used for sorting the scores. In fact, the 'Score' field is always present in a KScoreDialog object even if you didn't pass it to the constructor. However, it is possible to hide the 'Score' field (and in fact any field) from display using the KScoreDialog::hideField() function. It takes a Field flag from the same set that the constructor takes.

#include <KScoreDialog>

// timeString is a nicely formatted string
// e.g. "1:24" used for display
void newHighscore(const QString& timeString, int seconds)
{
  KScoreDialog ksdialog(KScoreDialog::Name | 
                        KScoreDialog::Time, this);
  
  KScoreDialog::FieldInfo scoreInfo;
  scoreInfo[KScoreDialog::Time] = timeString;
  scoreInfo[KScoreDialog::Score].setNum(seconds);
  ksdialog.hideField(KScoreDialog::Score);
  ksdialog.addScore(scoreInfo, KScoreDialog::LessIsMore)
  ksdialog.exec();
}