Development/Tutorials/Games/Palapeli Slicers
Tutorial Series | Programming with the Palapeli API |
Previous | Introduction to KDE4 programming |
What's Next | n/a |
Further Reading | Palapeli::Pattern, Palapeli::PatternConfiguration |
Abstract
This tutorial shows you how to create a pattern for Palapeli, that is: a plugin for the Palapeli libraries that describes an algorithm to split an image into pieces.
The pattern we will be constructing is quite easy: It splits an image into two equally sized pieces.
Structure
A pattern plugin consists of two classes. The first one (derived from Palapeli::PatternConfiguration) tells Palapeli what features this pattern plugin has and which configuration values it needs. The second one (derived from Palapeli::Pattern) does the actual slicing.
The code: mypattern.h
- ifndef MYPATTERN_H
- define MYPATTERN_H
- include <Palapeli/Pattern>
- include <Palapeli/PatternConfiguration>
class MyPattern : public Palapeli::Pattern
{
public:
MyPattern();
virtual ~MyPattern() {}
virtual int estimatePieceCount() const;
protected:
virtual void doSlice(const QImage& image);
};
class MyPatternConfiguration : public Palapeli::PatternConfiguration
{
public:
MyPatternConfiguration(QObject* parent = 0, const QVariantList& args = QVariantList());
virtual ~MyPatternConfiguration() {}
virtual Palapeli::Pattern* createPattern() const;
};
- endif // MYPATTERN_H
As described above, we have declared two classes deriving from the base classes Palapeli::Pattern and Palapeli::PatternConfiguration. For this simple example, we do only reimplement constructors, destructors and some pure virtual functions.
The code: mypattern.cpp
- include "mypattern.h"
- include <QImage>
- include <KPluginFactory>
- include <KPluginLoader>
K_PLUGIN_FACTORY(MyPatternFactory, registerPlugin<MyPatternConfiguration>();)
K_EXPORT_PLUGIN(MyPatternFactory("mypattern"))
MyPattern::MyPattern()
: Palapeli::Pattern()
{
}
int MyPattern::estimatePieceCount() const
{
return 2;
}
void MyPattern::doSlice(const QImage& image)
{
//construct pixmaps for the pieces
const int pieceWidth = image.width() / 2, pieceHeight = image.height();
QImage leftPiece = image.copy(QRect(0, 0, pieceWidth, pieceHeight));
QImage rightPiece = image.copy(QRect(pieceWidth, 0, pieceWidth, pieceHeight));
//add pieces; define a neighborship relation between them
addPiece(leftPiece, QRectF(0, 0, pieceWidth, pieceHeight));
addPiece(rightPiece, QRectF(pieceWidth, 0, pieceWidth, pieceHeight));
addRelation(0, 1, QPointF(pieceWidth, 0)); //0 and 1 are the consecutive indices of the pieces
}
MyPatternConfiguration::MyPatternConfiguration(QObject* parent, const QVariantList& args)
: Palapeli::PatternConfiguration(parent, args)
{
Q_UNUSED(parent)
Q_UNUSED(args)
setSizeDefinitionMode(Palapeli::PatternConfiguration::CustomSizeDefinition);
}
Palapeli::Pattern* MyPatternConfiguration::createPattern() const
{
return new MyPattern;
}
We will start with the MyPatternConfiguration class, because this is the logical entry point. The pattern configuration class is created when Palapeli is started. Its job is to manage the pattern's settings. In this case, there is nothing to configure. If you want to implement a size definition by the number of pieces in horizontal and in vertical direction (as for the standard rectangular piece pattern), you can simply set the size definition mode to Palapeli::PatternConfiguration::CountSizeDefinition. Arbitrary configuration can be achieved by adding widgets through the Palapeli::PatternConfiguration::addWidget method.
When the user has configured its game (and therefore the pattern), the Palapeli game engine will call the createPattern method to create a Palapeli::Pattern object. If you have added configuration values, pass them to the constructor of your pattern object, and save them in private variables. If you have chosen the CountSizeDefinition, you can use the xCount and yCount methods to retrieve the configured values. See the implementation of the standard rectangular pattern for details on how to use this size definition mode.
Now we have a Palapeli::Pattern instance.
Integrate into Palapeli: mypattern.desktop
[Desktop Entry]
X-KDE-Library=mypattern
X-KDE-PluginInfo-Author=The best KDE hacker
[email protected]
X-KDE-PluginInfo-Name=mypattern
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=http://kde-hackers.example.org/palapelipatterns
X-KDE-PluginInfo-Category=
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-ParentApp=libpalapelipattern
X-KDE-ServiceTypes=Palapeli/PatternPlugin
Type=Service
Icon=palapeli-pattern-mypattern
PatternIdentifier=mypattern
Name=My pattern
Name[de]=Mein Schnittmuster
Comment=The best pattern in the world
Comment[de]=Das beste Schnittmuster auf der ganzen Welt
Build everything: CMakeLists.txt
project(mypattern)
find_package(KDE4 REQUIRED)
find_package(Palapeli REQUIRED)
add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS})
include_directories(${KDE4_INCLUDES} ${PALAPELI_INCLUDE_DIR})
set(mypattern_SRCS
mypattern.cpp
)
kde4_add_plugin(mypattern ${mypattern_SRCS})
target_link_libraries(mypattern ${KDE4_KDEUI_LIBS} palapelipattern)
install(TARGETS mypattern DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES mypattern.desktop DESTINATION ${SERVICES_INSTALL_DIR})