-
hainv
9-Slice Trimmer là package để optimize Sprite hỗ trợ 9-Slice
Để mở cửa sổ 9-Slice Trimmer. Chọn KH-Tools/Nine-Slice Trimmer trên thanh Menu
Cửa sổ của tool như sau:
Hướng dẫn sử dụng:
Bước 1: Chọn ảnh cần cắt và config vị trí cần slice
Bước 2: Bật Read/Write option và Apply
Bước 3: Kéo Sprite vào Sprite Texture trong tool
Bước 4: Bấm Preview để kiểm tra ảnh sau khi cắt đã đúng chưa
Bước 5: Bấm Trim & Save để cắt Sprite
Bước 6: Tắt Read/Write trong ảnh vừa tạo
Ảnh mới nhận được
Tài liệu tham khảo thêm: https://github.com/KingHipUnity/Unity-NineSliceTrimmer/blob/main/README.md
-
hainv
Viết thêm Cheat vào file CheatMethodHandle.cs
Quy tắc đặt tên Cheat mới_<Section> _<Tên Cheat>
trong đó các Cheat có cùng Section sẽ được gộp vào chung 1 mụcCheat hỗ trợ 2 loại hàm void và biến static bool
ví dụpublic void _MS2_ShowLog() { Debug.Log("MS2 Show Log Clicked"); } public static bool _IsDemoBool { get { return PlayerPrefs.GetInt("DebugKey_IsDemoBool", 0) == 1; } set { PlayerPrefs.SetInt("DebugKey_IsDemoBool", value ? 1 : 0); } }
Để sử dụng Cheat, bấm vào button đầu khỉ ở ngoài màn hình
Click vào Section để mở ra các Cheat trong cùng 1 section
Click vào từng Cheat để thực hiện hàm cheat -
hainv
Script Build được viết trong File MKBuild.cs
-
Đối với build bằng Unity Editor. Chọn Build trên thanh menu và chọn mục cần build
Sau khi build xong output file sẽ ở folder Build ( ngang hàng với Folder Assets )
Định dạng file APK: Android_yyyyMd_Hm.apk -
Đối với sử dụng trong pipeline CI/CD
Sử dụng Command:
<Path To Unity Editor> -projectPath <Path To Project> -executeMethod Monkey.BuildTool.Editor.MKBuild.Build -outputPath <Path Output> -buildPlatform <Platform> -isProd true -batchmode -quit
Platform: bao gồm: Android, iOS
isProd: true hoặc false
Ví dụ
/Applications/Unity/Hub/Editor/2022.3.57f1/Unity.app/Contents/MacOS/Unity -projectPath /Users/monkey/Workspace/monkeyx_ci/monkey_story_2 -executeMethod Monkey.BuildTool.Editor.MKBuild.Build -buildPlatform iOS -isProd true -outputPath /Users/monkey/Workspace/monkeyx_ci/build/ios -batchmode -quit
-
-
hainv
Các bước thực hiện để có thể test game bằng Game Tool
Bước 1: Xoá các thành phần không cần thiết trong game nếu có
EventSystem, SoundManager, AudioListener đã được load trong Game Tool nên không cần để trong scene game.Bước 2: Gán Addressable cho Scene game
2.1: Mở cửa sổ Addressables Groups bằng cách sau:
2.2: Kéo Scene game vào group Games trong Addressable
2.3: Chuột phải vào Addressable vừa kéo chọn Simplify Addressable Name
Bước 3: Thêm Game Config trong File GameConfigSO trong đường dẫn: Assets/5.Manager/GameTool/Data
ở mục Addressable chọn scene vừa tạo
Bước 4: Chạy Scene GameTool và test lại.
-
hainv
Hướng Dẫn Quy Tắc Sử Dụng Git Trong Unity Project
1. Quy tắc đặt tên Branch
Việc đặt tên branch có hệ thống giúp quản lý dễ dàng hơn và tránh nhầm lẫn trong quá trình phát triển. Dưới đây là quy tắc đặt tên branch áp dụng cho dự án Unity:
1.1. Các loại branch chính
- main: Chứa phiên bản ổn định của dự án, chỉ merge code đã kiểm thử kỹ lưỡng.
- develop: Nhánh chính để phát triển, nơi tập hợp các tính năng trước khi merge vào
main
. - [user]/feature/: Dành cho các tính năng mới.
- [user]/bugfix/: Dành cho các sửa lỗi.
- [user]/hotfix/: Sửa lỗi khẩn cấp trên
main
.
1.2. Cách đặt tên branch
Khi dự án có nhiều thành viên, mỗi người nên có namespace riêng để dễ dàng xác định ai đang làm việc trên nhánh nào.
Cấu trúc chung:
[tên-thành-viên]/[loại-branch]/[mô-tả-ngắn-gọn]
Ví dụ:
hainv/feature/weapon-system
hainv/bugfix/fix-ui-button
hainv/hotfix/crash-loading-screen
Việc sử dụng tên thành viên giúp dễ dàng theo dõi ai chịu trách nhiệm cho từng nhánh và tránh trùng lặp tên branch.
2. Quy tắc Commit
Commit nên rõ ràng, ngắn gọn và có ý nghĩa để dễ theo dõi lịch sử thay đổi.
Chỉ commit những file mà mình thay đổi
2.1. Cấu trúc commit message
[Loại commit]: [Mô tả ngắn gọn] [Giải thích chi tiết (nếu cần)]
Loại commit phổ biến:
feat
: Thêm tính năng mớifix
: Sửa lỗirefactor
: Cải tiến code không làm thay đổi tính năngdocs
: Cập nhật tài liệustyle
: Thay đổi không ảnh hưởng logic (format, tab, dấu cách)
Ví dụ:
feat: Thêm hệ thống quản lý vũ khí - Thêm cơ chế trang bị vũ khí - Thêm animation thay đổi vũ khí
fix: Sửa lỗi nhân vật không thể nhảy khi đang chạy - Cập nhật input system - Điều chỉnh logic kiểm tra trạng thái nhân vật
3. Merge Flow
Việc merge code cần tuân theo một quy trình nhất định để tránh lỗi và đảm bảo tính ổn định.
3.1. Quy trình Merge
- Tạo branch mới từ
develop
hoặcmain
trong trường hợp hotfix. - Commit & Push: Sau khi hoàn thành công việc, commit code và push lên remote repository.
- Tạo Pull Request (PR): Yêu cầu merge vào
develop
hoặcmain
. - Code Review: Thành viên nhóm kiểm tra code và đưa ra phản hồi.
- Fix review (nếu có): Chỉnh sửa theo góp ý.
- Merge: Gộp commit nếu cần trước khi merge vào nhánh chính.
- Xóa branch (sau 3 bản release, branch của thành viên nào thì thành viên đó sẽ chịu trách nhiệm xoá branch của mình).
3.2. Các quy tắc khi Merge
- Chỉ merge vào
main
từdevelop
hoặchotfix/*
. - Các tính năng mới nên merge vào
develop
trước khi lênmain
. - Không merge trực tiếp vào
main
. - Luôn đảm bảo code đã được test kỹ trước khi merge.
4. Lưu ý Khi Dùng Git Trong Unity
- Sử dụng
.gitignore
: Yêu cầu file.gitignore
có các mục nhưLibrary/
,Temp/
,Logs/
,*.csproj
,*.unitypackage
,*.sln
,*.userprefs
để tránh đẩy file không cần thiết lên repository. - Tránh merge conflict: Luôn pull bản mới nhất trước khi làm việc để tránh xung đột.
- Commit thường xuyên: Giúp theo dõi tiến trình dễ dàng và giảm thiểu mất mát dữ liệu.
Tài liệu này giúp chuẩn hóa quy trình làm việc với Git trong dự án Unity, giúp nhóm làm việc hiệu quả và giảm thiểu lỗi khi quản lý mã nguồn.
-
hainv
Coding Convention cho Unity - C#
1. Quy tắc đặt tên (Naming Conventions)
1.1 Biến và hằng số
- Biến cục bộ (Local variables): sử dụng camelCase, bắt buộc có access modifier.
private int playerScore; protected float moveSpeed;
- Biến thành viên (Fields):
- Luôn có access modifier, không dùng
_
trước biếnprivate
.
private int health;
- Nếu là
public
,protected
dùng PascalCase và bắt buộc quy định{ get; set; }
.
public int MaxHealth { get; set; } [SerializeField] private float moveSpeed;
- Luôn có access modifier, không dùng
- Hằng số: Dùng toàn bộ chữ hoa với
_
giữa các từ.public const float GRAVITY = 9.81f; private readonly int MAX_LIVES = 3;
1.2 Hàm và phương thức (Methods)
- Dùng PascalCase.
void MovePlayer(); int CalculateScore();
1.3 Class, Struct và Interface
- Class & Struct: PascalCase.
public class PlayerController {} public struct PlayerStats {}
- Interface: Bắt đầu với chữ
I
, dùng PascalCase.public interface IDamageable {}
1.4 Namespace
- Dùng PascalCase, nên có cấu trúc theo thư mục.
namespace Game.Core {} namespace Game.UI {}
1.5 Enum
- Dùng PascalCase và gán giá trị mặc định.
public enum GameState { Idle = 0, Playing = 1, Paused = 2, GameOver = 3 }
2. Quy tắc định dạng mã (Formatting)
2.1 Dấu ngoặc nhọn
{}
- Mở dấu
{
trên cùng dòng với khai báo.if (isRunning) { Run(); }
- Với khối code một dòng, luôn sử dụng
{}
.if (isJumping) { Jump(); }
2.2 Khoảng trắng
- Dùng 2 dấu cách (không dùng tab).
- Giữa các toán tử, thêm khoảng trắng.
int sum = a + b;
- Không có khoảng trắng trước dấu
(
trong phương thức.void Attack(int damage) {}
3. Quy tắc tổ chức mã (Code Organization)
3.1 Thứ tự trong Class
- Fields
- Properties
- Unity Methods (Start, Update, FixedUpdate, LateUpdate, ...)
- Methods (Public → Private)
- Event Handlers
Ví dụ:
public class Player : MonoBehaviour { // Fields private int health; // Properties public int Health { get; set; } // Unity Methods private void Start() { Debug.Log("Game Started"); } private void Update() { Move(); } // Methods public void TakeDamage(int amount) { health -= amount; } }
3.2 Quy tắc sử dụng MonoBehaviour
- Tránh sử dụng
Find()
,FindObjectOfType()
trongUpdate()
vì hiệu suất kém. - Dùng
SerializeField
thay vìpublic
cho biến cần hiển thị trên Inspector.
4. Bình luận và Tài liệu (Comments & Documentation)
- Sử dụng
///
để thêm mô tả.
/// <summary> /// Di chuyển người chơi theo hướng chỉ định. /// </summary> /// <param name="direction">Hướng di chuyển.</param> public void Move(Vector3 direction) {}
- Chỉ bình luận những đoạn code khó hiểu hoặc cần giải thích.
// Giảm máu của người chơi khi bị tấn công health -= damage;
5. Xử lý sự kiện và delegate
- Tên event dùng PascalCase, có hậu tố
Event
.
public event Action OnPlayerDeathEvent;
- Khi gọi event, kiểm tra
null
.
OnPlayerDeathEvent?.Invoke();
6. Sử dụng ScriptableObject
- Dùng
ScriptableObject
để lưu dữ liệu chung thay vìSingleton
.
[CreateAssetMenu(fileName = "GameSettings", menuName = "Game/GameSettings")] public class GameSettings : ScriptableObject { public float volume; public int maxEnemies; }
7. Best Practices
- Sử dụng
readonly
hoặcconst
cho các biến không thay đổi. - Tránh sử dụng
static
trừ khi cần thiết. - Tránh sử dụng
string
so sánh trực tiếp (==
), thay vào đó dùngenum
hoặcnameof
. - Sử dụng
Linq
cẩn thận, tránh dùng trongUpdate()
. - Luôn kiểm tra
null
trước khi truy cập đối tượng. - Sử dụng LogMe thay vì Debug
8. Hướng dẫn import Convention Rule cho Visual Studio 2019 và Rider
Visual Studio 2019
- Mở Visual Studio 2019.
- Vào
Tools
→Options
. - Chọn
Text Editor
→C#
→Code Style
. - Chỉnh sửa theo quy tắc đặt tên và format đã đề cập.
- Lưu lại và áp dụng.
Rider
- Mở Rider.
- Vào
File
→Settings
. - Chọn
Editor
→Code Style
→C#
. - Cấu hình quy tắc đặt tên, format theo convention.
- Lưu lại và áp dụng.
Tài liệu này giúp duy trì mã nguồn thống nhất, dễ bảo trì và tối ưu hiệu suất trong Unity C#. Việc tuân theo coding convention sẽ giúp dự án của bạn dễ đọc, dễ mở rộng và chuyên nghiệp hơn.
- Biến cục bộ (Local variables): sử dụng camelCase, bắt buộc có access modifier.
-
hainv
Support Base for Monkey Junior 5.0
Core Structure:
Support System: Management of all the services
We implemented multiple Services to Support Monkey Junior 5.0How to use the Support System:
SupportSystem class is a Singleton class and DontDestroyOnScene Object.
Support System must attached to the GameObject and Execute before any class.
The services will automatically initialize.
To use the Service, follow the codeIDownloadService DownloadService = SupportSystem.Instance[SupportSystem.ServiceIDs.DownloadService] as IDownloadService;
Explanation:
IDownloadSerivce: Interface of Service
SupportSystem.ServiceIDs.DownloadService: Service type name
Services:
1. UpdateService: Manage the update method of the MonoBehaviour class
Based on the best practice: Update in every class is worse on the performance.
https://blog.unity.com/engine-platform/10000-update-calls
So Update Service is the solution for that:1.1. Sample:
using Monkey.Support; using UnityEngine; public class TestUpdateServiceScript : MonoBehaviour, IUpdate { public void OnDisable() { this.RemoveMe(); } public void OnEnable() { this.AddMe(); } public void UpdateMe() { Debug.Log("Update Me: " + Time.realtimeSinceStartup); } }
1.2. Explanation:
- The class that uses UpdateService must inherit IUpdate interface
- The UpdateMe method will be called every frame.
- UpdateService will work for both the MonoBehaviour class and the normal class.
- Manage list classes active in Update Service:
2. UserDataService: Manage the User Data, Profile Data, and Profile Setting of Users. To use UserDataService, call from Interface IUserDataService.
2.1. Interface:
public interface IUserDataService { /// <summary> /// Get Profile Data /// </summary> /// <returns>UserProfileModel</returns> public UserProfileModel GetProfile(); /// <summary> /// Get User Data /// </summary> /// <returns>UserModel</returns> public UserModel GetUser(); /// <summary> /// Get All Profile Settings /// </summary> /// <returns>List of ProfileSettingModel</returns> public List<ProfileSettingModel> GetProfileSettings(); /// <summary> /// Get Specific Profile Setting /// </summary> /// <param name="setting">Setting Name</param> /// <returns>ProfileSettingModel</returns> public ProfileSettingModel GetProfileSetting(string setting); }
2.2. Sample:
var userService = SupportSystem.Instance[SupportSystem.ServiceIDs.UserDataService] as IUserDataService; var user = userService.GetUser();
3. DataSyncService: Manage the Course Data, and Award Data (Pet Items, Sticker, Coin). To use UserDataService, call from Interface IDataSyncService.
3.1. Interface:public interface IDataSyncService { #region Data Course /// <summary> /// Get Lesson Data /// </summary> /// <param name="course">Course ID</param> /// <param name="lessonId">Lesson ID</param> /// <returns></returns> LessonReportDataSync GetLessonData(TYPE_COURSE course, string lessonId); /// <summary> /// Get Course Data /// </summary> /// <param name="course">Course ID</param> /// <returns></returns> DataCourseSyncModel GetCourseData(TYPE_COURSE course); /// <summary> /// Update Lesson Data /// </summary> /// <param name="course">Course ID</param> /// <param name="lesson">New Lesson Data</param> void UpdateLessonData(TYPE_COURSE course, LessonReportDataSync lesson); #endregion #region Pet&Award /// <summary> /// Get Current Coin /// </summary> /// <returns></returns> int GetCoin(); /// <summary> /// Set Coin Data /// </summary> /// <param name="coinChanged">Coin Changed</param> void SetCoin(int coinChanged); /// <summary> /// Get Theme Data /// </summary> /// <param name="themeId">Theme ID</param> /// <returns></returns> DataThemesModel GetTheme(string themeId); /// <summary> /// Add new Sticker /// </summary> /// <param name="themeId">Theme ID</param> /// <param name="stickerId">Sticker ID</param> void AddSticker(string themeId, int stickerId); /// <summary> /// Get All Pet Items /// </summary> /// <returns></returns> List<PetItem> GetPetItems(); /// <summary> /// Get List Used Pet Item /// </summary> /// <returns></returns> List<int> GetUsedItems(); /// <summary> /// Check Pet Item is Used /// </summary> /// <param name="itemId">Item ID</param> /// <returns></returns> bool IsUsedItem(int itemId); /// <summary> /// Get List New Pet Items /// </summary> /// <returns></returns> List<int> GetNewItems(); /// <summary> /// Check Pet Item is New /// </summary> /// <param name="itemId"></param> /// <returns></returns> bool IsNewItem(int itemId); /// <summary> /// Add a Pet Item /// </summary> /// <param name="ItemId">Item ID</param> /// <param name="isNew">Is tag New Item, for the default IsNew = false</param> void AddItem(int ItemId, bool isNew = false); /// <summary> /// Change Pet Item State: Used, Unuse /// </summary> /// <param name="ItemId">Item ID</param> /// <param name="isUsed">Is Item Used</param> void ChangeItemState(int ItemId, bool isUsed); #endregion }
3.2. Sample:
var syncData = SupportSystem.Instance[SupportSystem.ServiceIDs.DataSyncService] as IDataSyncService; syncData.GetCourseData(TYPE_COURSE.MJ5);
4. EventTrackingService: Send tracking, events, data to React Native. To use UserDataService, call from Interface IEventTrackingService.
4.1. Interface
public interface IEventTrackingService { /// <summary> /// Push Event to React Native to Tracking, Sync Data /// </summary> /// <param name="nameEvent">Event name</param> /// <param name="typeEvent">Event Type</param> /// <param name="properties">Properties</param> /// <param name="typeToPushEvent">Event Type: AWS, CLEVERTAP, AWS_AND_CLEVERTAP, AIRBRIDGE</param> void PushEvent(string nameEvent, string typeEvent, Dictionary<string, object> properties, TYPE_EVENT typeToPushEvent = TYPE_EVENT.AWS); }
4.2. Sample
var trackingService = SupportSystem.Instance[SupportSystem.ServiceIDs.EventTrackingService] as IEventTrackingService; Dictionary<string, object> properties = new Dictionary<string, object>() { { "completed", complete}, { "time_on_screeen", endTimeLesson - startTimeLesson}, { "age", UserManager.instance.currentProfile.Age} }; trackingService.PushEvent("mx_learn_AI_lesson", EnvironmentConfig.awsLearnLesson, properties, TYPE_EVENT.CLEVERTAP);
5. AddressableService: Download Game assets and course assets. To use UserDataService, call from Interface IAddressableService.
5.1. Interface
public interface IAddressableService { /// <summary> /// Download Addressable Group /// </summary> /// <param name="groupName">Group Name</param> /// <param name="callback">Callback when Download finished</param> /// <param name="progress">Callback the progress</param> /// <param name="total_retry">No need to change the value</param> /// <returns></returns> IEnumerator DownloadGroup(string groupName, Action<bool> callback, Action<float> progress = null, int total_retry = 0); void LoadAssets<T>(string asset_name, Action<AsyncOperationHandle<T>> callback) where T : UnityEngine.Object; /// <summary> /// Check when Addressable service ready /// </summary> /// <returns></returns> bool IsServiceActive(); }
5.2. Sample
var AddressableService = SupportSystem.Instance[SupportSystem.ServiceIDs.AddressableService] as IAddressableService; yield return new WaitUntil(() => AddressableService.IsServiceActive()); yield return AddressableService.DownloadGroup("lrc", (success)=> { Debug.Log("Download Success? " + success); }, (progress)=> { Debug.Log("Progress: " + progress); });
6. DownloadService: Manage the Download process for Assetbundle, words, and lesson data. To use DownloadService, call from Interface IDownloadService.
6.1. Interface
public interface IDownloadService { /// <summary> /// Download a file in the background. /// </summary> /// <param name="info"> Info item download </param> public void DownLoadFileInBackGround(ItemDownload info); /// <summary> /// Download list files in the background. /// </summary> /// <param name="list_info"> List info item download </param> /// <param name="sucessCallBack"> Call back when successful download </param> /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param> /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param> public void DownLoadListFileInBackGround(List<ItemDownload> list_info, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack); /// <summary> /// Download a file in the background by priority. /// </summary> /// <param name="info">Info item priority download</param> public void DownLoadFilePriority(ItemDownload info); /// <summary> /// Download list files in the background by priority. /// </summary> /// <param name="list_info"> List info item priority download </param> /// <param name="sucessCallBack"> Call back when successful download </param> /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param> /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param> public void DownLoadListFilePriority(List<ItemDownload> list_info, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack); /// <summary> /// Download all files bundle words in Lesson. /// </summary> /// <param name="idLesson"> Id of lesson </param> /// <param name="sucessCallBack"> Call back when successful download </param> /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param> /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param> public void DownLoadWordsInLesson(int idLesson, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack); /// <summary> /// DownLoad file addressable by name addressable /// </summary> /// <param name="nameAddressable"> Name of addressable </param> /// <param name="sucessCallBack"> Call back when successful download </param> /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param> /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param> public void DownLoadAddressable(string nameAddressable, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack); /// <summary> /// Get link host download file bundle word in course. /// </summary> /// <returns> Return link host link host download file bundle word </returns> public string GetLinkDownloadWord(); /// <summary> /// Get link host download file zip activity in course. /// </summary> /// <returns> Return link host link host download file zip activity </returns> public string GetLinkDownloadAct(); }
6.2. Sample
var downloadService = SupportSystem.Instance[SupportSystem.ServiceIDs.DownloadService] as IDownloadService; downloadService.GetLinkDownloadAct();
7. Popup Service: Manage the Popups in the game, Push and Pop the Popup on scene. To use PopupService, call from Interface IPopupService.
7.1. Interface
public interface IPopupService { /// <summary> /// Show popup by name class /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data"></param> /// <param name="showType"></param> /// <param name="actionShow"></param> /// <returns> return popup </returns> public T Show<T>(object data = null, ShowType showType = ShowType.DissmissCurrent, Action actionShow = null) where T : Panel; /// <summary> /// Close popup by name class /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data"></param> /// <param name="actHide"></param> public void Hide<T>(object data = null, Action actHide = null) where T : Panel; /// <summary> /// Close all popups /// </summary> /// <param name="actHideAll"></param> public void HideAll(Action actHideAll = null); }
7.2. Sample
public class PopupTestService : Panel { public override void Hide(object data = null, Action actionHide = null) { base.Hide(data, actionHide); } public override void Show(object data = null, bool duplicated = false, Action actionShow = null) { base.Show(data, duplicated, actionShow); } public void OnClickBtnClose() { Hide(null, () => { Debug.LogError("OnClickBtnClose"); }); } public void OnClickBtnOpenPopup2() { var popup = SupportSystem.Instance[SupportSystem.ServiceIDs.PopupService] as IPopupService; popup.Show<PopupTestService2>(null, PopupService.ShowType.NotHide); } }
8. Assetbundles Service: Manager the Asset Bundle and get data game. To use AssetbundlesService, call interface IAssetbundlesService..
8.1. Interface
public interface IAssetbundlesService { /// <summary> /// Get Data Game Primitive /// </summary> /// <param name="dictWordInforDetail"> Dictionary info word detail with key is link down load word and value is WordInforDetail </param> /// <param name="listWord"> List word model in file word.json </param> /// <returns> Dictionary<int, DataGamePrimitive> </returns> public Task<Dictionary<int, DataGamePrimitive>> GetDataGamePrimitive(Dictionary<string, WordInforDetail> dictWordInforDetail, List<ListWordModel> listWord); /// <summary> /// Get asset in bundle by type T /// </summary> /// <typeparam name="T"> Type asset </typeparam> /// <param name="bundle_name"> Name bundle </param> /// <param name="asset_name"> Name asset </param> /// <param name="local_path_file"> Path bundle in storage device </param> /// <param name="on_done"> Action invoke when get asset complete </param> /// <param name="on_error"> Action invoke when get asset fail </param> /// <returns> Asset with type T </returns> public Task<T> ResourceGetAssetInBundle<T>(string bundle_name, string asset_name, string local_path_file, string link_download, Action<object> on_done = null, Action<object> on_error = null) where T : UnityEngine.Object; }
8.2. Sample
var assetbundleService = SupportSystem.Instance[SupportSystem.ServiceIDs.AssetbundleService] as IAssetbundlesService; string linkBundle = "https://monkeymedia.vcdn.com.vn/App/uploads/course_install/bundle/hdr/ios/";//course.d.w_b; string linkWord = "https://vnmedia2.monkeyuni.net/App/zip/hdr/word_bundle/ios/";//course.d.w_b; string bundle_name = "course_install_ai_speaking_v2_78_1716429352.bundle"; string asset_name = "course_installation.json"; string local_path = $"{Ultis.persistentDataPath}/zips/{bundle_name}"; var json = await assetbundleService.ResourceGetAssetInBundle<TextAsset>(bundle_name, asset_name, local_path, linkBundle + bundle_name, (object d) => { Debug.LogError("Complete" + d?.ToString());}, (object d) => { Debug.LogError("Fail" + d?.ToString()); });