【Unity】第二回 ソーシャルゲームを作る 〜ユーザ登録処理の実装〜【AWS × Laravel】

スポンサーリンク
PC創作
マイケル
マイケル
みなさんこんにちは!
マイケルです!!
エレキベア
エレキベア
クマ〜〜〜〜!!
マイケル
マイケル
Laravelも勉強したことだし、
ソシャゲ開発の続きを進めるぞーー!!
エレキベア
エレキベア
そういえばソシャゲの環境構築をやっていたクマね
マイケル
マイケル
その通り!
今回は UnityとLaravelを連携させたユーザ登録処理 を実装していくぞ!
エレキベア
エレキベア
これは楽しみクマ
スポンサーリンク

参考書籍

マイケル
マイケル
前回に引き続き、こちらの参考書を参考に進めていきます!

エレキベア
エレキベア
書いてある内容がなかなか難しいクマね
マイケル
マイケル
俺もLaravel勉強してやっと内容がわかってきたところだよ・・・。
スポンサーリンク

実装イメージ

マイケル
マイケル
実装イメージはこんな感じだ!


① クライアントからサーバへユーザ登録リクエストを送る。
② サーバ側のDB登録を実施する。
③ サーバからクライアントへ登録結果レスポンスを送る。
④ クライアント側のDB登録を実施する。

Screenshot 2020 11 23 1 15 09
エレキベア
エレキベア
サーバ側もクライアント側も登録するクマね
マイケル
マイケル
使うたびにDBアクセスするわけにもいかないから
ローカルにも保存しておくわけだね
マイケル
マイケル
実際に動かしてみるとこのようになります!
Screenshot 2020 11 23 1 19 07↑登録するユーザ名を入力して登録する。
Screenshot 2020 11 23 1 19 21↑登録完了後、ユーザ名が表示される。
Screenshot 2020 11 23 1 23 04↑MySQL登録結果
Screenshot 2020 11 23 1 22 46↑SQLite登録結果
マイケル
マイケル
画面の動きは少ないけど、サーバ・クライアント共に
DB登録できる状態です!
ここまでできるように実装していきましょう!
エレキベア
エレキベア
新たな扉クマ〜〜〜〜〜
スポンサーリンク

テーブルの作成

マイケル
マイケル
まずはサーバ側のテーブルを作成しましょう!
テーブル作成の細かい手順は過去の記事で紹介しているのでご参考ください!
エレキベア
エレキベア
なつかしクマ〜〜〜〜
マイケル
マイケル
今回はユーザを登録するための UserProfile テーブルを作成します!
php artisan make:migration create_user_profile_table
↑マイグレーションファイルの作成
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUserProfileTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('user_profile', function (Blueprint $table) {
            $table->string('user_id', 37)->charset('utf8');
			$table->string('user_name', 32)->charset('utf8');
			$table->unsignedInteger('banana')->default(0);
			$table->unsignedInteger('banana_free')->default(0);
			$table->unsignedInteger('friend_coin')->default(0);
			$table->unsignedSmallInteger('tutorial_progress')->default(0);
            $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
			$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
			$table->primary('user_id');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('user_profile');
    }
}
マイケル
マイケル
ファイルを作成したらマイグレーションを実行しましょう!
php artisan migrate
マイケル
マイケル
これでテーブルが作成されました!
ついでに後々使用する、モデルファイルも作成しておきましょう!
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class UserProfile extends Model
{
    protected $table = 'user_profile';
    public $incrementing = false;
    protected $primaryKey = 'user_id';
    public $timestamps = false;
}
エレキベア
エレキベア
準備完了クマ〜〜〜〜〜
スポンサーリンク

クライアント側の実装

