Unity Çevrimiçi Skor Tablosu Eğitimi
Bu eğitimde Unity'te oyununuzda çevrimiçi skor tablosunu nasıl uygulayacağınızı göstereceğim.
Bu önceki eğitimin devamı niteliğindedir: Unity PHP ve MySQL ile Oturum Açma Sistemi.
Liderlik tablosuna sahip olmak, oyununuza rekabet gücü katarak tekrar oynanabilirliği artırmanın harika bir yoludur.
Daha önce olduğu gibi, bu eğitimde cPanel'in yanı sıra PHP ve MySQLi (MySQL'in geliştirilmiş bir sürümü) içeren bir sunucu gerekir.
Uygun fiyatlı premium VPS barındırma veya daha ucuz Paylaşılan Barındırma alternatifini kontrol etmekten çekinmeyin.
Öyleyse devam edelim!
Mevcut komut dosyasında değişiklik yapma
Yukarıdaki eğitimi izlediyseniz artık 'SC_LoginSystem' adında bir komut dosyasına sahip olursunuz. Liderlik tablosu özelliğini bazı kodlar ekleyerek hayata geçireceğiz.
- 'SC_LoginSystem' betiğini açın
İlk olarak gerekli değişkenleri ekleyerek başlıyoruz:
//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;
NOT: currentScore değişkeni oyunda oyuncu puanlarını takip etmek için kullanacağınız değişkendir. Bu değer sunucu'e gönderilecek ve veritabanında saklanacaktır; bilgisayar korsanlığına karşı koruma sağlamak için bu değerin obfuscate ayarlanması önerilir.
Daha sonra, puanların gönderilmesinden ve skor tablosunun alınmasından sorumlu olacak 2 Numaralandırıcı ekliyoruz. Aşağıdaki kodu, son parantez kapatılmadan önce betiğin sonuna ekleyin:
//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;
}
Sırada liderlik tablosu kullanıcı arayüzü var. void OnGUI()'den sonra aşağıdaki kodu ekleyin:
//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();
}
}
Aşağıdaki kodu void OnGUI() içine ekleyin (kapanış parantezinden önce):
//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());
}
}
}
Ve son olarak, değiştiğinde oyuncu puanını göndermekten sorumlu bir kod içeren void Update(). Tüm değişkenlerden sonra betiğin başına aşağıdaki kodu ekleyin:
//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;
}
}
}
**Test** kısmına dikkat edin, oynanabilir bir oyunumuz olmadığından, Q tuşuna basarak puanı artırıyoruz (Puanlama sistemine sahip bir oyununuz varsa daha sonra kaldırabilirsiniz, örn.). jeton +1 puan vb. toplayın)
Oynat tuşuna bastığınızda ve giriş yaptığınızda 2 yeni öğeyi fark edeceksiniz: 'Leaderboard' düğmesi ve ekranın üst kısmındaki Puan değeri.
Şimdi MySQL tablosu oluşturmaya geçiyoruz.
MySQL tablosu oluşturma
Kullanıcı puanları ayrı bir MySQL tablosunda saklanacaktır.
- CPanel'e giriş yapın
- VERİTABANLARI bölümünde "phpMyAdmin" seçeneğine tıklayın
- Önceki eğitimde oluşturduğunuz veritabanına tıklayın ve ardından SQL sekmesine tıklayın.
- Aşağıdaki kodu sorgu düzenleyicisine yapıştırın ve ardından tıklayın. "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;
Yukarıdaki sorgu, ana 'sc_users' tablosuna referans olarak user_id ile birlikte en yüksek puanları saklayacak 'sc_user_scores' adında yeni bir tablo oluşturacaktır.
Son kısım sunucu tarafı mantığının uygulanmasıdır.
Sunucu tarafı mantığını uygulama
Sunucu tarafı mantığı, puanların alınmasından/saklanmasından ve sıralama tablosunun alınmasından sorumlu olacak PHP komut dosyalarından oluşacaktır.
İlk komut dosyası score_submit.php'dir.
- Yeni bir PHP betiği oluşturun ve içine aşağıdaki kodu yapıştırın:
skor_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";
}
?>
Son komut dosyası leaderboard.php'dir.
- Yeni bir PHP betiği oluşturun ve içine aşağıdaki kodu yapıştırın:
lider tablosu.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";
}
?>
- Hem Score_submit.php'yi hem de Leaderboard.php'yi önceki eğitimde PHP betiklerini yüklediğiniz klasöre yükleyin.
Her şey ayarlandıktan sonra Liderlik Tablosu'na tıkladığınızda puanınız/sıralamanız, puanlarına göre en iyi 100 oyuncuyla birlikte yüklenecektir: