الوحدة على الانترنت المتصدرين البرنامج التعليمي
في هذا البرنامج التعليمي، سأوضح كيفية تنفيذ لوحة المتصدرين عبر الإنترنت في لعبتك في Unity.
هذا استمرار للبرنامج التعليمي السابق: Unity نظام تسجيل الدخول باستخدام PHP وMySQL.
يعد الحصول على لوحة صدارة طريقة رائعة لزيادة إمكانية إعادة اللعب من خلال إضافة مستوى من القدرة التنافسية إلى لعبتك.
كما كان من قبل، يتطلب هذا البرنامج التعليمي خادمًا مزودًا بـ cPanel بالإضافة إلى PHP وMySQLi (نسخة محسنة من MySQL).
لا تتردد في التحقق من استضافة VPS المميزة ذات الأسعار المعقولة أو بديل Shared Hosting الأرخص.
لذلك دعونا نستمر!
إجراء تعديل على البرنامج النصي الموجود
إذا اتبعت البرنامج التعليمي أعلاه، فسيكون لديك الآن برنامج نصي يسمى 'SC_LoginSystem'. سنقوم بتنفيذ ميزة المتصدرين عن طريق إضافة بعض التعليمات البرمجية إليها.
- افتح البرنامج النصي 'SC_LoginSystem'
أولاً نبدأ بإضافة المتغيرات الضرورية:
//Leaderboard
Vector2 leaderboardScroll = Vector2.zero;
bool showLeaderboard = false;
int currentScore = 0; //It's recommended to obfuscate this value to protect against hacking (search 'obfuscation' on sharpcoderblog.com to learn how to do it)
int previousScore = 0;
float submitTimer; //Delay score submission for optimization purposes
bool submittingScore = false;
int highestScore = 0;
int playerRank = -1;
[System.Serializable]
public class LeaderboardUser
{
public string username;
public int score;
}
LeaderboardUser[] leaderboardUsers;
ملاحظة: المتغير currentScore هو ما ستستخدمه في اللعبة لتتبع نتائج اللاعبين. سيتم إرسال هذه القيمة إلى server وتخزينها في قاعدة البيانات، ومن المستحسن التعتيم تلك القيمة للحماية من الاختراق.
بعد ذلك، نضيف عدادين سيكونان مسؤولين عن إرسال النتائج واسترداد لوحة المتصدرين. أضف الكود أدناه في نهاية البرنامج النصي قبل إغلاق القوس الأخير:
//Leaderboard
IEnumerator SubmitScore(int score_value)
{
submittingScore = true;
print("Submitting Score...");
WWWForm form = new WWWForm();
form.AddField("email", userEmail);
form.AddField("username", userName);
form.AddField("score", score_value);
using (UnityWebRequest www = UnityWebRequest.Post(rootURL + "score_submit.php", form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
print(www.error);
}
else
{
string responseText = www.downloadHandler.text;
if (responseText.StartsWith("Success"))
{
print("New Score Submitted!");
}
else
{
print(responseText);
}
}
}
submittingScore = false;
}
IEnumerator GetLeaderboard()
{
isWorking = true;
WWWForm form = new WWWForm();
form.AddField("email", userEmail);
form.AddField("username", userName);
using (UnityWebRequest www = UnityWebRequest.Post(rootURL + "leaderboard.php", form))
{
yield return www.SendWebRequest();
if (www.isNetworkError)
{
print(www.error);
}
else
{
string responseText = www.downloadHandler.text;
if (responseText.StartsWith("User"))
{
string[] dataChunks = responseText.Split('|');
//Retrieve our player score and rank
if (dataChunks[0].Contains(","))
{
string[] tmp = dataChunks[0].Split(',');
highestScore = int.Parse(tmp[1]);
playerRank = int.Parse(tmp[2]);
}
else
{
highestScore = 0;
playerRank = -1;
}
//Retrieve player leaderboard
leaderboardUsers = new LeaderboardUser[dataChunks.Length - 1];
for(int i = 1; i < dataChunks.Length; i++)
{
string[] tmp = dataChunks[i].Split(',');
LeaderboardUser user = new LeaderboardUser();
user.username = tmp[0];
user.score = int.Parse(tmp[1]);
leaderboardUsers[i - 1] = user;
}
}
else
{
print(responseText);
}
}
}
isWorking = false;
}
التالي هو واجهة المستخدم المتصدرين. أضف الكود أدناه بعد OnGUI() الفارغ:
//Leaderboard
void LeaderboardWindow(int index)
{
if (isWorking)
{
GUILayout.Label("Loading...");
}
else
{
GUILayout.BeginHorizontal();
GUI.color = Color.green;
GUILayout.Label("Your Rank: " + (playerRank > 0 ? playerRank.ToString() : "Not ranked yet"));
GUILayout.Label("Highest Score: " + highestScore.ToString());
GUI.color = Color.white;
GUILayout.EndHorizontal();
leaderboardScroll = GUILayout.BeginScrollView(leaderboardScroll, false, true);
for (int i = 0; i < leaderboardUsers.Length; i++)
{
GUILayout.BeginHorizontal("box");
if(leaderboardUsers[i].username == userName)
{
GUI.color = Color.green;
}
GUILayout.Label((i + 1).ToString(), GUILayout.Width(30));
GUILayout.Label(leaderboardUsers[i].username, GUILayout.Width(230));
GUILayout.Label(leaderboardUsers[i].score.ToString());
GUI.color = Color.white;
GUILayout.EndHorizontal();
}
GUILayout.EndScrollView();
}
}
أضف الكود أدناه داخل الفراغ OnGUI() (قبل قوس الإغلاق):
//Leaderboard
if (showLeaderboard)
{
GUI.Window(1, new Rect(Screen.width / 2 - 300, Screen.height / 2 - 225, 600, 450), LeaderboardWindow, "Leaderboard");
}
if (!isLoggedIn)
{
showLeaderboard = false;
currentScore = 0;
}
else
{
GUI.Box(new Rect(Screen.width / 2 - 65, 5, 120, 25), currentScore.ToString());
if (GUI.Button(new Rect(5, 60, 100, 25), "Leaderboard"))
{
showLeaderboard = !showLeaderboard;
if (!isWorking)
{
StartCoroutine(GetLeaderboard());
}
}
}
وأخيرًا، سيتم إلغاء Update()، والذي سيحتوي على الكود المسؤول عن إرسال نتيجة اللاعب، بمجرد تغييره. أضف الكود أدناه في بداية البرنامج النصي بعد كل المتغيرات:
//Leaderboard
void Update()
{
if (isLoggedIn)
{
//Submit score if it was changed
if (currentScore != previousScore && !submittingScore)
{
if(submitTimer > 0)
{
submitTimer -= Time.deltaTime;
}
else
{
previousScore = currentScore;
StartCoroutine(SubmitScore(currentScore));
}
}
else
{
submitTimer = 3; //Wait 3 seconds when it's time to submit again
}
//**Testing** Increase score on key press
if (Input.GetKeyDown(KeyCode.Q))
{
currentScore += 5;
}
}
}
لاحظ الجزء **Testing**، نظرًا لعدم وجود لعبة قابلة للعب، فإننا ببساطة نزيد النتيجة بالضغط على Q (يمكنك إزالتها لاحقًا إذا كان لديك بالفعل لعبة بنظام تسجيل، على سبيل المثال. جمع قطعة نقدية +1 نقطة، الخ.)
عندما تضغط على تشغيل وتسجيل الدخول، يجب أن تلاحظ عنصرين جديدين: الزر 'Leaderboard' وقيمة النتيجة في أعلى الشاشة.
ننتقل الآن إلى إنشاء جدول MySQL.
إنشاء جدول MySQL
سيتم تخزين نتائج المستخدم في جدول MySQL منفصل.
- تسجيل الدخول إلى لوحة التحكم CPanel
- انقر على "phpMyAdmin" ضمن قسم قواعد البيانات
- انقر فوق قاعدة البيانات التي قمت بإنشائها في البرنامج التعليمي السابق ثم انقر فوق علامة التبويب SQL
- الصق الكود أدناه في محرر الاستعلام ثم انقر فوق "Go"
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
--
-- Table structure for table `sc_user_scores`
--
CREATE TABLE `sc_user_scores` (
`row_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`user_score` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
--
-- Indexes for table `sc_user_scores`
--
ALTER TABLE `sc_user_scores`
ADD PRIMARY KEY (`row_id`),
ADD UNIQUE KEY `user_id` (`user_id`);
--
-- AUTO_INCREMENT for table `sc_user_scores`
--
ALTER TABLE `sc_user_scores`
MODIFY `row_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
COMMIT;
سيؤدي الاستعلام أعلاه إلى إنشاء جدول جديد يسمى 'sc_user_scores' والذي سيخزن أعلى الدرجات مع user_id كمرجع للجدول 'sc_users' الرئيسي.
الجزء الأخير هو تطبيق المنطق من جانب الخادم.
تنفيذ المنطق من جانب الخادم
سيتألف المنطق من جانب الخادم من نصوص PHP التي ستكون مسؤولة عن استلام/تخزين النتائج واسترداد لوحة المتصدرين.
النص الأول هو score_submit.php.
- قم بإنشاء برنامج PHP جديد والصق الكود أدناه بداخله:
Score_submit.php
<?php
if(isset($_POST["email"]) && isset($_POST["username"]) && isset($_POST["score"])){
$errors = array();
$email = $_POST["email"];
$username = $_POST["username"];
$submitted_score = intval($_POST["score"]);
$user_id = -1;
$current_highscore = -1;
//Connect to database
require dirname(__FILE__) . '/database.php';
//Check if the user already registered, retrieve its user_id and score value (if exist)
if ($stmt = $mysqli_conection->prepare("SELECT u.user_id,
(SELECT user_score FROM sc_user_scores WHERE user_id = u.user_id LIMIT 1) as user_score
FROM sc_users u WHERE u.email = ? AND u.username = ? LIMIT 1")) {
/* bind parameters for markers */
$stmt->bind_param('ss', $email, $username);
/* execute query */
if($stmt->execute()){
/* store result */
$stmt->store_result();
if($stmt->num_rows > 0){
/* bind result variables */
$stmt->bind_result($user_id_tmp, $score_tmp);
/* fetch value */
$stmt->fetch();
$user_id = $user_id_tmp;
$current_highscore = $score_tmp;
}else{
$errors[] = "User not found.";
}
/* close statement */
$stmt->close();
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
$errors[] = "Something went wrong, please try again.";
}
//Submit new score
if(count($errors) == 0){
if(is_null($current_highscore) || $submitted_score > $current_highscore){
if(is_null($current_highscore)){
//Insert new record
if ($stmt = $mysqli_conection->prepare("INSERT INTO sc_user_scores (user_id, user_score) VALUES(?, ?)")) {
/* bind parameters for markers */
$stmt->bind_param('ii', $user_id, $submitted_score);
/* execute query */
if($stmt->execute()){
/* close statement */
$stmt->close();
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
//Update existing record
if ($stmt = $mysqli_conection->prepare("UPDATE sc_user_scores SET user_score = ? WHERE user_id = ? LIMIT 1")) {
/* bind parameters for markers */
$stmt->bind_param('ii', $submitted_score, $user_id);
/* execute query */
if($stmt->execute()){
/* close statement */
$stmt->close();
}else{
$errors[] = "Something went wrong, please try again.";
}
}else{
$errors[] = "Something went wrong, please try again.";
}
}
}else{
$errors[] = "Submitted score is lower than the current highscore, skipping...";
}
}
if(count($errors) > 0){
echo $errors[0];
}else{
echo "Success";
}
}else{
echo "Missing data";
}
?>
النص الأخير هو leaderboard.php.
- قم بإنشاء برنامج PHP جديد والصق الكود أدناه بداخله:
المتصدرين.php
<?php
//Retrieve our score along with leaderboard
if(isset($_POST["email"]) && isset($_POST["username"])){
$returnData = array();
$email = $_POST["email"];
$username = $_POST["username"];
//Connect to database
require dirname(__FILE__) . '/database.php';
//Get our score and rank
$returnData[] = "User";
if ($stmt = $mysqli_conection->prepare("SELECT us.user_score,
(SELECT COUNT(row_id) FROM sc_user_scores WHERE user_score >= us.user_score LIMIT 1) as rank
FROM sc_user_scores us
WHERE us.user_id = (SELECT user_id FROM sc_users WHERE email = ? AND username = ? LIMIT 1) LIMIT 1")) {
/* bind parameters for markers */
$stmt->bind_param('ss', $email, $username);
/* execute query */
if($stmt->execute()){
/* store result */
$stmt->store_result();
if($stmt->num_rows > 0){
/* bind result variables */
$stmt->bind_result($score_tmp, $user_rank);
/* fetch value */
$stmt->fetch();
//Append
$returnData[0] .= "," . $score_tmp . "," . $user_rank;
}
/* close statement */
$stmt->close();
}
}
//Get top 100 players
if ($stmt = $mysqli_conection->prepare("SELECT u.username, us.user_score
FROM sc_users u RIGHT JOIN sc_user_scores us ON u.user_id = us.user_id
WHERE u.user_id IS NOT NULL ORDER BY us.user_score DESC LIMIT 100")) {
/* execute query */
if($stmt->execute()){
$result = $stmt->get_result();
while ($row = $result->fetch_assoc())
{
$returnData[] = $row["username"] . "," . $row["user_score"];
}
/* close statement */
$stmt->close();
}
}
//The returned string will use '|' symbol for separation between player data and ',' for separation inside the player data
echo implode('|', $returnData);
}else{
echo "Missing data";
}
?>
- قم بتحميل كل من Score_submit.php وleaderboard.php إلى نفس المجلد الذي قمت بتحميل نصوص PHP النصية فيه من البرنامج التعليمي السابق.
بعد إعداد كل شيء، عند النقر على لوحة المتصدرين، يجب تحميل درجاتك/تصنيفك مع أفضل 100 لاعب بناءً على نتائجهم: