2014年6月28日土曜日

【Unity、Photon】The appId this client sent is unknown on the server (Cloud).

PhotonCloudを使ってゲーム作ってます。

PUN+(PhotonCloudをUnityで使うためのアセット)に入ってるRandomMatchMakerを修正しながら使ってるんだけど
通常はJoinedに落ち着くステートがなぜかPeerCreatedで止まることがある。
(何度も実行できていたものが突然エラーするようになる)

少し見てみると下記エラーが出ている模様。
The appId this client sent is unknown on the server (Cloud). Check settings. If using the Cloud, check account.
UnityEngine.Debug:LogError(Object)
NetworkingPeer:OnOperationResponse(OperationResponse) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:991)
ExitGames.Client.Photon.PeerBase:DeserializeMessageAndCallback(Byte[])
ExitGames.Client.Photon.EnetPeer:DispatchIncomingCommands()
ExitGames.Client.Photon.PhotonPeer:DispatchIncomingCommands()
PhotonHandler:Update() (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs:76)
直前まで実行できていたのだしappIdが間違ってるとも思えない…

原因不明。

今日だけで3回なったけど
どれも数分待つと繋がるようになるっぽい。


昨日の夜、うに部屋に投稿された下記ゲームでも
同じ症状に遭遇したので
PhotonCloud側か自分のネットワークのどちらかが調子悪いのだろうか??

協力型アスレチック攻略ゲーム(仮) 体験版
http://unityroom.com/game/000082

ま、まだ致命的じゃないからいいんだけど。

こちらもに書いてみました。

ゆにひろば「PhotonCloudのStateがPeerCreatedで止まる症状」
http://www54.atpages.jp/unitylib/forum/viewtopic.php?f=7&t=42

もし知ってるよって人がいましたら情報ください。
よろしくおねがいします。

2014年6月20日金曜日

【CakePHP、OpAuth】Opauth-completeController could not be found.

一昨日から3日間、計8時間ぐらい悩んでやっと解決できたのでメモ。

環境

Windows + XAMPP + ローカルのCakePHPを使ったサイト

http://localhost/unityroom2/
でアクセスできるサイトを構築中
※unityroom2はサイト名なので適当に読み替えてください。

ローカル的には
C:\xampp\htdocs\unityroom2\app
C:\xampp\htdocs\unityroom2\lib
C:\xampp\htdocs\unityroom2\...
とCakePHPのフォルダが並んでるイメージ

やりたいこと

Twitterを使ったユーザー認証をしたい!
ただそれだけ。

ソーシャル認証に特化したOpAuthというものがあったのでそれを使おうとしてました。
https://github.com/uzyn/cakephp-opauth

やったこと

CakePHPのインストール

http://cakephp.jp/
ここから安定版ダウンロードして
C:\xampp\htdocs\unityroom2\
以下に配置

その他もろもろ初期設定

saltの設定とか
データベースの設定とか
DebugKitの導入とか
細々したのを終わらせて下記画面がでるところまでやった

CakePHP-OpAuthの導入

OpAuth自体はCakePHPに限定されずいろんなフレームワークで使えるみたい。
それをCakePHPで使えるようにしてくれるプラグインをまずは入れる。

ここからダウンロード
https://github.com/uzyn/cakephp-opauth
解凍して出てきたものを
C:\xampp\htdocs\unityroom2\app\Plugin\Opauth
に突っ込む。(Opauthフォルダは作る)

OpAuthの導入

ここからダウンロード(Download->Opauth core only)
http://opauth.org/
解凍して出てきたものを
C:\xampp\htdocs\unityroom2\app\Plugin\Opauth\Vendor\Opauth
に突っ込む

TwitterStrategyの導入

ここからダウンロード
https://github.com/opauth/twitter
解凍して出てきたものを
C:\xampp\htdocs\unityroom2\app\Plugin\Opauth\Strategy\Twitter
に突っ込む(Twitterフォルダは作る)

CakePHP-OpAuthの設定

C:\xampp\htdocs\unityroom2\app\Config\bootstrap.php
に下記を追記
CakePlugin::load('Opauth', array('routes' => true, 'bootstrap' => true));