マイケル
マイケル
テーブルを作成したら、クライアント側の実装に入りましょう!
下記の部分になります!
Screenshot 2020 11 23 1 15 09のコピー
エレキベア
エレキベア
サーバにリクエストを送る処理と
サーバからレスポンスを受け取ってSQLiteに保存する処理クマね
マイケル
マイケル
その通り!
画面はシンプルに下記のような感じです!
Screenshot 2020 11 23 1 27 48
マイケル
マイケル

① 入力フォームにユーザ名を入力して決定ボタン押下
② 入力した名前でユーザ情報を登録してスタートボタンとユーザ名を表示
の流れになります!
エレキベア
エレキベア
(このゲームはなんなんだクマ・・・。)

SQLiteUnityKitのインポート

マイケル
マイケル
それではまずはUnityでSQLiteが使えるように
SQLiteUnityKitをインポートしましょう!
マイケル
マイケル
僕は下記サイトを参考にしながら導入しました!

参考サイト:
UnityでSQLiteを扱う方法

① SQLiteUnityKitをクローンする
git clone https://github.com/Busta117/SQLiteUnityKit.git
② クローンしたファイルを下記に配置する
Screenshot 2020 11 23 1 24 03
Screenshot 2020 11 23 1 24 20
マイケル
マイケル
導入は以上で完了です!!
エレキベア
エレキベア
簡単2ステップクマ〜〜〜〜

SQLiteのテーブル作成処理

マイケル
マイケル
SQLiteのアクセス方法は、以下のようになります!
下記のようにUserProfileテーブルのクラスを作成しましょう!
using System;

[Serializable]
public class UserProfileModel
{
	public string user_id;
	public string user_name;
	public int banana;
	public int banana_free;
	public int friend_coin;
	public int tutorial_progress;
}

public static class UserProfile
{
	public static void CreateTable()
    {
		string query = "create table if not exists user_profile (user_id text, user_name text, banana int, banana_free int, friend_coin int, tutorial_progress int, primary key(user_id))";
		SqliteDatabase sqlDB = new SqliteDatabase(GameUtil.Const.SQLITE_FILE_NAME);
		sqlDB.ExecuteQuery(query);
	}

	public static void Set(UserProfileModel user_profile)
    {
		string query = "insert or replace into user_profile (user_id, user_name, banana, banana_free, friend_coin, tutorial_progress) values (\"" + user_profile.user_id + "\", \"" + user_profile.user_name + "\", " + user_profile.banana + ", " + user_profile.banana_free + ", " + user_profile.friend_coin + ", " + user_profile.tutorial_progress + ")";
		SqliteDatabase sqlDB = new SqliteDatabase(GameUtil.Const.SQLITE_FILE_NAME);
		sqlDB.ExecuteNonQuery(query);
	}

	public static UserProfileModel Get()
    {
		string query = "select * from user_profile";
		SqliteDatabase sqlDB = new SqliteDatabase(GameUtil.Const.SQLITE_FILE_NAME);
		DataTable dataTable = sqlDB.ExecuteQuery(query);
		UserProfileModel userProfileModel = new UserProfileModel();
		foreach (DataRow dr in dataTable.Rows)
        {
			userProfileModel.user_id = dr["user_id"].ToString();
			userProfileModel.user_name = dr["user_name"].ToString();
			userProfileModel.banana = int.Parse(dr["banana"].ToString());
			userProfileModel.banana_free = int.Parse(dr["banana_free"].ToString());
			userProfileModel.friend_coin = int.Parse(dr["friend_coin"].ToString());
			userProfileModel.tutorial_progress = int.Parse(dr["tutorial_progress"].ToString());
		}
		return userProfileModel;
    }
}
マイケル
マイケル
それぞれ、

CreateTable()メソッド → テーブル作成処理
Set()メソッド → レコード登録処理
Get()メソッド → レコード取得処理

の処理になっています。
エレキベア
エレキベア
他のDBと同じようにSQLを発行するクマね
マイケル
マイケル
その通り!
ちなみにアクセスするファイル名などは、
下記のように定数クラスを作成して設定しています。
using System;

