[Hướng Dẫn] Làm Fruit Ninja đơn giản

PiratePirate Posts: 31Registered
edited August 2019 in Unity
Sau khi làm tutor quay camera, mình tính làm luôn 1 tutor đơn giản cho 1 game 2D đơn giản. Mặc dù là game 2D nhưng vẫn phải xài 1 tí 3D cho mấy món đồ :D. Code này tập trung chủ yếu vào gameplay nên những thứ khác như animation, 3D modeling, ... mình sẽ không nói tới.

Đầu tiên mọi người cần chuẩn bị resource đầy đủ. Mình sẽ lấy 5 model đơn giản thôi: 3 trái cây, 1 trái lựu và 1 trái bom. Và một số linh tinh khác bạn có thể kiếm trên mạng được. Ai không có model 3D có thể lấy tạm một số hình cơ bản Unity tạo sẵn.

3hWiv7Djpg

Phần 1: Tạo project, đưa 1 trái cây vào màn hình.
Vì đây là game 2D nên khi tạo proj, mình chọn 2D. Trong game 2D các bạn lưu ý vẫn xài được yếu tố 3d nha.
Đầu tiên, vì mình muốn nhắm đến là game trên điện thoại nên mình vào window game, chọn ratio là 16:9.
Theo kinh nghiệm thì mình sẽ tạo sẵn một số folder trong Asset để sau này tiện quản lý như Scene, Prefab, Script, Material vv. Mình xài 3d model từ Blender nên mình tạo thêm folder Blender.

p3TNDNIjpg

Bây giờ ta lưu Scene lại.
Bây giờ ta tạo Background cho Game. Bạn có thể google bất cứ hình nào phù hợp trên Google. Sau đó kéo thả ảnh từ Assets vào. Lưu ý nên đặt trong window Hierachy, vì nó sẽ tự động đặt ở chính giữa camera. Chỉnh Scale lại cho phù hợp.

kNAfqB6jpg

Bây giờ ta tạo các Object đại diện cho trái cây. Nếu bạn xài Blender, cứ thoải mái kéo thả từ Asset qua. Nếu bạn không có hình, bạn có thể sử dụng 1 số khối cơ bản. Từ Hierachy, chọn Create, chọn các khối cơ bản (4 khối đầu tiên). Để dễ phân biệt, ta cũng nên tô màu cho chúng khác nhau.
Vào thư mục Material trong Window Proj, chọn Create Material. Ở các Material này, bạn tạm thời chỉ quan tâm đến màu sắc ở khu vực  Albedo.

w2H86JZjpg

Sau khi chọn xong, bạn kéo thả từng Material vào vật bạn thích. Thành quả bạn có được:

PokLFGjjpg.

Hay: 
y04srQXjpg

Chọn một trong các vật vừa tạo trong Hierachy. Vào window Inspector, bạn sẽ thấy các thông số của vật đó.

Khu vực bên trên là thông tin cơ bản của Object, như Name, Tag, Layer, Prefab, vv. Tag được dùng để đánh dấu Object đó là gì. Ví dụ, trong một game đua xe, xe đua và xe cảnh sát cùng chạy script như nhau, nhưng để phân biệt, xe cảnh sát sẽ có tag Cảnh sát, xe mình sẽ có tag Player, xe khác sẽ có tag Bike. Nếu Player va chạm Cảnh sát, Game Over. Chỉ bằng tag, ta có thể dùng chung code cho cả ba xe, rất tiện lợi.
Ở ví dụ này ta sẽ đặt tag là Fruit.

