 
      特定のユーザーからのゲームからサイトへのレコードの追加に関する記事の続き。 最初の部分では、 Laravelに記録ページを作成し、それらを追加するためのAPI(匿名ユーザーと許可ユーザーの両方)を準備しました。 このパートでは、完成したUnity on the WallのUnityゲームを完成させ、アカウントにログインして、認証トークンを使用してLaravelのサイトにレコードを送信します。
準備する
例として、最も単純な機能を備えたネズミについてランナーを使用することを提案します。ネズミは壁に沿ってい、パンは上に落ちます。 Unity 2017.1のプロジェクトはgithubからダウンロードできます。 必要に応じて、他のプロジェクトを使用できます。ここでは、その実装の原則とオプションの1つのみが考慮されます。
このチュートリアルでは、 Laravelの最初の部分から完成したサイトも使用します。 こちらからダウンロードできます。 http://127.0.0.1:8000/でサイトを利用可能にするには、次のコマンドを使用する必要があります。
php artisan serve
Unityでプロジェクトを開きます。 基本的なゲームプレイは次のとおりです。
 
      Playをクリックすると、ラットを制御し、特定の境界で壁に沿って移動し、落下するパンをかわすことができます。 左上にはポイントカウンターがあり、下には残りのライフがあります。 Escを押すと、一時停止メニュー(認証フォームを追加する必要がある空のパネル)が表示されます。 ゲーム終了後、 Rボタンを再起動できます。
最初に行うことは、匿名レコードを追加することです。
匿名記録
Create -> C# Script
      
      Project
      
      ]パネルの
Create -> C# Script
      
      コマンドを使用して、
Scripts
      
      フォルダーに新しいスクリプトを
Create -> C# Script
      
      。 それを
WWWScore
      
      と呼び、 Unityに使用するエディター( Visual Studio 、 MonoDevelop )で結果の
WWWScore.cs
      
      ファイルを
WWWScore.cs
      
      ます。
最初に、サーバーのアドレスを保存するフィールドを追加します。 Unityの [
Inspector
      
      ]パネルからこのプライベート変数を変更できるように、