namespace GameUtil
{
    public static class Const
    {
        /** DB情報 */
        public const string SERVER_URL = 【サーバURL】;
        public const string SQLITE_FILE_NAME = 【SQLiteファイル名】;

        /** エラーID */
        public const string ERROR_DB_UPDATE = "1";
    }
}
↑定数クラス
マイケル
マイケル
あとは今作成したテーブルクラスを呼び出す処理を記述します!
SceneのManagerクラスとして下記を作成しましょう!
using System;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class TitleManager : MonoBehaviour
{
    /** UI部品 */
    private const string REGIST_USER_NAME_TEXT = "RegistUserNameText";
    private const string START_USER_NAME_TEXT = "StartUserNameText";
    private const string REGIST_MSG_TEXT = "RegistMsg";
    private const string START_CANVAS = "StartCanvas";
    private const string REGIST_CANVAS = "RegistCanvas";
    private InputField registUserNameText;
    private Text startUserNameText;
    private Text registMsgText;
    private GameObject StartCanvas;
    private GameObject RegistCanvas;

    /** DBモデル */
    private UserProfileModel userProfileModel;

    private void Awake()
    {
        // SQLiteのDBファイル作成
        string DBPath = Application.persistentDataPath + "/" + GameUtil.Const.SQLITE_FILE_NAME;
        if (!File.Exists(DBPath)) {
            File.Create(DBPath);
        }
        // テーブル作成処理
        UserProfile.CreateTable();
    }

    void Start()
    {
        StartCanvas = GameObject.Find(START_CANVAS);
        RegistCanvas = GameObject.Find(REGIST_CANVAS);
        registUserNameText = GameObject.Find(REGIST_USER_NAME_TEXT).GetComponent<InputField>();
        startUserNameText = GameObject.Find(START_USER_NAME_TEXT).GetComponent<Text>();
        registMsgText = GameObject.Find(REGIST_MSG_TEXT).GetComponent<Text>();

        // UserProfileの取得
        userProfileModel = UserProfile.Get();
        if (!string.IsNullOrEmpty(userProfileModel.user_id))
        {
            // ユーザ登録済:StartCanvas表示
            StartCanvas.SetActive(true);
            RegistCanvas.SetActive(false);
            startUserNameText.text = "User:" + userProfileModel.user_name;
        }
        else
        {
            // ユーザ未登録:RegistCanvas表示
            StartCanvas.SetActive(false);
            RegistCanvas.SetActive(true);
        }
    }

    // --------------- ボタン押下時処理 ---------------
    // 登録ボタン押下
    public void PushRegistButton()
    {
        if (string.IsNullOrEmpty(registUserNameText.text))
        {
            // ユーザ名未入力の場合
            registMsgText.text = "ちゃんと入力するクマ";
            
        }
        else if (registUserNameText.text.Length > 5)
        {
            // ユーザ名が5文字以上の場合
            registMsgText.text = "5文字以内で入力するクマ";
        }
        else
        {
            // ユーザ登録処理
            Action action = () => {
                StartCanvas.SetActive(true);
                RegistCanvas.SetActive(false);
                startUserNameText.text = "User:" + registUserNameText.text;
            };
            StartCoroutine(CommunicationManager.ConnectServer("registration", "?user_name=" + registUserNameText.text, action));
        }
    }

    // スタートボタン押下
    public void PushStartButton()
    {
        // スタートボタン押下時の処理を書く!!
    }
}
マイケル
マイケル
DB処理に関連するのは下記部分です。
Awake()の中で
SQLiteのDBファイル作成とUserProfileテーブルの作成処理
を記述することで、ゲーム起動時に必ず作成するようにしています。
マイケル
マイケル
また、Start()の中では
UserProfileテーブルのレコードが登録されているかどうか
をチェックして処理を分岐させています。

public class TitleManager : MonoBehaviour
{

・・・略・・・

