Lập trình game cờ vua - Bài 5 - Tạo và lập trình bàn cờ vua (Phần 2)
Back To BlogsChúng mình đã cùng các bạn tạo ra được bàn cờ. Bài viết này sẽ hướng dẫn các bạn các bước tiếp theo tạo và lập trình các ô cờ
Viết Script logic cho ô cờ
Mình sẽ vào folder script, tạo folder ChessBoard, tạo script ChessBoardCell.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ChessBoardCell : MonoBehaviour { [SerializeField] private GameObject _cellCanMove; private Vector2 _cellPos; private BoardManager _boardManager; public void Setup(Vector2 position, BoardManager boardManager) { _cellPos = position; _boardManager = boardManager; FillColor(this.GetComponent<SpriteRenderer>(), (int) position.x, (int) position.y); } private void FillColor(SpriteRenderer cell, int x, int y) { bool oddY = (y % 2 != 0) ? true : false; bool oddX = (x % 2 != 0) ? true : false; if((oddY && oddX)||(!oddY && !oddX)) { cell.color = new Color32(120, 79, 72, 255); return; } } private void OnMouseDown() { } }
Trong script này sẽ có 3 trường, 1 trường là gameobject _cellCanMove, 1 trường vector2 cellPos, còn lại là BoardManager.
Tiếp theo là phương thức cài đặt cho ô cờ, trong phương thức này mình sẽ truyền parameter vị trí ô cờ, BoardManager vào các trường tương ứng, cũng như là gọi tới hàm tô màu ô cờ để giúp bàn cờ có màu caro xen kẽ thay vì 1 màu như hiện tại.
Trong hàm FillColor mình sẽ có logic như sau, mình sẽ tính ra ô đang ở x chẵn hay lẻ và y chẵn hay lẻ, logic của ô màu đen đó là ô nằm ở cùng x y chẵn hoặc x y lẻ sẽ là màu đen, còn ô mà x y không cùng chẵn hoặc không cùng lẻ sẽ là màu trắng.
Ngoài ra mình còn sử dụng thêm phương thức OnMouseDown() cho script này để gọi tới khi mà người chơi nhấn lên trên ô cờ.
Mình sẽ import asset bên ngoài vào là sprite crosshair (mình có đính kèm các sprite sẽ dùng trong game ở dưới cuối bài), đầu tiên mình vẫn tạo folder con trong folder sprite đặt tên là Board, sau đó kéo sprite từ bên ngoài vào.
Sau đó mình sẽ tạo 1 gameobject square trong prefab Cell đặt tên là CanMove, và sprite vừa import vào.
Vì sprite nhỏ hơn ô cờ nên mình quyết định resize gameobject này và đổi màu sang màu xanh (các bạn có thể đổi màu qua bất kỳ màu nào các bạn muốn).
Ẩn gameobject CanMove đi vì nó sẽ chỉ hiện khi chúng ta nhấn vào, nên không cần thiết lúc nào cũng hiện, kéo script ChessBoardCell vào gameobject Cell, cũng như kéo ref của object CanMove vào trường trong script ChessBoardCell.
Đã xong giờ thì Ctrl+S để lưu prefab lại và vào lại script BoardManager để gọi hàm Setup() cell trong hàm CreateBoard().
Tiếp theo kéo prefab vừa tạo vào trường cellPrefab trong Inspector BoardManager.
Lúc này các bạn có thể xóa Cell trên scene. Tiếp theo mình sẽ gọi hàm tạo bàn cờ từ GameManager.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class BoardManager : MonoBehaviour { //Creating a reference field for the cell prefab in the Unity Editor [SerializeField] private GameObject _cellPrefab; private ChessBoardCell[,] _allCells = new ChessBoardCell[8, 8]; // (1) private List<ChessBoardCell> _onSuggestCells; internal GameManager GameManager; public ChessBoardCell[,] AllCells { get => _allCells;} public void InitBoard(GameManager gameManager) { this.GameManager = gameManager; _onSuggestCells = new List<ChessBoardCell>(30); CreateBoard(); } private void CreateBoard() { //Creating the all the cells for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { //Instantiating a new cell from the Cell Prefab GameObject newCell = Instantiate(_cellPrefab, transform); //Setting the position of the Cell newCell.transform.position = new Vector2(x, y); ////Setting up the Cells (2) _allCells[x, y] = newCell.GetComponent<ChessBoardCell>(); _allCells[x, y].Setup(new Vector2Int(x, y), this); } } } }
(1) Mình tạo thêm 1 mảng 2 chiều của ChessBoardCell để dễ quản lý các ô cờ trong bàn cờ, khi cần chỉ cần vị trí của ô cờ để gọi ra.
(2) Thêm logic thêm ô cờ vào trong mảng đã tạo, và gọi tới ô cờ mới thêm hàm Setup truyền vào vị trí của ô cờ và BoardManager.
Viết Script logic chọn ô cờ
Trước tiên các bạn vào prefab Cell trước đó, và thêm vào component BoxCollider2D.
Các bạn chỉ cần thêm vào là đc, giải thích sơ qua thì trong hệ thống physics của Unity sẽ có collider và trigger để xử lý va chạm, thì trong Unity 2d và 3d sẽ có các component collider khác nhau, tùy vào trường hợp và hình dáng của 2d object hoặc 3d object mình sẽ chọn loại collider khác nhau, trong trường hợp này thì đây là hình vuông, nên mính sẽ chọn box collider 2d, và đối với hàm OnMouseDown muốn được gọi vào thì mình bắt buộc phải có box collider này. Các bạn có thể tham khảo thêm về Collider tại link này: Unity - Manual: Colliders và link này Unity - Scripting API: Collider
Tiếp theo mình sẽ tạo ra 1 object là Select sẽ hiện ra khi người chơi click vào ô cờ sẽ hiện ra để cho người chơi biết rằng mình đã click vào ô cờ đó.
Với object này mình cũng sẽ tạo như object CanMove trong prefab Cell và dùng sprite crosshair nhưng không đổi màu.
Tiếp theo mình sẽ vào script GameManager thêm trường cho cellSelectedObject để có thể gọi tới cell selected object khi người chơi click vào 1 ô, và mình cũng tạo thêm action
gán action này với hàm đặt vị trí cho cellSelectedObject để khi ô cờ được nhấn thì sẽ gọi qua action này tới và gọi tới hàm đặt vị trí này.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager: MonoBehaviour { //Creating a reference field for the cell prefab in the Unity Editor [SerializeField] private BoardManager_board; private GameObject _cellSelectedObj; public Action<Vector2> OnClickOnCell; private void InitGame() { _board.InitBoard(this); OnClickOnChessPiece += OnPlayerClickOnChessPiece; StartGame(); } private void StartGame() { } private void EndGame() { } private void OnPlayerClickOnChessPiece(Vector2 currentChessPiecePos, ChessPiece chessPiece, Action<ChessPiece> suggestWaysForMove) { _cellSelectedObj.SetActive(true); _cellSelectedObj.transform.position = currentChessPiecePos; } }
Mình sẽ assign action với hàm OnPlayerClickOnCell, trong hàm này sẽ truyền vào vị trí của ô cờ được người chơi nhấn vào, đồng thời set active cho cellSelectedObj và đặt vị trí cellSelectedObj bằng với vị trí ô cờ được nhấn
Tiếp theo mình sẽ vào script ChessBoardCell để update hàm OnMouseDown() như sau:
private void OnMouseDown() { _boardManager.GameManager.OnClickOnCell?.Invoke(_cellPos); }
Mình gọi tới GameManager thông qua boardManager để gọi tới action OnClickOnCell và truyền tham số cellPos vào.
Giờ mình sẽ ra ngoài scene và kéo ref gameobject Select vào GameManager và chạy thử game.
Kết quả là không có gì xảy ra, tại vì Select object đang nằm ở dưới Hierachy, trong game 2D và UI khi object cùng layer nằm ở trên thì sẽ được hiển thị đè lên object cùng layer nằm ở dưới.
Nên lúc này mình có 2 hướng giải quyết, 1 là mình sẽ thêm 1 layer khác cho Select object, 2 là mình sẽ thay đổi order in layer của Select object, mình sẽ chọn thay đổi order in layer là 1, còn cell thì mình vẫn để là 0.
Sau đó mình ẩn Select object trước khi chạy game vì Select object sẽ được set active trong lúc chạy, và mình chạy game, và đây là kết quả.
Giờ mình sẽ ra ngoài scene và kéo ref gameobject Select vào GameManager và chạy thử game.
Tác giả: Nguyễn Minh Thuận & Nguyễn Văn Khánh