Phương pháp tách biệt View và Logic
Ý nghĩa của việc tách việt View và Logic.
Nhìn chung, giao diện người dùng (UI) của game thường rất phức tạp với nhiều yếu tố và trạng thái quan trọng. Hơn nữa, chúng còn sử dụng nhiều animation, đòi hỏi sự tinh chỉnh tỉ mỉ và thường xuyên phải làm lại do thay đổi yêu cầu.
Trong bối cảnh đó, để xây dựng UI một cách hiệu quả và dễ bảo trì, chúng ta cần phải xây dựng một workflow cho phép kiểm tra ngay lập tức các UI đã tạo, chỉnh sửa rồi lại kiểm tra.
Áp dụng điều này vào bối cảnh chuyển màn hình "out-game" (các phần ngoài gameplay chính như menu, shop...) điều đó có nghĩa là chúng ta cần xây dựng một môi trường cho phép dùng dữ liệu giả (mockup) để kiểm tra hoạt động ngay lập tức ở cấp độ từng màn hình mà không cần phải chạy ứng dụng từ đầu.
Để làm được điều đó, cần phải tách biệt View khỏi Logic và xây dựng một nền tảng cho phép truyền mockup vào View.
Vì vậy trong bài viết này, Haruki Yano giới thiệu về phương pháp tách biệt View và Logic bằng cách sử dụng USN
Mô tả màn hình sẽ tạo trong bài viết này.
Trong bài viết này chúng ta sẽ tạo một màn hình với 3 ảnh được bố trí như sau:
- Ảnh bên trái (FIXED) là hình ảnh luôn được hiển trị ở trang này.
- Ảnh ở giữa (LOCAL) sẽ ngẫu nhiên tải và hiển thị một hình ảnh từ LOCAL 01 đến LOCAL 03 được lưu trên máy
- Ảnh bên phải (REMOTE) sẽ tải và hiển thị ngẫu nhiên một hình ảnh từ REMOTE 01 đến REMOTE 03 được lấy trên mạng về.

Mỗi hình ảnh là một button, khi nhấn vào sẽ mở ra một modal tương ứng.

Đầu tiên, viết toàn bộ vào View.
Trước tiên hãy thử triển khai mô tả trên bằng cách viết tất cả vào View.
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using UnityScreenNavigator.Runtime.Core.Modal;
using UnityScreenNavigator.Runtime.Core.Sheet;
namespace ViewLogicSeparation.Scripts
{
public class MainSheet : Sheet
{
[SerializeField] private Button _fixedButton;
[SerializeField] private Button _localButton;
[SerializeField] private Button _remoteButton;
[SerializeField] private RawImage _fixedImage;
[SerializeField] private RawImage _localImage;
[SerializeField] private RawImage _remoteImage;
// Initialization process
public override IEnumerator Initialize()
{
_fixedImage.texture = Resources.Load<Texture>("tex_button_fixed");
_fixedButton.onClick.AddListener(OnFixedButtonClicked);
_localButton.onClick.AddListener(OnLocalButtonClicked);
_remoteButton.onClick.AddListener(OnRemoteButtonClicked);
yield break;
}
// Cleanup process
public override IEnumerator Cleanup()
{
_fixedImage.texture = null;
_fixedButton.onClick.RemoveListener(OnFixedButtonClicked);
_localButton.onClick.RemoveListener(OnLocalButtonClicked);
_remoteButton.onClick.RemoveListener(OnRemoteButtonClicked);
yield break;
}
// Processing before this screen is displayed
public override IEnumerator WillEnter()
{
_localImage.texture = Resources.Load<Texture>($"tex_button_local_{Random.Range(1, 4):D2}");
// Download and get the texture
var url = $"http://foo/bar/tex_button_remote_{Random.Range(1, 4):D2}.png";
var uwr = UnityWebRequestTexture.GetTexture(url);
yield return uwr.SendWebRequest();
_remoteImage.texture = ((DownloadHandlerTexture)uwr.downloadHandler).texture;
}
// Processing before this screen is hidden
public override void DidExit()
{
_localImage.texture = null;
_remoteImage.texture = null;
}
private void OnFixedButtonClicked()
{
// When the Fixed button is clicked, open Modal01
ModalContainer.Find("Main").Push("Modal01", true);
}
private void OnLocalButtonClicked()
{
// When the Local button is clicked, open Modal02
ModalContainer.Find("Main").Push("Modal02", true);
}
private void OnRemoteButtonClicked()
{
// When the Remote button is clicked, open Modal03
ModalContainer.Find("Main").Push("Modal03", true);
}
}
}Tạo View và ModalContainer một cách phù hợp sau đó gán các tham chiếu của chúng vào các trường [SerializeField]
Tiếp theo, chỉ cần dùng SheetContainer.Show() để hiển thị sheet này là bạn có thể xác nhận rằng nó hoạt động bình thường