Configure::write('Opauth.Strategy.Twitter', array(
    'key' => '**********API key***********',
    'secret' => '**************API secret************'
));
KeyはTwitterDeveloperからこぴぺ。

認証後のデータを受け取るコントローラを作成

C:\xampp\htdocs\unityroom2\app\Controller
にUsersController.phpを作成
<?php

class UsersController extends AppController
{
    function complete()
    {
        pr($this->request->data);
        $this->autoRender = false;
    }
}

認証後に上記コントローラへ飛ぶように設定

C:\xampp\htdocs\unityroom2\app\Config\routes.php
に下記を追加
Router::connect(
   '/opauth-complete/*', 
   array('controller' => 'users', 'action' => 'complete')
);

ここまでで一度実行

http://localhost/unityroom2/auth/twitter
にアクセス

すると下記エラー。

これはググるといろんなところに書かれているが、
Cakeをルートじゃなく1階層下に入れているから。

C:\xampp\htdocs\unityroom2\app\Config\bootstrap.php
に下記行を追加するとこのエラーは消える
Configure::write('Opauth.path', '/unityroom2/auth/');


再度実行するとTwitterの認証画面が出る


認証&エラー


こいつ!こいつが消せなくてめっちゃ困ってた。

対応

エラーでぐぐるとこれが出てくる
https://github.com/uzyn/cakephp-opauth/issues/21

その中に
I found the issue: I was specifying the route after calling CakePlugin::routes(); in my routes.php file
なんて記述を見つけたので先ほど書いたRouter::connectを移動してみた。


もう一度下記にアクセス
http://localhost/unityroom2/auth/twitter

あれ。。。さっきはこれでも同じエラー出てたんだけど
今ブログ書くために最初からやり直してたらこれで直った・・・

さっきは
C:\xampp\htdocs\unityroom2\app\Plugin\Opauth\Controller\OpauthAppController.php
の114行目を下記のように書き換えて対応してました。
//      $CakeRequest = new CakeRequest('/opauth-complete');
        $CakeRequest = new CakeRequest('/users/complete');

動いた画面。

以下ずらずらとTwitterからの情報が並びます。
URLはhttp://localhost/unityroom2/auth/callbackだけど
動作的にはちゃんとUsersController呼ばれてるみたい。
よくわからんけど解決。

疑問

疑問1

Twitter Developersのアプリケーション設定
WebSiteやCallbackURLは何入れても何も変わらなかった。
URLっぽいのが入ってればなんでもいいのか?

2014年6月12日木曜日

【CakePHP】MVCの決まりとか書き方とか忘れそうなので自分用にメモ


うに部屋を改修するためにCakePHPを覚え始めました。

教材はこちら
PHPも使いこなせてない状態で無理に覚えようとしてるのでかなり必死です。
とりあえず覚えたことをすぐ読み返せるようにメモしていきます。


DB

テーブル関係

決まり

・テーブル名は複数形 例)posts
・小文字なのか?(未確認)

必ず作る列

・id int not null auto_increment primary key
・created datetime default null
・modified datetime default null
created,modifiedに関してはなくてもいいけど作っとくとCakeが勝手に書き込んでくれるらしい。すんごい。

SQLの例

create table posts (
    id int not null auto_increment primary key
    ,title varchar(50)
    ,body text
    ,created datetime default null
    ,modified datetime default null
)

Model

決まり

・ファイルは[/app/Model/]に配置する
・クラス名は単数形のCamel方式 例)Post
・ファイル名はクラス名.php
・AppModelを継承する
・中身は何も書かなくてもいい?(未確認) 書かなくても読み書きできてる。

ソース例

<?php

class Post extends AppModel
{

}



View

決まり

