2012年5月12日土曜日

振り分けフリック!公開しました

迫り来る矢印をフリックで振り分けよう。
prunus.jpのゲーム第1弾『振り分けフリック!』を公開しました。

    振り分けフリック! - Prunus

プレイ動画をどうぞ。



遊び方


3本の道を矢印が降りてきます。
矢印に合わせて画面をフリックしてください。

◆緑の矢印は降りてくる道がフリックする方向になります。

左の道  :左にフリック
真ん中の道:下にフリック
右の道  :右にフリック

◆赤の矢印は矢印の向きがフリックする方向になります。

左向き  :左にフリック
右向き  :右にフリック

振り分けが速ければ速いほど多くの点数がもらえます。
瞬時に判断してフリックしてください。

ゲームモード


◆とことん振り分け

ミスをするまでひたすら振り分け。
だんだん速くなっていきます。

◆タイムアタック

30秒間の制限付き。
高得点でレベルアップ!

その他


Game Centerに対応。
目指せ世界ランキング1位!

やり込めば矢印以外も選択できるようになります。

無料。是非お試し下さい!


2012年4月28日土曜日

Game Centerでハマったこと

Game CenterのLeaderboardを扱うにあたって、ハマったことをメモしておきます。

アカウントは新規に作成する


開発中のGame Centerで利用するアカウントは新規に作成しないとおかしなことになってしまいます。
Leaderboardにスコアが反映されなかったり。

Game Centerアカウントをログアウトする方法


デフォルトでインストールされているGame Centerアプリを起動し、「自分」→「アカウント」をタッチ→「サインアウト」

このゲームはGameCenterに認識されません


実機でこのメッセージが表示されGame Centerに接続されないという現象が起きました。
アカウントのサインアウト→サインインや、アカウントの新規作成を試しましたが解消せず。
結局、アプリを削除し、インストールし直したら正常に接続できるようになりました。

アプリ申請をしたあと


iTunes Connectのアプリバージョン詳細ページで、Leaderboardの各項目を有効にしなくてはいけないみたいです。 気が付いて良かった。

2012年4月25日水曜日

ゲームを作ってた

ここ1ヶ月、cocos2dを使ってゲームを作ってました。
ようやく今日審査に提出。GW明けには公開されるかな。どうだろう。

2012年4月15日日曜日

twitterのweb intents

tweetをUIWebViewで簡単にやりたかったのです。

Web Intents | Twitter Developers

urlとviaとtextとhashtagsを指定すればそれなりに良いみたい。


2012年4月14日土曜日

Ease actionとtransition

Spriteのactionに利用するEase Action。
Transitionには使えないのかなと思って調べてみるとありました。

How to ease Scene transitions

このままだとビルドが通らなかったので若干修正。
#import 
#import "cocos2d.h"

@interface MyCCTransitionSlideInR : CCTransitionSlideInR {
    
}

@end
#import "MyCCTransitionSlideInR.h"

@implementation MyCCTransitionSlideInR

-(CCActionInterval*) easeActionWithAction:(CCActionInterval*)action
{
 return [CCEaseInOut actionWithAction:action rate:2.0f];
}

@end
うまくいきました。

2012年4月5日木曜日

macでupdatedb

メモです。

sudo /usr/libexec/locate.updatedb

以上です。

2012年3月20日火曜日

Xcode4でiOS3(iPhone 3G)向けアプリをビルドする方法

Xcode4でビルドしたアプリを、iPhone 3G(iOS 3.x)で実行させる方法を紹介します。
様々調べた結果、以下で詳しく説明されていました。

iOS 3.x support in Xcode 4 - Stack Overflow

前提として、オーガナイザーでiPhone 3Gが認識されているものとします。



Development Targetを変更


最初の状態では、ターゲットにiPhone 3Gを選ぶことすらできません。


選べるようにするために、Development Targetを3.0にします。プロジェクト設定の[Summary]で設定します。

これで、iPhone 3Gを選べるようになるのですが、まだまだ実行できません。そんなに簡単にはいきません…


armv6サポート


iPhone 3Gはarmv6というCPUアーキテクチャが利用されています(iPhone 3GS以降はarmv7)。
これをサポートする設定をしなければなりません。
プロジェクト設定の[Build Settings]で[Architectures]に"armv6"を追加します。




続いて、[Build Settings]で[Linking]→[Other Linker Flags]に"-weak-lSystem"を追加します。


最後にInfo.plistの"Required device capabilities"という項目から"armv7"を削除します。



ソースコードの修正


ソースコードの修正が必要です。

1つ目はUIDeviceのuserInterfaceIdiomを利用しているコードです。
iPhoneとiPadを見分けるのに利用されているのですが、iOS3.2より前だとこのメソッドが定義されていないためアプリが不正終了してしまいます。
以下のように修正します。
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {

UI_USER_INTERFACE_IDIOMマクロはuserInterfaceIdiomメソッドが利用できるか確認してくれるので安心して使えます。

2つ目はAppDelegateのapplication:didFinishLaunchingWithOptions:内のコードです。

self.window.rootViewController = self.viewController;
[self.window addSubview:self.viewController.view];

以上、これで無事にiPhone 3G/iOS 3でアプリを開発できます。

2012年3月17日土曜日

「漢字ルーペ」リリース!&アップデート!


2年近く前からiPhoneアプリを趣味で作ってきましたが、公開までやってみようと思い立ち、ついに先日リリースできました!

漢字ルーペ   漢字ルーペ - Prunus

「あの漢字はどうやって書くんだっけ?」そんな時に使えるアプリです。
既に1回アップデートしていて、ちょいちょい機能が増えていってます。

  •  文字を拡大表示
  • 選べるフォント(ゴシック/明朝/筆順)
  • 横にすると全画面表示(ピンチイン・アウトによる拡大縮小が可能)

無料なのでぜひ使ってみてください m(_ _)m

 

UIWebViewのエラー処理

UIWebViewをさわっていたのですが、エラー処理で詰まってしまいました。

デリゲートメソッドwebView:didFailLoadWithError:にエラー処理(アラート表示)をいれたのですが、stopLoadingで読み込みをキャンセルした場合もこれが呼ばれてしまう。


さぁ困ったぞ、と1日経って良く見てみたら、NSErrorでエラー内容が取れるではないかと。
このリファレンスの「URL Loading System Error Codes」という項目にNSURLErrorDomainのエラー一覧があります。
NSURLErrorCancelledのときはアラート表示をしないという処理で大丈夫そうです。

以下ソース。
// エラー
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    LOG(@"UIWebView: error");
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    
    // stopLoadingでキャンセルされた場合はアラートを表示しない
    if (!(   [error.domain isEqualToString:NSURLErrorDomain]
          && error.code == NSURLErrorCancelled)) {
        // アラート表示
        [self showAlert];
    }
    
    [self updateButtonStatus];
}
できました。良さそうです。

iAdを組み込む

せっかくなのでiAdを試してみました。やりたかった事は以下の通りです。
  • iAdが表示できなかったらAdMobの広告を表示したい
  • iOS3はiAdが使えないので、 無条件でAdMobを表示したい

登録


で、まずはiAdを利用するために、様々申請が必要です。全てiTunes Connectで行います。
以下のページに詳しく解説されていました。ほとんどこの通りにやりました。

 Contracts, Tax, and Banking 銀行と税金の契約 | iPhone使いへの道

 あ、1点だけ違う点が。「Account Holder Name(口座名義)」をカタカナで入力しました。入力時に脇のヘルプにそのように書いてあったので。

コーディング


申請が無事完了したら、次は一番大事なコーディングです。
これもまた、以下のページを参考にさせていただきました。

管理人の部屋: [続] iAdをメインにしてAdmobをバックアップとして設置

大枠はそのままなのですが、若干手を加えたので、ソースを掲載します。
あとで使い回しをしやすいように、カテゴリでソースを分けてあります。

ViewController+Ad.h
#import "ViewController.h"
#import <iAd/iAd.h>
#import "GADBannerView.h"

@interface ViewController()
{
    BOOL _iAdIsVisible;
    ADBannerView *_iAdView;
    BOOL _isEnableAdMob;
    GADBannerView *_adMobView;
}
@end

@interface ViewController(Ad) <ADBannerViewDelegate, GADBannerViewDelegate>

// 広告を開始する
- (void)startAd;

// 広告を解放する
- (void)releaseAd;

// private methods
- (void)startiAd;
- (void)startAdMob;
- (void)stopAdMob;

@end

ViewController+Ad.m
#import "ViewController+Ad.h"

#define ADMOB_PUBLISHER_ID @"???????????????"

@implementation ViewController(Ad)

- (void)startAd
{
    // iAd (iOS4.0以上)
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.0) {
        [self startiAd];
    }
    else {
        [self startAdMob];
    }
    
    return;
}

- (void)releaseAd
{
    // AdMob
    if (_isEnableAdMob) {
        _adMobView.delegate = nil;
        [_adMobView release];
    }
    
    //iAd
    _iAdView.delegate = nil;
    [_iAdView release];
    
    return;
}

#pragma mark - iAd

- (void)startiAd
{
    LOG(@"iAd:startiAd");
    
    // iAd初期化
    _iAdView = [[ADBannerView alloc] initWithFrame:CGRectZero];
    
    // サイズ設定
    NSString *identifier;
    if (&ADBannerContentSizeIdentifierPortrait != nil) {
        identifier = ADBannerContentSizeIdentifierPortrait;
    }
    else {
        identifier = ADBannerContentSizeIdentifier320x50;
    }
    _iAdView.requiredContentSizeIdentifiers = [NSSet setWithObject:identifier];
    _iAdView.currentContentSizeIdentifier = identifier;
    
    // 下に配置
    CGSize bannerSize = [ADBannerView sizeFromBannerContentSizeIdentifier:identifier];
    _iAdView.frame = CGRectOffset(_iAdView.frame, 0, self.view.frame.size.height - bannerSize.height);
    
    // 隠しておく
    _iAdView.hidden = YES;
    _iAdView.alpha = 0.0f;
    
    // delegate
    _iAdView.delegate = self;
    
    [self.view addSubview:_iAdView];
}

// iAdによって広告がloadされた時に実行される
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
    LOG(@"iAd:bannerViewDidLoadAd");
    
    // AdMob非表示
    [self stopAdMob];
    
    if (_iAdIsVisible == NO) {
        // iAdを表示
        [UIView beginAnimations:@"iAdViewShow" context:NULL];
        _iAdView.alpha = 1.0f;
        [UIView commitAnimations];
        _iAdView.hidden = NO;
        _iAdIsVisible = YES;
    }
}

// iAdが広告の読み込みに失敗したときに実行される
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
    LOG(@"iAd:didFailToReceiveAdWithError %@", [error localizedDescription]);
    
    if (_iAdIsVisible) {
        // iADを隠す
        _iAdView.hidden = YES;
        _iAdView.alpha = 0.0f;
        _iAdIsVisible = NO;
    }
    
    // Admob開始
    [self startAdMob];
}

// ユーザが広告をタップしたときに実行される
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
    LOG(@"Banner view is beginning an ad action");
    BOOL shouldExecuteAction = YES;
    if (!willLeave && shouldExecuteAction)
    {
        // ここにコードを挿入して、広告と競合する可能性のあるサービスを一時停止する
    }
    return shouldExecuteAction;
}

#pragma mark - AdMob

- (void)startAdMob
{
    LOG(@"AdMob:startAdMob isEnableAdMob: %d", _isEnableAdMob);
    
    if (_isEnableAdMob) return;
    
    // 確保
    _adMobView = [[GADBannerView alloc]
                  initWithFrame:CGRectMake(0.0,
                                           self.view.frame.size.height - GAD_SIZE_320x50.height,
                                           GAD_SIZE_320x50.width,
                                           GAD_SIZE_320x50.height)];
    
    // 隠しておく
    _adMobView.hidden = YES;
    _adMobView.alpha = 0.0f;
    
    // 配置
    _adMobView.adUnitID = ADMOB_PUBLISHER_ID;
    _adMobView.delegate = self;
    _adMobView.rootViewController = self;
    [self.view addSubview:_adMobView];
    
    // リクエスト
    GADRequest *request = [GADRequest request];
    [_adMobView loadRequest:request];
    
    _isEnableAdMob = YES;
    
    return;
}

- (void)stopAdMob
{
    LOG(@"AdMob:stopAdMob isEnableAdMob: %d", _isEnableAdMob);
    
    if (_isEnableAdMob == NO) return;
    
    // 解放
    [_adMobView removeFromSuperview];
    _adMobView.delegate = nil;
    [_adMobView release];
    _isEnableAdMob = NO;
    
    return;
}

- (void)adViewDidReceiveAd:(GADBannerView *)adView
{
    LOG(@"AdMob:adViewDidReceiveAd");
    
    // AdMobを表示
    [UIView beginAnimations:@"AdMobViewShow" context:NULL];
    adView.alpha = 1.0f;
    [UIView commitAnimations];
    adView.hidden = NO;
    
    return;
}

- (void)adView:(GADBannerView *)view didFailToReceiveAdWithError:(GADRequestError *)error
{
    LOG(@"AdMob:didFailToReceiveAdWithError %@", [error localizedFailureReason]);
    [self stopAdMob];
}

@end

アプリ申請


残る注意点としては、アプリ申請後にiTunes Connectの[Manage Your Applications]でiAdを有効にするのをお忘れなく、といったところでしょうか。


iAdを組み込んだアプリを申請しました。どうなるか楽しみです。

2012年3月11日日曜日

効果音をループ再生する

iPhoneで効果音(短いサウンド)を再生するには、System Audio Servicesを利用します。
AVFoundationと違って扱いは楽なのですが、その分機能が制限されています。
ループ再生の方法も提供されていないので、再生が終わったら再び再生するという方法で実現してみました。

ボタンが選択状態の間、効果音をループ再生します。

