ラベル Unity の投稿を表示しています。 すべての投稿を表示
ラベル Unity の投稿を表示しています。 すべての投稿を表示

2015年7月10日金曜日

【スマフォアプリマネタイズ】Unity Ads ミートアップ in 大阪 に参加してきた


7/8に大阪で開催されたUnityAdsの勉強会に参加してきました。

【スマフォアプリマネタイズ】Unity Ads ミートアップ #4 in 大阪

UnityAdsミートアップって集まりは毎月東京でやってるらしいです。
今回はたまたま関西での開催だった模様。

到着〜勉強会開始まで

19:45頃に到着したときには15人ぐらいいたかな?
遅刻だと思って急いで来たけどみんな唐揚げ食べてた。
ちゃんとタイムテーブル見てみると20:30開始、19:30は乾杯だったw
タイムテーブル

数人知り合いがいたのでとりあえずビールで乾杯。
唐揚げとピザを食べながらビール。しかも無料。なんて幸せな・・・

20:30頃、Lサイズのピザ3枚が届いたのと同時に勉強会開始。
始まる頃にはみんなお腹いっぱい

20:30〜 Unity Ads トレンドのご案内

Unityジャパン松井さんの発表。
UnityAdsはこんなものですよ〜とか。
どういうアプリに実装されてますよ〜。みたいな紹介。

導入アプリの数や広告数、フィルレート、eCPMとかふむふむって聞いてた。
ところどころの数字は喋っちゃダメって言ってたから伏せとく。
(どこがダメだったかは酔っ払ってて覚えてない)

導入数に関して言うと今年頭からすでに2倍以上になってるらしい。

あとは代表的な広告の表示方法の紹介とか。

代表的な広告表示方法

UnityAdsは動画広告のみなので表示するタイミングが重要。
ざっくりと4種類紹介された。

アイテムプレゼント型

動画みたらアイテムあげるよ!的なあれ。
見るか見ないかユーザーが選べるしいいよね。最近増えてるのも納得。
コンバージョン、eCPM共に高い。

強制表示型

定期的に強制表示されるやつ。かなりうっとうしい。
5秒でスキップできる場合が多いけどそれでもイライラしちゃう。
コンバージョンは並、eCPMは高い。

コンティニュー型

動画みたらもう一度コンティニューさせてあげるよってやつ。
毎回じゃなくハイスコアに届きそうなときとか、ユーザーが悔しい思いをしたときに出すと効果的らしい。たしかに。広告じゃないけどツムツムとかそうやね。
コンバージョンやや高い、eCPMは高い。

ゲーム開始前表示型

開始前に見ると強くてニューゲームできるよ。みたいな。
今からこのゲームを遊ぶ!ってときに出すから効果は低いらしい。
コンバージョン、eCPM共に低い。

Unityを信じて!

この言葉が印象的だったw
効果の高い広告が出やすいように自動的に最適化されていくから2〜3ヶ月は変にいじらず使ってみて。って言ってた。
いじるってブラックリストやホワイトリストで表示する広告をカスタマイズすることね。

21:15~ Unityのアプリに動画広告を実装するには

続いて鎌田さんの発表。
ソースコード見せながらこんな感じで実装できますって紹介。

実装方法

1.UnityAdsのアセットをインポート

※Unity5.2からはUnityAdsが標準ライブラリに含まれるみたいで、アセットのインポートは不要になるらしい。

2.実装する

コードはこれだけ。
using UnityEngine.Advertisements;
public class UnityAdsTest : MonoBehaviour
{
   void Start()
   {
   if(Advertisement.isSupported && Advertisement.isInitialized)
     {
      Advertisement.Initialize("gameID");
     }
   }

   public void ShowAds()
   {
      if( Advertisement.isReady())
      {
        Advertisement.Show();
      }
   }
}
あら簡単。

このままゴリゴリ書き進めてもいいけど
完了・中断とかのコールバック実装やiOS、Android両対応とか
ちょっと踏み込むとだんだん面倒になってくる。(らしい)

次はそれを解決できるヘルパーの紹介。

もっと楽な実装方法

Unity Ads Helper
UnityAdsの実装を超簡単にしてくれるヘルパー。
使い方は上記リンクをみてね。

iOS,AndroidのgameIDを一緒に設定できたり、
OnFinished,OnSkipped,OnFailedとかのコールバックを簡単に実装できたり。
かなり便利そうに見えた。

実装サンプルプロジェクトの紹介

unity-ads-demo
さっきのヘルパーを作ってる人のデモらしい。


動画をみたらコインをプレゼント〜ってありがちな使い方のサンプル。
一度見るとしばらくは「動画を見る」ボタンが押せないクールダウンタイムの実装もされてるので参考にどうぞ。

動画のスキップについて

アイテムプレゼント型の実装だとスキップできない場合が多いよね。
逆に強制表示型だと5秒でスキップみたいなのが多い。

UnityAdsの管理画面からスキップ可否やスキップ可能までの秒数が設定可能だそうな。

UnityAdsの強み

  • eCPMが高い
  • ゲームに特化してる
  • 実装が楽
こんな感じのことを話してた。

Unity5.2以降はアセットの追加すら不要になるみたいだからかなり楽になるね。

まとめ

実装も楽そうだし使ってみましょー。
ゲーム系アプリであれば導入して損はなさそうです。


あと今後はミートアップってことでお肉食べてしゃべる会を目指すらしいですよ。
お肉食べたくなったらUnityの人に連絡しましょう!


Unity系記事まとめ

2015年4月30日木曜日

【Unity、Mac】エディタをVisual Studio Codeに変更する。

昨夜発表されて話題になってたVisualStudioCode、インストールしてUnityで使えるように設定してみました。
今日はMacでのお話。Windowsの人はVisualStudio使ってるだろうし。

環境

OS X Yosemite 10.10.3
Unity 5.0.0 f4
Visual Studio Code 0.1.0

Visual Studio Codeのインストール

https://code.visualstudio.com/
ここから落としてきて解凍。アプリケーションフォルダに移動するだけ。
簡単に起動した。

Unityでの設定

Unityメニュー->Unity->Preferences

External Tools->External Script Editor->Browse...

Visual Studio Code.appを選択

ソリューションファイルを開く

Unityメニュー->Assets->Sync MonoDevelop Project

これでソリューションファイル(.sln)が作られてVisual Studio Codeで開かれる。
File->Open(もしくはCommand+Option+O) でフォルダを開くダイアログを開き、
Unityのプロジェクトフォルダ(.slnファイルがあるフォルダ)を選択する。
Visual Studio Codeの一番下に pick a project と表示されていると思うのでそれを押す。

ソリューションファイルを選択します。どっちでも良さそう?短い方を選んだ。
変なコンソール立ち上がったけど使いそうにないので閉じとく。
(どうみてもブラウザのデバッグウィンドウだな•••)

肝心のエディタ側はエラー出てる。
Error: Cannot start Omnisharp because Mono version >=3.10.0 is required

エラー対応(monoのインストール)

