ガチャを引く
カードを一覧表示して、削除もできるようになった。次は、ガチャゲームを作ってカードを追加していこう。このゲームには、次の機能が必要になる。
- プレイヤーがガチャを引ける回数には制限がある
- カードのレア度は、カードのランクと連動している(SSカードはCカードより出にくい)
具体的には、各レア度の確率は次の通りである。
| Rank | SS | S | A | B | C |
| Rarity (%) | 5% | 10% | 20% | 30% | 35% |
データベース
まず、各プレイヤーが持つガチャの回数を保存するために、データベースに新しいテーブルを作る。必要なのは、ユーザーIDと回数だけである。
まず、各プレイヤーが持つガチャの回数を保存するために、データベースに新しいテーブルを作る。必要なのは、ユーザーIDと回数だけである。
INSERT INTO `gacha` (`user_id`, `count`) VALUES ('1', '3');

PHP スクリプト
ガチャを引く回数を求める
新しいAPIが2つ必要になる。1つはガチャの残り回数を確認するもの、もう1つは実際にガチャを引くものである。まずは簡単な方から始めよう。get_gacha_count.phpという新しいスクリプトを作る。これは単純な SELECT 文で、プレイヤーの残り回数を調べるだけである。テーブルにレコードが無い場合は、0を返す。
いつも通り、まずは GET パラメータでテストしてみよう。調べたい user_id を引数として渡す。
<?php
// JSONを返すべき
header("Content-Type: application/json; charset=utf-8");
// 接続
$dbh = new PDO('mysql:host=localhost; dbname=card_game', "root", "", [PDO::ATTR_PERSISTENT => true]);
// ユーザーIDを取得
$userID = $_GET'user_id'];
// SQL文を構築
$sql = "SELECT * FROM gacha WHERE user_id = " . $userID;
// デフォルトとして 0 を返す
$json['count'] = 0;
// 見つけたら、回数を取得
$result = $dbh->query($sql);
if ($result->rowCount() == 1)
{
$record = $result->fetch();
$json['count'] = $record['count'];
}
// 返す
print(json_encode($json));
?>
user_id=1とuser_id=3でテストすると、次のような結果が得られる。
|
|
|
これが求めていた正しい出力である。次のステップに進む前に、$_GET を $_POST に変更するのを忘れないでください。
ガチャを引く
次のスクリプトは、ガチャを実際に引く処理を行う。いくつかの処理が必要になるので、少し複雑である。
- SSからCまでの中から、ランダムにカードのランクを決める
- 決まったランクのカードを、すべてデータベースから取得する
- その中から、ランダムに1枚を選ぶ
- 選んだカードを、プレイヤーの持っているカード一覧に追加する
- ガチャの残り回数を1減らす
- 新しく手に入れたカードの情報を、JSONでゲーム(Unity)側に返す
この処理は、4つの関数に分けて順番に呼び出すことができる。まずは、ランダムにランクを決める処理から始めよう。gacha_pull.php という新しいスクリプトを作ってください。
確率でランダムにカードのランクを決める
// 確率によりランダムランクを作成
// 0:C ~ 4:SS
function createRandomRank()
{
// 0~100までの乱数を生成
$chance = rand(0, 100)
// 5% 以下だったら、SSランク(4)のカードになる
if ($chance < 5)
return 4;
// 15% 以下だったら、Sランク(3)のカードになる
if ($chance < 15)
return 3;
// 35% 以下だったら、Aランク(2)のカードになる
if ($chance < 35)
return 2;
// 65% 以下だったら、Bランク(1)のカードになる
if ($chance < 65)
return 1;
// 残りは C(0)
return 0;
}
このスクリプトは、0から100までのランダムな数を生成し、累積確率を順番にチェックしながら、0(C) から 4(SS) までのランクを1つ見つけて返す。
ランクを指定してデータベースからランダムにカードを選ぶ
次のスクリプトは、0から4までのランク値を受け取り、データベースを検索して、その中からランダムに1枚のカードのレコードを返す。
// ランクを用いて、ランダムのカードを返す
// $dbh: データベースを検索するためのPDO
// $rank: カードのランク
function getCardWithRank($dbh, $rank)
{
// SQL文を構築
$sql = "SELECT * FROM cards WHERE rank = " . $rank;
// すべてのレコードを取得
$result = $dbh->query($sql);
$records = $result->fetchAll();
// ランダムのを選択
$count = sizeof($records);
$idx = rand(0, $count-1);
return $records[$idx];
}
プレイヤーにカードを追加する
このステップでは、user_cards テーブルを更新して、プレイヤーの持っているカードを反映させる。もしプレイヤーがすでにそのカードを持っていたら、count に1を足す必要がある。逆に、まだ持っていなければ、count を1として新しいレコードを追加する必要がある。幸い、SQL には INSERT ... ON DUPLICATE という特別な文がある。読むのは少し複雑だが、だいたい次のような形になる。
INSERT INTO table (カラム1, カラム2, ...) VALUES (値1, 値2, ..)
ON DUPLICATE KEY UPDATE カラム1 = 値1, カラム2 = 値2, ...
この場合、重複するレコードが見つかったら、新しく追加する代わりに更新される。ただし、そのためには、重複してはいけないフィールドを「UNIQUE」として指定しておく必要がある。続ける前に、phpMyAdmin を開いて user_cards テーブルを編集してみよう。
user_idとcard_id の両方を選択して、「UNIQUE」に設定してください。こうすることで、user_id と card_id の組み合わせが重複するレコードは存在できないと、データベースに伝えることができる。例えば、
user_id = 3, card_id = 1
は、
user_id = 3, card_id = 2
や
user_id = 2, card_id = 1
と共存できる。少なくともどちらかのフィールドが違うからである。しかし、user_id = 3, card_id = 1というレコードをもう一度追加しようとすると、その組み合わせは一意でなければならないため、エラーになりデータベースには追加されない。この2つの列の組み合わせが一意であることは、次の画面で確認できる。

