×

Warning

JUser: :_load: Unable to load user with ID: 1175

Rock, Paper, Scissors - Full Tutorial

Who doesn't like a good old fashion game of Rock, Paper, Scissors? So here's an example app of it...  This tutorial is broken up into 3 parts:
Part 1 will focus on how to create the logic aspects (QML/JavaScript and C++).
Part 2 will create a user friendly user interface (UI) to liven up the app with graphics (QML).
Part 3 will combine the logic and UI, as well as add some additional features such animations and a help page.

Before getting into the explanations the full source code this app has been posted to github: https://github.com/bcs925/BrianScheirerOpenSource/tree/master/RockPaperScissors

And the app can be downloaded from App World (only available on BB10, Dev Alpha):  http://appworld.blackberry.com/webstore/content/135020/?model=Dev%20Alpha&lang=en

I like to do the logic first because I figure if you can't get the functionality working why bother making a pretty UI?  So without further ado... Let's get started!

Part 1: The Logic

Since this example uses both QML/JavaScript and C++ for the logic it is necessary to have some amount of UI.  As well as creating a barebones UI allows you to test that everything is working as it should. One thing to especially notice is that I chose identifiers for the id of each item to be representative of what the item is or does.  This will be especially true once the final UI is made in Part 2 and things won't be this close together in the code.

First part of the test UI will be 3 buttons: Rock, Paper, and Scissors.  These will act as the 3 signals that control the game.

        Container {
            Button {
                id: rockbutton
                objectName: "rockbutton"
                text: "ROCK!"
                onClicked: {
                }
            }
            Button {
                id: paperbutton
                objectName: "paperbutton"
                text: "PAPER!"
                onClicked: {
                }
            }
            Button {
                id: scissorsbutton
                objectName: "scissorsbutton"
                text: "SCISSORS!"
                onClicked: {
                }
            }
        }

Next is a Label that states what option the computer decided to pick:

            Label {
                id: computerpick
                text: "BlackBerry picks: ..."
            }

After that is the winner:

            Label {
                id: winnerlabel
                text: "Winner"
            }

Finally, there is a container that holds labels for your win/loss/tie record:

        Container {
            layout: StackLayout {
                layoutDirection: LayoutDirection.LeftToRight
            }
            Label {
                text: "Record: "
            }
            Label {
                id: win
                text: "0"
            }
            Label {
                text: "-"
            }
            Label {
                id: lose
                text: "0"
            }
            Label {
                text: "-"
            }
            Label {
                id: tie
                text: "0"
            }
        }