[SerializeField]
      
      指定します。
 [SerializeField] private string serverURL = "http://127.0.0.1:8000/";
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      デフォルトでは、アドレスをLaravelのサイトと同じに設定します。 必要に応じて、変更できます。
次に、匿名ユーザーからレコードを追加する機能に移りましょう。 この関数は、POST要求をサーバーに送信し、応答を待ちます。 そのようなリクエストを処理するオプションとして、 コルーチンを使用して関数を並行して実行します。 コルーチンで使用する関数は次のようになります。
 public IEnumerator AddRecord(int score) { WWWForm form = new WWWForm(); form.AddField("score", score); WWW w = new WWW(serverURL + "api/anonymrecord", form); yield return w; if(!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { Debug.Log(" !"); } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      POSTリクエスト(
GameController
      
      クラスから呼び出されたときに渡す
score
      
      変数の値)のデータを追加し、
GameController
      
      リクエストを作成し、結果を待ちます 。 サーバーからの応答が到着すると(または要求のタイムアウトが切れると)、コンソールに「 レコードが追加されました!」というメッセージが表示されます。 、または失敗した場合のエラー情報。
[
Inspector
      
      ]パネルの[ コンポーネントを追加 ]ボタンを使用するか、オブジェクト上でマウスを使ってスクリプトをドラッグするだけで、
WWWScore.cs
      
      スクリプトを
Game Controller
      
      オブジェクトに追加します。
 
      ここで、スクリプト
GameController.cs
      
      編集し、そこにコルーチンコールを追加します。
 void Update () { if (gameover){ // ,          if (!gameoverStarted) { gameoverStarted = true; //   restartText.SetActive(true); //   //   StartCoroutine(GetComponent<WWWScore>().AddRecord(score)); } // ... } else { // ... } // ... }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      コルーチンは、ゲームが終了した瞬間に一度-ゲームの再起動インターフェイスをオンにした直後に呼び出されます。 Rを押すと、シーンが再開され、再びゲームの最後に到達して、レコードが追加されます。
スクリプトを保存し、ゲームを確認します。 ゲームの終了後しばらくすると、「 レコードが追加されました!
 
      サイトでハイスコアを開き、リクエストが実際に送信されたことを確認できます。
 
      匿名の追加レコードが機能します。 承認に移りましょう。
認証コード
Login(string email, string password)
      
      認証関数
Login(string email, string password)
      
      を
WWWScore.cs
      
      、それをコルーチンに渡します。 レコードを追加する機能と同様に、 LaravelのサイトにPOSTリクエストを生成し、その中のデータセットをアドレスhttp://127.0.0.1:8000/oauth/tokenに送信します 。 記事の最初の部分で、承認に必要なデータセットを検討しました。
 WWWForm form = new WWWForm(); form.AddField("grant_type", "password"); form.AddField("client_id", "<Client ID>"); form.AddField("client_secret", "<Client Secret>"); form.AddField("username", email); //   form.AddField("password", password); //   form.AddField("scope", "*");
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      クエリ結果を受け取ったら、
json
      
      からデータを変換する必要があります。 これは、
json
      
      をオブジェクトに変換することにより、 JsonUtilityを使用して実行できます。
WWWScore
      
      クラスの
WWWScore
      
      前に、同じ
WWWScore.cs
      
      ファイルでオブジェクトのクラスを
WWWScore
      
      ます。
 [Serializable] public class TokenResponse { public string access_token; }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      覚えているように、受け取った
json
      
      オブジェクトには4つのフィールドがありますが、クラスで記述する
access_token
      
      フィールドのみが必要です。 これで、json変換をオブジェクト自体に追加できます。
TokenResponse tokenResponse = JsonUtility.FromJson<TokenResponse>(w.text);
認証トークンを受け取ったら、保存する必要があります。 簡単にするために、ユーザー設定を保存するためだけに設計されたPlayerPrefsクラスを使用します。
 PlayerPrefs.SetString("Token", tokenResponse.access_token);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      トークンを保存した後、それを使用してこのユーザーからレコードを追加できます。 ただし、その前に、現在のユーザーに関する情報を要求して、ログインしているユーザーをゲームに表示することもできます。 これを行うには、対応していない関数でコルーチンを呼び出しますが、この関数はまだ利用できません。
StartCoroutine(GetUserInfo());
この関数も作成します。
  完全なログイン機能コード 
        
        
        
      
    
       [Serializable] public class TokenResponse { public string access_token; } public class WWWScore : MonoBehaviour { // ... public IEnumerator Login(string email, string password) { WWWForm form = new WWWForm(); form.AddField("grant_type", "password"); form.AddField("client_id", "3"); form.AddField("client_secret", "W82LfjDg4DpN2gWlg8Y7eNIUrxkOcyPpA3BM0g3s"); form.AddField("username", email); form.AddField("password", password); form.AddField("scope", "*"); WWW w = new WWW(serverURL + "oauth/token", form); yield return w; if (!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { TokenResponse tokenResponse = JsonUtility.FromJson<TokenResponse>(w.text); if (tokenResponse == null) { Debug.Log("  !"); } else { //     PlayerPrefs.SetString("Token", tokenResponse.access_token); Debug.Log(" !"); //    StartCoroutine(GetUserInfo()); } } } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      ユーザー情報の取得
http://127.0.0.1:8000/api/userでGETリクエストを実行し、リクエストのヘッダーに認証データを登録し、リクエスト内の他のデータを送信しないようにする必要があり
null
      
      (
null
      
      )。
 Dictionary<string, string> headers = new Dictionary<string, string>(); headers.Add("Authorization", "Bearer " + PlayerPrefs.GetString("Token")); WWW w = new WWW(serverURL + "api/user", null, headers);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      前の関数と同様に、
json
      
      構造の全体から必要な唯一のフィールド(名前)を持つ別のクラスを作成するために必要な解析のために、
json
      
      を答えとして取得します。
 [Serializable] public class UserInfo { public string name; }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      jsonをこのクラスのオブジェクトに変換します。
UserInfo userInfo = JsonUtility.FromJson<UserInfo>(w.text);
設定にユーザー名を保存します。
 PlayerPrefs.SetString("UserName", userInfo.name);
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        完全なGetUserInfo関数コード 
        
        
        
      
    
       //  TokenResponse // ... [Serializable] public class UserInfo { public string name; } public class WWWScore : MonoBehaviour { // ... //  Login // ... public IEnumerator GetUserInfo() { Dictionary<string, string> headers = new Dictionary<string, string>(); headers.Add("Authorization", "Bearer " + PlayerPrefs.GetString("Token")); WWW w = new WWW(serverURL + "api/user", null, headers); yield return w; if (!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { UserInfo userInfo = JsonUtility.FromJson<UserInfo>(w.text); if (userInfo == null) { Debug.Log("  !"); } else { //     PlayerPrefs.SetString("UserName", userInfo.name); Debug.Log("  !"); } } } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      レコードを追加するためのコードの変更
承認されたユーザーからレコードを追加
AddRecord(int score)
      
      は、
AddRecord(int score)
      
      関数のコードをわずかに
AddRecord(int score)
      
      ます。 設定に認証トークンが入力されているかどうかを確認するチェックを追加します。入力されている場合は、ユーザーに関する情報を受信したときと同じ方法でヘッダーに追加します。唯一の違いは、POSTリクエストのデータでレコードを送信することだけです。
 WWW w; if (PlayerPrefs.HasKey("Token")) { Dictionary<string, string> headers = new Dictionary<string, string>(); byte[] rawData = form.data; headers.Add("Authorization", "Bearer " + PlayerPrefs.GetString("Token")); w = new WWW(serverURL + "api/record", rawData, headers); } else { w = new WWW(serverURL + "api/anonymrecord", form); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
        変更されたAddRecord関数の完全なコード 
        
        
        
      
    
       public IEnumerator AddRecord(int score) { WWWForm form = new WWWForm(); form.AddField("score", score); WWW w; if (PlayerPrefs.HasKey("Token")) { Dictionary<string, string> headers = new Dictionary<string, string>(); byte[] rawData = form.data; headers.Add("Authorization", "Bearer " + PlayerPrefs.GetString("Token")); w = new WWW(serverURL + "api/record", rawData, headers); } else { w = new WWW(serverURL + "api/anonymrecord", form); } yield return w; if(!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { Debug.Log(" !"); } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      終了コード
ゲームからユーザーを結婚するには、設定でユーザーに関するすべてのデータを削除する必要があります。 この場合、他の設定はないため、すべての設定をクリアします。 プロジェクトではこれに注意してください。
 public void Logout() { PlayerPrefs.DeleteAll(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      メインコントローラー
次に、ユーザー認証を操作するためのメインゲームコントローラー(
GameController.cs
      
      )を準備します。 これらを
loginObj
      
      は、
loginObj
      
      許可
loginObj
      
      と
logoutObj
      
      出口パネルを持つオブジェクトが必要です。 認証パネルには、電子メールアドレス(
inputFieldEmail
      
      )およびパスワード(
inputFieldPassword
      
      )の入力フィールドが含まれます。 また、アカウントにログインしたユーザーの名前を表示するには、碑文
userNameText
      
      が必要です。
 //   public GameObject loginObj; //   public GameObject logoutObj; //  E-mail public GameObject inputFieldEmail; //   public GameObject inputFieldPassword; //     public GameObject userNameText;
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      承認のために、
Login()
      
      関数を作成します。これは、 Loginボタンをクリックして呼び出され、パスワードでメールアドレスを読み取り、
WWWScore.cs
      
      から同じ名前の関数でコルーチンを呼び出します。
 public void Login() { var email = inputFieldEmail.GetComponent<InputField>().text; var password = inputFieldPassword.GetComponent<InputField>().text; StartCoroutine(GetComponent<WWWScore>().Login(email, password)); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      終了関数は非常に単純です- 終了ボタンをクリックして呼び出され、
WWWScore.cs
      
      から
WWWScore.cs
      
      なしで同じ名前の関数を呼び出します。
 public void Logout() { GetComponent<WWWScore>().Logout(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      承認パネルと終了パネルの表示を切り替えるには、対応する設定がPlayerPrefsに保存されているかどうかを確認し、それに応じて目的のパネルを表示します。
 public void SetLoginVisible() { if (PlayerPrefs.HasKey("Token")) { loginObj.SetActive(false); logoutObj.SetActive(true); } else { loginObj.SetActive(true); logoutObj.SetActive(false); } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      同様に、ユーザー名を表示するには、名前の設定を確認し、存在しない場合はAnonymousと記述します 。
 public void SetUserName() { if (PlayerPrefs.HasKey("UserName")) { userNameText.GetComponent<Text>().text = PlayerPrefs.GetString("UserName"); } else { userNameText.GetComponent<Text>().text = ""; } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      最後の2つの関数は、対応する設定を変更するとき(および初期化プロセス中)にのみ呼び出す必要がありますが、このチュートリアルのフレームワーク内では、
Update()
      
      関数でこれを実行できます。
 void Update () { // ... //   // ... SetUserName(); SetLoginVisible(); }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      
      次に、視覚コンポーネントに目を向けます。
認証インターフェース
認証インターフェースを追加します。
Canvas
      
      オブジェクトにネストされた
Pause
      
      パネルの[ 有効化]チェックボックスをオンにします。 新しい空のオブジェクトを作成し ( Create Empty )、それを
Login
      
      と呼び、
Title
      
      ( Pause text)と同じレベルで、
Pause
      
      パネル内に配置します。
Graphic Raycaster
      
      コンポーネントを追加し
Graphic Raycaster
      
      (ネストされた要素を正しく機能させるため)。
 
      この
Login
      
      オブジェクトに
InputFieldEmail
      
      と
InputFieldPassword
      
      2つの入力フィールドを追加し(
InputFieldPassword
      
      > Input Field )、わかりやすくするためにプレースホルダーテキストを変更します。
InputFieldEmail
      
      オブジェクトの入力フィールドコンポーネントで、[ コンテンツタイプ]フィールドのデータタイプを[ 電子メールアドレス]に変更し、
InputFieldPassword
      
      オブジェクトを[ パスワード]に変更します。
ButtonLogin
      
      ボタン(
ButtonLogin
      
      > Button )を同じ
Login
      
      オブジェクトに追加します。 インターフェイスは次のようになります(フォントとコンポーネントのサイズを使用する場合)。
 
      以前に作成した関数を、
ButtonLogin
      
      ボタンをクリックするイベントにバインドします。
Inspector
      
      パネルのButtonコンポーネントについては、 On Click()イベントのプラス記号をクリックし、リストからEditorとRuntimeを選択し(デバッグ中の正しい作業のため)、そこにGame Controllerオブジェクトをドラッグします(マウスまたはオブジェクトフィールドの隣の選択円をクリックして選択します) ) この後に表示されるポップアップメニューで、
GameController
      
      コンポーネントとその中の
Login()
      
      関数を選択します。
 
      Login
      
      オブジェクトのEnableチェックボックスをオフにします-その表示は
GameController.cs
      
      で規制されてい
GameController.cs
      
      。
終了インターフェース
Pause
      
      ネストされた
Login
      
      オブジェクト(
Graphic Raycaster
      
      コンポーネントを忘れないでください)と同様に、新しい
Logout
      
      オブジェクトを作成しましょう。
ButtonLogout
      
      ボタンのみを
Logout
      
      オブジェクトに追加します。 前のボタンと同様に、同じ名前のオブジェクトの
GameController
      
      コンポーネントの
Logout()
      
      関数をclickイベントに添付します。
 
      Logout
      
      オブジェクトと
Pause
      
      パネル自体の「有効化」チェックボックスをオフにします。
ユーザー名の表示
User
      
      テキスト要素( UI-> Text )を
Pause
      
      要素の前のメイン
Canvas
      
      に追加し、その中にAnonymousを書き込み(または、碑文が
GameController.cs
      
      で割り当てられるため、空白のままにし
GameController.cs
      
      )、右上隅に配置します。 許可されたユーザーの名前がここに表示されます。
 
      コントローラーへのオブジェクトの割り当て
GameController
      
      オブジェクトを選択します。 インスペクターパネルでは、
Game Controller
      
      コンポーネントには、前のコードで追加した空のフィールドがいくつかあります。 階層パネルからマウスをドラッグするか、フィールドの近くにある選択円をクリックしてリストから選択することにより、適切なオブジェクトを割り当てます。
 
      テスト中
最後の部分、つまりすべてが正常に機能することを確認します。 ゲームを起動してEscを押します 。 私たちの前に承認パネルが開きます。 サイトに登録されているユーザーのデータを収集します(前回の記事でhabr@habrahabr.ru / habrahabrを使用しました )。
 
      [ ログイン ]ボタンをクリックします。 成功した場合、しばらくするとユーザー認証パネルが終了パネルに置き換えられ、対応するボタンのみが残されます。 匿名ではなく、 Habrが右上に書き込まれます-サイトのユーザー名。
 
      ここで、もう一度Escを押してレコードを設定すると、匿名ユーザーからではなく、許可されたユーザーから送信されます。
 
      これは、サイトのレコードページに移動して確認できます。
 
      これで私の最初のチュートリアルは終わりです。 私はそれについての質問に答えてうれしいです!
  完全なWWWScore.csコード 
       using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [Serializable] public class TokenResponse { public string access_token; } [Serializable] public class UserInfo { public string name; } public class WWWScore : MonoBehaviour { [SerializeField] private string serverURL = "http://127.0.0.1:8000/"; public IEnumerator AddRecord(int score) { WWWForm form = new WWWForm(); form.AddField("score", score); WWW w; if (PlayerPrefs.HasKey("Token")) { Dictionary<string, string> headers = new Dictionary<string, string>(); byte[] rawData = form.data; headers.Add("Authorization", "Bearer " + PlayerPrefs.GetString("Token")); w = new WWW(serverURL + "api/record", rawData, headers); } else { w = new WWW(serverURL + "api/anonymrecord", form); } yield return w; if(!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { Debug.Log(" !"); } } public IEnumerator Login(string email, string password) { WWWForm form = new WWWForm(); form.AddField("grant_type", "password"); form.AddField("client_id", "3"); //   form.AddField("client_secret", "W82LfjDg4DpN2gWlg8Y7eNIUrxkOcyPpA3BM0g3s"); //   form.AddField("username", email); form.AddField("password", password); form.AddField("scope", "*"); WWW w = new WWW(serverURL + "oauth/token", form); yield return w; if (!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { TokenResponse tokenResponse = JsonUtility.FromJson<TokenResponse>(w.text); if (tokenResponse == null) { Debug.Log("  !"); } else { //     PlayerPrefs.SetString("Token", tokenResponse.access_token); Debug.Log(" !"); //    StartCoroutine(GetUserInfo()); } } } public IEnumerator GetUserInfo() { Dictionary<string, string> headers = new Dictionary<string, string>(); headers.Add("Authorization", "Bearer " + PlayerPrefs.GetString("Token")); WWW w = new WWW(serverURL + "api/user", null, headers); yield return w; if (!string.IsNullOrEmpty(w.error)) { Debug.Log(w.error); } else { UserInfo userInfo = JsonUtility.FromJson<UserInfo>(w.text); if (userInfo == null) { Debug.Log("  !"); } else { //     PlayerPrefs.SetString("UserName", userInfo.name); Debug.Log("  !"); } } } public void Logout() { PlayerPrefs.DeleteAll(); } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        完全なGameController.csコード 
       using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; //   [System.Serializable] public class PanClass { //   public GameObject panObj; //      public float start; //    public float pause; } public class GameController : MonoBehaviour { //   public PanClass pan; //   public Vector2 spawnValues; //     public GameObject scoreText; //      public GameObject restartText; //      public GameObject pausePanel; //     public float scoreRate = 1.0F; // ,     public int scoreAdd = 10; //  public static int score; //    public static bool gameover; //     private float nextScore = 0.0F; //  ,         private bool gameoverStarted; //   public GameObject loginObj; //   public GameObject logoutObj; //  E-mail public GameObject inputFieldEmail; //   public GameObject inputFieldPassword; //     public GameObject userNameText; void Start () { //   ( ) gameover = false; score = 0; gameoverStarted = false; //    StartCoroutine(PanSpawn()); } void FixedUpdate() { if (!gameover) { //   scoreText.GetComponent<Text>().text = score.ToString(); } } void Update () { if (gameover){ // ,          if (!gameoverStarted) { gameoverStarted = true; //    restartText.SetActive(true); //   StartCoroutine(GetComponent<WWWScore>().AddRecord(score)); } //   R if (Input.GetKey(KeyCode.R)) { //   SceneManager.LoadScene(0); } } else { if (Input.GetKeyDown(KeyCode.Escape)) { if (Time.timeScale != 0) { //    Time.timeScale = 0; pausePanel.SetActive(true); } else { //    Time.timeScale = 1; pausePanel.SetActive(false); } } } //   if (!gameover && (Time.time > nextScore)) { nextScore = Time.time + scoreRate; score = score + scoreAdd; } SetUserName(); SetLoginVisible(); } //   IEnumerator PanSpawn() { //      yield return new WaitForSeconds(pan.start); //  ,    while (!gameover) { //          Vector2 spawnPosition = new Vector2(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y); Quaternion spawnRotation = Quaternion.identity; Instantiate(pan.panObj, spawnPosition, spawnRotation); yield return new WaitForSeconds(pan.pause); } } //  public void Login() { var email = inputFieldEmail.GetComponent<InputField>().text; var password = inputFieldPassword.GetComponent<InputField>().text; StartCoroutine(GetComponent<WWWScore>().Login(email, password)); } //  public void Logout() { GetComponent<WWWScore>().Logout(); } //     public void SetLoginVisible() { if (PlayerPrefs.HasKey("Token")) { loginObj.SetActive(false); logoutObj.SetActive(true); } else { loginObj.SetActive(true); logoutObj.SetActive(false); } } //      public void SetUserName() { if (PlayerPrefs.HasKey("UserName")) { userNameText.GetComponent<Text>().text = PlayerPrefs.GetString("UserName"); } else { userNameText.GetComponent<Text>().text = ""; } } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      前編
Laravelの準備完了プロジェクト
Unity基本プロジェクト (
master
      
      ブランチ)
Unityの準備完了プロジェクト (
final
      
      ブランチ)