カード削除
To delete cards, we need to create a new API in PHP thatカードを削除するには、PHPで新しいAPIを作る必要がある。このAPIは以下のことを行う。
Receives the user idユーザーIDを受け取るReceives a list of card ids to remove (including duplicates)削除したいカードIDのリストを受け取る(重複あり)Runs an SQL query that reduces the count by 1 for each card that matches the requestリクエストに一致するカードごとに、カウントを1ずつ減らすSQLクエリを実行するIf the count reaches zero, remove the record from the databaseカウントが0になったら、そのレコードをデータベースから削除する
Removing cards using SQLSQLを使ってカードを削除する
First, let's see how decreasing the count in SQL would look like. Let's say we want to decrease まず、SQLでカウントを減らす方法を見てみよう。例えば、user_id = 1, 1、card_id = 1 by two cards. Since this user has 2 cards of card_id1のカードを2枚減らしたいとする。このユーザーはcard_id = 1, this would remove all cards. We can decrease the count by telling MySQL to subtract 2 from the field "count" like so:1のカードを2枚持っているので、これで全部なくなることになる。MySQLに「count」という項目から2を引くよう指示すれば、カウントを減らせる。以下のようにする
UPDATE user_cards SET count = count - 2 WHERE user_id = 1 and card_id = 1;
This is telling MySQL to take the column "count" and subtract it by 2, but only for これは、user_id = 1and card_id1かつcard_id = 1. After running it we get:1の行だけ、「count」という列から2を引くようMySQLに指示している。実行すると、以下のようになる。

We can check that the count went to zero. All we have to do next is remove all records where count is 0 or less. We can easily do that with DELETE.カウントが0になったことが確認できる。次にやるべきことは、countが0以下になったレコードを全部削除することだけである。これはDELETEを使えば簡単にできる。
DELETE FROM user_cards WHERE count <= 0;
We can use these two instructions in PHP to remove cards from players. Let's design our APIこの2つの命令をPHPで使えば、プレーヤーからカードを削除できる。それでは、APIを設計していこう。
PHP スクリプト
Before始める前に、データベースを元に戻しておこう。phpMyAdmin we get started, let's restore our database. Run the following SQL command in phpMyAdmin:で以下のSQLコマンドを実行してください。
REPLACE INTO `user_cards` (`id`, `user_id`, `card_id`, `count`) VALUES
(1, 1, 1, 2), (2, 1, 2, 1), (3, 1, 5, 1),(4, 1, 8, 2),
(5, 1, 6, 1), (6, 2, 3, 5), (7, 2, 6, 3),(8, 2, 12, 1);
Now, let's design our script. Create a new file called では、スクリプトを設計していこう。delete_player_cards.php. In our API, we are going to request the client to send us the user id and how many cards to delete for each card id. Since the amount of cards to be deleted is variable, we are going to request the client to send the cards to be deleted as a JSON object that looks like this:という新しいファイルを作ってください。このAPIでは、クライアント側からユーザーIDと、カードIDごとの削除枚数を送ってもらう。削除するカードの枚数は毎回変わるので、削除したいカードを以下のようなJSONオブジェクトとして送ってもらうことにする。
{
"user_id" : "1",
"cards" : [
{
"id" : "1",
"count" : 2
},
{
"id" : "8",
"count" : 1
},
]
}
In this example, we want to remove 2 copies of card id "1", and 1 copy of card id "8" for user id "1". Since we don't have any way to send data yet, let's code it directly into the script first. We'll use POST later to send the data from Unity.この例では、ユーザーID「1」のカードID「1」を2枚、カードID「8」を1枚削除したいということになる。まだデータを送る仕組みがないので、最初はスクリプトの中に直接書き込んでおこう。Unityからデータを送る部分は、後でPOSTを使って作る。
<?php
// JSONを返すべき
header("Content-Type: application/json; charset=utf-8");
// 接続
$dbh = new PDO('mysql:host=localhost; dbname=card_game', "root", "", [PDO::ATTR_PERSISTENT => true]);
// テスト中にデータを固定
$data = '{
"user_id" : "1",
"cards" : [
{ "id" : "1", "count" : 2 },
{ "id" : "8", "count" : 1 }
]
}';
// JSONに変換
$json = json_decode($data, true);
// ユーザーIDと削除したいデータの分ける
$user_id = $json['user_id'];
$card_list = $json['cards'];
?>
Now we can build our SQL statement using a for loop to iterate over each card delete request in the array.次に、forループを使って、配列の中の削除リクエストを1つずつ処理しながらSQL文を組み立てていく。
// SQL文を構築
foreach ($card_list as $card)
{
$sql = "UPDATE user_cards SET count = count - " . $card['count']
. " WHERE user_id = " . $user_id
. " AND card_id = " . $card['id'];
// 確認しましょう
print($sql . "\n");
}
If we run it, we should see something like this:実行すると、以下のような結果になるはずである。