TStBEOAjpg
[
Gán các vật bằng tag mới.

Tiếp theo, ta sẽ xem vào các thành phần yếu tố (Component). Khi xem thành phần yếu tố, bạn sẽ thấy đã có một vài yếu tố có sẵn. Đầu tiên là Transform. Đây là yếu tố mà mọi vật dều có. Nó giúp cho Unity xác định được vị trí, chiều xoay và độ lớn của object.

Bây giờ, ta kéo xuống, sẽ thấy nút bấm Add New Component. Đây là nút bấm để tạo thêm các yếu tố mới. Ta sẽ thấy được các Component có thể tiếp cận được, từ của Unity tới code của bản thân. Ta sẽ add vào yếu tố Rigid Body 3D.

DoWQdWEjpg

Bấm nút play ở phía trên và xem thử.

C502BuJjpg.
Bạn sẽ thấy vật đó vừa rơi khỏi màn hình. Ta sẽ áp dụng yếu tố này để cho vật vận tốc, cũng như cho vật rơi xuống.
Làm tương tự với các trái cây còn lại.
Bây giờ ta lưu các vật vừa tạo thành Prefabs.
Kéo thả các vật vào cửa sổ Profile, trong thư mục Prefabs, ta sẽ thấy xuất hiện một file mới. Đó là prefab của vật được kéo vào, là kiểu mẫu vật cho ta sử dụng sau này.
2Durhyfjpg
Sau khi lưu Prefabs xong, ta lưu Scene lại lần nữa bằng Ctrl S. Xong hướng dẫn 1.

Comments

  • dsiver144dsiver144 Posts: 1,064Registered
    Good job bro. Sau này nhất định phải học Unity. xD
  • PiratePirate Posts: 31Registered
    Hướng dẫn 2:
    Trong hướng dẫn này, mình sẽ hướng dẫn cách tạo liên tục trái cây và cho chúng biến mất khi rơi ra khỏi màn hình.
    Tạm thời xóa các trái cây trong Hierachy. Chúng đã nằm trong thư mục Prefabs để lát nữa sử dụng.

    Bây giờ, ta sẽ tạo liên tục trái cây này thông qua 1 Script.
    Vào Hierachy, chọn Create, Create Empty Object. Bạn sẽ được vật mới tên GameObject. Double Click vào tên để Rename thành Fruit Generator.
    Ta vào Window Inspector, Add Component, kéo xuống hẳng chọn New Script, gõ tên Script bạn thích vào. Sau đây, mình sẽ hướng dẫn code trong C#. Mình vẫn đặt tên là Fruit Generator.
    vgU8Ni6.jpg
    Trong Window Project, kéo Script tên Fruit Generator trong thư mục Assets vào thư mục Script.
    wEIAzXE.jpg.

    Bây giờ, ta chỉnh sửa Script. Double Click vào Script vừa tạo. Nó sẽ vào Editor của bạn. Mình sử dụng VS nên sẽ chỉnh code trong đó. Gõ vào như sau:
    E2UZnDF.jpg

    Mình xin giải thích như sau: Mọi Object trong Unity đều có một Life Cycle riêng (google nó sẽ ra đầy đủ), trong đó cơ bản nhất là 2 method: Start và Update.
    Start là method được gọi ngay khi Component được tạo ra. Update là method được gọi trong mỗi frame của chương trình.

    public GameObject[] fruits là một giá trị mảng các GameObject, được sử dụng Public. GameObject trong Script có thể là 1 Object trong Hierachy hoặc là 1 Prefab. 1 thứ thú vị trong Unity, giá trị Public có nhiều ý nghĩa hơn là việc Component bên ngoài có thể can thiệp. Khi đặt Public trong code, bạn sẽ được tùy chỉnh giá trị này ngay trong Inspector, như cách bạn tùy chỉnh nó bằng Transform vậy.

    Đối với code này, fruits sẽ là các Prefab trái cây đã được tạo trong hướng dẫn trước. Size = Fruits.Length là để lấy số lượng Prefabs được đưa vào, để tiện sử dụng sau này, nếu ta tăng giảm số lượng Prefab. Vì đây là công việc có thể thực hiện NGAY TỪ ĐẦU và chỉ thực hiện MỘT LẦN DUY NHẤT nên ta để trong Start.
    Tiếp theo, ta xem method Update. Instantiate là một function dùng để tạo một Object mới trong Hierachy từ Prefabs đang có. Bằng cách này, ta có thể tạo liên tục trái cây với đầy đủ thông số cần thiết.

    Ta quay lại Unity. Chọn Fruit Generator trong Hierarchy, vào Window Inspector, xem Component Fruit Generator. Ở đây, ta sẽ thấy có một giá trị mới là Fruits, ta đưa các Prefabs vào đây để lát nữa code sẽ tạo ra chúng. Nhập giá trị Size vào. Giá trị này cũng tương ứng là Fruits.Length trong code vừa rồi. Kéo thả các Prefab từ thư mục Prefab vào các dòng trong Fruits. Ta sẽ được:
    [img][/img].
    Giờ ta bắt đầu chạy thử bằng cách bấm nút Play.
    C502BuJ.jpg.
    Ta sẽ được:
    KWrJ5gw.jpg

    Aizz, nhìn game giờ thật kì dị. Bởi vì Update được gọi vào mỗi frame, tương ứng với thời gian ngắn, ta sẽ tạo một trái mỗi frame. Khá nhiều đúng không. Để giảm tải việc này, ta sẽ cho việc tạo thực hiện 2 giây một lần.

    IPl4LYw.jpg.

    Time.time là một giá trị của C#, thể hiện thời gian trong chương trình.  time0 là giá trị của Script mình, dùng làm mốc thời gian. deltaTime là khoảng thời gian giữa mỗi lần xuất hiện trái cây. Ý tưởng là ở mỗi frame, nếu thời gian so với mốc lón hơn deltaTime, mình sẽ tạo quả, đồng thời cập nhật lại time0.
    Bấm nút play, ta sẽ thấy vật được xuất hiện sau mỗi 2 giây.
    Nếu để ý trong Hierachy, ta sẽ thấy càng ngày càng nhiều Object. Đó là bởi vì, mặc dù các GameObject này không còn nhìn thấy nữa, nhưng chúng vẫn còn xuất hiện trong game. Để xóa chúng, ta cần viết 1 Script để xóa chúng.
    Để xóa một gameobject hoàn toàn khỏi game, ta có câu lệnh: Destroy(a) với a là biến kiểu GameObject cần bị xóa. Để xóa chính bản thân mình, ta có câu lệnh, Destroy(gameObject) với gameObject đại diện cho GameObject sở hữu Component ta đang code.

    Giới thiệu về Destroy xong, ta bắt tay vào xóa chúng nào. Có 2 cách thực hiện và mình sẽ giới thiệu cả hai.
    Cách 1: Xóa trái cây nếu chúng có tọa độ thấp hơn 1 mức nhất định.
    B1: Tạo một script mới, tên FruitRemover.
    B2: Gõ như sau:
    ckoaREX.jpg
    Cách này được: Ngắn gọn, dễ hiểu.

    Cách 2: Xóa một trái cây nếu chúng va chạm một vật có khả năng xóa vật.
    B1: ta cho mỗi trái một Component có sẵn của Unity là Collider (có nhiều loại Collider, chọn hình dáng cho phù hợp. Vì đây là Object 3D nên chọn Collider 3D. Thế Collider là gì. Như tên gọi của nó, nó có khả năng kiểm tra xem, chúng có bị va chạm hay không. Đồng thời, chúng cũng có khả năng kiểm tra vị trí của chuột với vật. 
    6mcra3u.jpg
    va22esS.jpg
    OktDbik.jpg

    Bấm chữ Apply để lưu vào Prefabs nha các bạn.

    AjLYaBx.jpg

    B2: Tạo một Cube mới, tên Object Remover. Dịch chuyển vật này xuống vị trí chứa các trái rơi xuống. Trong Inspector, ta xóa 2 Component Mesh Renderer và Mesh Filter, còn lại Box Collider.
    lD23f6b.jpg
    B3: Tất cả Colider của Fruit và Object Remover, tick vào ô Trigger. Nhớ Apply vào Prefab đối với các Fruit.
    Tạo Script mới cho Object Remover, tên ObjectRemover. Gõ vào:
    xTMCXWD.jpg
    Tadaa. Vậy là ta đã xóa được các vật phẩm thừa thải. Ở chính trong ObjectRemover này, ta sẽ kiểm tra xem vật có phải là một trái chưa được chém hay không, để quản lý mạng, vân vân.

    Ở phần sau, ta sẽ cho các vật này được ném lên ở các vị trí random và cho phép chúng ta chém chúng.
  • PiratePirate Posts: 31Registered
    Hướng dẫn 3:
    Ở phần trước, ta đã tạo ra trái cây ở mỗi 2 giây. Nhưng chúng đều xuất hiện tại một vị trí duy nhất. Và lại từ giữa màn hình nữa chứ!. Đó là bởi vì Prefab lưu lại mọi thông tin của Object, kể cả vị trí của chúng.
    Để thay đổi điều này, ta quay lại code Fruit Generator ở phần trước.
    Để tiện cho code này, ta dời Object Remover xuống một tí, để các trái cây xuất hiện không bị ăn lập tức bởi Object Remover.

    Trước tiên, ta cần xác định, vị trí xuất hiện của quả nằm ở đâu. Để có được giá trị chính xác, ta thử ngay trên Window Scene. Di chuyển 1 trái cây và để ý chỉ số ở Component Transform. Lưu ý, di chuyển giá trị z k quan trọng, miễn năm trước background và sau camera.
    Đối với mình, trái cây phải nằm dưới tầm nhìn camera nhưng vẫn trong khoảng nhìn khi được ném lên, vậy chỉ số cần thiết là: y <= -7, và x từ -9 đến 9. Để dễ lựa chọn, ta sẽ chọn y = -7 và x là một giá trị Random, từ -9 đến 9.
    Để code dễ hiểu, ta sẽ tạo ra Vector vị trí trước khi tạo ra sản phẩm đó. Ta gọi là Vector3 fPosition.

    fPosition = new Vector3(Random.Range(-9, 9), -7);
    Trong đó, new Vector3(a, b) là để tạo một Vector 3 chiều có giá trị a, b, 0.
    Ta gán vị trí của nó bằng cách chỉnh lại dòng lệnh Instantiate thành:

    a = Instantiate(fruits, fPosition, Quaternion.identity) as GameObject;
    Trong đó, Quaternion.identiy là độ xoay mặc định của gameobject mẫu.

    Vị trí xuất hiện đúng rồi đấy, nhưng rồi nó cũng sẽ rơi xuống ObjectRemover và biến mất. Lúc này, ta cần ném chúng lên, bằng cách gán Velocity cho vật. Lưu ý, để có velocity, Object phải có Rigidbody. Để đưa vật lên cao, vector3 velocity phải có y > 0. Để tính toán chính xác Vy là bao nhiêu, ta xài công thức vật lý: v^2 = 2as. Vậy ta xác định, a và s trước.

    S là khoảng cách đi lên, vị trí ban đầu là -7, vị trí sau, ta chọn là một vị trí có y từ 2 đến 4. Vậy S = Random.Range(9, 11);
    A ở đây là trọng trường, a = g = 9.81f. Vậy vy =Mathf.sqrt(2*9.81f*s);

    Vậy v = new Vector3(0, vy); và gán velocity bằng công thức: GetComponent<Rigidbody>().velocity = v;

    Sau khi chỉnh sửa như trên, ta được:
    QFn8PBo.jpg.

    Test thử đi nào.

    Hoạt động, thì hoạt động được rồi đấy, nhưng vẫn còn khá cứng ngắt. Ta sẽ ném xiên vật và xoáy nữa. Để dễ chơi, nếu vật nằm bên trái, ta sẽ ném về bên phải và ngược lại.
    vx = (fPosition.x < 0) ? 3 : -3 - fPosition.x / 3;
    Và chỉnh v thành v = new Vector3(vx, vy).
    Còn để ném xiên, ta điều chỉnh giá trị angular velocity của Component Rigidbody, tương tự điều chỉnh velocity. Mình chọn Vector3.one.

    Sau khi code, mình sẽ được một code giống thế này.

    t8IzLo4.jpg.

    Và test lần nữa. Kết thúc hướng dẫn 3.
    CBKFNsp.jpg
  • Dang_KhoaDang_Khoa Posts: 3,861Administrators
    Link hình sao die quá trời vậy
    :my: :my: :my:
  • PiratePirate Posts: 31Registered
    Có một hình mà Boss :v
  • Black FaceBlack Face Posts: 424Registered
    Pirate wrote:
    Có một hình mà Boss :v

    126b47.png

    2ab7b4.png
  • PiratePirate Posts: 31Registered
    Éc :| Để kiếm cách khác đăng hình v.
  • Dang_KhoaDang_Khoa Posts: 3,861Administrators
  • PiratePirate Posts: 31Registered
    OK, thanks Khoa. Để mình cập nhật lại.
  • Dang_KhoaDang_Khoa Posts: 3,861Administrators
    OK hết bị mất hình rồi
    (y) (y) (y)
  • HydraHydra Posts: 1,004Moderators
    Nice. TTC có thêm một Unity-er
  • Dang_KhoaDang_Khoa Posts: 3,861Administrators
    Thôi chết, nãy thấy 2 bài cùng lúc, mình bấm gộp xong nó bay đâu mất rồi, sorry Pirate nha
    :my: :my: :my:

    Unity ở TTC thì có Hydra, Dang_Khoa, Black Faces, kumuzu, serene... còn nữa thì mình không nhớ
    :3 :3 :3
  • PiratePirate Posts: 31Registered
    OK. Để mình post lại.
    Update model mới:
    gsaH2oh.png

    Mình tính sẽ không làm trái lựu nữa vì cái này không căn bản, cũng như đặc trưng của Fruit Ninja rồi.
    Mọi người chuẩn bị 1 model mới cho Bomb, và lưu Prefabs nó nha.
    B1: Đưa model từ window Project vào Scenehoặc tạo hình cơ bản tại window Hierarchy/Create
    B2: Tạo Material trong thư mục Material và drop vào Object.
    B3: Tạo tag Bomb và đặt tag cho object mới là Bomb.
    B4: Tạo các component cho Bomb tương tự các trái cây khác.
    B5: Drop Object vào thư mục Prefab để lưu lại.

    Ở ví dụ sau, mình sẽ chỉ cách chém trái cây và tính điểm, chưa đụng tới bom.
    Hướng dẫn 4:
    Để bắt đầu, ta sẽ tạo thứ xuất hiện điểm trước. Vào Hierarchy, chọn Create/UI/Text.

    P6vVH9N.png

    Chữ có thể hơi khó nhìn nên bạn nên Disable Background trước. Làm thế nào để Disable nó? Đầu tiên, ta chọn background ở Hierarchy hoặc Scene, rồi qua Inspector, tắt dấu tick ở đó.

    Fqvcyjf.png

    Ta được:

    NEnrxNU.png

    Để thấy được trên Scene, bạn vào trong Hierarchy, double click vào Object Canvas/Text (sẵn tiện đổi tên thành Score), ta sẽ được phóng ra xa. Cái hình tròn bự bên ngoài đại diện cho màn hình của bạn. Như vậy, bạn có thể biết nó sẽ xuất hiện ở đâu.

    yhyuoc1.png

    Bây giờ, vào Inspector, ta cố định vị trí của dòng chữ New Text đó. Bấm vào khu vực màu đỏ, và cố định 1 trong 9 điểm cố định của màn hình.

    ViGmGP6.png

    Mình chọn góc trái trên, nên hình chọn hính trong hình tròn vàng. Tiếp đến dịch chuyển dòng chữ trong Scene.

    Tiếp theo, ta muốn thay đổi dòng chữ, ta chỉnh ở Component Text (Script). Ở đây mình chỉnh màu, chỉnh chữ và Font Size. Mình được:

    PmdIzo0.png

    Sau đó, tạo Script tên scoreControler, gõ vào:
    Od8hTGI.png
    Sau đó, đưa script này cho object Text vừa tạo lúc nãy.
    Script này khá đơn giản, ai học về OOP là hiểu về cái này.

    Bây giờ, tạo Script fruitController. Gõ vào:
    pMOGMYB.png

    Mình giải thích code như sau:
    void OnMouseDown và void OnMouseEnter khá giống với Update, khi nó được kiểm tra mỗi frame và sẽ gọi nếu điều kiện thỏa mãn. 2 function này chỉ gọi nếu obj có collider.
    Đối với: OnMouseDown, điều kiện là bấm chuột vào nó (không tính bấm chỗ khác rồi đi vào).
    OnMouseEnter, điều kiện là con chuột đi ngang qua vùng colider của object.
    Input.GetMouseButton là để kiểm tra tình trạng nút chuột, trong đó 0 là của chuột trái.

    Và test kiểm tra.
    0mvyCmy.png
    Mình "chém" được 41 trái.

    Tiếp theo, mình sẽ nói về bom và quản lý mạng.
Sign In or Register to comment.