UnityについてくるMonoが古いからこのエラー出るっぽい。
terminal.app起動して brew install mono
$ brew install mono
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/mono-3.10.0
######################################################################## 100.0%
==> Pouring mono-3.10.0.yosemite.bottle.tar.gz
==> Caveats
To use the assemblies from other formulae you need to set:
  export MONO_GAC_PREFIX="/usr/local"
==> Summary
🍺  /usr/local/Cellar/mono/3.10.0: 1128 files, 218M

エディタ再起動

もいちどSync MonoDevelop Project でOK
エラーなく起動した〜。

感想

難なくインストールできた。
ちょー軽いしgitも認識してくれるみたいでいい感じ。
変数や関数の参照数を出してくれるのもいいね。インラインで参照元も見れるし。
Atomと同じくCommand+Pでなんでも検索ボックスが出てくるみたい。
(画像はコード整形したかったから検索してみた図)
やりたいことができない場合はとりあえずこれ開いて適当に入力してみるといいかも。

そのうちAtomのようにプラグインパラダイスになるんやろなー。
しばらく使ってみましょい。

20150501追記

今まで痛MonoDevelopを使ってたみなさん。
痛VSCodeにも出来るみたいですよ~。

標準MonoDevelopだと日本語入力ができなくて不便だから痛MonoDevelopにしたはずなのに。
あれ、いなくなると寂しい・・・って方、下記を参考にどうぞ。


2015年3月4日水曜日

Unity5リリース!無料版でゲームエンジンの全ての機能が利用可能に!

おっさんドヤ顔
プレスリリース:UNITY、ゲームエンジンUNITYの最新バージョン UNITY 5を公開

Unity5、ついにリリースされましたね!

Unity4のときはProでしか使えなかった機能のほとんどがFree版でも使えるようになったようです。数百ドル分のアセットを買わないとできなかったことが全て無料でできるようになったと考えるととてもありがたいですね!

物理ベースシェーディングやレンダーテクスチャ、プロファイラにポストプロセスエフェクト、、、全てPersonal(無料版)で制限なく使えます。アセットバンドルも試してみよう。あと個人的に2Dのスプライトパッカーが使えるようになったのが嬉しい!

Proの機能がほぼ全て無料版におりて来ちゃった感じです。


間違った事書いてるかもなので詳細は下記リンクから直接確認お願いしますー。

UnityPersonal(無料版)とProfessionalの違い

http://unity3d.com/jp/get-unity

Unity 5エンジンの概要(Personalでも全て利用可能)

http://unity3d.com/jp/unity/engine-features


Android / iOS / その他のプラットフォーム

気になるAndroid / iOSへの書き出しですが、前年度に$100,000以上の売り上げが無い場合は無料版で制限無く書き出せるようです。(Unityロゴのスプラッシュスクリーンが表示されます)

Android/iOS Proが存在するのはあくまでも前年度$100,000以上売り上げたパブリッシャーが購入必須になるだけみたいですね。すばらしい。

すでにUnity5Pro買っちゃったんだけど…って人は?

すでにUnity5プレオーダーをした方で、Unity5 Personal版を利用したい方は条件さえ満たせば払い戻しを受ける事ができるようです。
詳しくは下記FAQを確認ください。

http://unity3d.com/jp/unity/faq


Unity仮面からのありがたい一言



Unity5を使っておもいっきりゲーム開発を楽しみましょう!


他のUnity関連記事もぜひご覧ください。
Unity系記事まとめ

2015年3月1日日曜日

【Unity】とっても簡単に扱えるBGM再生クラスを作ってみた。フェードイン、フェードアウト対応版

こちらの記事(【Unity】AudioManagerクラスを作ろう)の改良版です。

上記記事ではBGMの再生はできましたが、BGM切り替えがスムーズではありませんでした。また、オーディオファイルをインスペクタ上から一つ一つセットしなければいけないなど、いろいろと不満が残っていました。

それらを解消すべく作り直してみたので紹介します。

ダウンロード

UnityPackage

手っ取り早く使いたい方はこちら。
https://github.com/naichilab/Unity-BgmManager/archive/master.zip

ソースコード

GitHubで公開してます
https://github.com/naichilab/Unity-BgmManager

これ以降は使い方の説明とかです。

やりたいこと

  • BGMを再生できること。
  • とにかく簡単に扱えること。
  • BGMのフェードイン、フェードアウトに対応すること。
    • フェードインとは:音量0からゆっくり大きくなっていくこと
    • フェードアウトとは:音量がゆっくり小さくなっていくこと
  • BGMのクロスフェードに対応すること。
    • クロスフェードとは:フェードアウトとフェードインを組み合わせてBGM切り替えを行うこと
  • フェード時間とかを調整できること。
意識したのはこれくらい。
とりあえずBGMだけです。
SEについてもそのうち作ろう。

サンプル


Hosted by UnityRoom.com
PlayボタンでBGM再生開始。
他のBGMへ切り替える際、少し重なって聞こえると思います。これがクロスフェード。
(Playを押してから音が出るまでにちょっと時間があるので分かりづらいかな?)

使い方

Unityプロジェクトを開く

新規Projectでも既存のProjectでもなんでもOK

BgmManagerのダウンロード

https://github.com/naichilab/Unity-BgmManager
こちらのURLにある”Download ZIP”ボタンからダウンロード


BgmManagerのインポート

