2013年12月31日火曜日

2013年を振り返ってみる。


気がつけば間もなく2014年ですね。
趣味で開発を始めた2013年。来年の自分のために軽く振り返ってみます。

やったこと

1月

ちょっと暇な時間ができ、ふとAndroidアプリを作ろうと思い立つ。
本買って勉強開始。
始めて触るJavaやEclipse。さくさく動くけどめんどくさいOpenGL。
とても面白かった。

2月

2週間ぐらいで1つ目のアプリ完成。

さっそくGooglePlay開発者登録してリリース。
2/7リリース Androidアプリ:「104[トランプゲーム]」

ソースコードぐっちゃぐちゃだけど最初だし気にしない。

この頃にブログやTwitterも始めました。
Twitterで個人開発者探したらiOS開発者ばかりで寂しかった記憶がw
Android開発者らしき方々を片っ端からフォローさせていただきました。

3月、4月

1個だして満足しちゃってやる気の谷へ突入。
テストアプリを10個ぐらい作ってた気がするけどリリースまで持っていく気力がない。

5月

GWに友人たちとフグ食べに日間賀島へ行った。
なんか作るか!って話になりやる気復活。

そのまま一週間後にアプリ完成。
5/11リリース Androidアプリ:「うて!!」

さらに一週間でもう一つ完成。
5/19リリース Androidアプリ:「Golf(トランプゲーム)」

本当は翌週にもう一本出すつもりだったんだけどここで大ニュースが。
→Unityのモバイル用ライセンスの無償化

めっちゃテンション上がったの覚えてる。
その夜さっそくブログにまとめた。
【Unity無償化】Unityインストールから実機で実行するところまでやってみた。

この日以降すっかりUnityブログになっちゃいましたね。
検索流入もUnity一色に染まりました。

6月

黄本のサンプルをベースに一本完成。

そのままさくっとリリース
6/16リリース Androidアプリ:「ボールラン」

このアプリ会社の休憩所での評判はよかったです。
3Dってだけで「おっ?」って感じ。
加速度センサー使うアプリはやってる人を隣で見てるのが一番楽しい。

7月、8月、9月、10月

リリースはしてませんが少しずつUnity触ってました。
Unityを触り始めるとiOSアプリ開発も視野に入るわけで…。
結局作りたい欲求に勝てずMacBook購入。
MacBookAirを買いました!

ついでにiPhone5をゲットして寝かせ運用開始。
そのままの勢いでiOS開発者登録も完了。

でも仕事がむっちゃ忙しくて全然まとまった時間とれず
だらだらと時間だけがすぎていく…。

そんな中10月にあほげー開催
第11回あほげーにエントリーしました
24時間でゲームを作るって言うアレ。

だらだら時間を浪費してた中でこの24時間はいい刺激になりました。
24時間で形にできるんだもの。
仕事忙しかろうがリリースできないわけないよね。

11月

ちゃんとアプリ作り始める。
元々作りたかったステージいっぱい系のゲームに挑戦。
作りやすそうだったからパズルにしたんだけど
問題用意するのがこんなに大変だとは思わなかったw

12月

12月頭に完成。始めてのApple審査待ちへ。
「リジェクトされた!」ってつぶやいてみたかったけど一発で通過しました。

始めてのiOSアプリをリリース。
12/10リリース iOSアプリ「ナンバーコネクト」

そのままAndroid対応してリリース
12/15リリース Androidアプリ:「ナンバーコネクト」

なんとか年内にiOSアプリを出すことができました〜。

DL数/収益

来年の比較用にまとめておきましょ。
収益はどこまで書いていいのかわからんしざっくりで。

Android
 ・104[トランプゲーム]  (434DL)
   ・バナー:400円弱
 ・うて!!  (1064DL)
   ・バナー:1500円弱
   ・CPIウォール:3500円ちょい
   ・終了時:300円ちょい
 ・Golf[トランプゲーム]  (135DL)
   ・アイコン:600円弱
   ・バナー:700円弱
 ・ボールラン  (1682DL)
   ・バナー:3000円ちょい
   ・CPIウォール:500円ちょい
 ・ナンバーコネクト  (34DL)
   ・バナー:30円
iOS
 ・ナンバーコネクト  (1724DL)
   ・バナー:2500円ちょい
   ・CPIウォール:1000円弱
ブログ  (110000PV)
 ・バナー:7000円弱

トピックス

・iOSアプリのDL数がたった半月で全てのAndroidアプリを抜いた。
 ・iOSすんごい。
・1週間で作った「うて!!」がなんだかんだで一番稼いでる。
 ・棒人間とGAMEFEATは相性があきらかにいい。
 ・自分的には一番つまらないゲームなんだけど稼ぎたいならこっち路線行くべきなんだろうなぁ。
・ブログが意外に稼いでくれてる。
 ・Unityすんごい。
・合計収益2万超えてるやん!
 ・びっくり
 ・広告会社バラバラだから収益ゼロだけどw

反省

やる気にムラがありすぎですね。
週1で出したり半年も出さなかったりとか色々ひどい。
この品質ならせめて月1は出していきたい…

来年はもう少しペース上げます!
といいたいけど挙式控えてるからマイペースにやります。


それではみなさま、一年お疲れさまでした!!!
よいお年を!

2013年12月22日日曜日

【H25 NW】ネットワークスペシャリスト試験合格までの勉強法と参考書を紹介

ネットワークスペシャリスト

まえがき

こちらの記事にも書きましたがネットワークスペシャリスト試験に合格することができました。
【H25 NW】平成25年ネットワークスペシャリスト試験に受かりました。

なんとか一発合格できたので
それなりに勉強法は間違ってなかったのかなと思います。
実際に勉強し挑んでみてわかったことなど、
少しでもこれから受験される方の役に立てればと思い、書き残しておきます。

※あくまで私の所感なので参考程度にどうぞ〜。

背景

ちょっと背景から。

やってる仕事

今やってる仕事はこんな感じです。
  • とある会社の社内SE
  • 主にC#を使ってWindows用ソフトを作ったり保守したり
  • Windowsのサーバークライアント型アプリがほとんど
  • システム開発(プログラミング)経験は4年目ぐらい
仕事がネットワーク関係かっていうとそんなことないです。

受験理由

システム屋してるとユーザーさんから
「ソフトが繋がらないんだけど」とかアバウトな問い合わせをよく受けます。

