310 likes | 450 Views
Simple Game Development in Cascades. JAM42 Eric Harty Brian Scheirer May 14-16, 2013. Who are we?. Brian Scheirer @BrianScheirer. Eric Harty @Ebscer. So We Made a Game. In Cascades…. Full Source Code. Download the full source code from Github at
E N D
Simple Game Development in Cascades JAM42 Eric Harty Brian Scheirer May 14-16, 2013
Who are we? Brian Scheirer @BrianScheirer Eric Harty @Ebscer
So We Made a Game In Cascades…
Full Source Code Download the full source code from Github at https://github.com/Ebscer/BlackBerryLive-JAM42
Level Selection Screen • Entry point for our game • Allows users to jump ahead, replay levels or continue where they last left off • Same basic code as Starbeams • LevelButton.qml objects in a ScrollView • Remember last played level
LevelButton.qml import bb.cascades 1.0 Container { property int value: 0 background: levelButtonBack.imagePaint//ImagePaintDefinition preferredWidth: 144 preferredHeight: 144 gestureHandlers: [ TapHandler { onTapped: { levelSelectionPage.newLevel(value) } } ] }
Level Selection (part 2) attachedObjects: [ ComponentDefinition { id: levelButtonObject source: “LevelButton.qml” } ]
Level Selection (part 3) • ScrollView { • Container { • id: levels • onCreationCompeted: { • for(vari=0;i<max_level; i++){ • var b = levelButtonObject.createObject() • b.value = i • levels.add(b) • } • } • } • }
Level Creation • Load the level • JavaScript function • Setup win/loss conditions and score • Variable scoring • QTimer • User input • Switch Buttons • Submit Button
Level Creation: Load Level onCurrent_levelChanged: { LevelFunctions.nextLevel(current_level); } … function nextLevel(theLevel) { switch (theLevel) { case 1: //level conditions break; }
Level Creation: Win Conditions ImageButton { defaultImageSource: "asset:///images/Sub1.png" pressedImageSource: "asset:///images/Sub2.png" onClicked: { varbox1postion = Number(box1.translationX); varbox2postion = Number(box2.translationX); vartube1score = Number(0); vartube2score = Number(0); // if/else statement for tube2score based off box2postion // if/else statement for tube2score based off box2postion gameTimer.stop(); round_score= tube1score + tube2score; subDialog.open(); } }
Level Creation: Loss Conditions qmlRegisterType<QTimer>("bb.cascades", 1, 0, "QTimer"); attachedObjects: [ QTimer { id: gameTimer interval: 1000 onTimeout: { timeRemaining.value -= 1; timeLabel.text = timeRemaining.value; if (timeRemaining.value == 0) { //end game loseDialog.open(); } } } ]
Level Creation: User Input gestureHandlers: [ TapHandler{ onTapped: { if (switch2.text == "on") { if (right2.isPlaying() == true) { right2.stop(); } else if (left2.isPlaying() == true) { left2.stop(); } switch2.text = "off"; mySwitch2.imageSource = "asset:///images/Switch2.png"; } … //else do the opposite } } ]
Animation • Translation Animations • Duration • Position • Easing Curves • Use onEndedfunction to alternate animations
Animation (Part 2) Container { id: box2 animations: [ TranslateTransition { id: right2 toX: 500 duration: 2000 onEnded: { left2.play(); } } ] }
In-App Purchases • Used in our game to progress past the second level • A better way to offer upgrades than having a separate app • Additional features • “Power-ups”
In-App Purchases (c++) // use PaymentServiceControl.cpp from the paymentservice sample // first line for testing only PaymentManager::setConnectionMode(PaymentConnectionMode::Test); qmlRegisterType<PaymentServiceControl>("com.blackberry.payment", 1, 0, "PaymentServiceControl"); https://github.com/blackberry/Cascades-Samples/tree/master/paymentservice
In-App Purchases (qml part 1) import com.blackberry.payment 1.0 attachedObjects: [ PaymentServiceControl { id: paymentControl onPurchaseResponceSuccess: { // handle successful purchase } onInfoResponseError: { if(errorText==“alreadyPurchased”) { //handle successful purchase } else { //purchase failed (if needed) } } } ]
In-App Purchases (qml part 2) import com.blackberry.payment 1.0 varinAppId = “UnlockLevel3" varinAppSku = “UnlockLevel3“ varinAppName = “Unlock the third level” varinAppMetaData = “Allows you to play past level 2” paymentControl.purchase(inAppId,inAppSku,inAppName,inAppMetaData)
Scoreloop Leaderboards • Scoreloop is a free service provided by BlackBerry • Scoreloop services are run on a separate thread • Leaderboard GUI is based on a ListView
Scoreloop BBLiveGame::BBLiveGame(bb::cascades::Application *app) { mScoreLoop = ScoreLoopThread::instance(); mAppData = 0; mScoreLoop->start(); } void BBLiveGame::submitScore(int score, int mode) { if(mAppData!=0) { ScoreLoopThread::SubmitScore(mAppData,score,mode); } } ScoreLoopThread* BBLiveGame::scoreLoop() { return ScoreLoopThread::instance(); }
Scoreloop leaderboard qml ListView { id: leaderboardList dataModel: GroupDataModel { id: leaderboardModel grouping: ItemGrouping.None sortingKeys: [“rank”] } onCreationCompleted: { App.scoreloop().LoadLeaderboardCompleted.connect(getdata) App.loadLeaderboard(“all-time”,100) } } function getdata(leaderboardData) { leaderboardModel.insertList(leaderboardData) }
Scoreloop leaderboard thread void ScoreLoopThread::LoadLeaderboard(AppData_t *app, SC_ScoresSearchList_t searchList, unsigned int count) { SC_Client_CreateScoresController(app->client, &app-> scoresController, LoadLeaderboardCompletionCallback, app); SC_Range_t range; range.offset = 0; range.length = count; SC_ScoresController_LoadScores(app->scoresController, range); } void ScoreLoopThread::LoadLeaderboardCompletionCallback (void *userData, SC_Error_t completionStatus) { AppData_t *app = (AppData_t *) userData; SC_ScoreList_h scoreList = SC_ScoresController_GetScores(app->scoresController); QVariantList leaderboardData; continued on next slide
Scoreloop leaderboard thread part 2 QVariantList leaderboardData; unsigned int i, numScores = SC_ScoreList_GetCount(scoreList); for (i = 0; i < numScores; ++i) { SC_Score_h score = SC_ScoreList_GetAt(scoreList, i); SC_User_h user = SC_Score_GetUser(score); SC_String_h login = user ? SC_User_GetLogin(user) : NULL; QVariantMap scoreData; scoreData["rank"] = SC_Score_GetRank(score); scoreData["simpleScore"] = SC_Score_GetResult(score); scoreData["username"]=login?SC_String_GetData(login):"<unknown>"; leaderboardData.append(scoreData); } emit(instance()->LoadLeaderboardCompleted(leaderboardData)); SC_ScoresController_Release(app->scoresController);
Next Steps… Cocos2dx
Cascades + Native Gaming libraries • What? Using Cascades with native gaming libraries is easy. ForeignWindow control lets you embed a native game window to Cascades UI. • Who? Native BB10 App look-and-feel with Cascades UI Focus on native game development and not UI Overlaycascades controlsover their native game
What is Cocos2D Framework for 2D Games, graphics apps Simplifies: Flow control between scenes Sprites with actions [move, rotate, scale…] Effects [waves, twirl, lens…] Particle Systems [explosions, fireworks …]
Cascades + Native Gaming libraries • How? [https://github.com/rmadhavan/Cocos2dxIntegrated] • Use Case: Running Cocos2dx in Cascades • Import Cocos2dx libraries. • Modify Cocos2dx library to use a child window under Cascades’ Window group. • Modify Z-order of Cocos2dx window either behind (Z < 0) or in front (Z > 0) • Build cocos2dx libraries. • Create a new cascades project. • Include Cocos2dx headers and libs to the cascades project. • Create a ForeignWindowControl and bind cocos2dx game window • Execute cocos2dx game loop in a new thread. • If Cocos2dx is underlay, use cascades event to modify Scene. • If Cocos2dx is overlay, use Cocos2dx event handling to modify Scene.
Q & A Questions & Answers
Be in touch • Eric Harty • Twitter: @Ebscer • Email: eric@ebscer.com • Site: http://news.ebscer.com/ • Brian Scheirer • Twitter: @BrianScheirer • Site: http://bbcascades.com/
THANK YOU JAM42 Eric Harty Brian Scheirer May 14-16, 2013