ZIPファイルを解凍して出てくる
BgmManager.unitypackageをダブルクリックしてUnityに取り込む
サンプル不要ならチェックを外してください。
※サンプルに同梱したmp3ファイルはSHW様(http://shw.in/)提供のものです。

サンプルの実行

SampleフォルダにあるSampleシーンを開きます。
HierarchyビューにBgmManagerが配置されていれば準備完了です。
実行してBGMを再生できる事を確認してください。

サンプルを実行するだけならこれで終わり。これ以降は各自用意されたBGMファイルを再生する方法と、スクリプトからの呼び出し方法の解説です。

BGMファイルの追加

BGMファイルは下記フォルダに存在するものが自動的に読み込まれます。
・Resources
 ┗Audio
  ┗BGM
(Resourcesフォルダはどの階層にあっても大丈夫です。)

フェードパラメータの調整

BgmManagerにはいくつかのパラメータがあります。

  • Debug Mode
    • ONにするとサンプル実行と同じように簡易ウィンドウが表示されます。
  • Target Volume
    • フェードイン完了時の音量です。
  • Time to Fade
    • フェードイン(アウト)の開始〜完了までの時間です。
  • Crossfade Ratio
    • クロスフェードの重なり率を指定します。
      • 0を指定した場合、フェードアウト完了を待ち、フェードインが開始されます。
      • 1を指定した場合、フェードアウトとフェードインが同時に開始されます。

スクリプトからの再生・停止

すきなスクリプトから下記1行でBGMを再生できます。
BgmManager.Instance.Play ("BGMファイル名");
すでに別の曲が再生中の場合は、勝手にクロスフェード再生します。

停止する場合は下記いずれかを呼び出します。
//フェードアウト後、停止います。
BgmManager.Instance.Stop ();
//ただちに再生を停止します。
BgmManager.Instance.StopImmediately ();


スクリプトからパラメータの変更

こんな感じ。
BgmManager.Instance.DebugMode = false;
BgmManager.Instance.TargetVolume = 0.8f;
BgmManager.Instance.TimeToFade = 3.0f;
BgmManager.Instance.CrossFadeRatio = 0.5f;
再生・停止と一緒ですね。

参考サイト



サンプルファイル提供


その他

フェードイン(アウト)は直線的な補間しかしてないですし、インアウトをそれぞれ別の長さにすることもできないです。
まぁとにかく簡単に使える物を目指したので今後も実装する事は無いかな…

是非使ってみてください〜。



Unity系記事まとめ

2014年12月14日日曜日

【Unity、PUN】Photon Unity Networkingのコールバックメソッド一覧


PhotonCloudを使えばUnityで簡単にオンラインゲームが作れますね。

接続に失敗したとき、部屋に誰か入ってきたとき、など
ことあるごとに呼び出されるコールバックメソッドたち。
インテリセンスも効かないし毎度調べるのも面倒なので一覧にしてみた。

誰かが作ってたと思うけど自分用にまとめ直し。
ちなみに超適当和訳なので怪しいと思ったら原文読んでください。
(PhotonNetworkingMessage列挙型のXMLコメントに全て書かれてます)

もうちょい使ったらよく使うもの同士まとめた記事も書こうとおもう。

OnConnectedToPhoton

/// <summary>
/// サーバーへの初期接続が確立したとき呼び出されます。
/// </summary>
/// <remarks>
/// このコールバックはサーバーとの通信が可能かどうかの判断をするためにみ有効です。
/// ほとんどの場合、OnFailedToConnectToPhoton()もしくはOnDisconnectedFromPhoton()で十分です。
/// これが呼び出ばれたときには低レベルでの接続は確率されています。
/// この後、PUNはAppIDやユーザー、その他の情報をバッググラウンドで送信します。
/// また、マスターサーバーからゲームサーバーへ移った際には呼び出されません。
/// </remarks>
void OnConnectedToPhoton(){}

OnLeftRoom

/// <summary>
/// ローカルユーザー、クライアントが部屋を出たときに呼び出されます。
/// </summary>
/// <remarks>
/// 部屋を出るとき、PUNはあなたをマスターサーバーへ移動させます。
/// あなたがロビーを使う前、もしくは部屋に入る(作る)前、
/// OnJoinedLobby() もしくは OnConnectedToMaster() が再度呼び出されます。
/// </remarks>
void OnLeftRoom(){}

OnMasterClientSwitched

/// <summary>
/// マスタークライアントが退場し、新しいマスタークライアントに切り替わった後に呼び出されます。
/// 古いマスタークライアントは既にプレイヤー一覧からは削除されています。
/// </summary>
/// <remarks>
/// このクライアントが部屋に入ったときには、このコールバックは呼び出されません。
/// </remarks>
void OnMasterClientSwitched(PhotonPlayer newMasterClient){}

OnPhotonCreateRoomFailed

/// <summary>
/// CreateRoom()の呼び出しが失敗した場合に呼び出されます。
/// オプションパラメータによってエラーコードおよびエラーメッセージを提供します。
/// </summary>
/// <remarks>
/// よくあるのは「指定した部屋名がすでに使用されている」などです。
/// PhotonNetwork.logLevel を PhotonLogLevel.Informational 以上二している場合、
/// PUNはいくつかの情報をログ出力します。
/// </remarks>
void OnPhotonCreateRoomFailed(){}
void OnPhotonCreateRoomFailed(object[] codeAndMsg){
 //codeAndMsg[0]は エラーコード です。(int)
 //codeAndMsg[1]は デバッグメッセージ です。(string)
}

OnPhotonJoinRoomFailed

/// <summary>
/// JoinRoom()の呼び出しが失敗した場合に呼び出されます。
/// オプションパラメータによってエラーコードおよびエラーメッセージを提供します。
/// </summary>
/// <remarks>
/// よくあるのは「部屋が存在しない」「すでに満員」などです。
/// PhotonNetwork.logLevel を PhotonLogLevel.Informational 以上二している場合、
/// PUNはいくつかの情報をログ出力します。
/// </remarks>
void OnPhotonJoinRoomFailed(){}
void OnPhotonJoinRoomFailed(object[] codeAndMsg){
 //codeAndMsg[0]は エラーコード です。(int)
 //codeAndMsg[1]は デバッグメッセージ です。(string)
}

OnCreatedRoom

/// <summary>
/// このクライアントが部屋を作成し、入室する際に呼び出されます。
/// この後、OnJoinedRoom() は同様に呼び出されます。
/// </summary>
/// <remarks>
/// このコールバックは部屋を作成(PhotonNetwork.CreateRoom)したクライアント上でのみ、呼び出されます。
/// クライアントはいつでも閉じる(もしくは接続を切る)可能性があり、
/// タイミングによってはOnCreatedRoomは呼び出されません。
/// 
/// もし部屋に関する特定のプロパティや"開始信号"が必要な場合、
/// 部屋の状態を確認するためにマスタークライアントを作り、
/// OnMasterClientSwitched()を実装するのが安全です。
/// </remarks>
void OnCreatedRoom(){}

OnJoinedLobby

/// <summary>
/// マスターサーバー上のロビーに入った際に呼び出されます。
/// 部屋のリストが更新されるとOnReceivedRoomListUpdate()が呼び出されます。
/// </summary>
/// <remarks>
/// 注意:PhotonNetwork.autoJoinLobby が false の場合、
/// OnConnectedToMaster() が呼び出され、部屋のリストが利用可能になることはありません。
/// 
/// ロビーに居る間、部屋のリストは自動的に一定間隔で更新されます。
/// (間隔はあなたが変更する事はできません。)
/// </remarks>
void OnJoinedLobby(){}

OnLeftLobby

/// <summary>
/// ロビーを退出した際に呼び出されます。
/// </summary>
/// <remarks>
/// (よくわからんかった。以下原文)
/// When you leave a lobby, [CreateRoom](@ref PhotonNetwork.CreateRoom) and [JoinRandomRoom](@ref PhotonNetwork.JoinRandomRoom) 
/// automatically refer to the default lobby. 
/// </remarks>
void OnLeftLobby(){}

OnDisconnectedFromPhoton

/// <summary>
/// Photonサーバーから切断した際に呼び出されます。
/// </summary>
/// <remarks>
/// いくつかのケースでは、OnDisconnectedFromPhoton()の前に他のコールバックが呼び出されます。
/// 例)OnConnectionFail() や OnFailedToConnectToPhoton()
/// </remarks>
void OnDisconnectedFromPhoton(){}

OnConnectionFail

/// <summary>
/// 何らかの原因で接続が失敗した際に OnDisconnectedFromPhoton() に続いて呼び出されます。
/// </summary>
/// <remarks>
/// サーバーへ到達できない場合は代わりに OnFailedToConnectToPhoton()
/// が呼び出され、エラーの原因はStatusCodeとして提供されます。
/// </remarks>
void OnConnectionFail(DisconnectCause cause){}

OnFailedToConnectToPhoton

/// <summary>
/// Photonサーバーへの接続が確立される前に接続呼び出しが失敗すると呼び出されます。
/// OnDisconnectedFromPhoton() に続いて呼び出されます。
/// </summary>
/// <remarks>
/// (よくわからんかった。以下原文)
/// OnConnectionFail only gets called when a connection to a Photon server was established in the first place.
/// </remarks>
void OnFailedToConnectToPhoton(DisconnectCause cause){}

OnReceivedRoomListUpdate

/// <summary>
/// 部屋のリストが更新された場合に呼び出されます。
/// 新規か更新かの違いはありません。
/// これはマスターサーバー上のロビー内でのみ呼び出されます。
/// </summary>
/// <remarks>
/// 全てのタイプのロビーがクライアントへの部屋リスト通知を提供するわけではありません。
/// 中にはサーバーサイドでのマッチメイキングに特化し、サイレントのものもあります。
/// 
/// PUNでは PhotonNetwork.GetRoomList() による部屋リストの取得が可能です。
/// 取得される各項目はカスタムプロパティを含んだRoomInfoです。
/// これらの情報はロビー上で部屋を作る際に定義したものです。
/// </remarks>
void OnReceivedRoomListUpdate(){}

OnJoinedRoom

/// <summary>
/// 部屋に入った際に呼び出されます。(部屋作成時もしくは参加時)
/// これは全てのクライアント(マスタークライアント含む)で呼び出されます。
/// </summary>
/// <remarks>
/// このメソッドはプレイヤーキャラクタの生成のためによく使われます。
/// もしあなたがより"積極的に"呼び出す必要がある場合は
/// 代わりに PhotonView.RPC を利用する事が出来ます。
/// 
/// これが呼び出されたとき、
/// あなたは PhotonNetwork.playerList を介して
/// 部屋に存在するプレイヤーにアクセスできます。
/// また、Room.customProperties を介して部屋のカスタムプロパティも利用できます。
/// ゲームを開始できる人数がいるかどうかは、Room.playerCount で確認できます。
/// </remarks>
void OnJoinedRoom(){}

OnPhotonPlayerConnected

/// <summary>
/// リモートプレイヤーが部屋に入ったときに呼び出されます。
/// 入室したプレイヤーは既に PhotonNetwork.playerList に追加されています。
/// </summary>
/// <remarks>
/// もしあなたのゲームが特定の人数で始まる場合、このコールバックが役立ちます。
/// Room.playerCount を確認し、開始できるか確認しましょう。
/// </remarks>
void OnPhotonPlayerConnected(PhotonPlayer newPlayer){}

OnPhotonPlayerDisconnected

/// <summary>
/// リモートプレイヤーが部屋を抜けた際に呼び出されます。
/// 退室したプレイヤーは既に PhotonNetwork.playerList から除外されています。
/// </summary>
/// <remarks>
/// あなたのクライアントが PhotonNetwork.leaveRoom を呼び出した場合、
/// PUNは残ったクライアント上でこのメソッドを呼び出します。
/// リモートクライアントの接続が切れると、
/// 数秒後のタイムアウトの後、このコールバックが呼び出されます。
/// </remarks>
void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer){}

