STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • 0
    • Sao chép

    Lưu Trữ Thông Tin Game với PlayerPrefs

    Hướng dẫn sử dụng và thao tác với class PlayerPrefs trong Unity để lưu thông tin và trạng thái trong game.
    12/03/2016
    25/09/2020
    6 phút đọc
    Lưu Trữ Thông Tin Game với PlayerPrefs

    Lưu điểm số, thông tin của game hay trạng thái lần chơi gần nhất là một điều quan trọng trong bất kì game nào. Người chơi không muốn mỗi lần chơi game ra phải chơi lại từ đầu giống như lúc vừa cài đặt, chơi lại từng màn đã qua.

    Unity hỗ trợ sẵn tính năng lưu lại thông tin và trạng thái trong game thông qua lớp PlayerPrefs. Bài viết này sẽ hướng dẫn cách thao tác với PlayerPrefs để thực hiện tính năng "save game" với Unity.

    Lưu trạng thái game

    PlayerPrefs hỗ trợ lưu trữ 3 kiểu dữ liệu cơ bản: Int, Float, và String.

    Tương ứng với 3 phương thức là SetInt, SetFloat, SetString.

    Cả 3 phương thức này đều nhận vào:

    • 2 tham số trong đó tham số đầu tiên là tên đại điện cho giá trị được lưu trữ.
    • Tham số còn lại là nội dung cần lưu trữ.

    Cần ghi nhớ key này để có thể lấy lại được nội dung đã lưu trữ về sau.

    Mỗi khi thực hiện các hàm set thì dữ liệu chỉ thực sự được lưu xuống đĩa khi gọi hàm Save().

    Dưới đây là cách dùng PlayerPrefs để lưu thông tin người chơi.

    PlayerPrefs.SetString("username", "PhamNgocPhuoc");
    PlayerPrefs.SetString("password", "stdio1235");
    PlayerPrefs.SetInt("level", 10);

    Truy xuất thông tin

    Sau khi đã sử dụng PlayerPrefs để lưu trữ thông tin, sử dụng các phương thức GetInt, GetFloat, GetString để truy xuất các nội dụng đã lưu trữ.

    Cũng giống như các phương thức Set ở trên, khi dùng các phương thức Get phải lựa chọn hàm tương ứng với kiểu dữ liệu đã ghi trước đó.

    Các hàm Get(X) nhận vào 1 tham số là tên của key và có kiểu trả về X (với XInt, Float hoặc String).

    Truy xuất các thông số đã lưu trữ ở trên như sau:

    String _userName = PlayerPrefs.GetString("username");
    String _password = PlayerPrefs.GetString ("password");
    Int _level = PlayerPrefs.GetInt("level");
    

    Nếu truyền vào 1  Key chưa tồn lại, ứng mỗi phương thức Get sẽ trả về cho 1 giá trị mặc định.

    • GetString thì giá trị đó là 1 chuỗi trỗng "".
    • GetFloat0.0f.
    • GetInt0.

    Một số phương thức hỗ trợ

    DeleteAll Xóa tất cả các key và giá trị đã được lưu trữ.
    DeleteKey Xóa 1 key cụ thể.
    GetFloat Trả về giá trị float tương ứng với key nếu key tồn tại.
    GetInt Trả về giá trị int tương ứng với key nếu key tồn tại.
    GetString Trả về giá trị string tương ứng với key nếu key tồn tại.
    HasKey Trả về true nếu key tồn tại.
    Save Lưu trữ tất cả dữ liệu được chỉnh sửa xuống đĩa.
    SetFloat  Lưu giá trị float theo key vào bộ nhớ chính.
    SetInt Lưu giá trị int theo key vào bộ nhớ chính.
    SetString Lưu giá trị string theo key vào bộ nhớ chính.

    Đường dẫn tệp tin lưu trữ

    Nơi lưu trữ dữ liệu của PlayerPrefs ở các nền tảng khác nhau:

    • Mac OS: thư mục ~/Library/Preferences trong tập tin unity.[company name].[product name].plist.
    • Windows: lưu trữ ở registry dưới đường dẫn HKCU\Software\[company name]\[product name].
    • Linux: lưu trữ ở đường dẫn ~/.config/unity3d/[CompanyName]/[product name].
    • Windows Store Apps: %userprofile%\AppData\Local\Packages\[ProductPackageId]>\LocalState\playerprefs.dat.
    • WebPlayer: PlayerPrefs được lưu trữ trong tệp tin nhị phân với đường dẫn:
      • Mac OS X: ~/Library/Preferences/Unity/WebPlayerPrefs/
      • Windows: %APPDATA%\Unity\WebPlayerPrefs/

    Bảo mật

    Nếu truy cập vào trong đường dẫn lưu trữ PlayerPrefs thì có thể nhận thấy rằng các thông tin lưu trữ trong đó đều ở dạng nguyên gốc như lúc truyền vào. Điều này làm cho các thông tin này dễ dàng bị sửa đổi bất hợp pháp dẫn đến sai lệch thông tin của game hay đánh cắp thông tin người dùng (username, password, email, ...).

    Dưới đây là màn chơi của game AngryBird được viết bằng Unity trong đó giá trị High Score được dùng để đánh dấu lại số điểm cao nhất từng đạt được của màn chơi đó sử dụng PlayerPrefs và thông tin mà PlayerPrefs lưu trữ. Giá trị này có thể dễ dàng được thay đổi bằng tay và dẫn đến game cũng bị ảnh hưởng theo.

    Giá trị High Score trước khi bị chỉnh sửa:

    lưu trữ thông tin game với playerprefs

    Nơi lưu trữ giá trị High Score trên môi trường Windows:

    Lưu trữ thông tin game với playerprefs

    Giá trị High Score sau khi đã chỉnh sửa:

    Lưu trữ thông tin game với playerprefs

    Để hạn chế điều này có thể sử dụng các phương thức Encrypt hoặc Decrypt có sẵn trong C# để mã hóa dữ liệu trước khi lưu trữ xuống.

    Bài viết hiện thực đơn giản 1 lớp dùng cho việc mã hoá và giải mã tập tin như sau:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace EncryptStringSample
    {
        public static class StringCipher
        {
            // This constant string is used as a "salt" value for the PasswordDeriveBytes function calls.
            // This size of the IV (in bytes) must = (keysize / 8).  Default keysize is 256, so the IV must be
            // 32 bytes long.  Using a 16 character string here gives us 32 bytes when converted to a byte array.
            private static readonly byte[] initVectorBytes = Encoding.ASCII.GetBytes("tu89geji340t89u2");
    
            // This constant is used to determine the keysize of the encryption algorithm.
            private const int keysize = 256;
    
            public static string Encrypt(string plainText, string passPhrase)
            {
                byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
                using (PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
                {
                    byte[] keyBytes = password.GetBytes(keysize / 8);
                    using (RijndaelManaged symmetricKey = new RijndaelManaged())
                    {
                        symmetricKey.Mode = CipherMode.CBC;
                        using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes))
                        {
                            using (MemoryStream memoryStream = new MemoryStream())
                            {
                                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                                {
                                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                                    cryptoStream.FlushFinalBlock();
                                    byte[] cipherTextBytes = memoryStream.ToArray();
                                    return Convert.ToBase64String(cipherTextBytes);
                                }
                            }
                        }
                    }
                }
            }
    
            public static string Decrypt(string cipherText, string passPhrase)
            {
                byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
                using(PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null))
                {
                    byte[] keyBytes = password.GetBytes(keysize / 8);
                    using(RijndaelManaged symmetricKey = new RijndaelManaged())
                    {
                        symmetricKey.Mode = CipherMode.CBC;
                        using(ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes))
                        {
                            using(MemoryStream memoryStream = new MemoryStream(cipherTextBytes))
                            {
                                using(CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                                {
                                    byte[] plainTextBytes = new byte[cipherTextBytes.Length];
                                    int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                                    return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    Cách sử dụng và thao tác với lớp StringCipher:

    using System;
    using System.Linq;
    
    namespace EncryptStringSample
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Please enter a password to use:");
                string password = Console.ReadLine();
                Console.WriteLine("Please enter a string to encrypt:");
                string plaintext = Console.ReadLine();
                Console.WriteLine("");
    
                Console.WriteLine("Your encrypted string is:");
                string encryptedstring = StringCipher.Encrypt(plaintext, password);
                Console.WriteLine(encryptedstring);
                Console.WriteLine("");
    
                Console.WriteLine("Your decrypted string is:");
                string decryptedstring = StringCipher.Decrypt(encryptedstring, password);
                Console.WriteLine(decryptedstring);
                Console.WriteLine("");
    
                Console.ReadLine();
            }
        }
    }

    Áp dụng mã hóa đối với trường hợp phía trên, lúc này giá trị HighScore sẽ được mã hóa thành một chuỗi kí tự không quy tắc.

    Lưu trữ thông tin game với playerprefs

    Chuỗi ký tự này có thể đảm bảo thông tin không bị đánh cắp hoặc chỉnh sửa trái phép nhưng chỉ ở mức tương đối an toàn. Các hacker vẫn có thể phát hiện ra thuật toán mã hóa đang dùng, mã hóa 1 chuỗi kết quả khác tương tự và thay thế vào đó. Nhưng dù sao thì đây vẫn là 1 cách tương đối tốt để tự bảo mật dữ liệu cho game.

    0
    Lập Trình Game

    Lập Trình Game

    Kiến thức, kỹ thuật, kinh nghiệm lập trình game.

    Khi bạn nhấn vào liên kết sản phẩm do STDIO đề xuất và mua hàng, STDIO có thể nhận được hoa hồng. Điều này hỗ trợ STDIO tạo thêm nhiều nội dung hữu ích.. Tìm hiểu thêm.

    Đề xuất

    Hiện Thực Game Zero Với Unity - Phần 4 - Scene Và Popup
    Hướng Dẫn Hiện Thực Game Zero Với Unity. Thiết kế hệ thống scene và ...
    Phát Triển Game Funny Halloween Pumpkins với Cocos2d-x - Phần 1
    Hướng dẫn làm game cụ thể bằng Cocos2d-x với code mẫu và game mẫu.

    Khám phá

    Giới Thiệu Thị Trường Tiền Điện Tử Và Công Nghệ Lưu Trữ
    Trình bày tổng quát về đồng tiền điện tử, mô hình giao dịch, công nghệ ...
    Đọc và Ghi File trong Python
    Đọc và ghi file text với Python thông qua code ví dụ với các mode cơ bản ...
    28/03/2015
    Hiện Thực Game Zero Với Unity - Phần 3 - Điểm Số Và Progress Timer
    Hướng Dẫn Hiện Thực Game Zero Với Unity. Hướng dẫn cài đặt tính năng ...
    Lưu Trữ Dữ Liệu trong Android với Unity
    Hướng dẫn đọc và ghi file trên Android với đường dẫn ...
    Tạo High Score với Cocos2d-x 3.x.x
    Bài viết hướng dẫn lưu dữ liệu với các kiểu interger, float, double hay ...
    Hành Trình của Một Gói Tin
    Cách một gói tin được tạo ra và truyền đi trên mạng Internet theo mô ...
    Tín Hiệu Số Và Tương Tự - Analog/Digital
    Trong ngành điện tử nói chung và trong lập trình vi điểu khiển nói ...
    Tìm Hiểu về fstream
    Kiến thức về file là một trong những kiến thức quan trọng đối với các ...
    11/05/2015
    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020