なかじまの開発ブログ

アプリ開発における備忘録などなど。

MENU

DropBox Core APIを使おう【Objective-C】

データを同期するのに使えます!

アプリの登録

下記URLからサインインをしてください。
Dropbox - Sign in

『My Apps』の『Create app』から登録します。

1.Choose an API
 Dropbox APIを選択します。

2.Choose the type of accsess you need
 全てのアクセスを許可するならばFull Dropboxを選択します。
 アプリ固有のフォルダのみアクセスを許可するならばApp folderを選択します

3.Name your app
 アプリケーションの名前を入力します。(別に実際に使うアプリと名前をあわせる必要はないけど、わかりやすいほうがいい)

SDKの準備

下記URLの iOS 『Install SDK』からダウンロードしてください。
Dropbox - Core API

ダウンロード終了後、解凍してプロジェクトにドラッグしてください。

さらに『QuartzCore.framework』と『Security.framework』を追加してください。

f:id:s_nakajima:20160311173451p:plain

アプリの認証

『AppDelegate.m』

#import <DropboxSDK/DropboxSDK.h>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // DropBox初期設定 『Full Dropbox』を選択したならkDBRootDropbox 『App folder』を選択したならkDBRootAppFolder
  // App key と App secret は先ほど登録したアプリケーションから確認することができます。
  DBSession *session = [[DBSession alloc] initWithAppKey:@"App key" appSecret:@"App secret" root:kDBRootAppFolder];
  [DBSession setSharedSession:session];

  return YES;
}

// 認証完了
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url sourceApplication:(NSString *)source annotation:(id)annotation {
  if ([[DBSession sharedSession] handleOpenURL:url]) {
    if ([[DBSession sharedSession] isLinked]) {
      NSLog(@"認証成功");
    }
    return YES;
  }
  return NO;
}

プロジェクト→TAGETSのプロジェクト→info→URL Typesの『URL Schemes』に『db-登録したアプリケーションのApp key』を入力してください。
f:id:s_nakajima:20160311175932p:plain


『.m』
ボタンの押下処理などで

// DropBoxログイン画面を出す
if (![[DBSession sharedSession] isLinked]) {
  [[DBSession sharedSession] linkFromController:self];
}

押下処理などでログイン画面がでたらOKです。
f:id:s_nakajima:20160311180719p:plain


DBRestClientを準備

『ViewController.m』

#import <DropboxSDK/DropboxSDK.h>

@interface ViewController () <DBRestClientDelegate>
@property (nonatomic, strong) DBRestClient *restClient;
@end

- (void)viewDidLoad {
  // DBRestClientを準備
  self.restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]];
  self.restClient.delegate = self;
}

ファイル取得・一覧取得

// ファイル取得 ファイル名の前に / をつけて指定
[self.restClient loadMetadata:@"/test.txt"];

// ファイル一覧取得
[self.restClient loadMetadata:@"/"];
- (void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
  NSLog(@"取得成功");
  NSLog(@"ファイル名:%@", metadata.filename);
}

- (void)restClient:(DBRestClient *)client loadedMetadataFailedWithError:(NSError *)error {
  NSLog(@"取得失敗");
}

アップロード(新規・上書き)