OnPhotonRandomJoinFailed

/// <summary>
/// JoinRandom() の呼び出しが失敗した際に呼び出されます。
/// オプションパラメータによってエラーコードおよびエラーメッセージを提供します。
/// </summary>
/// <remarks>
/// よくあるのは「全ての部屋が満員」「一つも部屋がない」などです。
/// もし(JoinLobbyやTypedLobbyを介して)複数のロビーを使用している場合、
/// 他のロビーは接続可能な部屋を持っているかもしれません。
/// PhotonNetwork.logLevel を PhotonLogLevel.Informational 以上二している場合、
/// PUNはいくつかの情報をログ出力します。
/// </remarks>
void OnPhotonRandomJoinFailed(){}
void OnPhotonRandomJoinFailed(object[] codeAndMsg){
 //codeAndMsg[0]は エラーコード です。(int)
 //codeAndMsg[1]は デバッグメッセージ です。(string)
}

OnConnectedToMaster

/// <summary>
/// PhotonNetwork.autoJoinLobby が false の状態で、
/// マスターサーバーへ接続および認証が完了した際に呼び出されます。
/// </summary>
/// <remarks>
/// もしあなたが PhotonNetwork.autoJoinLobby に true をセットしている場合、
/// これの代わりに OnJoinedLobby() が呼び出されます。
/// 
/// あなたがロビーにいない場合でも、部屋を作ったり参加したりできます。
/// デフォルトのロビーはその場合に用いられます。
/// PhotonNetwork.joinLobby によってロビーに入っている場合を除いて、
/// 利用可能な部屋のリストが更新される事はありません。
/// </remarks>
void OnConnectedToMaster(){}

OnPhotonSerializeView

/// <summary>
/// PhotonViewが定期的に同期するデータをカスタマイズするために実装します。
/// PhotonViewによってネットワークアップデートが観察されるたびに呼び出されます。
/// </summary>
/// <remarks>
/// このメソッドはPhotonViewによって監視対象にされているスクリプト上で呼び出されます。
/// PhotonNetwork.sendRateOnSerialize はこのメソッドが呼び出される頻度に影響します。
/// PhotonNetwork.sendRate はこのクライアントによってパッケージが送信される頻度に影響します。
/// 
/// このメソッドの実装によって、PhotonViewが定期的に同期するデータをカスタマイズすることができます。
/// あなたのコードは クライアントから何が送信され、何を受信するか、を定義することができます。
/// 
/// 他のコールバックとは異なり、PhotonView.observed に設定されたScriptでのみ呼び出されます。
/// 
/// このメソッドを利用するためには、PhotonStreamが必要不可欠です。
/// 書き込みを行う側のクライアント(PhotonStream.isWriting == true)と
/// 読み取りを行う側のクライアントに別れてデータの送受信を行います。
/// 
/// もし書き込みを行わないと、PUNは更新をスキップします。
/// これを利用すればネットワークの帯域幅を節約する事が出来ます。
/// 
/// 送信を行わない場合、受信側はOnPhotonSerializeViewが呼び出されていないことに注意してください。
/// そのため「x回の受信ごとに」といった処理はできません。
/// </remarks>
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info){}

OnPhotonInstantiate

/// <summary>
/// PhotonNetwork.Instantiate によって GameObject(とその子供)が生成された際に呼び出されます。
/// </summary>
/// <remarks>
/// PhotonMessageInfoパラメータは「誰が」「いつ」作成したかを提供します。
/// (「いつ」は PhotonNetworking.time に基づきます。)
/// </remarks>
void OnPhotonInstantiate(PhotonMessageInfo info){}

OnPhotonMaxCccuReached

/// <summary>
/// CCUの制限(一時的な物)によってサーバーへの接続が切断された際に呼び出されます。
/// </summary>
/// <remarks>
/// これが発生した場合は、一定時間をおいて再試行してください。
/// これが発生した場合、すでに切断されているため部屋に入ることはできません。
///
/// あなたは新しいライセンスの適用や拡張サブスクリプションによってCCUの制限を上げる事が出来ます。
/// CCU制限に達したとき、PhotonCloudはあなたにメールを送信します。
/// また、Webページ上のダッシュボードでも確認できます。
/// </remarks>
void OnPhotonMaxCccuReached(){}

OnPhotonCustomRoomPropertiesChanged

/// <summary>
/// 部屋のカスタムプロパティが変更された際に呼び出されます。
/// 引数のpropertiesThatChanged には Room.SetCustomProperties() 
/// でセットされた全てのプロパティが含まれます。
/// </summary>
/// <remarks>
/// v1.25以降、このメソッドは1つの引数を持ちます。(Hashtable propertiesThatChanged)
/// ローカル上での変更においても、カスタムプロパティの変更は
/// 必ずRoom.SetCustomPropertiesによって行われる必要があります。
/// </remarks>
void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged){}

OnPhotonPlayerPropertiesChanged

/// <summary>
/// カスタププレイヤープロパティが変更された際に呼び出されます。
/// プレイヤーと変更されたプロパティは object[] として渡されます。
/// </summary>
/// <remarks>
/// v1.25以降、このメソッドは1つの引数を持ちます。(object[] playerAndUpdatedProps)
/// これには2つのエントリが含まれます。
/// [0] は影響を受けた PhotonPlayer です。
/// [1] は変更されたプロパティのハッシュテーブルです。
/// (私たちはUnityのGameObject.SendMessageの仕様により、object[]を使用している。)
/// 
/// ローカル上での変更においても、カスタムプロパティの変更は
/// 必ずPhotonPlayer.SetCustomPropertiesによって行われる必要があります。
/// </remarks>
void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps){
    PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
    Hashtable props = playerAndUpdatedProps[1] as Hashtable;
    //...
}

OnUpdatedFriendList

/// <summary>
/// サーバーが FindFriends リクエストに対してPhotonNetwork.Friendsを更新し、
/// 応答を送信した際に呼び出されます。
/// </summary>
/// <remarks>
/// フレンドリストはPhotonNetwork.Friendsによって
/// 名前の一覧、オンライン状態、(もし入っているなら)部屋などを取得できます。
/// </remarks>
void OnUpdatedFriendList(){}

OnCustomAuthenticationFailed

/// <summary>
/// カスタム認証に失敗し、切断された際に呼び出されます。
/// </summary>
/// <remarks>
/// ユーザーの入力や不正なトークン/シークレットなどによってカスタム認証は失敗することがあります。
/// もし認証に成功した場合、このメソッドは呼ばれません。
/// (一般的には) OnJoinedLobby() か OnConnectedToMaster() を実装します。
/// 
/// ゲームの開発中、それはサーバーサイドの謝った設定により失敗することがあります。
/// そのような場合は、デバッグメッセージをログに記録する事は非常に重要です。
/// 
/// あなたがあなたのアプリに対して(ダッシュボード上で)カスタム認証を設定しない限り、これが呼ばれる事はありません。
/// </remarks>
void OnCustomAuthenticationFailed(string debugMessage){}

OnWebRpcResponse

/// <summary>
/// PUNがWebRPCを受信した際に呼び出されます。
/// PhotonNetwork.WebRPC を参照してください。
/// </summary>
/// <remarks>
/// 重要:もしPhotonがあなたのWebServiceに到達できるならresponse.ReturnCodeは0です。
/// 応答の内容はあなたのWebServiceが送信した物です。
/// あなたはこれを元にWebResponseのインスタンスを生成できます。
///
/// 例)WebRpcResponse webResponse = new WebRpcResponse(operationResponse);
///
/// 注意:OperationResponseクラスは下記名前空間に含まれています。
/// using ExitGames.Client.Photon; 
/// 
/// PhotonからのOperationResponse.ReturnCodeは以下の通りです。
///  0 : OK
/// -3 : Webサービスが未設定です。(ダッシュボード、WebHooksを確認)
/// -5 : Webサービスは現在RPCのためのpath/nameを持っていません。(少なくともAzureのため)
/// </remarks>
void OnWebRpcResponse(OperationResponse response){}

OnOwnershipRequest

/// <summary>
/// PhotonViewの現在の所有者であるあなたに対して、
/// 他のプレイヤーが所有権を要求したときに呼び出されます。
/// </summary>
/// <remarks>
/// viewAndPlayerには2つのエントリが含まれます。
/// [0] は対象のPhotonViewです。
/// [1] は要求を行ったPhotonPlayerです。
/// </remarks>
void OnOwnershipRequest(object[] viewAndPlayer){
 PhotonView view = viewAndPlayer[0] as PhotonView;
 PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer;
 //...
}

2014年12月11日木曜日

【Unity、UniRx】画面の向きが変化したことを検出する


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その9。

やりたいこと

ReactiveExtensionsを使って画面の向きが変化したことを検出する。

やり方

Input.deviceOrientationで現在のデバイスの画面の向きを取れるので、これが変化した時だけ値を発行させる。
ソース全体はこちらのGithub

これだと実機で試してねってなっちゃうので、せっかくなのでWebPlayerでも雰囲気確認できるようにCube置いてみた。
Hosted by UnityRoom.com

ついでにトースト表示クラスをシングルトンにしてみた。
CanvasとEventSystemをスクリプトからする方法がわからない。

2014年11月10日月曜日

【Unity、UniRx、Photon】PUNをRx対応してみた


@Baiteen

↓のツイートを見て、気になったので作ってみた。

やりたいこと

ReactiveExtensionsを使ってPhotonのコールバック地獄から脱出する。

環境

Unity(v4.6 beta)
UniRx(v4.5)
PUN(v1.28.3)

やったこと

1.UniRxインポート。
2.【Unity,Photon】PhotonCloudでオンラインゲームつくっちゃおーを参考にPUNをインポート&設定
3.PhotonRx.ObservableMonoBehaviourクラス作成。
これだけ。
ソースコードは長いので一番下。
ホントはGuthubとかに上げれればいんだけど、時代の流れについていけれない。

(追記 ここから)

GithubにGistっていうお手軽なのがあったので、そっちにあげてみました。

(追記 ここまで)

一応使ってみて機能としてはできたっぽいんだけど、Photonの使い方を知らないので確認できず。。。
誰か使ってみてくれたら嬉しいな。。。

参考サイト

neuecc/UniRx - Github
Photon Cloudのイベント一覧 - テラシュールブログ
Public API - Photon Unity Networking v1.27


ソースコードと使い方はUniRx.ObservableMonoBehaviourを真似してこんな感じ。



2014年11月1日土曜日

【Unity、UniRx】クリック回数が偶数なら赤を、奇数なら青を動かす


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その8。