    /** DBモデル */
    private UserProfileModel userProfileModel;

    private void Awake()
    {
        // SQLiteのDBファイル作成
        string DBPath = Application.persistentDataPath + "/" + GameUtil.Const.SQLITE_FILE_NAME;
        if (!File.Exists(DBPath)) {
            File.Create(DBPath);
        }
        // テーブル作成処理
        UserProfile.CreateTable();
    }

    void Start()
    {

・・・略・・・

        // UserProfileの取得
        userProfileModel = UserProfile.Get();
        if (!string.IsNullOrEmpty(userProfileModel.user_id))
        {
            // ユーザ登録済:StartCanvas表示
            StartCanvas.SetActive(true);
            RegistCanvas.SetActive(false);
            startUserNameText.text = "User:" + userProfileModel.user_name;
        }
        else
        {
            // ユーザ未登録:RegistCanvas表示
            StartCanvas.SetActive(false);
            RegistCanvas.SetActive(true);
        }
    }

・・・略・・・

}
↑テーブル作成と取得処理
エレキベア
エレキベア
タイトル画面起動時にテーブルを作成すれば
漏れが無くなるわけクマね
マイケル
マイケル
その通りだ!
そしてユーザ名を入力して決定ボタンを押下した時の処理は以下の部分!
入力チェックをした後、これから作成する「ConnectServer()」メソッドを呼び出しているよ!


・・・略・・・

    // --------------- ボタン押下時処理 ---------------
    // 登録ボタン押下
    public void PushRegistButton()
    {
        if (string.IsNullOrEmpty(registUserNameText.text))
        {
            // ユーザ名未入力の場合
            registMsgText.text = "ちゃんと入力するクマ";
            
        }
        else if (registUserNameText.text.Length > 5)
        {
            // ユーザ名が5文字以上の場合
            registMsgText.text = "5文字以内で入力するクマ";
        }
        else
        {
            // ユーザ登録処理
            Action action = () => {
                StartCanvas.SetActive(true);
                RegistCanvas.SetActive(false);
                startUserNameText.text = "User:" + registUserNameText.text;
            };
            StartCoroutine(CommunicationManager.ConnectServer("registration", "?user_name=" + registUserNameText.text, action));
        }
    }

・・・略・・・

}
エレキベア
エレキベア
ここからサーバにリクエストに送るクマね
マイケル
マイケル
そういうことさ!
それじゃサーバとの連携クラスを作成していこう!

サーバとの連携処理

マイケル
マイケル
サーバとの連携クラスは下記になります!
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using System;
using System.Linq;

[Serializable]
public class ResponseObjects
{
	public UserProfileModel user_profile;
}

public class CommunicationManager : MonoBehaviour
{

	public static IEnumerator ConnectServer(string endpoint, string paramater, Action action = null)
    {
		// *** リクエストの送付 ***
		UnityWebRequest unityWebRequest = UnityWebRequest.Get(GameUtil.Const.SERVER_URL + endpoint + paramater);
		yield return unityWebRequest.SendWebRequest();
		// エラーの場合
		if (!string.IsNullOrEmpty(unityWebRequest.error))
		{
			Debug.LogError(unityWebRequest.error);
			yield break;
		}

		// *** レスポンスの取得 ***
		string text = unityWebRequest.downloadHandler.text;
		Debug.Log("レスポンス : " + text);
		// エラーの場合
		if (text.All(char.IsNumber))
		{
			switch (text)
			{
				case GameUtil.Const.ERROR_DB_UPDATE:
					Debug.LogError("サーバーでエラーが発生しました。[データベース更新エラー]");
					break;
				default:
					Debug.LogError("サーバーでエラーが発生しました。[システムエラー]");
					break;
			}
			yield break;
		}

		// *** SQLiteへの保存処理 ***
		ResponseObjects responseObjects = JsonUtility.FromJson<ResponseObjects>(text);
		if (!string.IsNullOrEmpty(responseObjects.user_profile.user_id))
			UserProfile.Set(responseObjects.user_profile);
		// 正常終了アクション実行
		if (action != null)
		{
			action();
			action = null;
		}
	}
}
マイケル
マイケル
「UnityWebRequest」クラスを上記のように使用することで、
リクエストを送ったりレスポンスを受け取ったりできるようになります!
マイケル
マイケル
サーバ側でJSON形式で返すよう実装するので、
受け取り後、SQLiteへ保存しましょう!
エレキベア
エレキベア
こうしてみると内容が分かってきたクマ〜〜〜
マイケル
マイケル
以上でクライアント側の実装は完了です!
スポンサーリンク