This is exactly what we need to delete cards! Let's complete our script by executing the SQL statement and delete cards from the database.これはまさに、カードを削除するために必要なものである!SQL文を実行して、データベースからカードを削除するところまで作って、スクリプトを完成させよう。
// SQL文を構築
foreach ($card_list as $card)
{
$sql = "UPDATE user_cards SET count = count - " . $card['count']
. " WHERE user_id = " . $user_id
. " AND card_id = " . $card['id'];
$dbh->exec($sql);
}
// 最後に、countが0以下になったカードを削除
$dbh->exec("DELETE FROM user_cards WHERE count <= 0");
// 空のJSONを返す
print("{}")
and we can check before running our code:コードを実行する前の状態を確認してみよう。

and after:そして、実行した後はこうなる。

All that is left now is to replace our test JSON with the actual POST input. This is our final script:あとは、テスト用のJSONを実際のPOST入力に置き換えるだけである。以下が最終的なスクリプトになる。
<?php
// JSONを返すべき
header("Content-Type: application/json; charset=utf-8");
// 接続
$dbh = new PDO('mysql:host=localhost; dbname=card_game', "root", "", [PDO::ATTR_PERSISTENT => true]);
// POSTデータを取得
$data = $_POST['data'];
// JSONに変換
$json = json_decode($data, true);
// ユーザーIDと削除したいデータの分ける
$user_id = $json['user_id'];
$card_list = $json['cards'];
// SQL文を構築
foreach ($card_list as $card)
{
$sql = "UPDATE user_cards SET count = count - " . $card['count']
. " WHERE user_id = " . $user_id
. " AND card_id = " . $card['id'];
$dbh->exec($sql);
}
// 最後に、countが0以下になったカードを削除
$dbh->exec("DELETE FROM user_cards WHERE count <= 0");
// 空のJSONを返す
print("{}")
?>
Unityを使い、APIとの接続
Our次のステップは、Unity側を実装することである。PHPスクリプトが期待しているのと同じデータ構造を作る必要がある。APIRequest next step is to implement the Unity side. We need to create the same data structure our PHP script is expecting. The APIRequest will require the user id, and the list of card ids to delete:には、ユーザーIDと、削除したいカードIDのリストが必要になる。
// プレーヤーのカードを削除する
// userID:ユーザーID
// cards: 削除したい「カードID」→「数」のディクショナリー
public static async Awaitable DeleteCardsAsync(string userID, Dictionary<string, int> cards)
{
// JSONを構築
JArray list = new JArray();
foreach (var (id, count) in cards)
{
JObject card = new JObject();
card["id"] = id;
card["count"] = count;
list.Add(card);
}
JObject json = new JObject();
json["user_id"] = userID;
json["cards"] = list;
// POSTでデータを準備
var postData = new WWWForm();
postData.AddField("data", json.ToString());
// APIのURLへリクエストを送信
const string url = ServerAPI + "/delete_player_cards.php";
var webRequest = UnityWebRequest.Post(url, postData);
// 返事を待機し、終わり(何も返さない)
await webRequest.SendWebRequest();
}
Our final step is to modify the game UI so when the delete button is pressed, we collect the card information we need. Since the the request may take a few moments, we need to write an asynchronous method:最後のステップは、削除ボタンが押されたときに必要なカード情報を集められるよう、ゲームのUIを修正することである。リクエストには少し時間がかかることがあるので、非同期メソッドとして書く必要がある。
// 選択されたカードを削除
private void DeleteSelectedCards()
{
_ = DeleteCardsAsync();
}
// 選択されたカードを削除(非同期)
private async Awaitable DeleteCardsAsync()
{
// 削除ボタンを無効にする
deleteButton.interactable = false;
// 表示中のカードを巡り、選択されたものを処理
var cards = new Dictionary<string, int>();
foreach (Transform child in cardsList.transform)
{
// 選択されていない?
var card = child.GetComponent<CardDisplay>();
if (!card.IsSelected)
continue;
// 同じIDだったら、数える
cards.TryAdd(card.CardID, 0);
cards[card.CardID]++;
}
// カードがなければ、終わり
if (cards.Count == 0) return;
// サーバーに依頼し…
await APIRequest.DeleteCardsAsync(LoginController.UserID, cards);
// …再読み込み依頼
await LoadCardsAsync();
// 削除ボタンを有効にする
deleteButton.interactable = true;
}
All that's left is to select a few cards, and check if the database is updated:あとは、カードをいくつか選んで、データベースが更新されているか確認するだけである。