やりたいこと

ReactiveExtensionsを使ってクリック回数が偶数なら赤のCubeを、奇数なら青のCubeを動かす。
前回の記事からちょっとしか変わってないので、変更分だけ書くことにした。

変更したところ

SphereScriptのOnMouseDownAsObservableの文を以下のように変更する。
    //クリック回数のストリームとして変数に保持
    var clickCountStream = OnMouseDownAsObservable ()
      .Buffer (OnMouseDownAsObservable ().Throttle (System.TimeSpan.FromMilliseconds (250)))
      .Select (xs => xs.Count);

    //クリック回数が偶数なら、クリック回数に比例した右向きの力を赤い四角に加える
    clickCountStream
      .Where(cnt => cnt % 2 == 0)
      .Do(cnt => redRigidbody.AddForce(Vector3.right * cnt * 10))
      .Subscribe (t=>Debug.Log(t));

    //クリック回数が奇数なら、連打イベントを発生させる
    clickCountStream
      .Where(cnt => cnt % 2 != 0)
      .Do(cnt => OnBarrage(new BarrageEventArgs(cnt)))
      .Subscribe (t=>Debug.Log(t));
    
    //クリック回数をテキストにセット
    clickCountStream
      .Do(cnt => text.text = string.Format ("{0} clicks", cnt))
      .SelectMany(cnt => 
        //1秒かけて0→1、また1秒かけて1→0ってなってほしいんだけど、0→1、1→2ってなる。意味不明。
        TakeSec(1).Do(t=>text.setA(t)).Last().SelectMany(_=>TakeSec(1).Do(t=>text.setA(1-t)))
        )
      .Subscribe (t=>Debug.Log(t));

これで完成。
今回はうに部屋に投稿するのは辞めました。ランキングにノイズが入ってしまうので。。。
適当に実行してください。


2014年10月2日木曜日

【Unity、UniRx】クリック回数をトースト表示しつつ、オブジェクトを動かす


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その7。

やりたいこと

ReactiveExtensionsを使ってクリック回数をトースト表示しつつ、左右にあるCubeオブジェクトを動かす。
せっかくなので、左のCubeはRigitbodyにAddForceで、右のCubeはイベント経由で動かすようにした。

前回の記事が分かりづらいと評判だったので、前回の補足も兼ねて。

やったこと

(UniRxはインポート済み)
※前回からUnityのバージョンが 4.6 beta になってます。(uGUIを使ってみたかっただけ)

前回のなごりでPlaneを追加(Planeじゃなくてもいい)
暗いのでDirectional lightを追加
クリック用のSphereを追加
トースト表示するためのText追加(GameObject→UI→Text)。Textを追加すると勝手にCanvas、EventSystemも追加されるはず。
動かすためのCubeを2つ追加。左をBlueCube、右をRedCubeとしました。両方共にRigitbodyを追加。
Cubeに色を付けるためのMaterialを作成。BlueMaterialとRedMaterial。それぞれBlueCube,RedCubeにドラッグドロップでCubeに色がつくはず。
※Sphere、Cubeの位置は適当に調整してください。

C#Scriptを作成して名前をSphereScriptに変更
今回はもう一つC#Scriptを作成して名前をCubeScriptに変更

ここまででこんな感じになってるはず。

SphereScript、CubeScriptをそれぞれ以下のように変更
・SphereScript
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;

static class ColorExt
{
  /// 
  /// Textのアルファ値をセットする拡張メソッド
  /// 
  /// uGUIのText
  /// アルファ値
  public static void setA (this UnityEngine.UI.Text text, float a)
  {
    text.color = new Color(text.color.r, text.color.g, text.color.b, a);
  }
}

public class SphereScript : ObservableMonoBehaviour
{
  /// トースト表示用オブジェクト
  public GameObject Toast;

  /// 赤い四角オブジェクト
  public GameObject RedCube;

  /// 
  /// 指定秒間だけEveryUpdateを発行する
  /// 
  /// 
  /// 秒
  private IObservable TakeSec (double value)
  {
    //0秒〜経過秒が値として発行される
    return Observable.EveryUpdate().Scan(
        new { time=0f, offset=Time.time }
        , (a, t)=>new { time=Time.time - a.offset, offset=a.offset }
      ).Select(delta => delta.time)
      .TakeUntil(Observable.Timer(System.TimeSpan.FromSeconds(value)));
  }

  #region 連打イベント関連 ここはC#のイベントの説明読んで
  public class BarrageEventArgs : EventArgs
  {
    public int ClickCount;
    public BarrageEventArgs(int clickCount){ this.ClickCount = clickCount; }
  }
  public event EventHandler Barrage;
  private void OnBarrage (BarrageEventArgs e)
  {
    if (Barrage != null) Barrage(this, e);
  }
  #endregion

  ///  RXのサンプルがAwakeだったので、ここに書きました。 
  public override void Awake ()
  {
    //参考サイト:http://neue.cc/2010/07/28_269.html

    //トースト用オブジェクトからuGUIのTextを取り出して、透明にする
    var text = Toast.GetComponent ();
    text.setA(0);

    //赤い四角オブジェクトからRigidbodyを取り出して、設定(重力無視&自然に止まって欲しいので空気抵抗を与える)
    var redRigidbody = RedCube.GetComponent();
    redRigidbody.useGravity = false;
    redRigidbody.drag = 5;

    //nueuccさんのアドカレ記事をパクりました
    //クリック回数をトースト表示
    OnMouseDownAsObservable ()
      .Buffer (OnMouseDownAsObservable ().Throttle (System.TimeSpan.FromMilliseconds (250)))
      .Select (xs => xs.Count)
      //クリック回数をテキストにセット
      .Do(cnt => text.text = string.Format ("{0} clicks", cnt))
      //クリック回数に比例した右向きの力を赤い四角に加える
      .Do(cnt => redRigidbody.AddForce(Vector3.right * cnt * 10))
      //連打イベントを発生させる
      .Do(cnt => OnBarrage(new BarrageEventArgs(cnt)))
      .SelectMany(cnt => 
        TakeSec(1).Do(t=>text.setA(t)).Last().SelectMany(_=>TakeSec(1).Do(t=>text.setA(1-t)))
      )
      .Subscribe (t=>Debug.Log(t));

    // If you use ObservableMonoBehaviour, must call base method ← サンプルにこう書いてますので、そのまま。
    base.Awake ();
  }
}

・CubeScript
using UnityEngine;
using System.Collections;

public class CubeScript : MonoBehaviour {

  // Use this for initialization
  void Start () {
    //自分からRigidbodyを取り出して、設定(重力無視&自然に止まって欲しいので空気抵抗を与える)
    var rigidbody = this.GetComponent();
    rigidbody.useGravity = false;
    rigidbody.drag = 5;

    //Sphereを探し出して、SphereScriptを取り出して、連打イベントが発生したら自分に力を加える
    var sphereScript = GameObject.Find("Sphere").GetComponent();
    sphereScript.Barrage += (sender, e) => { 
      rigidbody.AddForce(Vector3.left * e.ClickCount * 10); 
    };
  }
 
}