・Controllerのメソッド1つに対して1つ作る(たぶん)
・ファイルは[/app/View/[Controller]/[メソッド名].ctp
・中身は普通にHTMLとPHP混在でいいっぽい
・Controllerのメソッド内でsetされた変数を呼び出せる
・Controllerで宣言されたヘルパークラスも使えるっぽい

ソース例
Controller内で下記のようにsetされている場合、
$this->[Model]->id = $id;
$this->set('hoge', $this->[Model]->read());
以下の感じのViewを書いておくと表示できる
<h2><?php echo h($post['Post']['title']); ?></h2>
<p><?php echo h($post['Post']['body']); ?></p>
すんごい

Controller

決まり

・ファイルは[/app/Controller/]に配置する
・クラス名は複数形+ControllerのCamel方式 例)PostsController
・ファイル名はクラス名.php
・AppControllerを継承する
・頭のほうにヘルパーを宣言しておくと便利
・メソッドを定義するとURLからアクセス可能になる
・PostsControllerにindexメソッドを定義した場合、
 http://hostname/sitename/Posts/index
 ってURLでアクセス可能になる。
 要するに [Controller]/[Method] でアクセス可能になるってこと。

ヘルパー

クラスのメンバ変数として宣言しておくと便利らしい(まだよくわからん)

書き方

public $helpers = array('Html', 'Form');
こんな感じ

Html

まだ調べてない
たぶん h()とかが入ってる。

Form

まだ調べてない

メソッド内でよく使いそうなもの

set

$this->set('foo','bar');
こうするとfoo変数にbarをセットできる。
Viewでfooを使えるようになる。

find('all')

$this->set('foo', $this->[Model]->find('all'));
これだけでDBからデータを取得できる。

read()

$this->[Model]->id = $id;
$this->set('hoge', $this->[Model]->read());
こうするとIDを指定したselectみたいになる。
↓の引数を受け取る方法を組み合わせて使う。

引数を受け取る

メソッドに引数をつけることができる
public function view($id = null)
とか。
こうすると /[Controller]/view/[id] ってURLでアクセスされた際に受け取れる。

2014年6月2日月曜日

【Unity】UnityRoom専用のTweetクラスを作りました。

この記事は古いです。

あたらしい情報はこちら