// ファイル取得
[self.restClient loadMetadata:@"/test.txt"];
- (void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
  NSLog(@"指定ファイルが存在していたので、上書き"); 

  NSString *sendText = @"あいうえお";
  NSString *localDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
  NSString *localPath = [localDirectory stringByAppendingPathComponent:filename];
  [sendText writeToFile:localPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
  // 上書きアップロード
  [self.restClient uploadFile:metadata.filename toPath:@"/" withParentRev:metadata.rev fromPath:localPath];
}

- (void)restClient:(DBRestClient *)client loadedMetadataFailedWithError:(NSError *)error {
  NSLog(@"指定ファイルが存在しないので、新規");

  NSString *sendText = @"あいうえお";
  NSString *filename = @"test.txt";  // ファイル名(拡張子がtxtなので、テキストファイルをアップロードします)
  NSString *localDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
  NSString *localPath = [localDirectory stringByAppendingPathComponent:filename];
  [sendText writeToFile:localPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
  // 新規アップロード
  [self.restClient uploadFile:filename toPath:@"/" withParentRev:metadata.rev fromPath:localPath];
}

- (void)restClient:(DBRestClient *)client uploadedFile:(NSString *)destPath from:(NSString *)srcPath metadata:(DBMetadata *)metadata {
  NSLog(@"アップロード成功");
}

- (void)restClient:(DBRestClient *)client uploadedFileFailedWithError:(NSError *)error {
  NSLog(@"アップロード失敗");
}

ダウンロード

// ファイル取得
[self.restClient loadMetadata:@"/test.txt"];
- (void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
  NSLog(@"指定ファイルが存在していたので、ダウンロード"); 

  NSString *localDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
  NSString *localPath = [localDirectory stringByAppendingPathComponent:filename];
  // ダウンロード
  [self.restClient loadFile:metadata.path intoPath:localPath];
}

- (void)restClient:(DBRestClient *)client loadedMetadataFailedWithError:(NSError *)error {
  NSLog(@"指定ファイルが存在しません");
}

- (void)restClient:(DBRestClient *)client loadedFile:(NSString *)destPath contentType:(NSString *)contentType metadata:(DBMetadata *)metadata {
  NSLog(@"ダウンロード成功");

  // データを表示する
  NSError *error = nil;
  NSString *text = [NSString stringWithContentsOfFile:destPath encoding:NSUTF8StringEncoding error:&error];
  NSLog(@"%@", text);
}

- (void)restClient:(DBRestClient *)client loadedFileFailedWithError:(NSError *)error {
  NSLog(@"ダウンロード失敗");
}

ファイルの削除

// ファイル取得
[self.restClient loadMetadata:@"/test.txt"];
- (void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
  NSLog(@"指定ファイルが存在していたので、削除"); 

  // 削除
  [self.restClient deletePath:metadata.path];
}

- (void)restClient:(DBRestClient *)client loadedMetadataFailedWithError:(NSError *)error {
  NSLog(@"指定ファイルが存在しません");
}

タッチイベントを取得する【cocos2d-x】

『.h』

#include "cocos2d.h"

class SampleLayer : public cocos2d::Layer {
public:
  virtual bool init();  // 初期化

  /* シングルタップイベント */
  // タッチ開始
  virtual bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
  // タッチ移動
  virtual void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);
  // タッチ終了
  virtual void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event);
  // タッチキャンセル
  virtual void onTouchCencelled(cocos2d::Touch* touch, cocos2d::Event* event);
};


『.m』

USING_NS_CC;

// 初期化
bool SampleLayer::init() {
  if (!Layer::init()) {
    return false;
  }

  // シングルタップイベントの取得
  auto touchListener = EventListenerTouchOneByOne::create();

  touchListener->onTouchBegan = CC_CALLBACK_2(SampleLayer::onTouchBegan, this);
  touchListener->onTouchMoved = CC_CALLBACK_2(SampleLayer::onTouchMoved, this);
  touchListener->onTouchEnded = CC_CALLBACK_2(SampleLayer::onTouchEnded, this);
  touchListener->onTouchCancelled = CC_CALLBACK_2(SampleLayer::onTouchCancelled, this);

  _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
}

// タッチ開始
bool SampleLayer::onTouchBegan(Touch* touch, Event* event) {
  return true;
}

// タッチ移動
void SampleLayer::onTouchMoved(Touch* touch, Event* event) {

}

// タッチ終了
void SampleLayer::onTouchEnded(Touch* touch, Event* event) {
  
}

// タッチキャンセル
void SampleLayer::onTouchCencelled(Touch* touch, Event* event) {
  // タッチ終了を実行
  onTouchEnded(touch, event);
}

Rabbian -Rescue Operation- リリースのお知らせ&画面説明

お待たせいたしました!

1月末のデジゲー博にて展示しましたRabbian2(仮)を
『Rabbian -Rescue Operation』というタイトルで本日よりリリースいたしました!

f:id:s_nakajima:20160307102806p:plain

現在はiOSのみで、価格は120円となっております。