SphereScriptをSphereに、CubeScriptをBlueCubeにドラッグドロップ
Sphereに追加したSphereScriptに変数Toast、RedCubeがあるので、それぞれText、RedCubeをドラッグドロップ

これで完成。
Hosted by UnityRoom.com


2014年9月28日日曜日

【Unity, NCMB】nifty cloud mobile backendを使ってみた。けどWebPlayerでConnectFailureする。

今日参加したLT大会で「ニフティクラウド Mobile Backend」というものの存在を知った。
機能の詳細については公式をみて。
公式サイト → http://mb.cloud.nifty.com/

正式名は「NIFTY Cloud mobile backend」略して「NCMB」
呼びづらい、覚えづらい、書きづらい…どうにかならんもんか。

簡単に言うと
・プッシュ通知やユーザー管理、データストレージなどが使える
 ・プラットフォームに依存しないランキング実装とかに使える
・国内サーバー
 ・海外サーバーに比べレスポンスが速い
・無料でもかなり使える
 ・最大でも月3万円
こんな感じ。

かなり便利そうなので試してみる事にした。

ここのクイックスタートを見ながら試してみたんだけど
http://mb.cloud.nifty.com/doc/quickstart_unity.html

下記エラーが出た。
Error occurred: Error: ConnectFailure (Unexpected error while trying to call method_GetSecurityPolicyBlocking : System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
  at System.Net.HttpWebRequest.CheckFinalStatus (System.Net.WebAsyncResult result) [0x00000] in <filename unknown>:0 
  at System.Net.HttpWebRequest.SetResponseData (System.Net.WebConnectionData data) [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000eb] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232 
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115 
  at UnityEngine.UnityCrossDomainHelper+WebRequestPolicyProvider.GetPolicy (System.String policy_url) [0x00000] in <filename unknown>:0 
  at UnityEngine.UnityCrossDomainHelper.GetSecurityPolicy (System.String requesturi_string, IPolicyProvider policyProvider) [0x00000] in <filename unknown>:0 
  at UnityEngine.UnityCrossDomainHelper.GetSecurityPolicyForDotNetWebRequest (System.String requesturi_string, System.Reflection.MethodInfo policyProvidingMethod) [0x00000] in <filename unknown>:0 
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000d0] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222 
  --- End of inner exception stack trace ---
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x000eb] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232 
  at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115 
  at System.Net.WebConnection.CheckUnityWebSecurity (System.Net.HttpWebRequest request) [0x00000] in <filename unknown>:0 ) 
 with: System.Collections.Hashtable ; 
   at System.Net.HttpWebRequest.EndGetRequestStream (IAsyncResult asyncResult) [0x00000] in <filename unknown>:0 
  at System.Net.HttpWebRequest.GetRequestStream () [0x00000] in <filename unknown>:0 
  at NCMB.Internal.NCMBConnection._sendRequest (System.Net.HttpWebRequest req, NCMB.NCMBException& error) [0x00000] in <filename unknown>:0 
まさかの404エラー。
でも「method_GetSecurityPolicyBlocking」みたいに書かれてる。
WebPlayer向けに設定してるしもしやと思ってAndroid向けに変えてみたらこのエラーは消えて通信成功した。

案の定WebPlayerのセキュリティポリシーによるものみたいやなぁ…
http://docs-jp.unity3d.com/Documentation/Manual/SecuritySandbox.html

ランキングロジックとかをWebPlayer、iOS、Androidで全て統一できないかと考えたんだけどなぁ。うーむ。

Unity系記事まとめ

発表してきました。【アセットまみれのLT大会 in 大阪 】

はじめに

今日はこれに参加し、初めてLTしてきました。

【9/27】【Unity】アセットまみれのLT大会 in 大阪 【関西】
http://unityassetjp.doorkeeper.jp/events/13003

※LT : Lightning Talk (3~5分の短いプレゼン)

・スケジュール通りのLTが6件(上記URL参照)
・飛び入りLTが4件
・そして少し時間が余ったのでポケット・クエリーズ佐々木様による発表が1件
計2時間ちょいでした。

全体の感想

Unityさんやゼンリンさん、ポケットクエリーズさんなど企業として来ている方の発表は聞きやすかったなぁ。話し手が落ち着いているので聞く側もとても楽だった。

今回メモは全く取ってないので他の方の発表内容に関するコメントはできません〜。
はじめて発表したのでここからは感想でも書いておこうと思います。

自分の発表の感想

自分は下記資料で発表しました。



資料作りで気をつけた点
・初LTだし緊張するから読むだけでいい資料にした
 →結果的に良かったと思う。自分はこれぐらいが楽。
・文字いっぱい書いても後ろの人読めないしMAX5行ぐらいにした
 →細かくても読まないし。
・5分から逆算して30枚程度(1枚10秒)ぐらいにした。
 →ちょうどよかったと思う。

話してるとき考えてた事
・いつも早口になっちゃうのでとにかくゆっくり話す
 →懇親会で聞いたら大丈夫でしたよって言ってもらえた。よかった。

しゃべってる最中は結構緊張しててあんまり覚えてません。
緊張に関してはあと2〜3回こういう機会があれば余裕も出てくるかな。
終わってみると5分はあっという間だったので
言いたい事をもっと絞らないとあかんなーと感じた。
特に今回の資料はアセットにこじつけたので少し話しづらかった。

そいえばMacの外部出力が快適でひじょーにやりやすかった。
プロジェクターにプレゼン再生中は手元のMacに次スライドも表示されてる。
原稿も書いておけば表示されるらしい。

おみやげ

  • UnityさんからUnityちゃんタオル
  • UnityさんからUnityPro90日トライアルライセンス
    なぜか発表を褒めていただけた…!うに部屋もっとやれってことっぽい。
  • ポケット・クエリーズさんよりクエリちゃんステッカー×2
いただきもの
ライセンスは真夏のアドベントカレンダーの参加賞でもいただいたので180日分になりました!イヤッホウUnityProで遊ぶぜ!

おわりに

とにかくやってよかった。
LTはプレゼンの練習にいいなー。
5分ぐらいならミスっても許されそうだし。
またやりたい。

2014年8月29日金曜日

【Unity、UniRx】クリック回数をトースト表示する


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その6。

やりたいこと

ReactiveExtensionsを使ってクリック回数をトースト表示する。

やったこと

(UniRxはインポート済み)
まずは、クリックするためのSphereを追加(Sphereじゃなくてもいい)
前回のなごりでPlaneを追加(Planeじゃなくてもいい)
トースト表示するためのText追加(せっかくなのでuGUI使いました)
それからC#Scriptを作成してコードを以下のように変更(今回もTestScriptにしました)
そしてTestScriptをSphereにドラッグ&ドロップしたら出来上がり
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;

