Làm việc với Mesh trong Unity 3D - Phần 2
Bài đăng này đã không được cập nhật trong 3 năm
Chào các bạn, như phần đầu chúng ta đã đi được hết những phần cơ bản như tạo cấu trúc thư mục, script, các method,... Nếu bạn chưa theo dõi qua phần đầu thì có thể xem ở đây: https://viblo.asia/nguyen.van.tung/posts/BYjv44OgvxpV
Kết quả của phần trước chúng ta làm được đó là mỗi khi kéo và thả chuột thì chúng ta sẽ vẽ được một line trên màn hình. Nhưng khi thả xong thì đường đó cũng biến mất. Vậy phần 2 ngày hôm nay chúng ta sẽ làm gì? Vâng phần 2 chúng ta sẽ tương tác trực tiếp tới mesh và các vertor sao cho khi chúng ta kéo và thả xong trên màn hình của chúng ta sẽ giữ được các đường thẳng, thêm vào đó là các collider. Mình sẽ cố gắng giải thích thật chi tiết cho những bạn nào mới học Unity. Ok chúng ta bắt đầu nhé.
Vẫn là class Level.cs, chúng ta sẽ tạo method CreateBox, method này sẽ có nhiệm vụ chính là cái mục đích của phần bài hôm nay của chúng ta như mình đã nói ở trên. Ở đây tôi sẽ vẽ và giữ các đường line bằng cách vẽ các box tương ứng với từng line.
void CreateBox (Vector3 p1, Vector3 p2)
{
}
p1 và p2 sẽ là các tọa độ điểm đầu và cuối khi chúng ta bắt đầu kéo và thả. Nói vậy là các bạn đoán được method này sẽ được đặt ở đâu rồi chứ.
void OnMouseUp ()
{
Debug.Log (mouseHit.ToString ());
dragging = false; //Khi nhả chuột, dừng động tác kéo.
CreateBox (mouseHit, MousePos ());
}
Tiếp theo chúng ta sẽ tạo ra Box Object tương ứng với đường line trong method
GameObject newLedge = new GameObject ("Block"); //Tạo mới một game object. Thằng này sẽ có nhiệm vụ giữ lấy cái mesh mà chúng ta tạo
// Tạo mới một mesh và add MeshFilter và MeshRenderer cho nó
Mesh newMesh = new Mesh ();
newLedge.AddComponent<MeshFilter> ();
newLedge.AddComponent<MeshRenderer> ();
Có thể nhiều bạn mới chưa biết MeshFilter với MeshRenderer là gì thì mình xin quất mấy cái khái niệm và link tham khảo vào đây chô các bạn tiện theo dõi, bởi lẽ nếu đã làm unity thì nó là cái bạn nên biết, à phải phải biết biết. 2 thằng này có quan hệ khá là khăng khít với nhau. Trước hết là MeshFilter:
The Mesh Filter takes a mesh from your assets and passes it to the Mesh Renderer for rendering on the screen. http://docs.unity3d.com/Manual/class-MeshFilter.html
MeshRenderer:
The Mesh Renderer takes the geometry from the Mesh Filter and renders it at the position defined by the object’s Transform component. http://docs.unity3d.com/Manual/class-MeshRenderer.html
Rồi, việc bây giờ là phải định nghĩa lên các thành phần của mesh. Trước hết là các vertices(đỉnh). Do là chúng ta làm game 2D nên chỉ cần tạo ra 6 đỉnh là được. Bởi chúng ta không cần nhìn thấy phần che khuất của object nên việc vẽ phần bị che khuất là không cần thiết. 6 đỉnh đó là: Đỉnh trước trên bên trái, trước dưới trái, đỉnh trước trên bên phải, đỉnh trước dưới bên phải và 2 đỉnh phía sau là sau trên trái và sau trên phải. Nhìn hình dưới để hình dung bạn nhé, kẻo tàu hỏa nhập ma thì bỏ mịa.
Tạo luôn các variable tương ứng:
Vector3 topLeftFront = p1;
Vector3 topRightFront = p2;
Vector3 topLeftBack = p1;
Vector3 topRightBack = p2;
Vector3 bottomLeftFront;
Vector3 bottomRightFront;
Game của chúng ta tuy rằng là game 2D nhưng mà va chạm, các tương tác vật lý vẫn là 3D, bởi vậy nên vẫn phải thiết lập độ sâu cho các box vậy nên vẫn phải quan tâm tới trục z của các đỉnh.
topRightFront.z = 0.5f;
topLeftFront.z = 0.5f;
topLeftBack.z = -0.5f;
topRightBack.z = -0.5f;
Thiết lập tọa độ các đỉnh một cách hợp lý, đỉnh dưới trái phía trước sẽ như đỉnh trên-trái-trước về các tọa độ trừ trục y sẽ bằng độ cao của box luôn, tương tự với đỉnh còn lại là dưới-phải-trước:
bottomLeftFront = topLeftFront;
bottomRightFront = topRightFront;
bottomLeftFront.y -= blockHeight;
bottomRightFront.y -= blockHeight;
Ok, vậy đã định nghĩa xong các đỉnh cho nó. Giờ là việc set các đỉnh trên tới mesh:
newMesh.vertices = new Vector3[]{topLeftFront, topRightFront, topLeftBack,
topRightBack, bottomLeftFront, bottomRightFront};
Tạo UVs cho mesh: (uv là gì? bạn có thể tham khảo thêm ở đây nhé: http://docs.unity3d.com/ScriptReference/Mesh-uv.html)
Vector2[] uvs = new Vector2[newMesh.vertices.Length];
for (int i=0; i< uvs.Length; i++) {
uvs[i] = new Vector2(newMesh.vertices[i].x, newMesh.vertices[i].z);
}
newMesh.uv = uvs;
Rồi giờ tạo cho nó các cái Triangles, cái này khá là khó hình dung nên mình sẽ quắt code lên đây trước, các bạn đọc qua rồi mình sẽ post cái hình lên cho các bạn dễ hình dung:
newMesh.triangles = new int[]{5, 4, 0, 0, 1, 5, 0, 2, 3, 3, 1, 0};
Chắc tới đây nhiều bạn sẽ chưa hiểu mấy cái số 5,4,0 ... là cái gì. Thì 0-> 5 lần lượt là 6 cái đỉnh như trên của chúng ta. Cũng dễ hiểu bởi nó là lần lượt các đỉnh của tam giác nên nó luôn luôn sẽ là bội số của 3.
Để ý vào hình trên và mảng int {5, 4, 0, 0, 1, 5, 0, 2, 3, 3, 1, 0} bạn sẽ nhận ra để tạo nên được box như chúng ta mong muốn thì chúng ta phải định nghĩa tới 4 cái triangle. Ở đây chúng ta định nghĩa 4 cái như sau: Cái thứ nhất: 5, 4, 0 Cái thứ 2: 0, 1, 5 Cái thứ 3: 0, 2, 3 và cái thứ 4: 3, 1, 0
Sau mỗi lần chính sửa chúng ta phải gọi tới
newMesh.RecalculateNormals();
để xác nhận việc thay đổi.
Vậy là mọi thứ đã xoàng xoàng rồi đấy. Công việc cuối cùng trong phần này của chúng ta đó là gán lại cái mesh vừa định nghĩa vào object của chúng ta và thêm cho nó cái material vào. Material thì bạn thích nó hiển thj thế nào, thích màu nào thì tự định nghĩa rồi attach vào blockMaterial nhé. Add cho nó cái MeshCollider và chọn một cái MeshCollider tương ứng và attacth vào blockPhysicMaterial. Thật ra phần này chưa cần thiết nói về nó lắm. Mình sẽ nói chi tiết ở phần sau hơn.
newLedge.GetComponent<MeshFilter>().mesh = newMesh;
if (blockMaterial) {
newLedge.GetComponent<MeshRenderer>().material = blockMaterial;
}
newLedge.AddComponent<MeshCollider>();
if(blockPhysicMaterial) newLedge.GetComponent<MeshCollider>().material = blockPhysicMaterial;
Vậy là xong rồi đấy, giờ bạn có thể chạy nó. Của mình chạy và mình tự vẽ các box này, mình chụp màn hình cả Scene View cả GameView và cả Hierarchy View để các bạn thấy luôn:
Chờ phần 3 nhé.
All rights reserved