Tiếp phần trước hôm nay mình sẽ hướng dẫn các bạn xử lý lượt chơi và kết thúc ván cờ.
1. Giới thiệu UI trong game
UI là User Interface tức là giao diện người dùng, ở trong game giao diện người dùng là 1 phần rất quan trọng, UI trong game là hệ thống các yếu tố đồ họa và tương tác mà người chơi sử dụng để điều khiển hoặc nhận thông tin từ trò chơi. UI giúp người chơi hiểu rõ trạng thái hiện tại của game, thực hiện các hành động, và điều hướng qua các menu hoặc tùy chọn khác nhau.
Hẳn các bạn có từng nghe về UI và UX, tuy nhiên 2 thứ này là 2 thứ riêng biệt, như mình nói ở trên UI là hệ thống hiển thị giao diện người dùng, giúp người chơi tương tác với game, còn UX thì là User Experience là về trải nghiệm của người chơi trong game từ cách chơi, cách thiết kế làm sao để thuận tiện cho người chơi thì đó là UX.
Đó là 1 vài điều cơ bản về UI và UX, vì mình là 1 game dev nên chỉ giải thích sơ như vậy thôi, còn nếu ai có hứng thú với Game Design thì có thể lên mạng tìm hiểu thêm.
2. Canvas trong Unity
Canvas trong Unity là 1 thành phần dùng để UI có thể được bố trí và hiển thị, và tất cả các UI element khác được tạo thì đều phải có Canvas đính kèm thì mới có thể hiển thị ra được. Nếu 1 đối tượng UI được tạo thì Canvas cũng sẽ được tự động tạo ra nếu trong scene chưa có đối tượng Canvas nào.
Link tham khảo: Canvas | Unity UI | 1.0.0
3. UI element và các component hay dùng trong Unity
Về các thành phần UI element có trong Unity thì về cơ bản mình sẽ có 1 bài loại sau đây:
Ngoài ra đối với với UI element các bạn nên tải thêm package TMP Pro trong package manager về để sử dụng, vì các UI element trong pack này sẽ tốt hơn trong việc format chữ, kiểm soát layout trong UI,...
Link tham khảo: TextMesh Pro Documentation | Unity UI | 2.0.0
4. Tạo Giao diện Scene Menu
Ban đầu khi bắt đầu dự án, mình có tạo 2 scene, 1 là Game, 2 là Menu, scene Game mình đã làm bữa giờ, bây giờ mình sẽ chuyển scene Start để tạo Main Menu UI.
Các bạn vào folder scene, chọn vào scene Start, nếu chưa các bạn chuột phải, Create/Scene và đặt tên là Start.
- Trong scene Start, mình chọn chuột phải UI/Image, và Unity sẽ tự động tạo ra Canvas như này, cũng như thêm 1 object là Event System (Event System là hệ thống có sẵn trong Unity, hỗ trợ chúng ta trong việc tương tác với UI, link tham khảo: Event System | Unity UI | 1.0.0 và Unity - Manual: Event System ).
Đặt tên gameobject Image mới tạo là GameMenu.
Tiếp theo mình muốn tấm hình này sẽ bao phủ toàn bộ màn hình, mình chọn vào Anchor Presets ở góc trên bên trái của component RectTransform, sau đó mình nhấn nút ALt trên bàn phím và chọn lựa chọn sau đây, tấm hình sẽ tự động được đặt full màn hình:
Kết quả là:
Tiếp theo mình sẽ trang trí 1 chút cho game, mình sẽ thêm 1 cái title cho game, cũng như 1 tấm hình trang trí cho game cờ vua, cách thêm cũng tương tự như cách các bạn tạo object GameMenu tuy nhiên mình sẽ tạo nó là con của GameMenu, và title mình sẽ tạo Text – Textmeshpro chứ không phải hình:
Mình đặt tên là GameTitleTxt, tiếp theo mình điền title game là CHESS 2D và đổi màu chữ thành màu đen, đặt size chữ cỡ 180 cho dễ nhìn, mình cũng căn lại lề cho title như sau:
Tiếp theo mình cũng làm như GameMenu object nhưng mình chọn top center và set y position là -400:
Tiếp theo mình thêm 1 empty gameobject đặt tên là GameIconContainer. Sau đó mình thêm 2 tấm hình làm gameobject con như sau:
Sau đó ở black icon và white icon mình kéo 2 quân vua vào để trang trí như sau:
Cái này thì tùy các bạn, vì đây chỉ là trang trí nên có thể làm như mình hoặc các bạn tự thiết kế theo ý các bạn.
Tiếp theo các bạn tạo 1 button – textmeshpro theo cách tương tự, và làm con của GameMenu luôn sau đó các bạn cũng có thể tùy chọn size sao cho hợp mắt các bạn, hoặc cũng có thể đổi màu sao tùy các bạn, sao cho cuối cùng thì sẽ có 1 cái nút để có thể cho người chơi nhấn để vào game như sau:
Tiếp theo mình sẽ viết logic để có thể chuyển scene, các bạn vào Script, tạo 1 folder con là UI, tạo script đặt tên là MainMenu, và gán script vừa tạo vào gameobject GameMenu.
Sau đó các bạn vào File/Build Settings, các bạn chọn Add Open Scene để add scene Start và Game.
Các bạn kéo scene Start lên trên như này:
Sau đó các bạn Ctrl + S, sau đó vào script MainMenu vừa tạo. Các bạn đơn giản tạo 1 hàm như sau:
public class MainMenu : MonoBehaviour { public void OnClickPlayBtn() { SceneManager.LoadScene(1); // Scene(1); } }
Hàm này đơn giản là dùng SceneManager (Được Unity cung cấp sẵn để quản lý scene) rồi gọi hàm LoadScene sau đó truyền scene index vô với index ở đây là số đằng sau tên scene ở trong Build Setting lúc nãy các bạn thêm scene vào, ở đây ta có scene 1 tương đương GameScene.
Sau đó các bạn vô lại editor, vào nút play, các bạn kéo xuống component Button, chọn dấu + chỗ OnClick, sau đó kéo GameMenu vào object như sau:
Tiếp theo các bạn làm như sau:
Các bạn kéo object GameMenu vào phần object, Cũng như bấm vào chỗ drop list, sẽ xổ xuống các lựa chọn, các bạn chọn MainMenu/OnClickPlayBtn, lúc này các bạn thành công cài đặt chức năng cho nút, lúc này các bạn play game từ đây, bấm play, game sẽ tự động chuyển scene vào trong Game scene/
5. Tạo Giao diện scene Game
Trong scen này mình cũng làm tương tự, tuy nhiên lúc này mình sẽ tạo object UI cha không phải là 1 tấm hình mà chỉ đơn giản là 1 gameobject trống thôi, mình làm như sau:
Sau đó mình sẽ tạo ra 2 nút ở góc trên bên trái để có thể reload lại game, hoặc thoát ra main menu như sau, về sprite thì mình có cung cấp từ những bài đầu, các bạn có thể dùng sprite của mình, hoặc có thể tải trên mạng về các sprite mà các bạn thích.
Sau đó mình thêm 2 cái text để hiển thị cho lượt chơi đang ở bên nào, vì hiện tại game của chúng ta chuyển lượt nhưng không có bất kỳ thứ gì cho người chơi biết rằng đã đổi lượt, mình thêm như sau:
Tiếp theo mình làm luôn 1 cái popup nhỏ sẽ được gọi lên khi có 1 bên thắng như sau:
Với popup này thì mình sẽ làm logic cho nó hiển thị người thắng, và 2 nút dùng để reload game hoặc thoát ra main menu như 2 nút đã làm ở trên, sau đó mình tắt popup này trên scene, vì mình sẽ gọi nó ở trong code sau.
Tiếp theo các bạn lại vào folder Scripts/UI tạo script mang tên MainGameUI.
public class MainGameUI : MonoBehaviour { [SerializeField] private TMP_Text _whiteTurnTxt; [SerializeField] private TMP_Text _blackTurnTxt; [SerializeField] private TMP_Text _winningTxt; [SerializeField] private GameObject _endGamePanel; public void ShowEndGameUI(ChessSkin chessSkin) { _endGamePanel.gameObject.SetActive(true); switch (chessSkin) { case ChessSkin.None: case ChessSkin.White: _winningTxt.text = "Black win!"; break; case ChessSkin.Black: _winningTxt.text = "White win!"; break; } } public void ChangeTurnTitle(ChessSkin turn) { switch (turn) { case ChessSkin.None: case ChessSkin.White: _whiteTurnTxt.gameObject.SetActive(true); _blackTurnTxt.gameObject.SetActive(false); break; case ChessSkin.Black: _whiteTurnTxt.gameObject.SetActive(false); _blackTurnTxt.gameObject.SetActive(true); break; } } public void OnClickRePlayGame() { SceneManager.LoadScene(1); } public void OnClickExitToMenu() { SceneManager.LoadScene(0); } }
Trong class này mình tạo 4 trường để chứa các object cần thay đổi hoặc bật tắt như text hiển thị lượt chơi và text thông báo thắng thua cũng như là popup end game.
Tiếp theo mình lại vào hàm Occupied trong ChessBoardCell gọi hàm KillOpponentKing này
Tiếp theo mình thêm function có logic hiển thị end game, truyền vào parameter ở đây mình sẽ gọi khi quân vua bị ăn, nên là khi truyền vào chess skin sẽ là màu của bên thua, nên sẽ hiển thị bên ngược lại là thắng, và bật popup này lên.
Tiếp theo là function chuyển lượt chơi, mình chỉ cần truyền vào thông tin lượt chơi tiếp theo là màu quân cờ, sau đó UI sẽ hiển thị text lượt chơi tương ứng.
Tiếp theo là 2 hàm tương ứng cho 2 nút bên ngoài UI, là reload scene, mình cũng gọi SceneManager.LoadScene(1) để load lại scene Game, và LoadScene(0) để trở về scene Menu.
Sau đó mình sẽ vào GameManager, để có thể gọi tới UI khi cần.
..... [SerializeField] private MainGameUI _mainGameUI; ..... Tiếp theo mình update cho hàm OnOnePlayerMoved(): private void OnOnePlayerMoved() { ..... _mainGameUI.ChangeTurnTitle(_currentGameTurn);..... }
Gọi hàm ChangeTurnTitle() và truyển parameter vào.
Tiếp theo mình update hàm EndGame, thay logic dùng debug.log lần trước bằng logic gọi tới hàm ShowEndGameUI():
private void EndGame(ChessSkin chessSkin) { _mainGameUI.ShowEndGameUI(chessSkin); OnClickOnCell -= OnPlayerClickOnCell; OnMoved -= OnOnePlayerMoved; }
Đã xong, giờ các bạn hãy ra editor và kéo script MainGameUI kéo vào MainGamePanel, sau đó kéo các thành phần cần thiết vào như sau:
Tiếp theo mình kéo ref MainGamePanel vào GameManager:
Tắt object text BlackTurn vì mới vào lượt chơi ban đầu sẽ là của quân trắng:
Sau đó mình nhấn play:
Lượt Trắng:
Lượt Đen:
Đã xử lý xong lượt chơi, tiếp theo mình sẽ gán chức năng cho các nút như cách làm ban nãy với nút Play ở MainMenu, nút reload sẽ gán cho hàm OnClickRePlayGame() còn nút X sẽ gán cho hàm OnClickExitToMenu().
Làm tương tự với popup EndGame, sau đó mình sẽ play game lại.
Tác giả: Nguyễn Minh Thuận & Nguyễn Văn Khánh