static class ColorExt
{
  /// 
  /// Textのアルファ値をセットする拡張メソッド
  /// 
  /// uGUIのText
  /// アルファ値
  public static void setA (this UnityEngine.UI.Text text, float a)
  {
    text.color = new Color(text.color.r, text.color.g, text.color.b, a);
  }
}

public class test1script : ObservableMonoBehaviour
{
  /// トースト表示用オブジェクト
  public GameObject Toast;

  /// Scanで匿名クラス使うとなぜかエラーするので、クラス定義
  private class Delta
  {
    public float time{ get; set; }
    public float offset{ get; set; }
    public Delta(float t, float o){ time = t; offset = o; }
  }

  /// 
  /// 指定秒間だけEveryUpdateを発行する
  /// 
  /// 
  /// 秒
  private IObservable TakeSec (double value)
  {
    //0秒〜経過秒が値として発行される
    return Observable.EveryUpdate().Scan(
        new Delta( 0, Time.time)
        , (a, t)=>new Delta( Time.time - a.offset, a.offset)
      ).Select(delta => delta.time)
      .TakeUntil(Observable.Timer(System.TimeSpan.FromSeconds(value)));
  }

  ///  RXのサンプルがAwakeだったので、ここに書きました。 
  public override void Awake ()
  {
    //参考サイト:http://neue.cc/2010/07/28_269.html

    //トースト用オブジェクトからuGUIのTextを取り出して、透明にする
    var text = Toast.GetComponent ();
    text.setA(0);

    //nueuccさんのアドカレ記事をパクりました
    //クリック回数をトースト表示
    OnMouseDownAsObservable ()
      .Buffer (OnMouseDownAsObservable ().Throttle (System.TimeSpan.FromMilliseconds (250)))
      .Select (xs => xs.Count)
      .Do(cnt => text.text = string.Format ("{0} clicks", cnt))
      .SelectMany(cnt => 
        //1秒かけて0→1、また1秒かけて1→0ってなってほしいんだけど、0→1、1→2ってなる。意味不明。
        Observable.Concat(TakeSec(1).Do(t=>text.setA(t)), TakeSec(1).Do(t=>text.setA(2-t)))
      ).Subscribe (t=>Debug.Log(t));

    // If you use ObservableMonoBehaviour, must call base method ← サンプルにこう書いてますので、そのまま。
    base.Awake ();
  }

}

こんな感じ。
Hosted by UnityRoom.com

どうにか思ったとおりの動きになったんだけど、理解できない部分がいくつか。
・Scanのseedを匿名クラスにすると、なぜかCannot implicitly convert type `anonymous type' to `anonymous type'って怒られる
・1秒で終わるObservableをConcatで2つ繋げると、なぜか単体で動かすのと違う動きになる、気がする、、、

追記

neueccさんからアドバイス頂いてScanの理解できない件解決しました。
timeの型がintとfloatになってるだけでした。
seedをnew {time=0f, offset=Time.time}にしたらOKでした。はずかし。

Concatの件もいろいろ試してたら思った感じの動きになりました。
Observable.Concat(TakeSec(1).Do(t=>text.setA(t)), TakeSec(1).Do(t=>text.setA(2-t)))

TakeSec(1).Do(t=>text.setA(t)).Last().SelectMany(_=>TakeSec(1).Do(t=>text.setA(1-t)))
てしたらそれっぽくなりました。全然わからん。



2014年8月22日金曜日

【Unity、uGUI】チュートリアル見ながら触ってみる。01.Canvas

ついにUnity4.6のベータ版が来ましたね。

Unity 4.6オープンβスタート。新GUI「uGUI」の試用が可能に | テラシュールブログ

待ちに待ったuGUIがやっと使えます。

ここにチュートリアルがあるようなのでのんびり見てみようと思います。
UI チュートリアル | Unity 公式

01. UI CANVAS

動画はここ 01. UI CANVAS
実際に動画見ながら試してたらむっちゃ時間かかった

Canvas

キャンバスはUI要素を表示するための重要なコンポーネント
Hierarchy->Create->UI->Canvasで作成可能。
すべてのUI要素はキャンバスの子供にする必要がある

キャンバスは2つ以上配置することもできる

新規UI要素を配置する際、シーンに一つもキャンバスが存在しない場合は自動的に作られる。
こんな感じでいきなりボタンなどを配置するとキャンバスも作られる

RenderMode

Canvasごとに異なるRenderModeを設定できる

Screen Space Overlay : RenderMode

もっとも基本的なRenderModeであり、規定値。
これを選択するとUIはシーン上にオーバーレイ表示され、最前面に描画される。
カメラなしでも表示できる。
このモードの場合、Canvasのサイズは自動的にスクリーンサイズに合うように変更される。
また、スクリーンサイズが変更になる場合も自動的に追従する。
よくあるGUI(操作ボタンとか)はこれで問題なさそうね。

Rect Transform

Canvasを含むすべてのUI要素はこのコンポーネント(RectTransformComponent)を持ってる。
UI要素はこのコンポーネントに基づいて動作する。(らしい、よく理解できんかった)
RenderModeにScreen Space Overlayを選んでいる場合、Canvasのこのコンポーネントの値はすべて自動的に入力される。(画面サイズとかに基づいて)
Rect Transformの詳細についてはこちら

CanvasのRectTransformを変更する必要があるのは後述するWorldSpaceに置いたときだけかな?
Buttonなどの子要素を移動する場合はこのコンポーネントを操作すればいいみたい。

PixelPerfectオプションがある。選択するとUI要素は描画時に一番近いPixelに合うように調整される。より鮮明にUI要素を描画したいときに選択するといい。
NGUIにもPixelPerfectってあったけど正直いつ使うのかわからない。

Screen Space Camera : RenderMode

ScreenSpaceOverlayによく似たRenderMode。
特定のカメラに連動して動作する。
だけどカメラなしでも表示できるっぽい。
(Render Cameraをセットしない場合Overlayと同じ動作なのかな?)


こんな感じでRenderCameraにカメラをセットして使う
Perspectiveカメラとの連動が分かりやすい。
ボタンのRectTransformComponentのRotationYを30度傾けてみた。

ScreenSpaceOverlay(上)とScreenSpaceCamera(下)を並べて
同じように30度傾けてみた。違いがわかりやすい。

もちろん連動したカメラのViewPort設定などが反映される。

カメラとの距離はPlaneDistanceで設定可能
カメラごとのClearFlagsやCallingMask、カメラ深度なども適用される。
カメラについての詳細はこちら

World Space : RenderMode

これを選択するとUI要素はシーン内に他のオブジェクト同様に配置される
これはカメラ必須。
このモードのときはRectTransformを自由に書き換えることができ、Scene内の好きな場所に配置できる

イベントカメラはどのカメラがイベントを受け取るかの設定に必要。
主にクリックイベントの取得とか。
※Receives Events って項目ないな。

キャラクター上にHPバーを表示したりとか、そういうときに使うのかな。

Sorting Layer

よくわからんかった。
描画順を制御できるらしい。
詳細はこちら

描画順

キャンバス内での描画順は上から。
これは直感的でいいね



今日はここまで~。

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