(もちろんAndroidもリリースいたしますので、もうしばらくお待ちください(*´з`))


ダウンロードはこちらから↓

Rabbian -Rescue Operation-

Rabbian -Rescue Operation-

  • fantec Co LTD
  • ゲーム
  • ¥120

ストーリー

突然ニモちゃんがオジャマモンスターにさらわれた!!
ニモちゃんを助けるためにオジャマモンスターを追いかけよう!
f:id:s_nakajima:20160307103148p:plain

画面説明

f:id:s_nakajima:20160307103946p:plain

基本の操作としては、タップのみです。
画面をスクロールすると、マップの確認ができます。


前作の『Working of Rabbian』もよろしくお願いいたします!

iOS

有料

Working of Rabbian

Working of Rabbian

  • fantec Co LTD
  • ゲーム
  • ¥120

無料

Working of Rabbian -FREE-

Working of Rabbian -FREE-

  • fantec Co LTD
  • ゲーム
  • 無料

UITabBarでUIViewControllerを切り替える【Objective-C】

準備

ViewControllerの表示したい場所にUITabBarを設置してください。

f:id:s_nakajima:20160304183815p:plain

設置したUITabBarは『ViewController.h』にOutlet接続(名前:tabBar)してください。


そしてTabBarのアイテムと同じ数のViewControllerをInterfaceBuilderに設置してください。

f:id:s_nakajima:20160304184049p:plain

そして各ViewControllerにメソッドとヘッダーファイル、StoryboardIDを設定してください。

(左:その1)(右:その2)
f:id:s_nakajima:20160304184157p:plainf:id:s_nakajima:20160304184203p:plain

コーディング

『ViewController.h』

@property (weak, nonatomic) IBOutlet UITabBar *tabBar;


『ViewController.m』

#import "FirstViewController.h"
#import "SecondViewController.h"

@interface ViewController()
@property (nonatomic) UITabBarController *barcon;
@end

@implementation ViewController

@synthesize tabBar;
@synthesize barcon;

- (void)viewDidLoad {
  [super viewDidLoad];

  // ViewControllerの呼び出し
  FirstViewController *firstView = [self.storyboard instantiateViewControllerWithIdentifier:@"firstview"];
  SecondViewController *secondView = [self.storyboard instantiateViewControllerWithIdentifier:@"secondview"];

  // ViewControllerをArrayに格納
  NSArray *tabitems = [NSArray arrayWithObjects:firstView, secondView, nil];

  // UITabBarControllerの設定
  barcon = [[UITabBarController alloc] init];
  [barcon setViewControllers:tabitems animated:NO];
  barcon.tabBar.frame = tabBar.frame;

  // UITabBarのアイテムの設定
    firstView.tabBarItem = [tabBar.items objectAtIndex:0];  // 1つ目
  secondView.tabBarItem = [tabBar.items objectAtIndex:1];  // 2つ目

  [self.view addSubview:barcon.view];
}

完成

f:id:s_nakajima:20160304185245p:plainf:id:s_nakajima:20160304185250p:plain

UDP通信で送信、受信、タイムアウト処理【Objective-C】

#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <sys/types.h>

bool readflag; // 受信したかどうか 初期値はfalseを代入しておく

送信

// 送信
- (void)dataSend:(NSString *)text {
  char *cstr = (char *)[text UTF8String]; // 送信したいテキストをchar型に変換

  // ソケットの作成
  CFSocketRef socket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketNoCallBack, NULL, NULL);

  struct sockaddr_in addr;
  addr.sin_len = sizeof(struct sockaddr_in);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = addr.sin_addr.s_addr = inet_addr((char *)[@"送り先のIPアドレス" UTF8String]);
  addr.sin_port = htons(ポート番号);
  CFDataRef address = CFDataCreate(NULL, (UInt8*)&addr, sizeof(struct sockaddr_in));
  
  CFDataRef senddata = CFDataCreate(NULL, (UInt8*)cstr, strlen(cstr));

  // 送信
  CFSocketSendData(socket, address, senddata, 3);

  // 解放
  CFRelease(socket);
  CFRelease(address);
  CFRelease(senddata);
}

受信

// 受信
- (void)dataRead {
  dispatch_group_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_group_create(), ^{
    char buf[2048];

    memset(buf, 0, sizeof(buf)); // 初期化

    // ソケットの作成
    int socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    // 受信アドレス
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(ポート番号)
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_len = sizeof(addr);

    // バインド
     bind(sock, (struct sockaddr*)&addr, addr.sin_len);

    // 受信
    int size = (int)recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
    if (size > 0) {
      NSString *getdataText = [NSString stringWithCString:buf encoding:NSUTF8StringEncoding];
      
      if((getdataText isEqualToString:@"End"]) {
        // 受信したデータが、タイムアウトで送信した文字列だった場合
        readflag = false; // 受信失敗(タイムアウト)
      } else {
        readflag = true;  // 受信成功
      }
    } else {
      NSLog(@"データなし");
    }
    close(sock);
  });
}

タイムアウト

自分で自分に何かしらを送ってやる

// タイムアウト
- (void)timeoutSend {
  NSString *text = @"End";

  char *cstr = (char *)[text UTF8String]; // 送信したいテキストをchar型に変換

  // ソケットの作成
  CFSocketRef socket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketNoCallBack, NULL, NULL);

  struct sockaddr_in addr;
  addr.sin_len = sizeof(struct sockaddr_in);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = addr.sin_addr.s_addr = inet_addr((char *)[@"自分のIPアドレス" UTF8String]);
  addr.sin_port = htons(ポート番号);
  CFDataRef address = CFDataCreate(NULL, (UInt8*)&addr, sizeof(struct sockaddr_in));
  
  CFDataRef senddata = CFDataCreate(NULL, (UInt8*)cstr, strlen(cstr));

  // 送信
  CFSocketSendData(socket, address, senddata, 3);

  // 解放
  CFRelease(socket);
  CFRelease(address);
  CFRelease(senddata);
}

使い方

送信処理をしたいメソッド内で(ボタン押下メソッドとか)

// 送信
[self dataSend:@"送信したいテキスト"];

// 受信
[self dataRead];

NSDate *start = [NSDate date];

while(1) {
  if (readflag == true) break; // 受信成功したならループを抜ける
  else {
    // 経過時間を取得して、指定した時間がたったらループを抜ける(この場合は5秒)
    if (-[start timeIntervalSinceNow] == 5) break;
  }
}

if (readflag == true) {
  readflag = false;

  // 受信後の処理
} else {
  // タイムアウト
  [self timeoutSend];
}

デジゲー博のことと載せていただいた記事まとめ

1月の30日31日に幕張メッセで開催された「デジゲー博SPECIAL in 闘会議2016」に出展をしてまいりました。(初出展!)


「Working of Rabbian」と「Rabbian2(仮)」を展示しました。

f:id:s_nakajima:20160215165412j:plain
(Rabbian2(仮)のプレイの様子)


ディスプレイ(?)は当日に考えたのですごいごちゃごちゃしました!笑

1日目(1月30日)のディスプレイ

f:id:s_nakajima:20160215165124j:plain

f:id:s_nakajima:20160215165152j:plain

f:id:s_nakajima:20160215165201j:plain

f:id:s_nakajima:20160215165215j:plain


1日目は「Working of Rabbian」のスプラッシュやオープニング、エンディングイラストを描いていただきましたRIKIさんが見に来てくださいました!(ありがとうございました!)

RIKIさん公式HP』
riki2riki.com



アイロンビーズを飾ったところ、結構注目してもらえた気がします…!

ですがそれぞれが目立ちすぎて、せっかく真ん中にある「LINEスタンプ販売中」の紙が全く目立たず。笑

2日目は反省を生かして、販売中の紙はパソコンで表示させていました!

2日目(1月31日)のディスプレイ

f:id:s_nakajima:20160215170243j:plain

f:id:s_nakajima:20160215170323j:plain

その反省がよかったのか、2日目のほうがたくさんの方の目にとまったと思います!(たぶん)
しかしディスプレイって難しい…!


当日はRabbian2が落ちまくったり、来場者さんがデバッグしてくれたりとはちゃめちゃでしたが、無事終わってよかったです(*'ω'*)


30日の夜は開発者の方たちで飲み会があったりと(その前日は酎ハイ・日本酒・ワインとちゃんぽんをかましてました笑)、
たくさんの方とお知り合いになれてやっと一歩踏み出せた感じがしました。(ブースにも来ていただきありがとうございます('◇')ゞ♪)


載せていただいた記事まとめ

『AppBankさん』
www.appbank.net

な、なんとアイキャッチがニモちゃんだ~!ひえ~!


『TAPPLIさん』
tappli.org

エピソードが少し照れますね、、(ちょっぴりドヤ顔)


『うにさん』
cocoamix.jp

うにさんにも載せていただきました~!


私の知る限りこの3つになります!
ありがとうございました!


アプリのDL、スタンプのDL、そしてブースに足を運んでいただき、ありがとうございました!
まだ駆け出し感いっぱいの私ですが、どうかこれからもよろしくお願いいたします。


こちらもどうぞ

『LINEスタンプ』
nsdevelop.hatenablog.com

『Working of Rabbian iOS無料版』

Working of Rabbian -FREE-

Working of Rabbian -FREE-

  • fantec Co LTD
  • ゲーム
  • 無料

『Working of Rabbian iOS有料版』

Working of Rabbian

Working of Rabbian

  • fantec Co LTD
  • ゲーム
  • ¥120

『Working of Rabbian Android
play.google.com

なかじまの新作のお知らせ【GO INTO SPACE 2】

お知らせの前に...

先日、前に作った『GO INTO SPACE』がアップデートから1年たったというのを友人のLINEで知りました!笑
自分のゲームなのに!

『GO INTO SPACE』iOS

GO INTO SPACE

GO INTO SPACE

  • Serina Nakajima
  • ゲーム
  • 無料

たまごを落とさずに飛ばしつつひたすらスコアを伸ばすゲームです。笑


そのGO INTO SPACEが!

なんと!

続編(?)がでます!

(時間がかかりすぎた!)


あらためまして、続編(?)の『GO INTO SPACE 2』を作りました。

f:id:s_nakajima:20160203095232p:plain

もう後はアップルさんに申請を残すのみとなっておりますので、2月にはリリースできるかなぁと。


今回は始めに書きました友人にもアイデアを出してもらいました!(ありがとうございます)

GO INTO SPACE 2 には『一応』ストーリーがありまして、カラス団にさらわれた親(にわとり)をたまごが助けに行くっていうストーリーなんですけど。

ゲームには全く導入がないのでわけがわからんかもです。笑

これは速攻で絵がかけたらいれようかなぁと思います…!

それではリリースしましたらよろしくお願いします!

1も是非プレイしてみてください(*'ω'*)