(´-`).。oO(めんどいな)と思いつつ笑顔で対応します。
そこでpingやtelnetを使って調べるんですよね。

はじめは先輩に教えられた通りやってただけですが
いつしかネットワークの仕組みが気になってきました。
なんでブラジルとTV会議ができるのか…とか

すでに基本情報処理、応用情報処理は持ってたので
次に受けるのはネスペで決まりですね。

もう一つの理由

自分が資格試験を受ける一番の理由は勉強するモチベーションを維持するためです。
小学時代の夏休みから計画性が無いのは分かりきってました。
大人になってたどり着いた唯一の勉強法が短期決戦です。
その方法に必要不可欠なのが適度なプレッシャーと期限。
それを意図的に作り出す一番簡単な方法が資格試験でした。

  • まず申し込む、それから参考書を買い始める。
  • 申し込み〜試験日までは1~3ヶ月程度でちょうど自分に合ってる。
  • 申し込んだら人に言う。落ちたら恥ずかしい状況に自分を追い込む。
落ちても勉強にはなるので合否は気にしません。

裏の理由

IT系の部署にとてもダンディーなオジサマがいるんですけどその人が高度情報処理の資格を3つ持ってるんですよね。ネスペ、DB、情報セキュリティだったかな?
年の近い先輩ら2人と話しててそれぞれ1つずつ取ったら勝てるんじゃね?
やってやろうぜ!って謎の対抗意識でがんばることになりました。

はい申し込み〜。

勉強法

だいぶ寄り道しましたね。戻ります。

まず解いてみる

はじめにこちらの参考書を買いました。
後述しますが過去問として利用しました。正直なくてもよかったです。
情報処理教科書 ネットワークスペシャリスト 2011年版情報処理教科書 ネットワークスペシャリスト 2011年版
山下 真吾
翔泳社
Amazonで詳しく見る
今買える最新版はこっちかな。
情報処理教科書 ネットワークスペシャリスト 2013年版情報処理教科書 ネットワークスペシャリスト 2013年版
ICTワークショップ
翔泳社
Amazonで詳しく見る
基本情報、応用情報を受けたときはこのシリーズ1冊で楽勝だったのでとりあえず買いました。
前後半に別れており、広く浅い説明と過去問2年分で構成されてます。

解説をさらっと流し読みしたあと、過去問に挑みました。
ここで絶望を味わいますw
午後問題がまっっっっっっっっったく分からん!
問題文に知らない言葉が3つ以上でてくると読む気も失せますね。

基礎知識のなさを痛感。これが試験1ヶ月前です。
諦めようか悩みましたが合格が目的じゃないので頑張ることにしました。

基礎を固める

次に読んだのがこれ。
マスタリングTCP/IP 入門編 第5版マスタリングTCP/IP 入門編 第5版
竹下 隆史,村山 公保,荒井 透,苅田 幸雄
オーム社
Amazonで詳しく見る
これは良書。断言できます。とりあえず読みましょう。
数多くの基本プロトコルを分かりやすい文章で解説されてます。
ここでまずは下記のようなことを理解します。
  • OSI参照モデルのイメージを掴む(必須)
  • どんなプロトコルがあるのか
  • 各プロトコルのイメージを掴む(どの階層でどんなことをしてるのか)
合わせて下記サイトも読みましょう。
とんっでもなく時間かかりますが分かりやすいです。
3分間NetWorking
OSI参照モデルについては本よりこちらの方が分かりやすいですね。

時間があればこちらのページも読んでおくといいと思います。
NetWork Study 1 : ネットワークエンジニアとして
自分は時間がなくて読み切れませんでしたが非常に分かりやすいです。

重要:上位プロトコルを下位プロトコルが包み込んで(カプセル化)通信してる。
ここから先の勉強を進める上でこのイメージの理解だけは必須です。
キーワードは「アプセトネデブ」

各プロトコルの詳細な動きはどーせ過去問解きながら確認していくことになります。
なのでこの時点ではあまり詳しく分かってなくてもいいです。

たくさん読むのでこれだけで1〜2週間持ってかれます。
ちょうどこの頃仕事が忙しくて次のステップに移れたのが試験6日前でしたw

まずは1年分、深く理解する

次に使ったのがこの本です。この本がなかったら間違いなく不合格でした。
ネスぺ21 本物のネットワークスペシャリストになるための最も詳しい過去問解説と合格のコツネスぺ21 本物のネットワークスペシャリストになるための最も詳しい過去問解説と合格のコツ
粕淵 卓,平田 賀一
星雲社
Amazonで詳しく見る
最新版はこちらでしょうか。
ネスぺ23 本物のネットワークスペシャリストになるための最も詳しい過去問解説と合格のコツネスぺ23 本物のネットワークスペシャリストになるための最も詳しい過去問解説と合格のコツ
粕淵 卓,平田 賀一
星雲社
Amazonで詳しく見る
2014/07/07追記
現在の最新版は下記になります。
どうも自社出版から出版社経由に変更された様子ですね。(著者も変更になっているし紛らわしい…)
購入して確認したところネスペXXシリーズと同じ構成で解説されていました。
白黒印刷から多色印刷になっており、少し読みやすくなっていますが、その代り少し値段が上がったようです。
ネスぺの剣25 ~ネットワークスペシャリストの最も詳しい過去問解説 (情報処理技術者試験)ネスぺの剣25 ~ネットワークスペシャリストの最も詳しい過去問解説 (情報処理技術者試験)
左門 至峰,平田 賀一
技術評論社
Amazonで詳しく見る
この本では1年分の午後問だけをとにかく深く300ページにも渡って解説してます。
ネスペ21の午後1の問1を例に挙げると
 ・問題は4ページ
 ・問題文を読み解く解説に15ページ
 ・設問を解く解説に12ページ
問題4ページに対して27ページの解説です。
でも順序立てて考える道筋を示してくれてるので本当に分かりやすい。

この本を一字一句"理解"しながら読み進めます。
本当に腑に落ちるまでじっくり読みます。
途中で出てきた分からない用語は先ほどの「マスタリングTCP/IP」や、
ネットで調べたりして基礎の理解に勤めます。

ここで驚いたのが午後問題がまるでパズルのように思えてきたこと。
この本を読むと分かるのですが問題を解くためのヒントが
問題文の各所に散りばめられてるんです。
一見しただけじゃ分からなくても自分の持ってる知識を総動員してじっくり考えてみると少しずつ見えてきます。それら全てが繋がって腑に落ちた瞬間の気持ちよさったらないですw

当時こんなこと呟いてますね

この本を真面目にやるととんでもなく時間がかかります。
たかだか30ページで4時間とか。
正直しんどいですが一問終わるごとに理解が深まってるのを感じられます。

これ1冊に4日。大体15時間かかりました。
この辺りで「お?行けるんじゃね?」とか思い始めます。(勘違いですけど。)

この時点で木曜日深夜。試験は日曜日です。
残された時間はあと2日。(やばい)

さらに過去問を解く

ネスペの試験で最新技術が取り上げられることは少なく、
もし出題されても基本の知識を組み合わせれば解けるようにできてます。
↑ってネスペ21に書いてあります。

そうはいっても自分が解けたのはたった1年分。しかも1回。
問題数にすると5問だけです。(午後1の問1、2、3、午後2の問1、2)

不安しかないw
でも焦っても仕方ないので過去問解くことに。
眠っていた最初の参考書を開きます。

お?
これが意外と解ける。明らかに始めて解いたときと感覚が違います。
もちろん知らない技術とかは追加で調べたりしますが
基本的なところはスラスラ解ける感じです。
ネスペ21がいかに基本を押さえてるか分かりますね。

これを金曜、土曜と時間の限り行いました。

寝る

書き忘れるところでした。
どんなに焦っててもちゃんと寝ましょう。
どんな勉強法より寝るのは大事です。

まとめ

・マスタリングTCP/IPは基礎知識を押さえるのに最適
 ・買って損はない良書
・ネスペシリーズは試験対策として最適
 ・最低でも1冊はやりたい
・Webは下記ページが参考になった
 ・3分間NetWorking
 ・ネットワークエンジニアとして
・最新技術とかどうでもいい
 ・とにかく基礎が重要
・アプセトネデブ
・寝る


いかがでしょうか。
もう少し計画的に時間を使えるのであれば
通常の過去問の代わりにネスペシリーズを全冊やるのがいいかと思います。
(落ちたら来年そうするつもりでした)


この方法でネットワークの知識が乏しい状態から一発合格できました。
この記事が少しでもこれから受験される方の力になればと思います。

ここまでお読みいただきありがとうございました。

2013年12月21日土曜日

【H25 NW】平成25年ネットワークスペシャリスト試験に受かりました。

ネットワークスペシャリスト

名前はカッコいいですけど知らない人も多いですよね。
こんな資格です。→ネットワークスペシャリスト試験

持ってたからなんだって?はい、すいません。
嬉しかったので書かせてください。

難しかった

これを10月20日に受験してきたんですけど正直落ちたと思ってました。
午後1が大問3つから2つを選ぶ選択制です。
早いこと2問を選んで時間いっぱい熟考しなきゃだめなんですが
全て分からない!2つ選ぼうにも選べない!
時間はどんどん減ってくしどーしよ!ってめっちゃ焦ってました。

当時のつぶやき

午後1で撃沈。午後2は意外とできたんですけどねぇ。
年1回しかない試験なのでまた1年後か、、、
と意気消沈で帰路につきました。

そして2ヶ月後・・・

それがまさかの

それがですよ。
昨日発表された合否判定を見てみたら、、、


!!!

え?

同じグループの受験者70人のうち、表示されてる番号はたった7人。

5度見ぐらいしました。

受験票の番号とモニターを交互に見て指差し確認もしました。

ほんとに自分の番号?

まじで?

受かってるーーーー!!!


あまりの驚きをそのままツイートしたところ
20人以上のフォロワーさんから”おめでとう”をいただきました。

これがほんとに嬉しかった。
受かったこと自体ももちろん嬉しいんですが
それよりがんばったことが報われた気がして嬉しかった。

個別に返事を差し上げましたが
ここでもう一度書かせてください。

ありがとうございます!

午後1は60点だったのであと1点少なかったら落ちてたんですよね。
ほんとギリギリですね。
まだ”スペシャリスト”にはほど遠いので
自信もって言えるように今後もがんばりましょ。

はい、長い独り言終わりです!
ありがとうございました。

2013年12月15日日曜日

【C#,LINQ】LINQ勉強会に行ってきました

今日はこれ行ってました。
第3回 LINQ勉強会

4時間ひたすらLINQのお話で内容ぎっしり。
にわかLINQerの自分はかなり必死に聞いていました。

とりあえず忘れないうちにメモ。

これまでのLINQ勉強会について

14:00~14:20 森理 麟さん(@moririring)
いままでこんな活動してきたよ〜。とか
LINQ勉強会は三回目だよ〜。とかの紹介でした。

LINQ 概要 + 結構便利な LINQ to XML

14:20~15:20 青柳 臣一さん(@ShinichiAoyagi)

LINQって?LINQの種類、LINQの書き方に始まり、
後半はLINQ to XMLの便利さについて語ってみえました。

LINQ to XML

W3Cの規定しているXmlDocumentとは全くの別物だそうな。
キーワード:XDocument, XElement, XAttribute
System.Xml.Linq名前空間を使うらしい。

以下のようにしてXMLを作り出すことが可能。
                var xml = new XDocument (new XElement ("AddressBook",
                    new XElement ("Person",
                        new XElement ("Name", "taro"),
                        new XElement ("Age", 20)),
                    new XElement ("Person",
                        new XElement ("Name", "hanako"),
                         new XElement ("Age", 20))
                         ));

これは楽そう。
VBだともっと変態的でソースコード上にいきなりXMLを書き始めることが可能らしい。
こうやって宣言したあとはもちろんLINQで使える。
                var q = xml.Elements ("AddressBook").Elements ()
                    .Where (x => x.Element ("Name").Value == "taro");

ふむふむ。
さらに取り出すときにXElementを直接キャストできるそうな。
                var q = xml.Elements ("AddressBook").Elements ()
                    .Where (x => (int)x.Element ("Age") == 20);

XElementクラスに主要な型へのキャストは大体定義してあるそうです。
もしElementがない場合などキャスト失敗するとException吐かれるんですが
Nullable型へキャストすればいいそうです。すんごい。

もしXPathを使いたい場合はSystem.Xml.XPath名前空間を使えばいいそう。
                var qq = xml.XPathSelectElements ("/AddressBook/Person[Age=20]")....

XPath? 使ったこと無いし良くわからんですはい。
聞いた感じだとLINQ to XMLだけでいいような。

全体的にかなり分かりやすかったです。
ゆっくり進めてくれたしかな?
LINQ大好きなのが伝わってきましたw

もう一つのLINQ - Queryable入門

15:30~16:20 よねやんさん(@yone64)

LINQ to SQLなどで使われるIQueryableを使ったLINQについての説明でした。 IEnumerableの方はいつも使ってますがIQueryableの知識は0だったのでとても面白かった。

EnumerableとQueryable

Enumerableはオンメモリ上の配列などを対象に順次評価していくのに対し、
Queryableは外部のデータソースに対して問い合わせを行うための物。
例えばLINQ to SQL。

自分で実装する場合、
IQueryable<T>, IQueryProvider, IQueryProvider<T>などを書いていく。

IQueryableを使ったLINQで書いていくと
コンパイルしたときにExpressionTree(式木)というものが生成されるそうです。
実行時にはそれを元にQuery(SQLとか)が生成され、外部データソースに問い合わせされる感じらしい。

実際にATNDのWebAPIを対象としたLINQ実装を紹介していました。
大まかな流れは理解できたし一度書いてみようかなとは思ったけど
実際に使っていくかというとどうかなぁといった感じ。
ちょっと複雑になるだけでコーディング量倍増しそうな感じだったw

ちなみにILは基礎教養らしいです。

資料の最後に参考URLが載ってるので時間あるときに読んでみよう。

An Internal of LINQ to Objects

16:30~17:30 株式会社グラニ 取締役CTO ノイエさん(@neuecc)

linq.jsとか作った世界的にもすごい人。
話し方も独特ですごい面白かったw

ひじょーに沢山の項目を話されてましたので気になったところだけ。

即時実行と遅延実行

・ToArray, First, Sum, などなどは即時実行
・IEnumerable<T>を返すものは遅延実行
 遅延実行される物はメモリ効率がよく好き放題繋いでも大丈夫。

・でも遅延実行=何度でも実行される可能性がある
 ToArrayなどで実体化(Materialization)しよう。

・IEnumerator<T>を扱うときは必ずusingすること。
 絶対。

Iterator復習

・IteratorはMoveNextのときに始めて実行される。
・そのため引数チェックのタイミング注意。
・内部的に分離することで引数チェックを確実に行う。

安定ソート、非安定ソート

・OrderByはQuickSort
・QuickSortは非安定ソート
・OrderByは安定ソート
ん?

シュワルツ変換?とかっていうイディオムを使って安定ソートを保証してるらしい。

OrderByを使ってシャッフル、最大値取得

seq.OrderBy(_ => Guid.NewGuid());
seq.OrderBy(x => x.Age).First();
seq.OrderByDescending(x=>x.Age).First();

SortにRandomを使うのは偏るらしいんだけどOrderByの仕組みを使えば大丈夫らしい。理由はよくわかんないけどすごい。MinMaxの取得も確かにこれ便利。
効率考えるとちゃんと別で実装すべきらしいけど手軽に使うなら十分みたい。

ToLookup

始めて聞いた。辞書のValue側がIEnumerableになってるものらしい。

クエリ構文は要らない子

そんな気はしてた!

それAny

始めて聞いたけど笑ったw たしかにそのとおりだw

Where連打

Where連打は正義。楽しい。
.Where(...).Where(...).Where(...)ってかいてると効率厨が沸いてくるらしい。
でもコンパイルすると&&に変換されるから大丈夫だって。すっげー。


この他にも色んなネタを話されてました。
資料のページ数を見るだけでも項目の多さが良くわかりますね。
どれも深く考察されててさすがだなーと思うばかりでした。


ここからはLT。

手積みでLINQ

アイライト 石野さん (@AILight)
IQueryableを使ったLINQを使うために便利な関数を紹介されてました。
(...ちょっと理解追いつかなかったけど認識合ってるかな?)

組み込みでもLINQ

shagaさん (@shohaga)
.Net MicroFramework+LINQの紹介をされていました。
組み込み機器でもLINQ使えるなんて面白いなぁ。

Codeer Friendly

イッシーさん (@StoneGuitar777)
PCの調子が悪かったようでテーマソングを流したのみでした。残念。
テスト自動化ツールのFriendlyというライブラリを開発されているそう。
懇親会でデモ見せてもらいましたが使い方次第で何でもできそう〜。



4時間みっちりとても勉強になりました。
IQueryableのあたりはよく分かってなかったので
イメージ掴めただけでも大収穫でした。
あとは勉強になったとともに自分はまだまだ勉強不足だなーと再認識。
がんばろー。

2013年12月14日土曜日

【Unity,Photon】PhotonCloudでオンラインゲームつくっちゃおー その2【応用編】

またまたPhotonCloudの勉強会に参加してきました。
Unityで Photon Cloudを使って、オンラインゲームを作っちゃおう【応用編】

前回の基礎編をまとめた記事はこちら
【Unity,Photon】PhotonCloudでオンラインゲームつくっちゃおー

前回の基礎編も簡単でしたが応用編もとても簡単でした。
たった4~50分で複数人同時プレイ可能なシューティングゲーム(もどき?)
ができてしまうので驚きです。
RigidBodyをどのように同期するのかが分かりとても参考になりました。

つくったもの

このスクショは自分のキャラだけですが、
複数人が同時に現れ、弾を打ち合います。
弾があたるとキャラクターは消滅(死に)ます。

つくりかた

公式のスライドが公開されてましたので載せておきます。
コーディングが少し必要ですが全部コピペで終わるので簡単ですよ。


学んだこと

・座標を同期する場合はMathf.Leapを使えば滑らかな動きにできる
・物理演算する/しないなどはPhotonView.isMineプロパティで制御を分ける
・RPCによる通知もisMineプロパティで制御するとよい(Ownerが責任を持つ感じ)
OnPhotonSerializeViewで好きな情報をやり取りできる
・何fpsで同期するかは、開発者が自由に決められる。
 具体的にはOnPhotonSerializeView内でTime.timeなどを使って間引けばよい。

だいぶPhotonの使い方見えてきたぞ〜。
年内にはiOSで一つ申請出したいな。

2013年12月3日火曜日

【Unity,iOS】シミュレータ向けにビルドするとDebugStringToFileエラーが発生する

リリース用にiPadスクリーンショットを取りたくてシミュレータ向けにビルドしたんだけどエラーした。

バージョン

・Unity 4.2.2f
・XCode 5.0.1

症状

Unity側でBuild&Run〜Xcodeプロジェクトが起動する。ここまでOK
そのままXCodeプロジェクトがビルドされて〜エラー。
Undefined symbols for architecture i386:
  "DebugStringToFile(char const*, int, char const*, int, int, int, int, int)", referenced from:
      prcore::Surface::ClearImage(prcore::color32 const&, prcore::Surface::ClearMode) in libiPhone-lib.a(blitter_integer.o)
      prcore::Surface::BlitImage(prcore::Surface const&, prcore::Surface::BlitMode) in libiPhone-lib.a(blitter_integer.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
実機で実行するには何の問題もない。なんやろ。

調べた

調べたら海外でも騒いでた。
ここは未解決だったけど。
http://forum.unity3d.com/threads/205241-XCode-5-Unity-4-2-2-on-OS-X-10-8-5
こっちで解決してた。
http://stackoverflow.com/questions/19871377/xcode-undefined-symbols-for-architecture-i386-debugstringtofile-when-building

Unity 4.3で解決済みだってさ。

解決

Unityを更新して解決。
よかったよかった。

2013年12月1日日曜日

【Unity】シーン遷移時のフェードイン・フェードアウトを実装してみた

お久しぶりです。
前回の記事からもう1週間も経ってるんですね。ブログ続けるの難しい…。

さて今日はScene遷移時のフェードイン・フェードアウトを実現できたのでまとめておきます。
フェードって言っても色々あると思いますけど
今回実装したのはだんだん暗くなって、だんだん明るくなるシンプルなアレです。

イメージ

  • だんだん暗くなり、Sceneが切り替わり、だんだん明るくなる
  • 暗くなる(明るくなる)時間は好きに指定したい
  • Application.LoadLevelと似たような感じで呼び出したい

デモ


Hosted by UnityRoom.com

ダウンロード

2015/03/22追記
大きく作り替えるとともにGitHubに公開しました。
ダウンロードおよび使い方はGitHubをご確認ください -> Unity-FadeManager | GitHub

従ってここから下は古い情報です。

実装

1時間弱で完成。
長いのでソースは一番下に載せておきます。


使い方

SingletonMonoBehaviour.csを用意

下記の記事にある"SingletonMonoBehaviour.cs"を用意しておく。
【前の記事】シングルトンの実装についてはこちら
【Unity】なんちゃらManagerクラスを作ろう(シングルトン)

FadeManagerの配置

・空のGameObjectを作成
・名前をFadeManagerにする
・AddComponentでFadeManagerを追加


呼び出す

Application.LoadLevelの代わりに下記のように書く
・FadeManager.Instance.LoadLevel("シーン名",フェード時間)
FadeManager.Instance.LoadLevel("Scene2",1.0f);

こんな感じ。
これだと1秒かけて暗くなり、Scene2に切り替わり、1秒かけて明るくなる。
いい感じ。


ソース

FadeManager.cs

using UnityEngine;
using System.Collections;

/// <summary>
/// シーン遷移時のフェードイン・アウトを制御するためのクラス
/// </summary>
public class FadeManager : SingletonMonoBehaviour<FadeManager>
{
 /// <summary>暗転用黒テクスチャ</summary>
 private Texture2D blackTexture;
 /// <summary>フェード中の透明度</summary>
 private float fadeAlpha = 0;
 /// <summary>フェード中かどうか</summary>
 private bool isFading = false;
 
 public void Awake ()
 {
  if (this != Instance) {
   Destroy (this);
   return;
  }

  DontDestroyOnLoad (this.gameObject);

  //ここで黒テクスチャ作る
  this.blackTexture = new Texture2D (32, 32, TextureFormat.RGB24, false);
  this.blackTexture.ReadPixels (new Rect (0, 0, 32, 32), 0, 0, false);
  this.blackTexture.SetPixel (0, 0, Color.white);
  this.blackTexture.Apply ();
 }
  
 public void OnGUI ()
 {
  if (!this.isFading)
   return;

  //透明度を更新して黒テクスチャを描画
  GUI.color = new Color (0, 0, 0, this.fadeAlpha);
  GUI.DrawTexture (new Rect (0, 0, Screen.width, Screen.height), this.blackTexture);
 }

 /// <summary>
 /// 画面遷移
 /// </summary>
 /// <param name='scene'>シーン名</param>
 /// <param name='interval'>暗転にかかる時間(秒)</param>
 public void LoadLevel(string scene, float interval)
 {
  StartCoroutine (TransScene (scene, interval));
 }
 
 
 /// <summary>
 /// シーン遷移用コルーチン
 /// </summary>
 /// <param name='scene'>シーン名</param>
 /// <param name='interval'>暗転にかかる時間(秒)</param>
 private IEnumerator TransScene (string scene, float interval)
 {
  //だんだん暗く
  this.isFading = true;
  float time = 0;
  while (time <= interval) {
   this.fadeAlpha = Mathf.Lerp (0f, 1f, time / interval);      
   time += Time.deltaTime;
   yield return 0;
  }

  //シーン切替
  Application.LoadLevel (scene);
  
  //だんだん明るく
  time = 0;
  while (time <= interval) {
   this.fadeAlpha = Mathf.Lerp (1f, 0f, time / interval);
   time += Time.deltaTime;
   yield return 0;
  }

  this.isFading = false;
 }

}

ポイント

・実行にはSingletonMonoBehaviourクラスが必要です。→こちら
・Application.LoadLevelの代わりにこのクラスのLoadLevelメソッドを使います。
・第一引数に遷移先シーン名を指定
・第二引数にフェードにかかる時間を指定

まとめ

Application.LoadLevelだと呼び出してから実際に切り替わるまでにタイムラグがあるので
ユーザーがボタンを押してからの反応が遅く、あれ?押したよね?ってなります。

これはユーザーにしたらすごいストレスですよね。
ボタンっぽくないボタンとか、押しても反応がないボタンとかしんどい。

今回のフェードを実装したことで
読み込みが多少遅くてもボタンを押した瞬間に
暗くなり始めるのでユーザーには多少親切になりました。
(そもそも読み込み早くしろよって言われればその通りですけど…^^;)

しばらくこれで使ってみよう。

それじゃまた!
Unity系記事まとめ

2013年11月25日月曜日

【Unity】デバッグ用にクラスのメンバ変数を列挙してみた

Twitterで気になる発言を発見。
上記のブログで紹介されてる関数を使えば
プロパティ名などをInspectorで表示されるような
ちょっと見やすい形に整形できるとのこと。

何かの役に立つかな?とのことなのでちょっと考えてみた。

考えてみた。

プロパティ名を手打ちしてまで使うものじゃないなー

プロパティを自動取得すれば使えるなー

そのまま列挙すればデバッグ時に便利じゃない?

ToString()でそのオブジェクトの内容を表示できるので
ToString2()みたいな関数を作ってより詳しい内容を表示しよう。

書いてみた。

MonoBehaviourExtensionsってクラスを作成
using System;
using System.Reflection;
using UnityEngine;
using UnityEditor;

public static class MonoBehaviourExtensions
{
 
 /// <summary>
 ///  MonoBehaviourを継承したクラスの内容を文字列として返します。
 /// </summary>
 public static string ToString2<T> (this T obj) where T : MonoBehaviour
 {
  Type t = typeof(T);
  
  var txt = new System.Text.StringBuilder ();
  
  //  GameObject名を取得
  txt.Append (((MonoBehaviour)obj).name);
  
  // Get Public Fields
  FieldInfo[] fields = t.GetFields ();
  foreach (FieldInfo f in fields) {
   string fName = ObjectNames.NicifyVariableName (f.Name);
   string fValue = f.GetValue (obj).ToString ();
   txt.Append (string.Format (" [{0}:{1}]", fName, fValue));
  }
  
  return txt.ToString ();
 }
}
こんな感じかな?

ポイント

・各クラスに実装するのが面倒だったので拡張メソッドで定義
 (MonoBehaviourを継承してToStringをOverrideでもいいけど)
・呼び出しクラスのPublicな変数一覧を取得
・変数名と値を取得
・変数名を紹介されてた関数を使って整形
・整形した変数名と値を列挙して返す

使ってみた。

適当なGameObjectにMyScriptという名前でスクリプトを追加
using UnityEngine;

public class MyScript : MonoBehaviour {
 
 public int PublicIntXXX = 10;
 public string PublicStringABC = "ABC";
 public int PublicPropertyIntYYY {get;set;}
 private int myPrivateIntXXX = 3;

 void Start () {
  Debug.Log(this.ToString2());
 }
}
こんな感じで内容を表示したいクラス内でToString2関数を呼ぶだけ。
Debug.Logで使うぐらいしかないけど…。
うまく表示できた。
これは地味に便利かもしれないね。

プロパティやPrivateメンバは省いてる。
PublicFieldメンバだけだと足りないかもしれないから
必要に応じてカスタマイズしよう。

Unity系記事まとめ

2013年11月23日土曜日

【Unity】AudioManagerクラスを作ろう

さて、前の記事でシングルトンを提供するクラスができたので
AudioManagerを仕上げてみました。
【前の記事】シングルトンの実装についてはこちら
【Unity】なんちゃらManagerクラスを作ろう(シングルトン)

イメージ

自分がAudioManagerを作ろうって思った時点で思い描いた仕様はこんな感じ。

  • デザイナ上でBGMやSEを好きなだけセットできる。
  • 好きな場所からいつでも再生、停止できる。
  • 再生する音源は音声ファイル名で指定する。
  • BGMは1つだけ再生。
  • SEは指定した数まで同時再生可能。


実装

できました。
ソースは長いので一番下に載せときました。

使い方

AudioManagerの配置

・空のGameObjectを作成
・名前をAudioManagerとかにしとく
・AddComponentでAudioManagerを追加
追加直後の状態

AudioClipをセット

・mp3ファイルとかをHierarchyビューにドロップ
 (これでAudioClipができる)
・AudioClipの名前は分かりやすい名前にしておく
 (呼び出すときに使うため)
・BGMListにAudioClipを好きなだけ追加
・SEListにAudioClipを好きなだけ追加
・MaxSEはSEの最大同時再生数です。好きな値で。
BGM2つ、SE3つセットしてみた所

テスト用スクリプト書いてみる

・MainCameraのAudioListenerを削除(or 無効化)
・空のGameObjectにこんな感じのコンポーネントを付ける
using UnityEngine;

public class script : MonoBehaviour {
 
 void OnGUI()
 {
  if(GUI.Button(new Rect(10,100,100,50),"BGM1"))
  {
   AudioManager.Instance.PlayBGM("bgm1");
  }
  if(GUI.Button(new Rect(110,100,100,50),"BGM2"))
  {
   AudioManager.Instance.PlayBGM("bgm2");
  }
  if(GUI.Button(new Rect(210,100,100,50),"BGMSTOP"))
  {
   AudioManager.Instance.StopBGM();
  }
  if(GUI.Button(new Rect(10,200,100,50),"SE1"))
  {
   AudioManager.Instance.PlaySE("se1");
  }
  if(GUI.Button(new Rect(110,200,100,50),"SE2"))
  {
   AudioManager.Instance.PlaySE("se2");
  }
  if(GUI.Button(new Rect(210,200,100,50),"SE3"))
  {
   AudioManager.Instance.PlaySE("se3");
  }
  if(GUI.Button(new Rect(310,200,100,50),"SESTOP"))
  {
   AudioManager.Instance.StopSE();
  }

 }
}
実行!

BGMが鳴る!切り替えられる!停止できる!
SEが鳴る!いっぱい鳴る!
完璧っす。

ソース

AudioManager.cs

using UnityEngine;
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;

public class AudioManager : SingletonMonoBehaviour<AudioManager> {
 
 public List<AudioClip> BGMList;
 public List<AudioClip> SEList;
 public int MaxSE = 10;
 
 private AudioSource bgmSource = null;
 private List<AudioSource> seSources = null;
 private Dictionary<string,AudioClip> bgmDict = null;
 private Dictionary<string,AudioClip> seDict = null;
 
 public void Awake()
 {
  if(this != Instance)
  {
   Destroy(this);
   return;
  }

  DontDestroyOnLoad(this.gameObject);
  
  //create listener
  if(FindObjectsOfType(typeof(AudioListener)).All(o => !((AudioListener)o).enabled))
  {
   this.gameObject.AddComponent<AudioListener>();
  }
  //create audio sources
  this.bgmSource = this.gameObject.AddComponent<AudioSource>();
  this.seSources = new List<AudioSource>();
  
  //create clip dictionaries
  this.bgmDict = new Dictionary<string, AudioClip>();
  this.seDict = new Dictionary<string, AudioClip>();
  
  Action<Dictionary<string,AudioClip>,AudioClip> addClipDict = (dict, c) => {
   if(!dict.ContainsKey(c.name))
   {
    dict.Add(c.name,c); 
   }
  };
  
  this.BGMList.ForEach(bgm => addClipDict(this.bgmDict,bgm));
  this.SEList.ForEach(se => addClipDict(this.seDict,se));
 }
 
 public void PlaySE(string seName)
 {
  if(!this.seDict.ContainsKey(seName)) throw new ArgumentException(seName + " not found","seName");
  
  AudioSource source = this.seSources.FirstOrDefault(s => !s.isPlaying);
  if(source == null)
  {
   if(this.seSources.Count >= this.MaxSE)
   {
    Debug.Log("SE AudioSource is full");
    return;
   }
   
   source = this.gameObject.AddComponent<AudioSource>();
   this.seSources.Add(source);
  }
  
  source.clip = this.seDict[seName];
  source.Play();
 }
 
 public void StopSE()
 {
  this.seSources.ForEach(s => s.Stop());
 }
 
 public void PlayBGM(string bgmName)
 {
  if(!this.bgmDict.ContainsKey(bgmName)) throw new ArgumentException(bgmName + " not found","bgmName");  
  if(this.bgmSource.clip == this.bgmDict[bgmName]) return;
  this.bgmSource.Stop();
  this.bgmSource.clip = this.bgmDict[bgmName];
  this.bgmSource.Play(); 
 }
 
 public void StopBGM()
 {
  this.bgmSource.Stop();
  this.bgmSource.clip = null;
 }
 
 
}

ポイント

・実行にはSingletonMonoBehaviourクラスが必要です。→こちら
・複数Scene跨いでも使えます。
・Scene内にAudioListenerが無い場合は生成します。
・AudioSourceを動的に生成します。


まとめ

やりたいと思ったことは実現できました。
でもListとかDictionaryとかLinqをガンガン使ってるので
ゲーム開発って視点で見ると無駄の多いソースなのかも。

アプリ開発始めたころは省メモリ意識してたんだけど
結構動いてくれるから気にしないで書いちゃうのよね。

ソース載っけてみたので
”もっとこうした方がいいよ。" とか "自分はこんな風にしてるよ。”
っていうのがある方は是非おしえてください!
人のソース読みたい…。

それじゃまた!
Unity系記事まとめ

【Unity】なんちゃらManagerクラスを作ろう(シングルトン)

どこからでも呼び出したいもの

Unityでゲーム作ってるとどこからでも呼び出したいクラスが欲しくなります。
命名するとなんちゃらマネージャーみたいになるやつ。
AudioManagerとか、SettingManagerとか、ParticleManagerとか
どこからでも呼び出せると便利で、でも2つ以上あったら変なもの。

じゃーどうすんの?って調べてると大体シングルトンっていう考え方に行き着くと思う。
シングルトンとは→Wikipedia
ようするにインスタンスを1個しか作らなければいいだけ。
よし使おー。

シングルトンを使ってみよう

ってことで普通にやろうとすると
AudioManagerクラスを作成→シングルトンになるよう変数、関数追加
SettingManagerクラスを作成→シングルトンになるよう変数、関数追加
ParticleManagerクラスを作成→シングルトンになるよう変数、関数追加
・・・

ってなる。
同じようなの作るたびにコピペでめんどくさい。
いや、めんどくさいというより何度も書くのが気持ち悪い。

そんなときこそ、

じぇねりくす

こんなことしなくていいようにC#には便利な機能があって、
ジェネリクスってものを使うと1回書くだけで再利用できるようになります。
ジェネリクスとは→ジェネリックス

よし作ろう!と思ったけど
MonoBehaviourが絡んでくるのでどう書いていいか良くわからない。

絶対先輩方が書いてるでしょってことでめっちゃ調べた。
あるわあるわいっぱいあるわ

[Unity3D]もっと楽なシングルトンの実装 : テラシュールウェア
Unity開発に関する50のTips 〜ベストプラクティス〜(翻訳): No hack, no work
[Unity]Generic Based Singleton for MonoBehaviours完全版(?) : ケットシーウェア

この中でも一番自分のイメージに近かった
50のTipsにあるものを使うことにしました。

SingletonMonoBehaviour

using UnityEngine;

public class SingletonMonoBehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
 private static T instance;
 public static T Instance {
  get {
   if (instance == null) {
    instance = (T)FindObjectOfType(typeof(T));
 
    if (instance == null) {
     Debug.LogError (typeof(T) + "is nothing");
    }
   }
 
   return instance;
  }
 }

}

使い方

using UnityEngine;

public class AudioManager : SingletonMonoBehaviour<AudioManager> {
    
    public void Awake()
    {
        if(this != Instance)
        {
            Destroy(this);
            return;
        }

        DontDestroyOnLoad(this.gameObject);
    }    
    
}
こんな感じ。
SingletonMonoBehaviourを継承するだけでシングルトンパターンが実装できます。
テラシュールウェアさんも書いてましたがDestroyについては
利用側(XXXManager)で実装することにしました。
そしてDontDestroyOnLoadはクラスに応じてって感じですね。
AudioManagerならタイトルとかのSceneで生成して使い回すだろうし書きました。


うんうんいい感じ。
MonoBehaviourよくわかってないから合ってるのかわからんけど使えそう。

次はAudioManager完成させよう。

Unity系記事まとめ

2013年11月22日金曜日

【Unity,Photon】PhotonCloudでオンラインゲームつくっちゃおー

これに参加してきましたー。
Unityで Photon Cloudを使って、オンラインゲームを作っちゃおう【導入編】

今回参加したセミナーはPhotonCloudっていうオンラインゲームを作るために便利ななんやかんやがあって、それの布教活動の一環らしいです。
結構頻繁にやってるらしくもうすぐ累計200名突破らしいー。パチパチ。

作ったもの


1時間半のセミナーの中でこういうの作りました。
Hosted by UnityRoom.com

複数ウィンドウ立ち上げて動かしてみるとマルチプレイが確認できると思います。

実際作ってた時間は30分もないと思う。ていうかコード書いてないし。
キャラクターは気持ち悪いけどすごい。
セミナー会場では全部で10体?の気持ち悪い物体が歩き回ってました。

セミナー内容

ざっくりとメモった内容をば。

Photon Cloudとは

ひとことで言うとオンラインゲームを作るために必要な
ネットワーク系の機能を集めたもの。
オンラインゲームを自分で作ろうと思うとサーバーを用意したりいろいろと大変だけど
photonを使えば何も用意しなくていいって感じ。
機能はいっぱい。メモるのめんどくさくなるぐらいいっぱいあった。
集合ロビーとか、マッチメイキングとかチャットとかほんと色々。
もちろん無料で始められます。

利用事例


トロッ娘

http://www.unitygames.jp/game/ug7000556

TicTacToePlus

Sketch with Friends

http://www.sketchwithfriends.net/

ダンジョンズ&ゴルフ

https://itunes.apple.com/jp/app/danjonzu-gorufu/id571639322

他にも色々。

すごいなー。
トロッ娘とか実質20時間ぐらいらしい。
くるくるさんのTicTacToePlusもCEDECの合間だけで作っちゃったとか!
びっくり。

ここから手を動かして作ってみる。

アカウント取得

http://cloud-jp.exitgames.com/

ここいってメールアドレス入れて新規登録。
そしたらメールがくるのでパスワード設定して終わり。
あら簡単。

Assetインポート

Unity起動しててきとーにプロジェクト作成。
AssetStoreで"Photon Unity Networking Free"ってのをインポート。
ほうほう

Photon Cloudの設定

インポートすると"PUN(Photon Unity Networking) Wizard"が立ち上がる。
※無ければOption+Pで開く
それのSetupからAppIDを入れてリージョンを選んでSave。

AppIDは登録時のメールからPhotonにログインすれば書いてある。

ネットワーク機能実装

ここから設定してく。
・サンプルSceneが開かれてると思うのでNew Sceneを作成
・空のゲームオブジェクト作成(PhotonScriptとか適当な名前にする)
・AddComponent -> Random Matchmaker
 これが勝手にマッチングしてくれるらしい。

ここで実行すると既に気持ち悪いのが出てくる。(落ちてく)

チャット機能実装

・空のゲームオブジェクト作成(Chatとか名前つける)
・AddComponent -> In Room Chat
 これで2つのコンポーネントが追加される。
   ・Photon View
     ↑これがついてるオブジェクトが同期対象となるみたい。
   ・In Room Chat
     チャットするやつ。

ユーザー名つける

RandomMatchmaker.csのStartメソッドを修正
    // Use this for initialization
    void Start()
    {
        PhotonNetwork.ConnectUsingSettings("0.1");
  
  if (string.IsNullOrEmpty(PhotonNetwork.playerName))
  {
   PhotonNetwork.playerName = "guest" + Random.Range(1, 99999);
  }
    }

ふむふむ。

あと諸々調整

・Plane置いて床にする。
・照明追加

実行

うごいた。
想像以上に簡単だった。
お手軽すぎる。(気持ち悪い)

ここまで30分程度。
残り時間はみんなでトロッ娘で遊んでました。

まとめ

チャットだけでも自分で作ろうとすると相当めんどいよね。
コンポーネントつけるだけで動いちゃうとか素敵!!
もう少し実用的なことをしようとすると色々複雑になってくるんだろうけど
「お手軽」に「オンラインゲーム」ってことは十分伝わりました。

いやーおもしろい。
来月応用編あるらしいし行けたらいいな。

おまけ

モバイル環境での実行について

以前どっかでPhotonはモバイルじゃ使えないって聞いたんですよね。
それがとても気になってたので一応質問してみました。
そしたらあっけなく「できますよ」って。

!!!!

マジか!

どうやらUnityFreeでもPhotonの有料アセットを購入すればiOS,Androidで動かすことができるみたいです。

たぶんこれかな。
Photon PUN+

Unity3Dがモバイル無料になったのにPhoton使えないとかダメじゃん!ってことで
がんばってくれたみたいです。

いやーありがたい!夢が広がるね!

参考サイト

公式サイト
http://www.photoncloud.jp/
Photon Unity Network (Asset Store)
http://u3d.as/2ey
Photon Cloud ユーザー助け合い所(FaceBook)
https://www.facebook.com/groups/photoncloudjp/

2013年11月16日土曜日

【Unity,Parse】Parse.comのサーバー日時が取得できないか試してみた。

Parse.comでサーバー日時が取りたくなったので試してみた。

やったこと

・サーバー日時の取得
・取得にかかる時間の計測

サーバー日時の取得

ここ見ながらプロジェクト作成

https://parse.com/apps/quickstart

こんな感じのスクリプトを書いた。

using Parse;
using UnityEngine;

public class testParse : MonoBehaviour
{
 void Start ()
 {
  ParseObject o = new ParseObject ("EVENT");
  o.SaveAsync ().ContinueWith (t => {
   Debug.Log ("TIMESTAMP " + o.UpdatedAt);
  });
 } 
}
ParseObjectを更新するとUpdatedAtってプロパティに
時間が入るようなのでそれを取ればいいみたい。

実行


問題なく取れた。
標準時っぽいね。

取得にかかる時間

スクリプトを変更

using Parse;
using UnityEngine;
using System.Collections;

public class testParse : MonoBehaviour
{
 
 private Queue msgQueue = new Queue ();

 void Start ()
 {
  msgQueue.Enqueue ("Start");
  
  ParseObject o = new ParseObject ("EVENT");
  o.SaveAsync ().ContinueWith (t => {
   msgQueue.Enqueue ("Saved Async Complete");
   msgQueue.Enqueue ("TIMESTAMP " + o.UpdatedAt);
  });
  
  msgQueue.Enqueue ("End");

 }
 
 void Update ()
 {
  if (msgQueue.Count > 0) {
   string msg = string.Format ("{0} {1}", Time.time, msgQueue.Dequeue ());
   Debug.Log (msg); 
  }
 } 
 
}
・別スレッドからTime.time呼べなかったからQueue使った。
・task.Wait()でいいと思うんだけど使うとなんかフリーズした。

実行

1秒ちょい。こんなもんか。

おまけ iPhoneでも計測

これも1秒ちょい。時間はそんな変わんなかった。
非同期で使えばそんなに気にならない時間なのかな〜。

2013年11月11日月曜日

ザッカーバーグもいいねって言ったと思うBaaSのParse.comからUnitySDKが出てたので使ってみた


Parse.comとFacebookの関係が知りたい人はこの記事を読んで。
Facebookの傘の下に入ったParseが初のデベロッパカンファレンスを開催

ってことでどれくらい簡単に使えるのか試しに使ってみました。

やったこと

1.Parse.comに書いてたQuickStart
2.ParseUserを使ってユーザ登録
3.ParseObjectを使ってデータ登録
4.Parse.comのDataBrowserを使ってどんなデータが入ったか確認

1.Parse.comに書いてたQuickStart

まずはParse.comにアクセス
ナビゲーションバーの Help → QuickStart
Unity選んでNewProject選んで・・・ま、書いてある通りやった。
そしたら書いてある通りの結果になった。
つまりQuickStartは簡単だった。

2.ParseUserを使ってユーザ登録

ParseUserっていうクラスが用意されてて、それを使うとユーザアカウント周りが簡単に作れるっていうので簡単に使ってみた。
でも、Unityでユーザ登録とかパスワード入力してログインとかはしたくないから、デバイス情報使って自動ログインさせることにした。
空のGameObject作って↓のスクリプトを追加
using UnityEngine;
using System.Collections;
using Parse;

public class ParseLoginScript : MonoBehaviour {

    // Use this for initialization
    void Start () {
        string deviceId = SystemInfo.deviceUniqueIdentifier;
       
        ParseUser.LogInAsync(deviceId, deviceId).ContinueWith(t=>{
            if(!(t.IsFaulted || t.IsCanceled)){
                Debug.Log ("login success");
            }else{
                Debug.Log ("login failure");
                var user = new ParseUser(){
                    Username = deviceId
                    , Password = deviceId
                };
                user.SignUpAsync().ContinueWith(t2=>{
                    if(!(t2.IsFaulted || t2.IsCanceled)){
                        Debug.Log ("signup success");
                    }else{
                        Debug.Log ("signup failure");
                    }
                });
            }
        });
    }
   
    // Update is called once per frame
    void Update () {
       
    }
}
初回実行すると"signup success"って出て、2回目実行すると"login success"って出た。
だけど起動してからsuccessするまでに1,2秒かかった。そんなもんか。
ユーザはもういいや。

3.ParseObjectを使ってデータ登録

どうやらParseUserと紐付けたデータを作ることができるみたいなので、そんな感じでやってみる。
ParseUser.CurrentUserで今ログインしてるユーザをとってこれるらしい。
↓のスクリプトを適当に呼び出し。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Parse;

public class ParseObjectScript {
    public void SetEvents() {
        var ev = new ParseObject("Event");
        ev["Title"] = "aaa";
        ev["User"] = ParseUser.CurrentUser;
        ev.SaveAsync().ContinueWith(t=>{
            if(!(t.IsFaulted || t.IsCanceled)){
                Debug.Log ("save success");
            }else{
                Debug.Log ("save failure");
            }
        });
    } 

    public IEnumerable GetEvents(){
        IEnumerable events;
       
        ParseObject.GetQuery("Event")
            .WhereEqualTo("User", ParseUser.CurrentUser)
            .FindAsync()
            .ContinueWith(t =>
            {
                Debug.Log ("load success");
            });
        return events;
    }   
一応saveもloadも成功したっぽい。

4.Parse.comのDataBrowserを使ってどんなデータが入ったか確認

QuickStartでも見たと思うけどDashboard見てみる。
テストで追加したユーザと合わせて2ユーザ作られてる。
そしてなぜかすごいAPIリクエスト数になってる??
DataBrowserで実際に保存されてるデータを確認してみる。
ユーザクラスちゃんと作られてる。
objectIdとcreatedAtとupdatedAtは勝手に入るらしい。
イベントクラスも作られてる。
LinqToSqlいいね。

って感じでかなり簡単に使えました。
データの保存以外にもPUSH通知とかJOB作れたりだとか画像処理とかもできるらしいので、気力があるときに使ってみたい。

2013年11月9日土曜日

【Unity,NGUI3.x】UIPanelとDrawCall

NGUI使っててDrawCallが減らせなくて困った。
原因は単純だったけど解決したのでメモ。

環境

・Mac
・Unity 4.2.2.f1
・NGUI 3.0.3g

つまづいたこと

NGUIでUIを大量に配置してたらDrawCallが30超えた。
同じUIAtlas使ってるしDepthも揃えたのになんでだろなーって思ってた。

原因

同じUIAtlasを使っていてもUIPanelを複数配置するとDrawCallが別れるんですね。
以前どこかで「まとめて動かすようなものはPanelに入れる」って読んだ気がしてUIPanel量産してましたw

ダメなパターン

Root(UIRoot)
┗Camera(Camera,UICamera)
 ┗Anchor(UIAnchor)
  ┗Panel(UIPanel)
   ┣Panel1(UIPanel)  ←まとめて動かす用
   ┃ ┗Sprite(UISprite)
   ┗Panel2(UIPanel)  ←まとめて動かす用
     ┗Sprite(UISprite)

2つのSpriteはどちらも同じAtlasを参照してますけどDrawCallは2ですね。

Panel1のInspector見てみてもDrawCallが別れてるのが分かります。

対応

じゃあどうするか?UIPanelを1つだけにすればいいんです。
Panel1,Panel2からUIPanelコンポーネントをむしり取りましょう。

大丈夫なパターン

Root(UIRoot)
┗Camera(Camera,UICamera)
 ┗Anchor(UIAnchor)
  ┗Panel(UIPanel)
   ┣Panel1(空のGameObject)  ←まとめて動かす用
   ┃ ┗Sprite(UISprite)
   ┗Panel2(空のGameObject)  ←まとめて動かす用
     ┗Sprite(UISprite)

これだけでDrawCallは1つになりました。
DrawCallは親Panelに集約されてますね。


Panel1,2は空のGameObjectになってしまったけど何の問題もなさそうです。

まとめ

DrawCallをとにかく減らしたいなら1つのUIPanelに配置する。
でも同時に表示しないUI(ゲーム画面用、ポーズ画面用など)はこだわる必要ないので別々のUIPanelにした方が楽に扱えそうですね。

疑問

DrawCallが増えてでもUIPanelを別けたい場合はあるだろうか?
パーティクル表示を(Atlas、Panelセットで)分離したいときとか?

参考

 ここでは別Panelでも1Callだったって書いてあるけど仕様変わったのかな。
 最初読んだとき良くわからなかったけど今じっくり読んでやっと分かった。やったこと同じだね。


楽しいUnityライフを!

2013年11月7日木曜日

【Unity,C#】RGBではなくHSVによる色指定

今日はこんなの作ってみた話。

ことの発端はNGUIでボタンを作ってて、
統一感のあるカラフルなボタンを作りたくなったこと。
Unityのエディタ上ならなら色選択ダイアログのスライダー動かすだけなんだけど、
スクリプトでやろうとしたらできなくて困った。
これ
ColorクラスはRGBでしか指定できない。
RGBをどう変えたら同じ雰囲気の別の色に変えられるか分からなかった。

調べてみたらHSVっていう方法で色を指定できればいいみたい。

HSV色空間


HSV色空間

RGBは名前の通り赤緑青の比率だけど、
HSVだと以下の3つで色を決定するらしい。
・Hue(色相)
  赤、青、黄色と言った色
・Saturation(彩度)
  色の鮮やかさ
・Value(明度)
  色の明るさ

なのでSとVを固定してHだけを変更すればやりたいことが実現できそう。

UnityEngine.Colorクラス

http://docs.unity3d.com/Documentation/ScriptReference/Color.html
RGBしか扱えないみたい。
当然コンストラクタもRGBしか用意してない。

HSVとRGBを変換できるものが必要。

調べた

EditorGUIUtility.HSVToRGB
  標準でも変換クラスはあるみたい。
HSVの値からRGBを返すユーティリティスクリプト
  作ってる人いた。でもちょっと物足りない。

ちょっと欲しい感じの見つからなかったので作ってみた。
ここに変換式も全部載ってたし。

作ったクラス

ColorHSV.cs

using System;
 
namespace UnityEngine
{
 /// <summary>
 /// HSV色空間を扱うクラス
 /// </summary>
 public static class ColorHSV
 {
  
  
  /// <summary>
  /// HSV色空間による指定でUnityEngine.Colorを作成します。
  /// </summary>
  /// <param name="h">色相(Hue) 0-360</param>
  /// <param name="s">彩度(Saturation) 0-255</param>
  /// <param name="v">明度(Value) 0-255</param>
  /// <returns></returns>
  public static Color FromHsv(int h, int s, int v)
  {
   while (h >= 360) h -= 360;
   while (h < 0) h += 360;
   if (s > 255) s = 255;
   if (s < 0) s = 0;
   if (v > 255) v = 255;
   if (v < 0) v = 0;
   
   return FromHsv((float)h, (float)s / 255.0f, (float)v / 255.0f);
  }
 
   
  
  
  /// <summary>
  /// HSV色空間による指定でUnityEngine.Colorを作成します。
  /// </summary>
  /// <param name="h">色相(Hue) 0.0-360.0</param>
  /// <param name="s">彩度(Saturation) 0.0-1.0</param>
  /// <param name="v">明度(Value) 0.0-1.0</param>
  /// <returns></returns>
  private static Color FromHsv(float h, float s, float v)
  {
   if (h > 360.0) throw new ArgumentOutOfRangeException("h", h, "0~360で指定してください。");
   if (h < 0.0) throw new ArgumentOutOfRangeException("h", h, "0~360で指定してください。");
   if (s > 1.0) throw new ArgumentOutOfRangeException("s", s, "0.0~1.0で指定してください。");
   if (s < 0.0) throw new ArgumentOutOfRangeException("s", s, "0.0~1.0で指定してください。");
   if (v > 1.0) throw new ArgumentOutOfRangeException("v", v, "0.0~1.0で指定してください。");
   if (v < 0.0) throw new ArgumentOutOfRangeException("v", v, "0.0~1.0で指定してください。");
   
   Color resColor = Color.clear;
   
   if (s == 0.0) //Gray
   {
    int rgb = Convert.ToInt16((float)(v * 255));
    resColor = new Color(rgb, rgb, rgb);
   }
   else
   {
    int Hi = (int)(Mathf.Floor(h / 60.0f) % 6.0f);
    float f = (h / 60.0f) - Hi;
    
    float p = v * (1 - s);
    float q = v * (1 - f * s);
    float t = v * (1 - (1 - f) * s);
    
    float r = 0.0f;
    float g = 0.0f;
    float b = 0.0f;
    
    switch (Hi)
    {
     case 0: r = v; g = t; b = p; break;
     case 1: r = q; g = v; b = p; break;
     case 2: r = p; g = v; b = t; break;
     case 3: r = p; g = q; b = v; break;    
     case 4: r = t; g = p; b = v; break;
     case 5: r = v; g = p; b = q; break;   
     default: break;
    }
    
    resColor = new Color(r,g,b);
   }
   
   return resColor;
  } 
 }
  
   
  
  
 /// <summary>
 /// UnityEngine.ColorのHSV色空間への拡張
 /// </summary>
 public static class ColorExtension
 {
  /// <summary>
  /// 色相(Hue)
  /// 0-360
  /// </summary>
  public static int h(this Color c)
  {
   float min = Mathf.Min(new float[]{c.r, c.g, c.b});
   float max = Mathf.Max(new float[]{c.r, c.g, c.b});
   
   if (max == 0) return 0;
   
   float h = 0;
   
   if (max == c.r) h = 60 * (c.g - c.b) / (max - min) + 0;
   else if (max == c.g) h = 60 * (c.b - c.r) / (max - min) + 120;
   else if (max == c.b) h = 60 * (c.r - c.g) / (max - min) + 240;
   
   if (h < 0) h += 360;
   
   return (int)Mathf.Round(h);
  }
  
   
  
  
  /// <summary>
  /// 彩度(Saturation)
  /// 0-255
  /// </summary>
  public static int s(this Color c)
  {
   float min = Mathf.Min(new float[]{c.r, c.g, c.b});
   float max = Mathf.Max(new float[]{c.r, c.g, c.b});
   
   if (max == 0) return 0;
   return (int)(255 * (max - min) / max);
  }
  
  
  /// <summary>
  /// 明度(Value)
  /// 0-255
  /// </summary>
  public static int v(this Color c)
  {
   return (int)(255.0f * Mathf.Max(new float[]{c.r, c.g, c.b}));
  }
  
   
  
  
  /// <summary>
  /// 現在の色を基準にHSV色空間を移動します。
  /// </summary>
  /// <param name="c"></param>
  /// <param name="offsetH">色相(Hue)オフセット値</param>
  /// <param name="offsetS">彩度(Saturation)オフセット値</param>
  /// <param name="offsetV">明度(Value)オフセット値</param>
  /// <returns></returns>
  public static Color Offset(this Color c, int offsetH,int offsetS,int offsetV)
  {
   int newH = (int)(c.h() + offsetH);
   int newS = (int)(c.s() + offsetS);
   int newV = (int)(c.v() + offsetV);

   return ColorHSV.FromHsv(newH,newS,newV);
  }
  
  
  /// <summary>
  /// 現在の色を文字列として返します。
  /// </summary>
  /// <returns></returns>
  public static string ToString2(this Color c)
  {
   return string.Format("R={0}, G={1}, B={2}, H={3}, S={4}, V={5}", 
   new object[]{
   c.r
   ,c.g
   ,c.b
   ,c.h()
   ,c.s()
   ,c.v()});
  }
 }
}

簡単な説明

1ファイル追加するだけで使えるように気をつけた。

ColorHSVクラス

HSV指定でUnityEngine.Colorのインスタンスを作るクラス
Color color = ColorHSV.FromHsv(0,100,255);

 H:0~360で指定
 S:0~255で指定
 V:0~255で指定
 S,Vは0~255ではなく0~1指定が一般的なのかな?
 RGBが0~255だったりするからそうしちゃった。
 色詳しくないし標準は知らない。

ColorExtensionクラス

UnityEngine.Colorクラスへの拡張メソッド群。

 Colorインスタンスから直接H、S、V取得可能に。
Color color = Color.red;
int h = color.h();
int s = color.s();
int v = color.v();

 ColorインスタンスからH、S、V指定でオフセット可能に。
Color color = ColorHSV(0,100,255);
Color color2 = color.Offset(30,0,0);
これ結構気に入ってる。

遊んでみた

NGUIのUISpriteを360枚配置、Hを1度ずつ変えてみた。
きもちわるっ!
まぁでも機能的には実現できたし満足。

Unity系記事まとめ

2013年11月3日日曜日

【Unity,NGUI3.x】Gridを使って等間隔に配置

ステージセレクトとかで1画面に25個とかボタンが並んでることありますよね。
どーやるのか調べてみたらNGUIに便利なクラスがありました。

Gridっていうものを使うらしいです。

試してみたので残しておきます。

作ったサンプル

適当なSpriteを等間隔に配置してみた。

環境

・Mac
・Unity 4.2.2.f1
・NGUI 3.0.3g

作り方

プロジェクトを用意

・NGUI3.0をインポート
  Examplesは使わないので削除
・以下の素材をインポート
  http://www.tasharen.com/ngui/tutorial3assets.unitypackage
・ProjectビューのMain Cameraも使わないので削除

パネルを用意

・NGUI->Create->Panel
 設定は規定のまま。

Spriteを追加

・NGUI->Create->Sprite
適当に画像を選んでサイズを調整。
これを横5列、縦5列に並べてみようと思います。

Gridを配置

・Game Object->Create Empty
・Panel直下に移動
・Transform.Scaleを1,1,1に変更←忘れがち!
 X,Y,Zの左にある[S]を押すだけで1,1,1になります。
・名前をGridに変更
・Gridを選んだ状態で、Component->NGUI->Interaction->Grid
これでUIGridコンポーネントを持ったオブジェクトができました。
こいつが綺麗に並べてくれるらしい。

並べるSpriteの準備

SpriteをGrid直下に移動し、25個コピーします。
当然まだ重なってますね。

Gridの設定

・Arrangement = Horizontal(水平)
・Max Per Line = 5(横5列)
・Cell Width = 65
・Cell Height = 65
ここでReposition Nowを押すと…
Gridの座標から右へ5個、改行されながら計25個。
綺麗に並びました。あー楽ちん。

まとめ

・等間隔に配置するにはUIGridコンポーネントを使う。
・直下に色々置いてRepositionNowするだけ。

Gridの座標から右(下)に向かって伸びてくみたい。
並んだ数の中心にPivotが欲しいけどそこは仕方ないのかな。
あと空のGameObjectを追加するところ、一発でPanel直下に生成できないのかな?
ショートカットとかありそうなものだけど。

Unity系記事まとめ
Related Posts Plugin for WordPress, Blogger...