一意なフィールドができたので、特別な INSERT ... ON DUPLICATE 文を使って、ユーザーとカードの組み合わせが存在するかどうかによって、追加または更新を行うことができる。だいたい次のような形になる。
INSERT INTO user_cards (user_id, card_id, count) VALUES ($userID, $cardID, 1)
ON DUPLICATE KEY UPDATE count = count + 1
この文は、新しいuser_id / card_idの組み合わせを、count = 1として追加しようとする。もし重複していたら、代わりにcountを1増やす。これで、次のようなPHP関数が書けるようになる。
// ユーザーにカードを追加する
// $dbh: データベースを検索するためのPDO
// $userID: ユーザーID
// $cardID: カードID
function addCardToPlayer($dbh, $userID, $cardID)
{
// SQL文を構築
$sql = "INSERT INTO user_cards (user_id, card_id, count) "
. "VALUES ($userID, $cardID, 1) "
. "ON DUPLICATE KEY UPDATE count = count + 1";
// 実行
$result = $dbh->exec($sql);
}
ガチャの回数を減らす
カードをプレイヤーに追加できたので、次はガチャの残り回数を減らす。これは、単純な UPDATE 文で実現できる。
// ガチャの数を減らす
// $dbh: データベースを検索するためのPDO
// $userID: ユーザーID
function decreaseGachaPullCount($dbh, $userID)
{
// SQL文を構築
$sql = "UPDATE gacha SET count = count - 1 "
. "WHERE user_id = " . $userID;
// 実行
$result = $dbh->exec($sql);
}
まとめる
あとは、これまで作った関数をすべて実行して、手に入れたカードの情報をJSONでプレイヤーに返すだけである。
// JSONを返すべき
header("Content-Type: application/json; charset=utf-8");
// 接続
$dbh = new PDO('mysql:host=localhost; dbname=card_game', "root", "", [PDO::ATTR_PERSISTENT => true]);
// ユーザーID
$userID = $_POST['user_id'];
$rank = createRandomRank();
$card = getCardWithRank($dbh, $rank);
addCardToPlayer($dbh, $userID, $card['id']);
decreaseGachaPullCount($dbh, $userID);
// カード情報を返す
$json['card']['id'] = $card['id'];
$json['card']['rank'] = $card['rank'];
$json['card']['picture_id'] = $card['picture_id'];
$json['card']['monster_name'] = $card['monster_name'];
$json['card']['atk_value'] = $card['attack'];
$json['card']['def_value'] = $card['defense'];
$json['card']['hp_value'] = $card['hit_points'];
print(json_encode($json));
Unityを使い、APIとの接続
次は、Unity側の作業に移る。まず、それぞれのPHP関数に対応するAPIリクエストを2つ作ろう。
APIRequest
ガチャの回数取得
// ガチャの回数を返す
// userID:ユーザーID
public static async Awaitable<int> GetGachaCountAsync(string userID)
{
// POSTでデータを準備
var postData = new WWWForm();
postData.AddField("user_id", userID);
// APIのURLへリクエストを送信
const string url = ServerAPI + "/get_gacha_count.php";
var webRequest = UnityWebRequest.Post(url, postData);
// 返事を待機する
await webRequest.SendWebRequest();
// 返事の文字列を取得
var webResponse = webRequest.downloadHandler.text;
// JSONからPlayerCardの配列へ変換
JObject response = JObject.Parse(webResponse);
// 返す
return (int)response["count"];
}
ガチャを引く
// ガチャを引く
// userID:ユーザーID
public static async Awaitable<JObject> GachaPullAsync(string userID)
{
// POSTでデータを準備
var postData = new WWWForm();
postData.AddField("user_id", userID);
// APIのURLへリクエストを送信
const string url = ServerAPI + "/gacha_pull.php";
var webRequest = UnityWebRequest.Post(url, postData);
// 返事を待機する
await webRequest.SendWebRequest();
// 返事の文字列を取得
var webResponse = webRequest.downloadHandler.text;
// JSONからPlayerCardの配列へ変換
JObject response = JObject.Parse(webResponse);
// 返す
return (JObject)response["card"];
}
GachaController
ガチャの回数
次に、GachaController.cs を更新する必要がある。このスクリプトは今のところアニメーションを再生するだけで、サーバーとはつながっていない。APIを使って残り回数を確認し、その回数分だけガチャを引けるように更新していこう。
UpdateGachaCountAsync() の中にある、次の行を置き換えてください。
// 未実装:サーバーに依頼し、数を取得
await Awaitable.NextFrameAsync();
int count = 1; // とりあえず固定
APIの呼び出しに置き換える。
// サーバーに依頼し、数を取得
int count = await APIRequest.GetGachaCountAsync(LoginController.UserID);
Unity上で試してみて、データベースで設定した通り「3」回が正しく取得できるか確認してください。
ガチャを引く
最後に、ガチャを引くAPIを GachaController とつなげて、結果をカード表示に反映させる必要がある。APIが返すカード情報は、CardDisplay が期待している形式とちょうど同じなので、わりと簡単につなげることができる。
PullGachaAsync() の中にある、次の行を置き換えてください。
// 未実装:サーバーに依頼し、ガチャを引き、
// カードを更新する
await Awaitable.NextFrameAsync();
次のように置き換える。
//サーバーに依頼し、ガチャを引き、カードを更新する
JObject data = await APIRequest.GachaPullAsync(LoginController.UserID);
card.SetData(data);
あとは、実際にガチャゲームを遊ぶだけである!回数が無くなるまで3回引いてみて、それからカード一覧に戻って、新しいカードが増えているか確認してください!




No comments to display
No comments to display