UnityRoomというUnityWebPlayer向けのゲームを公開できるサイトを運用しています。
→UnityRoom (http://unityroom.com/)

上記サイトでの利用を前提としたTwitter利用クラスを作りましたので
ゲームからスコアをつぶやかせるときなどにご利用ください。

注意

・UnityWebPlayer専用です。
・UnityRoomでの利用を前提とした作りです。

サンプル

「うに部屋Tweetサンプル」http://unityroom.com/game/000036
このようなことが簡単にできます。

ソースコード

・新規C#スクリプトを追加
  名前は"UnityRoomTweet"としてください。
・このスクリプトの内容を以下の通りにしてください。
using UnityEngine;

public static class UnityRoomTweet
{  
  const string SHAREURL = "http://twitter.com/share?";
 
 
  /// <summary>
  ///  ツイートします。
  /// </summary>
  /// <param name="text">本文</param>
  public static void Tweet (string text)
  {
    Tweet (text, -1);
  }
  /// <summary>
  /// ツイートします。
  /// </summary>
  /// <param name="text">本文</param>
  /// <param name="gameId">UnityRoomゲームID</param>
  public static void Tweet (string text, int gameId)
  {
    Tweet (text, gameId, null, null);
  }
 
  /// <summary>
  /// ツイートします。
  /// </summary>
  /// <param name="text">本文</param>
  /// <param name="gameId">UnityRoomゲームID</param>
  /// <param name="via">発言者(@を除いたTwitterIDを指定)</param>
  /// <param name="hashtag">ハッシュタグ(#は不要)</param>
  public static void Tweet (string text, int gameId, string via, string hashtag)
  {
    if (Application.platform == RuntimePlatform.WindowsWebPlayer 
      || Application.platform == RuntimePlatform.OSXWebPlayer) {
   
      string url = gameId != -1 ? string.Format ("http://unityroom.com/game/{0:000000}", gameId) : "";
   
      var sb = new System.Text.StringBuilder ();
      sb.Append (SHAREURL);
      sb.Append ("original_referer=");
      sb.Append ("&text=" + WWW.EscapeURL (text));
      if (!string.IsNullOrEmpty (url)) 
        sb.Append ("&url=" + WWW.EscapeURL (url));
      if (!string.IsNullOrEmpty (hashtag))
        sb.Append ("&hashtags=" + WWW.EscapeURL (hashtag));
      if (!string.IsNullOrEmpty (via))
        sb.Append ("&via=" + WWW.EscapeURL (via));
   
      Application.ExternalEval ("var F = 0;if (screen.height > 500) {F = Math.round((screen.height / 2) - (250));}window.open('" + sb.ToString () + "','intent','left='+Math.round((screen.width/2)-(250))+',top='+F+',width=500,height=260,personalbar=no,toolbar=no,resizable=no,scrollbars=yes');");
    } else {
      Debug.Log ("WebPlayer以外では実行できません。");
    }
  }
}

使い方の概要


Tweet関数には3つのオーバーロードがあります。

Tweet(string text)

本文のみのツイートを行います。

Tweet(string text, int gameId)

本文とともにゲームのURLをツイートします。
gameIdはUnityRoomゲーム画面のURL末尾にある数字です。
※2014/06/02 すみませんが現時点では一度公開いただかないと確認できません。

Tweet(string text, int gameId, string via, string hashtag )

本文、URL、投稿者、ハッシュタグを記載したTweetをします。
投稿者(via)
 @naichilabさんより といった部分です。
 @を除いたTwitterIDを指定してください。
ハッシュタグ(hashtag)
 #Unity1Week といった部分です。
 #を除いた文字列を指定してください。
 カンマ( , )で区切る事で複数のハッシュタグを指定できます。

viaとhashtagはnullもしくは空文字("")を指定すると付与されません。

呼び出しサンプル


ここではサンプルとしてOnGUIのButtonが押されたときにTweetするようにしてみます。

・新規C#スクリプトを追加
 名前は"CallTweet"とします。
・CallTweetスクリプトの内容を以下の様に記述します。
using UnityEngine;

public class CallTweet : MonoBehaviour
{
 
  void OnGUI ()
  {
    if (GUI.Button (new Rect (10, 20, 400, 90), "Tweet1(本文のみ)")) {
      UnityRoomTweet.Tweet ("本文のみのテストツイートです");
    }
    if (GUI.Button (new Rect (10, 120, 400, 90), "Tweet2(本文+URL)")) {
      UnityRoomTweet.Tweet ("本本文とURLのテストツイートです。", 36);
    }
    if (GUI.Button (new Rect (10, 220, 400, 90), "Tweet3(本文+URL+ハッシュタグ)")) {
      UnityRoomTweet.Tweet ("ハッシュタグ付きのツイートです。", 36, null, "Unity1Week");
    }
    if (GUI.Button (new Rect (10, 320, 400, 90), "Tweet4(本文+URL+ユーザー)")) {
      UnityRoomTweet.Tweet ("投稿者ID付きのTweetです。", 36, "naichilab", null);
    }
    if (GUI.Button (new Rect (10, 420, 400, 90), "Tweet5(本文+URL+ハッシュタグ+ユーザー)")) {
      UnityRoomTweet.Tweet ("全部入りツイートです。", 36, "naichilab", "Unity1Week");
    }
  }
}

・CallTweetスクリプトをMainCamera(なんでもいいです)にドラッグ&ドロップ

ここまででツイート関連の準備は完了です。

・UnityのメニューからFile->Build Settings

・WebPlayerを選択し、Switch Platformを押す。
 WebPlayerの横にUnityアイコンが出ればOK

・そのまま Build And Run
・保存フォルダを聞かれるので適当に付けます。
 自分は"WebPlayerRelease"としてます。
・保存すると自動的にWebブラウザが立ち上がり、UnityWebPlayerが実行されます。

以上です。

ぜひご利用ください。


UnityWebPlayerの公開サイト
→UnityRoom http://unityroom.com/

他の記事もどうぞ
Unity系記事まとめ

2014年6月1日日曜日

【Unity】MonoBehaviourのライフサイクルと呼ばれる順番

UnityでComponentが消えるときに処理をしたくてイベントがどういう順番で処理されてるのか調べた。ついでに複数のオブジェクトがある場合の処理順も軽く調べた。

公式に書かれてるMonoBehaviourのライフサイクルはこんな感じ。
http://docs.unity3d.com/Manual/ExecutionOrder.html
きっとポジションさん(@kitposition)教えてくださってありがとうございます。

この沢山あるイベントの中で知りたかったのは下記5つ。
  • Awake
  • OnEnable
  • Start
  • OnDisable
  • OnDestroy
これらの発生順をみてみた。

環境

・Unity 4.3.4f

調べ方

こんなスクリプトを用意
using UnityEngine;

public class LifeCycle : MonoBehaviour
{
 void Awake(){ Debug.Log(this.gameObject.name+"Awake"); }
 void OnEnable(){ Debug.Log(this.gameObject.name+"OnEnable"); }
 void Start(){ Debug.Log(this.gameObject.name+"Start"); }
 void OnDisable(){ Debug.Log(this.gameObject.name+"OnDisable"); }
 void OnDestroy(){ Debug.Log(this.gameObject.name+"OnDestroy"); }
}

Cubeとかに貼っ付けて実行するだけ。

んじゃ見てみる

1.シンプルに

・Cubeを置いて名前をCube1にする。
・Cube1にさっきのスクリプト付与
・実行し、停止
仕様通り。なるほど。

2.Componentのチェックを外してみる

・1の状態のCube1からLifeCycleコンポーネントのチェックを外す。
・実行し、停止
へぇ、AwakeとDestroyは呼ばれるのかい…

3.AddComponentしてみる

・2の状態を基準にMainCameraに下記スクリプトを付与
using UnityEngine;
using System.Collections;

public class AddComponentButton : MonoBehaviour
{
  public GameObject go;
  void OnGUI ()
  {
    if (GUI.Button (new Rect (100, 100, 100, 20), "Add")) {
      go.AddComponent<LifeCycle> ();
    }
  }
}
・実行し、OnGUIのボタンを押す
・停止
複数のComponent(MonoBehaviour)はそれぞれ個別のライフサイクルを持つ。
当たり前か…

4.GameObjectのチェックを外してみる

・1の状態を基準にCube1のチェックを外す
・実行し、停止
ログ残らず。そらそうだ。

5.2つのコンポーネント

・Cube作って名前をCube1とする
・Cube1に2つのLifeCycleコンポーネントを付ける
・実行し、停止
複数コンポーネントある場合でもAwakeとOnEnableは連続してるんやね。
逆にOnDisableとOnDestroyは個別に走るっぽい。

6.2つのコンポーネント②

・Cube2つ作って名前をCube1、Cube2にする
・それぞれにLifeCycleコンポーネントを付ける
・実行し、停止
あれ、OnDisableとOnDestroyが連続した。
Cube1->Cube2の順番になってるのは偶然か?

7.2つのコンポーネント③

・6の実行前の状態から
・Cube1をCube3にリネーム
・Cube2をCube1にリネーム
・Cube2をCube2にリネーム
・実行し、停止
お、ひっくり返った。
親子関係のない親のいないGameObjectはシーンに追加した順に扱われるのかな?

8.2つのコンポーネント④

・7のシーンを保存してUnity終了
・Unity起動(自動的にシーン回復)
・実行し、終了
再読み込みとかで名前順に並び変わったりするかと思ったけどなんも変わんなかった。
YAMLとかに書かれる順で変化しないのかな。

9.親子にしてみる

・8の状態を基準に、Cube2をCube1の子供にする
・実行し、停止
親→子の順で初期化されるかと思ったけどそうでもないのね。
OnDestroyだけ子→親だな…なんだろ。

10.親子にしてみる②

・9の状態から親子関係を外す
・7の方法と同じくCube1と2の名前を入れ替える
・再度Cube2をCube1の子にする
・実行し、停止
Awake〜Startは9の結果を入れ替わったね。親子関係は関係ないみたい。
でもOnDisable〜OnDestroyは同じ結果だ。子から先に破棄されるのかな。

まとめ

良くわかってないけど箇条書き
・初期化(Awake~OnEnable~Start)はシーンに追加した順
・親子関係は初期化順に影響しない
・破棄(OnDisable~OnDestroy)はシーンに追加した順だが、親子関係がある場合は子→親の順
・InspectorでComponentのチェックを外した場合、OnEnableからOnDisableが呼ばれなくなる。(OnAwake、OnDestroyは呼ばれる)

これ以上詳細はめんどいから調べない。
さがせば公式に書いてあるんだろうなぁ。


他の記事もどうぞ
Unity系記事まとめ
Related Posts Plugin for WordPress, Blogger...