Game Center Support
by Justin Mosiman · in iTorque 2D · 11/12/2010 (8:53 pm) · 66 replies
With the sad news from InstantAction, I feel that it is more important now than ever to keep iTGB alive. With that, I am going to post instructions on how to integrate Game Center within iTGB. I know that integrating Game Center with Open Feint is easier, but I feel that the two frameworks have a lot of overlapping features and I want to reduce the amount of bloat. If this code has been useful to you, I'd appreciate a War Evolved download :)
There is a lot of setup that you have to do within iTunes Connect to get Game Center to work, so instead of repeating it I'll just point you to the iTunes Connect Game Center docs. Even though the code is here, I still recommend reading the docs to be sure you don't miss anything and can understand what is happening.
Assuming you have iTunes Connect setup, perform the following steps:
1. Create GameCenter.mm and GameCenter.h within the platformiPhone directory in the Xcode Torque project.
2. Add the following to GameCenter.h:
3. Add the following code to GameCenter.mm:
4. Update GameCenterWrapper::reportScore() and GameCenterWrapper::reportAchievement() to include the score category/achievement id that was set in iTunes Connect.
5. To initialize Game Center, call the following Torque Script function:
6. To close Game Center, call:
7. To add a high score, call:
8. To award an achievement, call:
9. To show the leaderboard GUI, call:
10. To show the achievements GUI, call:
11. The Torque Script function gameCenterAuthenticationChanged(%isAvailable) is called whenever the authentication changes. Add this function somewhere in your game to handle logging into Game Center, such as showing the achievements or leaderboard.
Note that it is up to you to decide how you want to indicate that an achievement was achieved. There are more Game Center related functions exposed, and you can decide if you need to use them, but I haven't found a use for them.
If this code has been useful to you, I'd appreciate a War Evolved download :)
Justin
There is a lot of setup that you have to do within iTunes Connect to get Game Center to work, so instead of repeating it I'll just point you to the iTunes Connect Game Center docs. Even though the code is here, I still recommend reading the docs to be sure you don't miss anything and can understand what is happening.
Assuming you have iTunes Connect setup, perform the following steps:
1. Create GameCenter.mm and GameCenter.h within the platformiPhone directory in the Xcode Torque project.
2. Add the following to GameCenter.h:
//
// GameCenter.m
// Torque2D
//
// Created by Justin Mosiman on 10/29/10.
// Copyright 2010 Opsive, LLC. All rights reserved.
//
#import <GameKit/GameKit.h>
#include "console/console.h"
@interface GameCenter : UIViewController <GKLeaderboardViewControllerDelegate, GKAchievementViewControllerDelegate>
{
BOOL isAuthenticated;
BOOL gameCenterAvailable;
UIViewController *gameCenterViewController;
}
@property (nonatomic,retain) UIViewController *gameCenterViewController;
- (void)authenticateLocalPlayer;
- (void)registerForAuthenticationNotification;
- (void)authenticationChanged;
- (BOOL)isAuthenticated;
- (void)reportScore:(int64_t)score forCategory:(NSString*)category;
- (void)reportScore:(GKScore *)scoreReporter;
- (void)saveScoreToDevice:(GKScore *)score;
- (void)retrieveScoresFromDevice;
- (void)showLeaderboard;
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController;
- (void)reportAchievementIdentifier:(NSString*)identifier percentComplete:(float)percent;
- (void)reportAchievementIdentifier:(GKAchievement *)achievement;
- (void)saveAchievementToDevice:(GKAchievement *)achievement;
- (void)retrieveAchievementsFromDevice;
- (void)showAchievements;
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController;
- (void)close;
@end
static GameCenter *gameCenter;
namespace GameCenterWrapper {
void authenticate();
void reportScore(int score, int category);
void reportAchievement(int achievement);
bool isAuthenticated();
void showLeaderboard();
void showAchievements();
void close();
}3. Add the following code to GameCenter.mm:
//
// GameCenter.mm
// Torque2D
//
// Created by Justin Mosiman on 10/29/10.
// Copyright 2010 Opsive, LLC. All rights reserved.
//
#import "platformiPhone/GameCenter.h"
BOOL isGameCenterAvailable()
{
// Check for presence of GKLocalPlayer API.
Class gcClass = (NSClassFromString(@"GKLocalPlayer"));
// The device must be running running iOS 4.1 or later.
NSString *reqSysVer = @"4.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);
return (gcClass && osVersionSupported);
}
@implementation GameCenter
@synthesize gameCenterViewController;
//--------------------------------------------------------
// Static functions/variables
//--------------------------------------------------------
static NSString *getGameCenterSavePath()
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [NSString stringWithFormat:@"%@/GameCenterSave.txt",[paths objectAtIndex:0]];
}
static NSString *scoresArchiveKey = @"Scores";
static NSString *achievementsArchiveKey = @"Achievements";
//--------------------------------------------------------
// Authentication
//--------------------------------------------------------
- (void)authenticateLocalPlayer {
isAuthenticated = NO; // assume the player isn't authenticated
gameCenterAvailable = isGameCenterAvailable();
if(!gameCenterAvailable){
return;
}
gameCenterViewController = [[UIViewController alloc] init];
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error) {
if (error == nil){
// Insert code here to handle a successful authentication.
isAuthenticated = YES;
[self registerForAuthenticationNotification];
// report any unreported scores or achievements
[self retrieveScoresFromDevice];
[self retrieveAchievementsFromDevice];
// let the scripts know
Con::executef(2,"gameCenterAuthenticationChanged","1");
}else{
Con::executef(2,"gameCenterAuthenticationChanged","0");
}
}];
}
- (void)registerForAuthenticationNotification
{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self selector:@selector(authenticationChanged) name:GKPlayerAuthenticationDidChangeNotificationName object:nil];
}
- (void)authenticationChanged
{
isAuthenticated = NO; // assume the player isn't authenticated
gameCenterAvailable = isGameCenterAvailable();
if(!gameCenterAvailable){
return;
}
if ([GKLocalPlayer localPlayer].isAuthenticated){
// Insert code here to handle a successful authentication.
isAuthenticated = YES;
// report any unreported scores or achievements
[self retrieveScoresFromDevice];
[self retrieveAchievementsFromDevice];
// let the scripts know
Con::executef(2,"gameCenterAuthenticationChanged","1");
}else{
Con::executef(2,"gameCenterAuthenticationChanged","0");
}
}
- (BOOL)isAuthenticated
{
return gameCenterAvailable && isAuthenticated;
}
//--------------------------------------------------------
// Leaderboard
//--------------------------------------------------------
- (void)reportScore:(int64_t)score forCategory:(NSString*)category
{
if(!gameCenterAvailable)
return;
GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
if(scoreReporter){
scoreReporter.value = score;
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil){
// handle the reporting error
[self saveScoreToDevice:scoreReporter];
}
}];
}
}
- (void)reportScore:(GKScore *)scoreReporter
{
if(!gameCenterAvailable)
return;
if(scoreReporter){
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil){
// handle the reporting error
[self saveScoreToDevice:scoreReporter];
}
}];
}
}
- (void)saveScoreToDevice:(GKScore *)score
{
NSString *savePath = getGameCenterSavePath();
// If scores already exist, append the new score.
NSMutableArray *scores = [[[NSMutableArray alloc] init] autorelease];
NSMutableDictionary *dict;
if([[NSFileManager defaultManager] fileExistsAtPath:savePath]){
dict = [[[NSMutableDictionary alloc] initWithContentsOfFile:savePath] autorelease];
NSData *data = [dict objectForKey:scoresArchiveKey];
if(data) {
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
scores = [unarchiver decodeObjectForKey:scoresArchiveKey];
[unarchiver finishDecoding];
[unarchiver release];
[dict removeObjectForKey:scoresArchiveKey]; // remove it so we can add it back again later
}
}else{
dict = [[[NSMutableDictionary alloc] init] autorelease];
}
[scores addObject:score];
// The score has been added, now save the file again
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:scores forKey:scoresArchiveKey];
[archiver finishEncoding];
[dict setObject:data forKey:scoresArchiveKey];
[dict writeToFile:savePath atomically:YES];
[archiver release];
}
- (void)retrieveScoresFromDevice
{
NSString *savePath = getGameCenterSavePath();
// If there are no files saved, return
if(![[NSFileManager defaultManager] fileExistsAtPath:savePath]){
return;
}
// First get the data
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:savePath];
NSData *data = [dict objectForKey:scoresArchiveKey];
// A file exists, but it isn't for the scores key so return
if(!data){
return;
}
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
NSArray *scores = [unarchiver decodeObjectForKey:scoresArchiveKey];
[unarchiver finishDecoding];
[unarchiver release];
// remove the scores key and save the dictionary back again
[dict removeObjectForKey:scoresArchiveKey];
[dict writeToFile:savePath atomically:YES];
// Since the scores key was removed, we can go ahead and report the scores again
for(GKScore *score in scores){
[self reportScore:score];
}
}
- (void)showLeaderboard
{
if(!isAuthenticated)
return;
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != nil) {
leaderboardController.leaderboardDelegate = self;
UIWindow* window = [UIApplication sharedApplication].keyWindow;
[window addSubview: gameCenterViewController.view];
[gameCenterViewController presentModalViewController: leaderboardController animated: YES];
}
}
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
[gameCenterViewController dismissModalViewControllerAnimated:YES];
[viewController.view removeFromSuperview];
[viewController release];
}
//--------------------------------------------------------
// Achievements
//--------------------------------------------------------
- (void)reportAchievementIdentifier:(NSString*)identifier percentComplete:(float)percent
{
if(!gameCenterAvailable)
return;
GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
if (achievement){
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error){
if (error != nil){
[self saveAchievementToDevice:achievement];
}
}];
}
}
- (void)reportAchievementIdentifier:(GKAchievement *)achievement
{
if(!gameCenterAvailable)
return;
if (achievement){
[achievement reportAchievementWithCompletionHandler:^(NSError *error){
if (error != nil){
[self saveAchievementToDevice:achievement];
}
}];
}
}
- (void)saveAchievementToDevice:(GKAchievement *)achievement
{
NSString *savePath = getGameCenterSavePath();
// If achievements already exist, append the new achievement.
NSMutableArray *achievements = [[[NSMutableArray alloc] init] autorelease];
NSMutableDictionary *dict;
if([[NSFileManager defaultManager] fileExistsAtPath:savePath]){
dict = [[[NSMutableDictionary alloc] initWithContentsOfFile:savePath] autorelease];
NSData *data = [dict objectForKey:achievementsArchiveKey];
if(data) {
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
achievements = [unarchiver decodeObjectForKey:achievementsArchiveKey];
[unarchiver finishDecoding];
[unarchiver release];
[dict removeObjectForKey:achievementsArchiveKey]; // remove it so we can add it back again later
}
}else{
dict = [[[NSMutableDictionary alloc] init] autorelease];
}
[achievements addObject:achievement];
// The achievement has been added, now save the file again
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:achievements forKey:achievementsArchiveKey];
[archiver finishEncoding];
[dict setObject:data forKey:achievementsArchiveKey];
[dict writeToFile:savePath atomically:YES];
[archiver release];
}
- (void)retrieveAchievementsFromDevice
{
NSString *savePath = getGameCenterSavePath();
// If there are no files saved, return
if(![[NSFileManager defaultManager] fileExistsAtPath:savePath]){
return;
}
// First get the data
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:savePath];
NSData *data = [dict objectForKey:achievementsArchiveKey];
// A file exists, but it isn't for the achievements key so return
if(!data){
return;
}
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
NSArray *achievements = [unarchiver decodeObjectForKey:achievementsArchiveKey];
[unarchiver finishDecoding];
[unarchiver release];
// remove the achievements key and save the dictionary back again
[dict removeObjectForKey:achievementsArchiveKey];
[dict writeToFile:savePath atomically:YES];
// Since the key file was removed, we can go ahead and try to report the achievements again
for(GKAchievement *achievement in achievements){
[self reportAchievementIdentifier:achievement];
}
}
- (void)showAchievements
{
if(!isAuthenticated)
return;
GKAchievementViewController *achievements = [[GKAchievementViewController alloc] init];
if (achievements != nil){
achievements.achievementDelegate = self;
UIWindow* window = [UIApplication sharedApplication].keyWindow;
[window addSubview: gameCenterViewController.view];
[gameCenterViewController presentModalViewController: achievements animated: YES];
}
}
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
[gameCenterViewController dismissModalViewControllerAnimated:YES];
[viewController.view removeFromSuperview];
[viewController release];
}
//--------------------------------------------------------
// Goodbye
//--------------------------------------------------------
- (void)close
{
[gameCenterViewController release];
}
@end
//--------------------------------------------------------
// Wrapper
//--------------------------------------------------------
void GameCenterWrapper::authenticate(){
if(isGameCenterAvailable()){
gameCenter = [[GameCenter alloc] init];
[gameCenter authenticateLocalPlayer];
}
}
//
// If the category names are updated, make sure they are also updated in iTunes Connect.
//
void GameCenterWrapper::reportScore(int score, int category){
NSString *categoryID = [[NSString alloc] autorelease];
switch (category){
case 0:
categoryID = @"YOUR_CATEGORY_ID_0";
break;
case 1:
categoryID = @"YOUR_CATEGORY_ID_1";
break;
}
[gameCenter reportScore:score forCategory:categoryID];
}
void GameCenterWrapper::reportAchievement(int achievement){
NSString *achievementID = [[NSString alloc] autorelease];
switch (achievement){
case 0:
achievementID = @"YOUR_ACHIEVEMENT_ID_0";
break;
case 1:
achievementID = @"YOUR_ACHIEVEMENT_ID_1";
break;
}
[gameCenter reportAchievementIdentifier:achievementID percentComplete:100.0f]; // no partial achievements
}
bool GameCenterWrapper::isAuthenticated(){
return [gameCenter isAuthenticated];
}
void GameCenterWrapper::showLeaderboard(){
[gameCenter showLeaderboard];
}
void GameCenterWrapper::showAchievements(){
[gameCenter showAchievements];
}
void GameCenterWrapper::close(){
if(isGameCenterAvailable()){
[gameCenter close];
[gameCenter release];
}
}
ConsoleFunction(isGameCenterAvailable,bool,1,1,"()")
{
return isGameCenterAvailable();
}
ConsoleFunction(authenticateGameCenter,void,1,1,"")
{
GameCenterWrapper::authenticate();
}
ConsoleFunction(reportGameCenterScore,void,3,3,"(score, category id)")
{
GameCenterWrapper::reportScore(dAtoi(argv[1]),dAtoi(argv[2]));
}
ConsoleFunction(unlockGameCenterAchievement,void,2,2,"(achievement id)")
{
GameCenterWrapper::reportAchievement(dAtoi(argv[1]));
}
ConsoleFunction(isGameCenterAuthenticated,bool,1,1,"")
{
return GameCenterWrapper::isAuthenticated();
}
ConsoleFunction(showGameCenterLeaderboard,void,1,1,"")
{
GameCenterWrapper::showLeaderboard();
}
ConsoleFunction(showGameCenterAchievements,void,1,1,"")
{
GameCenterWrapper::showAchievements();
}
ConsoleFunction(closeGameCenter,void,1,1,""){
GameCenterWrapper::close();
}4. Update GameCenterWrapper::reportScore() and GameCenterWrapper::reportAchievement() to include the score category/achievement id that was set in iTunes Connect.
5. To initialize Game Center, call the following Torque Script function:
authenticateGameCenter();I put it in the initializeProject() function within game/main.cs. It needs to be one of the first things called once iTGB has initialized.
6. To close Game Center, call:
closeGameCenter();I put it within shutdownProject() of game/main.cs.
7. To add a high score, call:
reportGameCenterScore(%score,%category);
8. To award an achievement, call:
unlockGameCenterAchievement(%achievementID);
9. To show the leaderboard GUI, call:
showGameCenterLeaderboard();
10. To show the achievements GUI, call:
showGameCenterAchievements();
11. The Torque Script function gameCenterAuthenticationChanged(%isAvailable) is called whenever the authentication changes. Add this function somewhere in your game to handle logging into Game Center, such as showing the achievements or leaderboard.
Note that it is up to you to decide how you want to indicate that an achievement was achieved. There are more Game Center related functions exposed, and you can decide if you need to use them, but I haven't found a use for them.
If this code has been useful to you, I'd appreciate a War Evolved download :)
Justin
#43
05/10/2011 (11:11 pm)
@Mich, when can we look forward to that? It would be nice to have the GameCenter support asap.
#44
My best guess is soon(ish).
05/11/2011 (8:00 am)
@Henry - I don't have a date for you. I've been switching between iT2D and T3D demo work, so I'm not quite finished. The work (code, docs, example) should be wrapped up soon, but it needs to go through a day of QA before we can release the preview. QA is currently in the middle of a cycle for T3D 1.1, so I might not get their time this week.My best guess is soon(ish).
#46
05/13/2011 (11:50 pm)
@Justin - Thanks for this resource. It was very helpful in finding a final implementation. I scrapped the blocker concept since it had little-to-no effect, no matter how hard I tried to force a problem.
#47
Thanks for the post
My goal is to have
1) OpenFeint
2) iAd
3) GameCenter
4) Facebook connect (invite friends, publish)
I have OpenFeint running, thanks to this post
www.garagegames.com/community/forums/viewthread/104583
I *kind* of have iAd running
www.garagegames.com/community/forums/viewthread/126472
I defined a dedicated UIViewController, just wondering how well this integrates with this GameCenter own View Controller
it seems OpenFeint has some Facebook connection feature (have not tried it yet) so I was wondering if that would be enough or not;
I was wondering at the moment how much of an overlap this is.
Something like
1) OpenFeint alone is enough (allows Facebook and GameCenter connection)
2) OpenFeint + Game Center SDK is needed to access both
3) OpenFeint + Game Center + Facebook iOS SDK is needed
Any thoughts?
07/04/2011 (4:20 pm)
@JustinThanks for the post
My goal is to have
1) OpenFeint
2) iAd
3) GameCenter
4) Facebook connect (invite friends, publish)
I have OpenFeint running, thanks to this post
www.garagegames.com/community/forums/viewthread/104583
I *kind* of have iAd running
www.garagegames.com/community/forums/viewthread/126472
I defined a dedicated UIViewController, just wondering how well this integrates with this GameCenter own View Controller
@interface ViewController : UIViewController <ADBannerViewDelegate>
{
ADBannerView *adView;
}it seems OpenFeint has some Facebook connection feature (have not tried it yet) so I was wondering if that would be enough or not;
I was wondering at the moment how much of an overlap this is.
Something like
1) OpenFeint alone is enough (allows Facebook and GameCenter connection)
2) OpenFeint + Game Center SDK is needed to access both
3) OpenFeint + Game Center + Facebook iOS SDK is needed
Any thoughts?
#48
Thanks for your answer.
08/23/2011 (12:16 am)
Hi every body, should it be possible to have a tuto for game center with iTgb please ?Thanks for your answer.
#49
08/23/2011 (6:11 am)
@christian - 1.5 is shipping with Game Center built-in and it will have documentation.
#51
my usage is
log is
The odd thing is that putting an XCode breakpoint in the function "submitScore", the breakpoint is not triggered. Doing the same in "showLeaderboard" is OK.
Here is the function.
I am more familiar with the function "ConsoleMethod":
The minimum/maximum number of parameters is always "plus 2". Argument 0 is the object, Argument 1 is the function name, Argument 2 is the first argument, Argument 3 is the second argument, and so on.
Console Reference
I also tried the GameCenter project in the Preview 2, but it does not respond to the OnTouchUp event, so the SubmitScore function is not called.
Also the function declaration declares a "bool" return type and nothing is returned.
08/23/2011 (8:45 am)
I am using the 1.5 Preview 2 "submitScore" function but running in some problems:my usage is
function WordyButtonGameCenter::onMouseUp( %this, %modifier, %worldPosition, %clicks )
{
if( $platform $= "windows" )
return;
submitScore( 1, "test" );
showLeaderboard();
}log is
Quote:
Game Center Authentication has changed
gameCenterAuthenticationChanged: Unknown command.
Achievements cached
bannerViewDidLoadAd
scripts/menu.cs (133): ::submitScore - wrong number of arguments.
scripts/menu.cs (133): usage: submitScore(score)
The odd thing is that putting an XCode breakpoint in the function "submitScore", the breakpoint is not triggered. Doing the same in "showLeaderboard" is OK.
Here is the function.
ConsoleFunction(submitScore, bool, 3, 3, "(int score, string category) Submit a score to a leaderboard, defined by categoryn"
"@param score Numerical value of the score being reportedn"
"@param category String containing the unique category of the leaderboardn"
"@return True if the score was successfully submitted, false if there was an error")
{
// Convert the identifier from a char* to a NSString
NSString* category = [[[NSString alloc] initWithUTF8String:argv[2]] autorelease];
// Convert score from char* to an int
int score = dAtoi(argv[1]);
// Call the GameCenterManager method for reporting a score
[gameCenterManager reportScore:score forCategory:category];
}I am more familiar with the function "ConsoleMethod":
The minimum/maximum number of parameters is always "plus 2". Argument 0 is the object, Argument 1 is the function name, Argument 2 is the first argument, Argument 3 is the second argument, and so on.
Console Reference
I also tried the GameCenter project in the Preview 2, but it does not respond to the OnTouchUp event, so the SubmitScore function is not called.
Also the function declaration declares a "bool" return type and nothing is returned.
#52
That's why the function is not getting called.
@christian - Soon'ish. I cannot provide a date yet, as it depends on how the current sprint goes. Each sprint is two weeks in length. This is supposed to be the last one before we go into QA. This is just a heads up on our process and should not be used as a time line to bank on.
08/23/2011 (9:32 am)
@Pedro - The first problem I noticed is that you are using onMouseUp, which does not exist in Preview 2. It should be this:function WordyButtonGameCenter::onMouseUp(%this, %touchID, %worldPos)
{
}That's why the function is not getting called.
@christian - Soon'ish. I cannot provide a date yet, as it depends on how the current sprint goes. Each sprint is two weeks in length. This is supposed to be the last one before we go into QA. This is just a heads up on our process and should not be used as a time line to bank on.
#53
My post was not clear. I am using 1.4.1 and the function is being called. What I did was to get the GameCenter code (the mm and h files) from 1.5 and just add it to my 1.4.1 XCode project; I also had to add 2 extra files (engine/source/console/simBase.cc
engine/source/console/simBase.h)
I also tried the 1.5 Preview 2 but the GameCenter sample seems not to be working.
Anyway, I am also using OpenFeint and guess what? They also have a function "submitScore" :-)
I strongly suggest that you rename all the GameCenter functions to have a prefix , say "GameCenterSubmitScore"
I did this. But the mystery lingers. The function is being called, see log below, but the strange thing is that the breakpoint in it in XCode is not triggered.
08/23/2011 (9:44 am)
@MichaelMy post was not clear. I am using 1.4.1 and the function is being called. What I did was to get the GameCenter code (the mm and h files) from 1.5 and just add it to my 1.4.1 XCode project; I also had to add 2 extra files (engine/source/console/simBase.cc
engine/source/console/simBase.h)
I also tried the 1.5 Preview 2 but the GameCenter sample seems not to be working.
Anyway, I am also using OpenFeint and guess what? They also have a function "submitScore" :-)
I strongly suggest that you rename all the GameCenter functions to have a prefix , say "GameCenterSubmitScore"
I did this. But the mystery lingers. The function is being called, see log below, but the strange thing is that the breakpoint in it in XCode is not triggered.
Quote:
scripts/menu.cs (133): ::GameCenterSubmitScore - wrong number of arguments.
scripts/menu.cs (133): usage: (int score, string category) Submit a score to a leaderboard, defined by category
@param score Numerical value of the score being reported
@param category String containing the unique category of the leaderboard
@return True if the score was successfully submitted, false if there was an error
#54
08/23/2011 (9:48 am)
@Pedro - Since you have modified the source code, it's tough to create a reproduction case. Your latest console log points to a problem, though. Can you post the ConsoleFunction for GameCenterSubmitScore?
#55
The function is above on my #51 comment. It's exactly the same as the one you have in 1.5, except that I changed the name to "GameCenterSubmitScore" from "SubmitScore" in order not to conflict with Open Feint's own "SubmitScore".
The error should be easy to reproduce in the 1.5 code base, just call it somewhere like this
I will try a new project in 1.5 to do this.
08/23/2011 (10:47 am)
@MichaelThe function is above on my #51 comment. It's exactly the same as the one you have in 1.5, except that I changed the name to "GameCenterSubmitScore" from "SubmitScore" in order not to conflict with Open Feint's own "SubmitScore".
The error should be easy to reproduce in the 1.5 code base, just call it somewhere like this
submitScore( 1, "test" );
I will try a new project in 1.5 to do this.
#56
08/23/2011 (10:51 am)
@Pedro - Sorry to do this, but you'll have to humor me. Can you copy and paste the ConsoleFunction exactly how it is in the code? Also, the exact script where it gets called. When you are working with customized code, I have to see it fully.
#57
sure, not a problem.
Function is ( I actually added a bool return value just to have one less XCode warning)
regarding the script, it's more tricky; this is part of a large project; the function that calls it is (Note: I removed the extra string parameter here in the call; like this the log error does not happen, but the function is not called... I think)
this class is made with
and this function is
so basically a t2dStaticSprite that responds to a mouse up event;
again, I am using 1.4.1 with modified sources; I understand that this may next to impossible for you to debug, so I'll try to reproduce this with a new 1.5 project from start. I was planning of going to 1.5 anyway :-)
08/23/2011 (11:09 am)
@Michaelsure, not a problem.
Function is ( I actually added a bool return value just to have one less XCode warning)
ConsoleFunction(GameCenterSubmitScore, bool, 3, 3, "(int score, string category) Submit a score to a leaderboard, defined by category\n"
"@param score Numerical value of the score being reported\n"
"@param category String containing the unique category of the leaderboard\n"
"@return True if the score was successfully submitted, false if there was an error")
{
// Convert the identifier from a char* to a NSString
NSString* category = [[[NSString alloc] initWithUTF8String:argv[2]] autorelease];
// Convert score from char* to an int
int score = dAtoi(argv[1]);
// Call the GameCenterManager method for reporting a score
[gameCenterManager reportScore:score forCategory:category];
return 1;
}regarding the script, it's more tricky; this is part of a large project; the function that calls it is (Note: I removed the extra string parameter here in the call; like this the log error does not happen, but the function is not called... I think)
function WordyButtonGameCenter::onMouseUp( %this, %modifier, %worldPosition, %clicks )
{
if( $platform $= "windows" )
return;
GameCenterSubmitScore( $model.score );
showLeaderboard();
}this class is made with
CreateButton( %this, "WordyButtonGameCenter", "ButtonGameCenterImageMap", %this.x_button_2, %this.y_button_2, 64,64);
and this function is
function CreateButton( %scenegraph_obj, %class, %image_map, %xpos, %ypos, %xsize, %ysize )
{
%obj = new t2dStaticSprite()
{
scenegraph = %scenegraph_obj;
class = %class;
useMouseEvents = "1";
};
%obj.setVisible( true );
%obj.setImageMap( %image_map );
%obj.setPosition( %xpos, %ypos );
%obj.setSize( %xsize, %ysize );
%obj.setLayer( 1 );
return %obj;
}so basically a t2dStaticSprite that responds to a mouse up event;
again, I am using 1.4.1 with modified sources; I understand that this may next to impossible for you to debug, so I'll try to reproduce this with a new 1.5 project from start. I was planning of going to 1.5 anyway :-)
#58
This:
Should be:
You forgot to add the string containing the category of the leaderboard you are submitting to.
08/23/2011 (11:40 am)
Found the problem in function WordyButtonGameCenter::onMouseUpThis:
GameCenterSubmitScore( $model.score );
Should be:
GameCenterSubmitScore($model.score, "category");
You forgot to add the string containing the category of the leaderboard you are submitting to.
#59
I had been putting the string extra parameter on and off for testing purposes; originally this *was* what was causing the log message above
*However*, when I tried now, the function gets called... and I did nothing else... go figure... Tuesday voodoo... so, ignore all this apparent bug report, all seems to be fine
But it would be a good idea maybe to rename the functions in GameCenter.mm to have a prefix "GameCenter_" so that they not conflict with OpenFeint
08/23/2011 (12:21 pm)
@MichaelI had been putting the string extra parameter on and off for testing purposes; originally this *was* what was causing the log message above
submitScore( 1, "test" );
*However*, when I tried now, the function gets called... and I did nothing else... go figure... Tuesday voodoo... so, ignore all this apparent bug report, all seems to be fine
But it would be a good idea maybe to rename the functions in GameCenter.mm to have a prefix "GameCenter_" so that they not conflict with OpenFeint
#60
08/23/2011 (1:29 pm)
@Pedro - Good to hear it's working. I'll look into renaming some stuff in the final.
Employee Michael Perry
GarageGames
Set its property to hidden:
No worries. The Game Center implementation I wrote exposes everything to TorqueScript, has plenty of comments in the source code and is very well documented. You will not have to dive into Objective-C to use it, unless you wish to debug the source code or extend the system. This will be in the next iT2D release.