ボタンに結びつけるアクション。
- (IBAction)switchPlayingSE:(id)sender
{
    UIButton *button = sender;
    
    // 再生終了
    if (button.selected) {
        AudioServicesRemoveSystemSoundCompletion(_seID);
        AudioServicesDisposeSystemSoundID(_seID);
    }
    // 再生開始
    else {
        NSURL *url = [NSURLfileURLWithPath:[[NSBundlemainBundle] pathForResource:@"se"ofType:@"aif"]];
        AudioServicesCreateSystemSoundID((CFURLRef)url, &_seID);
        
        AudioServicesAddSystemSoundCompletion(_seID, NULL, NULL, soundCompletionProc, NULL);
        AudioServicesPlaySystemSound(_seID);
    }
    
    // ボタンの状態を切り替える
    button.selected = !button.selected;
}
AudioServicesAddSystemSoundCompletion()で再生が終わったあとに実行するハンドラを設定しています。
ハンドラは以下です。再び再生するのみ。
void soundCompletionProc(SystemSoundID ssID, void *clientData)
{
    // 再生完了したらもう一度再生する
    AudioServicesPlaySystemSound(ssID);
    
    return;
}

2012年3月9日金曜日

iPhone開発で使えそうなベクターアイコン

以下のサイトで、photoshopのシェイプ形式で様々なアイコンが公開されています。

Shapes4FREE

ライセンスが「個人利用、商用利用可」などかなり緩めに設定されています。
ありがたし。重宝しそうです。


xcode4でのローカライズ

xcode4.2でのローカライズ方法をまとめてみます。

文字列のローカライズ


これはもっと良い方法があるような気がするのですが(ソースコードを解析するツールがあるみたい)、私は以下の方法でやっています。
  1. プロジェクトのツリーを右クリックし、[New File]を選択する
  2. [Other]の[Empty]で、Localizable.stringsという名前のファイルを作成する

  3. 作成したファイルを選択し、右側のファイルインスペクターを表示する
  4. Localizationの+を押すと、Englishが追加される
  5. もう一回+を押し、Japaneseを追加する

  6. これでen.lprojフォルダとja.lprojフォルダにLocalizable.stringsが作成されます。

  7. [Open as] → [Property List]でLocalizable.stringsを開きます。適当に何か書き込んでおかないと開けないみたいです。
  8. あとは、Keyにキーワードを、Valueに文字列を追加していきます。

ローカライズ文字列をプログラム内で参照するには以下のようにします。
NSString *string = NSLocalizedString(@"keyword", @"説明");
第1引数にキーワードを入れます。


アプリケーション名のローカライズ


上で、Localizable.stringsのLocalizationでEnglishとJapaneseを追加したのと同じ手順で、InfoPlist.stringsをローカライズします。
あとは、CFBundleDisplayNameというキー名でアプリケーション名を設定します。



画像のローカライズ


上で、Localizable.stringsのLocalizationでEnglishとJapaneseを追加したのと同じ手順で画像をローカライズします。


ちなみに、ファイルをローカライズすると、Englishのリソースはen.lprojディレクトリに、Japaneseのリソースはja.lprojディレクトリに、自動で振り分けられます。


2012年3月7日水曜日

iPhoneでバイブレーション

iPhoneでバイブレーションを鳴らす方法は、効果音を鳴らす方法と同じです。

まずは、AudioToolBox.frameworkをリンクする必要があります。

プロジェクト設定から[Build Phases]を選択し、[Link Binary With Libraries]のプラスボタンを押し、AudioToolBox.frameworkを追加します。


あとは、ヘッダをimportした上で、
#import <AudioToolbox/AudioServices.h>
AudioServicesPlaySystemSoundを呼ぶだけです。
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
kSystemSoundID_VibrateがバイブレーションのサウンドIDです。

iOS5で明朝を表示する

開発側の話です。
iOS5で明朝フォントを使って文字を描画するには、drawRect:中で
[nsstring drawAtPoint:CGPointMake(left, top) withFont:[UIFontfontWithName:@"HiraMinProN-W3"size:fontSize]];
とやります。

でもなんかsizeWithFontしたときの高さがおかしいです・・・。

ちなみに、全フォントのファミリー名を表示するには以下のようにします。
NSArray *families = [UIFont familyNames];
id aFamily;
for (aFamily in families) {
    NSLog(@"\nfamilyName=%@\n  fontname=%@", aFamily, [UIFont fontNamesForFamilyName:aFamily]);
}

再開

「日誌」といいつつ2年近く間が空くとかありがちすぎて・・・
熱が出て苦しい今、これを機会に再開したいと思います。
ここ最近やったことをつらつら書いていきます。
m(_ _)m