Now it is time to create the logic within the buttons and C++ functions.  The way it made sense for me to do it was to let QML/JavaScript handle the setup for each choice then pass those choices to C++ for it to return the winner.  So for instance for the "rockbutton" onClicked signal it generates a "var = number" of 1-3 for the computer's choice and takes "1" as the user's choice for Rock. (For Scissors it is "2" and for Paper it is "3" for the user's choice.)  Then passes those two numbers into clickedRock() C++ function to find out the winner.  I am not going to go through each line individually but as you see below in the full code it is just a bunch of if/else statements for deciding who wins/loses/ties based off the rules of Rock, Paper, Scissors. 

Lastly, for the win/loss/tie record keeping, this is accomplished by looking at the outcome of the game and the previous total for either win/loss/tie. Based on the outcome the codeWinning() C++ function adds 1 to the appropriate value.

And that's it for logic.  See below for full code of main.qml, app.cpp, and app.hpp.  Since I didn't go too in depth, feel free to ask questions in the comments field about any aspect of the logic.

main.qml

import bb.cascades 1.0

Page {
    content: Container {
        Container {
            Button {
                id: rockbutton
                objectName: "rockbutton"
                text: "ROCK!"
                onClicked: {
                    var winning = win.text;
                    var losing = lose.text;
                    var ties = tie.text;
                    var number = Math.floor((Math.random() * 3) + 1);
                    var gameoutcome = app.clickedRock(1, number);
                    if (number == 1) {
                        computerpick.text = "BlackBerry picks: Rock";
                    } else if (number == 2) {
                        computerpick.text = "BlackBerry picks: Paper";
                    } else {
                        computerpick.text = "BlackBerry picks: Scissors";
                    }
                    if (gameoutcome == 1) {
                        winnerlabel.text = "You WIN!";
                    } else if (gameoutcome == 2) {
                        winnerlabel.text = "BlackBerry WINS!";
                    } else {
                        winnerlabel.text = "Draw";
                    }
                    if (gameoutcome == 1) {
                        win.text = app.codeWinning(winning);
                    } else if (gameoutcome == 2) {
                        lose.text = app.codeWinning(losing);
                    } else {
                        tie.text = app.codeWinning(ties);
                    }
                }
            }
            Button {
                id: paperbutton
                objectName: "paperbutton"
                text: "PAPER!"
                onClicked: {
                    var winning = win.text;
                    var losing = lose.text;
                    var ties = tie.text;
                    var number = Math.floor((Math.random() * 3) + 1);
                    var gameoutcome = app.clickedPaper(2, number);
                    if (number == 1) {
                        computerpick.text = "BlackBerry picks: Rock";
                    } else if (number == 2) {
                        computerpick.text = "BlackBerry picks: Paper";
                    } else {
                        computerpick.text = "BlackBerry picks: Scissors";
                    }
                    if (gameoutcome == 1) {
                        winnerlabel.text = "You WIN!";
                    } else if (gameoutcome == 2) {
                        winnerlabel.text = "BlackBerry WINS!";
                    } else {
                        winnerlabel.text = "Draw";
                    }
                    if (gameoutcome == 1) {
                        win.text = app.codeWinning(winning);
                    } else if (gameoutcome == 2) {
                        lose.text = app.codeWinning(losing);
                    } else {
                        tie.text = app.codeWinning(ties);
                    }
                }
            }
            Button {
                id: scissorsbutton
                objectName: "scissorsbutton"
                text: "SCISSORS!"
                onClicked: {
                    var winning = win.text;
                    var losing = lose.text;
                    var ties = tie.text;
                    var number = Math.floor((Math.random() * 3) + 1);
                    var gameoutcome = app.clickedScissors(3, number);
                    if (number == 1) {
                        computerpick.text = "BlackBerry picks: Rock";
                    } else if (number == 2) {
                        computerpick.text = "BlackBerry picks: Paper";
                    } else {
                        computerpick.text = "BlackBerry picks: Scissors";
                    }
                    if (gameoutcome == 1) {
                        winnerlabel.text = "You WIN!";
                    } else if (gameoutcome == 2) {
                        winnerlabel.text = "BlackBerry WINS!";
                    } else {
                        winnerlabel.text = "Draw";
                    }
                    if (gameoutcome == 1) {
                        win.text = app.codeWinning(winning);
                    } else if (gameoutcome == 2) {
                        lose.text = app.codeWinning(losing);
                    } else {
                        tie.text = app.codeWinning(ties);
                    }
                }
            }
        }
        Container {
            topMargin: 50.0
            Label {
                id: computerpick
                text: "BlackBerry picks: ..."
            }
            Label {
                id: winnerlabel
                text: "Winner"
            }
        }
        Container {
            layout: StackLayout {
                layoutDirection: LayoutDirection.LeftToRight
            }
            Label {
                text: "Record: "
            }
            Label {
                id: win
                text: "0"
            }
            Label {
                text: "-"
            }
            Label {
                id: lose
                text: "0"
            }
            Label {
                text: "-"
            }
            Label {
                id: tie
                text: "0"
            }
        }
    }
}

app.cpp

#include "app.hpp"

#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>

using namespace bb::cascades;

App::App()
{
    QmlDocument *qml = QmlDocument::create("main.qml");
    qml->setContextProperty("app", this);
    
    AbstractPane *root = qml->createRootNode<AbstractPane>();
    Application::setScene(root);
}

int App::clickedRock(int user1, int user2)
{
    int winner;

    if((user1 == 1) && (user2 == 2))
    winner=2;
    else if ((user1 == 1) && (user2 == 3))
    winner=1;
    else if ((user1 == 1) && (user2 == 1))
    winner=0;

    return (winner);

}

int App::clickedPaper(int user1, int user2)
{
    int winner;

    if((user1 == 2) && (user2 == 2))
    winner=0;
    else if ((user1 == 2) && (user2 == 3))
    winner=2;
    else if ((user1 == 2) && (user2 == 1))
    winner=1;

    return (winner);

}

int App::clickedScissors(int user1, int user2)
{
    int winner;

    if((user1 == 3) && (user2 == 2))
    winner=1;
    else if ((user1 == 3) && (user2 == 3))
    winner=0;
    else if ((user1 == 3) && (user2 == 1))
    winner=2;

    return (winner);

}

int App::codeWinning(int record)
{
    int add1;
    add1 = record+1;
    return add1;
}

app.hpp

#ifndef APP_H
#define APP_H

#include <QObject>


class App : public QObject
{
    Q_OBJECT

public:
    App();

Q_INVOKABLE int clickedRock(int user1, int user2);
Q_INVOKABLE int clickedPaper(int user1, int user2);
Q_INVOKABLE int clickedScissors(int user1, int user2);
Q_INVOKABLE int codeWinning(int record);


};

#endif // ifndef APP_H

Running a C++ Functions from QML

When I first read about Cascades "they" said use QML for the UI and C++ for the logic.  Okay, great so I wrote a function in C++ and made a pretty UI in QML... Now what?  In this example I'll go through the steps it takes to call a C++ function from the QML.  However this example won't have a pretty UI.

Learning BB10 Cascades... After HelloWorld

In this editorial posting I'd like to share my experiences/recommendations in BB10 Cascades app developing after completing the "HelloWorld" example. I want to share this because I originally wanted to get into mobile app developing years ago but always got stuck after HelloWorld and didn't really know where to go next. I eventually figured it out and part of me making a blog was to prevent others from struggling early on like I did.  I hope this helps anyone who ends up in a similar situation not give up.

Subscribe to this RSS feed
Subscribe to the official OSBB BBM Channel!

osbbchannelQR

C00013E89

Back to top