あんまりゲームセンター流行ってないのよね。友達申請とかめったにしないでしょ?
きっと同じことやるならFacebookとかTwitterでやるほうが遊んでもらえると思うんだけど難しそうなんでやってないです。ゲーセンはググってオリャーって簡単にできたのでメモっておきます。
なんか先週水曜にLINEでこういうクエスチョンが来たのと、
金曜にこういうゲームをリリースしてそこでも同じことやっていたので、まーやりたい人はいるのかな〜と思って。
画像の準備
ゲーセンでアイコン画像設定してない人はエラるので、その人ようのデフォルト画像を用意してResourcesに入れておきます。
・play_friends.png
まーこんな感じ(64×64)
それと正常にアイコン画像とれても正方形のが来るので、まん丸にマスクでトリミングするようの画像も用意してResourcesに入れておきます。
・play_friends_mask.png
まー
こんなやつ(64×64)
Retinaとか考えてないでしょ。・・・すいません。
コーディング〜♪
HighScores.hと.mをNSObjectでプロジェクトに追加しました。各々の友達プレイヤーの「名前(NSString)」と「アイコン画像(UIImage)」と「ハイスコア(int)」と「表示してないか、表示してる最中か、表示終わったか、を示すフラグ(int)」と「表示する座標たち(int)」なんかを管理する独自クラスです。
こっちがヘッダー部
//
// HighScores.h
// PiyoUP ← ※気にしない
//
// Created by marchEnterprise on 2013/10/26. ← ※気にしない
// Copyright (c) 2013年 marchEnterprise. All rights reserved.
//#import <Foundation/Foundation.h>
#define FLG_DISP_PLAYER_READY 0
#define FLG_DISP_PLAYER_START 1
#define FLG_DISP_PLAYER_END 2@interface HighScores : NSObject {
NSString *playerName;
UIImage *playerImage;int playerScore;
int flg_disp_player;
int playerDegree;
int x;
int y;}
@property (nonatomic, retain) NSString *playerName;
@property (nonatomic, retain) UIImage *playerImage;@property (nonatomic, assign) int playerScore;
@property (nonatomic, assign) int flg_disp_player;
@property (nonatomic, assign) int playerDegree;
@property (nonatomic, assign) int x;
@property (nonatomic, assign) int y;@end
こっちが実装部
//
// HighScores.m
// PiyoUP ← ※気にしない
//
// Created by marchEnterprise on 2013/10/26. ← ※他言無用
// Copyright (c) 2013年 marchEnterprise. All rights reserved.
//#import “HighScores.h”
@implementation HighScores
@synthesize playerName,playerImage;
@synthesize playerScore;
@synthesize flg_disp_player;
@synthesize playerDegree;
@synthesize x;
@synthesize y;@end
で、実際に表示するゲーム中のクラスにこれ導入するよ。
『コンプガチャ禁止』ではViewController.hと.mに入れてます、というかタイトル画面も結果画面もメインのガチャも全部ViewControllerにぶち込んであるんで、知るか!
こっちはヘッダー部
ViewController.h
#import <GameKit/GameKit.h>
…
//ゲームセンター識別子
#define GK_HIGHSCORE_STR @”net.marchenterprise.dontcomp.quest”
#define GK_HIGHSCORE_MAX 50 //友達の上位50人まで表示するよ、MAXはいまのとこ100まで
#define TAG_HIGHSCORES 300 //ハイスコア配列で使うタグ : 300〜349…
//タイマーインターバル
#define TIMER_INTERVAL (1/30.0f)
//シーン定数
#define SCENE_QUESTINIT 10
#define SCENE_QUEST 11
…// マクロ定義
// iPhone デバッグ用マクロ
//プロジェクトの設定を開き、「Debug」構成を選択してから、一番下のユーザ定義カテゴリの
//「GCC_PREPROCESSOR_DEFINITIONS」に「DEBUG」を追加しておきます。
//あとは、NSLog の代わりに LOG を使うようにすれば ok です。
#ifdef DEBUG
# define LOG(…) NSLog(__VA_ARGS__)
# define LOG_CURRENT_METHOD NSLog(@”%@/%@”, NSStringFromClass([self class]), NSStringFromSelector(_cmd))
#else
# define LOG(…) ;
# define LOG_CURRENT_METHOD ;
#endif//角度からラジアン値
#define degreesToRadians(x) (M_PI * (x) / 180.0)//整数のランダム値
#define randint(r) ((int) (random()%(r)))
…
@interface ViewController : UIViewController <GKLeaderboardViewControllerDelegate,…> {
…
//チックタイマー
int tickTimer;
//現在のシーン
int now_scene;//スクリーンサイズ
float screen_width, screen_height;
…
//リーダーボード取得フラグ
BOOL flg_highscoreload;
//ハイスコア配列
NSMutableArray *highScoreArray;}
…
//ゲームセンター処理
#pragma mark –
#pragma mark GAMECENTER// 1位〜GK_HISHSCORE_MAXまでのプレイヤー取得
-(void) retrieveTopScores;-(void) dispHighScores;
-(void) removeHighScores;
…
@end
こっちが実装部
ViewController.m
#import “HighScores.h”
…
@implementation ViewController
…// 初期化
#pragma mark –
#pragma mark Init-(void) viewDidLoad {
[super viewDidLoad];
…
//ハイスコア配列初期化
highScoreArray = [[NSMutableArray alloc] init];
…
//tickタイマー処理化
tickTimer = 0;
//シーン初期化
now_scene = SCENE_QUESTINIT;
//画面サイズを取得
screen_width = [[UIScreen mainScreen] bounds].size.width;
screen_height = [[UIScreen mainScreen] bounds].size.height;
LOG(@” >>screen_width,height=%f,%f”, screen_width,screen_height);
…
// tickタイマーの開始
[NSTimer scheduledTimerWithTimeInterval: TIMER_INTERVAL
target: self
selector: @selector(tick)
userInfo: nil
repeats: YES];}
…
// メインタイマー処理
#pragma mark –
#pragma mark MainTimer-(void) tick {
…
//シーンによる分岐
switch (now_scene) {
…
// MARK: SCENE_QUESTINIT
//クエスト画面の初期化 → ※ゲーム開始時の処理ね
case SCENE_QUESTINIT:if (tickTimer == 1) {
LOG(@” >>scene: SCENE_QUESTINIT : 初期化”);
…
//ゲーセン
//リーダーボード取得
[self retrieveTopScores];}
…
if (tickTimer == (int) (2.5f/TIMER_INTERVAL)) {
//シーンチェンジ
now_scene = SCENE_QUEST;
tickTimer = 0;
}break;
// MARK: SCENE_QUEST
//クエスト画面 → ※ゲーム中に毎フレーム呼ばれる処理ね
case SCENE_QUEST:
if (tickTimer == 1) {
LOG(@” >>scene: SCENE_QUEST : クエスト開始”);
}
…
//ハイスコア表示
[self dispHighScores];break;
…
}
}
…
//ゲームセンター処理
#pragma mark –
#pragma mark GAMECENTER
…
// 1位〜GK_HISHSCORE_MAXまでのプレイヤー取得
-(void) retrieveTopScores {LOG(@”%s”,__func__);
//ハイスコア配列を全消去
[highScoreArray removeAllObjects];//リーダーボード読み込み
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil) {leaderboardRequest.playerScope = GKLeaderboardPlayerScopeFriendsOnly;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeAllTime;
leaderboardRequest.category = GK_HIGHSCORE_STR;
leaderboardRequest.range = NSMakeRange(1,GK_HIGHSCORE_MAX);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores,
NSError *error) {
if (error != nil) {
// エラーを処理する。
LOG(@” >>leaderboardRequest error!”);
return;
}NSMutableArray *array = [NSMutableArray array];
//プレイヤーID配列を作成
for (GKScore *score in scores) {
[array addObject:score.playerID];
}[GKPlayer loadPlayersForIdentifiers:array withCompletionHandler:^(NSArray *players, NSError *error) {
if (error) {
// Report only with player ids
for (GKScore *score in scores)
LOG(@”loadPlayersForIdentifiers error! [%2d] %@: %@ (%@)”, score.rank, score.playerID, score.formattedValue, score.date);
return;
}for (int i = 0; i < scores.count; i++) { // Report with actual player names
GKPlayer *aPlayer = [players objectAtIndex:i];
GKScore *score = [scores objectAtIndex:i];LOG(@”[rank:%2d] alias(nickname):%@ score:%@ (date:%@)”, score.rank, aPlayer.alias, score.formattedValue, score.date);
HighScores *highScores = [[HighScores alloc] init]; highScores.flg_disp_player = FLG_DISP_PLAYER_READY;
highScores.playerName = aPlayer.alias;
highScores.playerDegree = 0;
highScores.x = 0;
highScores.y = 0;
NSString *value = [score.formattedValue stringByReplacingOccurrencesOfString:@”,” withString:@””];
highScores.playerScore = value.intValue;
LOG(@” >>playerScore=%d”,highScores.playerScore);[aPlayer loadPhotoForSize:GKPhotoSizeSmall withCompletionHandler:^(UIImage
*photo, NSError *error) {
if (error != nil || photo == nil)
{
// 必要に応じてエラーを処理する。
highScores.playerImage = [UIImage imageNamed:@”play_friends.png”];
LOG(@” ERROR! : get play_friends.png”);} else {
//イメージマスク切り抜き&縮小
UIImage *maskImage = [UIImage imageNamed:@”play_friends_mask.png”];
CGSize pImage = CGSizeMake(maskImage.size.width, maskImage.size.height);
CGRect rect = CGRectMake(0, 0, pImage.width, pImage.height);//マスク画像のCGImageRefを作成します
CGContextRef maskContext = CGBitmapContextCreate(NULL, pImage.width, pImage.height, 8, 0, NULL, (CGBitmapInfo)kCGImageAlphaOnly);
CGContextDrawImage(maskContext, rect, maskImage.CGImage);
CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext);
CGContextRelease(maskContext);//カラースペースを作成します。
CGColorSpaceRef genericColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef baseImageContext = CGBitmapContextCreate(NULL, pImage.width, pImage.height, 8, 0, genericColorSpace, (CGBitmapInfo) kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(genericColorSpace);// ベース画像のCGImageRefを作成します。
CGContextDrawImage(baseImageContext, rect, photo.CGImage);
CGImageRef baseImageRef = CGBitmapContextCreateImage(baseImageContext);
CGContextRelease(baseImageContext);
CGImageRef maskedImageRef = CGImageCreateWithMask(baseImageRef, maskImageRef);
UIImage *masked_photo = [UIImage imageWithCGImage:maskedImageRef];
CGImageRelease(maskedImageRef);
CGImageRelease(maskImageRef);
CGImageRelease(baseImageRef);//イメージ格納
highScores.playerImage = [UIImage imageWithCGImage:[masked_photo CGImage]];
LOG(@” >>w,h=%f,%f”,highScores.playerImage.size.width,highScores.playerImage.size.height);}
}];//ハイスコア配列に記録
[highScoreArray addObject:highScores];}
}];
}];}
flg_highscoreload = YES;
LOG(@” >>flg_highscoreload = YES”);
}-(void) dispHighScores {
int i=0;
for (HighScores *highScores in highScoreArray) {if (highScores.flg_disp_player == FLG_DISP_PLAYER_READY) {
//
// ハイスコアの非表示中
////ハイスコアの表示圏内に入ったか確認 → ※メインタイマーのtickとスクロール座標が連動しているという手抜き処理
if (tickTimer%50==0) {if ((int) (tickTimer/50) == (highScores.playerScore)) { → ※メインタイマーのtickと点数が連動しているという手抜き処理
//ハイスコアの表示開始
highScores.flg_disp_player = FLG_DISP_PLAYER_START;//ハイスコアの表示
highScores.x = screen_width+47+randint(100);
highScores.y = screen_height-50-40-randint(100);
highScores.playerDegree=360;//名前
UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.frame = CGRectMake(highScores.x-100, highScores.y+20, 200, 20);
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.textColor = [UIColor blackColor];
nameLabel.font = [UIFont boldSystemFontOfSize:14];
nameLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
nameLabel.textAlignment = NSTextAlignmentCenter;
nameLabel.text = highScores.playerName;
nameLabel.tag = TAG_HIGHSCORES+(i*2);
[self.view addSubview:nameLabel];
LOG(@” >>nameLabel=%@”, highScores.playerName);//アイコン画像
UIImageView *highImage = [[UIImageView alloc] initWithImage:highScores.playerImage];
[highImage setFrame:CGRectMake(0,0, 50, 50)];
[highImage setCenter:CGPointMake(highScores.x,highScores.y)];
highImage.tag = TAG_HIGHSCORES+(i*2)+1;
[self.view addSubview:highImage];
LOG(@” >>playerImage=%d,%d”, highScores.x,highScores.y);}
}} else if (highScores.flg_disp_player == FLG_DISP_PLAYER_START) {
//
// ハイスコアの表示中
//
highScores.x-=4;
highScores.playerDegree-=randint(10);//ハイスコアの表示移動
UILabel *nameLabel = (UILabel *) [self.view viewWithTag:TAG_HIGHSCORES+(i*2)];
UIImageView *highImage = (UIImageView *) [self.view viewWithTag:TAG_HIGHSCORES+(i*2)+1];
nameLabel.frame = CGRectMake(highScores.x-100, highScores.y+20, 200, 20);
[self.view bringSubviewToFront:nameLabel];[highImage setTransform:CGAffineTransformMakeRotation(degreesToRadians(highScores.playerDegree))];
[highImage setCenter:CGPointMake(highScores.x,highScores.y)];
[self.view bringSubviewToFront:highImage];//ハイスコアの表示終了チェック
if (highScores.x<-100) { LOG(@” >>highScores[%d]=%d END”,i,TAG_HIGHSCORES+(i*2));//ハイスコアの表示終了
highScores.flg_disp_player = FLG_DISP_PLAYER_END;
[nameLabel removeFromSuperview];
[highImage removeFromSuperview];
}
}
//次へインクリメント
i++;}
}
-(void) removeHighScores {
int i=0;
for (HighScores *highScores in highScoreArray) {if (highScores.flg_disp_player == FLG_DISP_PLAYER_START) {
UILabel *nameLabel = (UILabel *) [self.view viewWithTag:TAG_HIGHSCORES+(i*2)];
UIImageView *highImage = (UIImageView *) [self.view viewWithTag:TAG_HIGHSCORES+(i*2)+1];
highScores.flg_disp_player = FLG_DISP_PLAYER_END;
[nameLabel removeFromSuperview];
[highImage removeFromSuperview];
}i++;
}}
…
以上!かな。
で難しいゲームを作ると、ゲームスタートした瞬間に・・・
わらわらわら・・・ってでてくるんです、知るか!
あ、そうそう友達のアイコン画像50人分とか取ってくんのに通信して時間かかるんじゃねー?っていうのが疑問だったんだけどゲーセンがキャッシュしてるのかー知らぬ間にローカルに取ってきてんのか激はやでちょっとびっくりしたよ。
あ、たしかARCのプロジェクトだったはず。iOS7,Deployment6.0, XCode5.0.2。