サーバ側の実装

マイケル
マイケル
次はサーバ側の実装です!
下記の部分になります!
Screenshot 2020 11 23 1 15 09のコピー2
エレキベア
エレキベア
クライアントから受け取ったリクエストからDB登録して
レスポンスを返す
流れクマね
マイケル
マイケル
サーバ側の処理は非常にシンプルです!
下記Controllerクラスを作成しましょう!
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\UserProfile;

class RegistrationController extends Controller
{
    public function Registration(Request $request)
	{
		//ユーザーIDの決定
		$user_id = uniqid(); //例:4b3403665fea6

		//初期データの設定
		$user_profile = new UserProfile;
		$user_profile->user_id = $user_id;
		$user_profile->user_name = $request->user_name;
		$user_profile->banana = config('constants.BANANA_DEFAULT');
		$user_profile->banana_free = config('constants.BANANA_FREE_DEFAULT');
		$user_profile->friend_coin = config('constants.FRIEND_COIN_DEFAULT');
		$user_profile->tutorial_progress = config('constants.TUTORIAL_START');

		//データの書き込み
		try {
			$user_profile->save();
		} catch (\PDOException $e) {
			logger($e->getMessage());
			return config('error.ERROR_DB_UPDATE');
		}

		//クライアントへのレスポンス
		$user_profile = UserProfile::where('user_id', $user_id)->first();

		$response = array(
			'user_profile' => $user_profile,
		);

		return json_encode($response);
	}
}
マイケル
マイケル
リクエストを受け取ったら、
ユーザのユニークIDを生成してUserProfileテーブルへの登録処理後、
JSON形式で返却する
処理にしています!
マイケル
マイケル
ちなみに、こちらも config フォルダ内に下記のようなクラスを作成することで
定数として扱うことができます!
<?php

return array(
    'ERROR_DB_UPDATE' => 1,
);
<?php

return array(
    'BANANA_DEFAULT' => 0,
    'BANANA_FREE_DEFAULT' => 10,
    'FRIEND_COIN_DEFAULT' => 0,
    'TUTORIAL_START' => 0,
);
エレキベア
エレキベア
なるほどクマ〜〜〜〜〜
マイケル
マイケル
あとは下記のようにルーティングを設定すれば完了です!!
<?php

Route::get('/', function () {
    return view('welcome');
});
Route::get('registration', 'RegistrationController@Registration');
EQ 1↑完成図
エレキベア
エレキベア
完成したクマ〜〜〜!!!
スポンサーリンク

おわりに

マイケル
マイケル
というわけで今回はユーザ登録処理の実装でした!
どうだったかな?
エレキベア
エレキベア
サーバとの連携と聞くと難しそうクマが
やってみると案外できてうれしかったクマ
マイケル
マイケル
今回は簡単な処理だったけど、
ここから少しずつレベルアップしていこうね!!
マイケル
マイケル
それでは今日はこの辺で!
アデュー!!!
エレキベア
エレキベア
クマ〜〜〜〜〜〜〜

【Unity】ソーシャルゲームを作る 〜ユーザ登録処理の実装〜【AWS × Laravel】 〜完〜

コメント