Wednesday, April 30, 2014

Bài 8: Menu - từ cơ bản tới phức tạp ( Part2)

Hi 30-4, 1-5!

Tình hình là 2 ngày không được nghỉ, chả biết làm gì, đi làm thì chán chán, đi chơi thì 1 mình nên đành rảnh rỗi ngồi viết bài cho vui vậy. Các anh chị em giờ này chắc đang vi vu tận đẩu tận đâu rồi ấy nhỉ. Còn mình thì đi làm, nhưng mà không sao, double lương cũng tạm.

Bài trước chúng ta đã biết cách tạo Label chứa text và cách chỉnh font, cùng với việc tạo 1 menu chứa item để thực hiện 1 tác vụ nào đó. Để nhớ lâu, các bạn nên dùng VS 2012 gõ lại từng đoạn code nhé. Còn trong bài này chúng ta sẽ đi sâu hơn với một số công việc sau:

+ Tạo hiệu ứng chuyển cảnh cho mỗi Scene
+ Tạo công việc cho các nút của Menu
+ Thêm một chút hiệu ứng cho Label, ví dụ như chuyển động chẳng hạn.

Bắt đầu thôi. Các down file Source ở ĐÂY về, giải nén rồi paste đè vào thư mục Classes của project menu nhé.

Sau đó, bạn chỉnh file Menu.vcxproj (f:/android/project/menu/proj.win32) như thế này để không bị lỗi khi compile



Biên dịch rồi chạy thử cái xem thế nào

>cocos run -s f:/android/project/menu -p win32

Bạn có thấy thay đổi gì không, có hiệu ứng chuyển Scene, hiệu ứng dịch chuyển chữ, và Click vào 2 menu sẽ chuyển sang Scene khác. OK. Tiếp theo chúng ta sẽ đi vào chi tiết phần code xem làm thế nào để được như vậy.

Chi tiết phần Code

Các file SceneManager.h, và MenuLayer.h không thay đổi gì so với phẩn 1. Ở phần 2 này chúng ta thấy có 2 lớp mới xuât hiện đó là CreditLayer, PlayLayer để quản lý 2 thao tác khi nhấn vào 2 menu khác nhau của chúng ta. Bạn mở 2 file CreditLayer.h, và PlayLayer.h ra nhé

Nói chung là ko có gì đặc biệt phải không , ngoài mấy cái hàm tạo, hàm hủy, rồi hàm init, hàm back ( để ấn nút Back xuất hiện ở Scene này). 2 đối tượng này có mỗi một việc là tạo ra 2 cái Layer rồi sau đó sẽ dính vào 1 Scene nào đó. Bỏ qua 2 file này nhé.

A > Tiếp theo mở file CreditLayer.cpp ra, nhìn vào hàm init() // Hàm này tạo ra 1 layer trống để gắn đối tượng. Trong hàm init () này có đoạn code cần chú ý

auto back = MenuItemFont::create("Back", CC_CALLBACK_1(CreditLayer::back,this)); (1)
auto menu = Menu::create(back, NULL); (2)
menu->setPosition(visibleSize.width/2, visibleSize.height/2);
this->addChild(menu);

(1) Đây là câu lệnh quen thuộc đã học từ bài 7, nhiệm vụ tạo ra 1 item menu tên back, khi ấn vào item menu này sẽ gọi hàm CreditLayer::back() ở phía dưới
(2) là câu lệnh cũng quen thuộc có nhiệm vụ tạo ra 1 Menu chứa cái item menu back đã tạo ở trên.
Còn đoạn bên dưới là đặt vị trí Menu trên ở chính giữa màn hình, sau đó dính cái menu này vào Layer tạo ra bởi hàm init()

B > Tiếp theo mở file PlayLayer.cpp, ta thấy rằng các dòng code hoàn toàn tương tự file CreditLayer.cpp, cũng là tạo ra 1 nút back rồi gắn vào Layer này. Các bạn nghiên cứu kỹ lại cho nhớ nhé.

C > Tiếp theo chúng ta nghiên cứu file MenuLayer.cpp, file này có code khá giống Bài 7 đã nghiên cứu, tuy nhiên, nó bổ sung thêm 1 vài code tạo hiệu ứng di chuyển mấy cái Label, xem qua chút nhỉ. Trong hàm init() ta thấy các câu lệnh quen thuộc để tạo ra các Label chứa Text với font chữ, và cỡ chữ xác định, đặt chúng lên Layer tại các vị trí. Nhưng có 1 đoạn code khá lạ, chúng ta cùng xem:

titleLeft->setPosition(titleLeftPosBegin);
Action *titleLeftAction = Sequence::create(
                            DelayTime::create(delayTime),
                            EaseBackOut::create(MoveTo::create(1.0, titleLeftPosEnd)),
                            NULL);

titleLeft->runAction(titleLeftAction); // titleLeft là 1 cái Label nhé
this->addChild(titleLeft);

Đoạn code này hiểu như sau: nhiệm vụ của nó là tạo ra một hành động có tên titleLeftAction = lệnh Sequence::create(). Hành động này cụ thể là gì? hãy xem trong hàm Sequene::create(), hàm này có 3 tham số truyền vào
DelayTime::create(delayTime) // là tạo ra thời gian trễ
 EaseBackOut::create(MoveTo::create(1.0, titleLeftPosEnd)) // MoveTo::create(1.0, titleLeftPosEnd) là hàm tạo 1 hành động di chuyển từ điểm đầu tiên titleLeftPosBegin (đã tính toán ở đoạn code bên trên - trong source) đến điểm cuối titleLeftPosEnd ( cũng đã tính toán trong source), EaseBackOut là 1 lớp tạo ra hiệu ứng ( ko biết phải dịch là gì - đây là 1 trong các hiệu ứng di chuyển thông dụng )
NULL : tham số thứ 3 này chưa hiểu lắm, để hiểu sâu hơn hãy nghiên cứu ở đây http://www.cocos2d-x.org/reference/native-cpp/V3.0rc0/index.html

Lệnh titleLeft->runAction(titleLeftAction); là thực hiện cái hành động di chuyển ở bên trên bằng cách gọi function của đối tượng titleLeft ( đây là 1 cái Label ).

this->addChild(titleLeft); // Gắn cái Label vào Layer tạo bởi init(); 

Đoạn code bên dưới cũng tương tự thế, tạo ra 1 chuyển động cho 1 cái Label khác. OK chưa

Giờ thì tới đoạn này, khá khó hiểu

   for (Node *each : menu->getChildren())
    {
each->setScale(0.0f, 0.0f);
Action *action = Sequence::create(DelayTime::create(delayTime),
                                          ScaleTo::create(0.5f, 1.0f),
                                          NULL);
delayTime += 0.2f;
each->runAction(action);
     }

Đây là vòng lặp for để duyệt các item của Menu đó chính là nút Credits và nút New Game đó ( 2 nút này được tạo ra ở bên trên - trong Source, MenuLayer.cpp)

for (Node *each : menu->getChildren()) cũng khá lại so với for (i=0; i<n; i++) cơ bản của C++ nhỉ, hêhe, nhưng chính xác nó là 1 vòng lặp để duyệt các đơn vị của 1 tập nào đó.

Trong vòng lặp

each->setScale(0.0f, 0.0f); là chỉnh cái nút menu Credits , New Game về tỉ lệ 0, biến mất còn gì, sau đó đến lệnh

Action *action = Sequence::create(DelayTime::create(delayTime),
                                          ScaleTo::create(0.5f, 1.0f),
                                          NULL);
là tạo ra 1 hành động phóng to dần cái nút này lên với tỷ lệ nhất định ScaleTo::create(0.5f, 1.0f),
sau đó là thực hiện hành động each->runAction(action);  Kết quả là tạo 1 hiệu ứng cái nút đó phóng to dần lên thôi, đơn giản và dễ hiểu quá phải không.

D > Tiếp theo chúng ta nghiên cứu file SceneManger.cpp, file này dùng để quản lý các Scene được tạo ra và chạy như thế nào, đồng thời khi chuyển từ Scene này sang scene khác có kèm 1 hiệu ứng chuyển cảnh ( như làm mờ, lộn ngược, quay đảo, v.v...)

Mở file lên nào, Trời ơi, sao code dài thế ~150 dòng code cùng với rất nhiều hàm. Vâng, bạn ạ, thực ra code dài nhưng đơn giản dễ hiểu còn hơn đoạn code ngắn mà phức tạp đọc không hiểu gì. Mình nhớ có lần làm 1 bài tập lớn, search mạng đọc 1 cái code Java thì phải có sấp sỉ 10000 dòng (Notepad ++) đọc mãi mới xong. 

Trong file này tuy nhiều code nhưng thật ra có nhiều đoạn code chức năng na ná nhau đó là tạo ra 1 hiệu ứng chuyển cảnh cho Scene, thế nên mình chỉ giới thiệu với các bạn 1-2 đoạn thôi nhé. Bạn yên tâm rằng các hiệu ứng chuyển cảnh này đều được định nghĩa bằng các lớp tương ứng của Cocos2dx V3 nhé ( ví dụ: TransitionFlipY - lộn theo trục Y,  TransitionFade - làm mờ dần, TransitionZoomFlipX - phóng to theo trục X ) vậy đó

- Bài này đang tạm dừng...

Bài 9: Làm game đầu tiên - Tạo nhân vật (Part -1)

13 comments:

  1. Cho mình hỏi: Mình pase class mới đè vào classes cũ vào chưa sửa trong Menu.vcxspoj
    và mình buil vẫn OK không lỗi gì cả. Và chạy nó như bài 7.
    Sau đó mình sửa Menu.vcxspoj như trên hình buil vẫn OK nhưng nó không thay đổi gì so với bài 7 cả.
    Help me.

    ReplyDelete
    Replies
    1. Xóa debug trong thư mục Publish ( V3.1.1 ) hoặc bin (V3.0) đi build lại bạn ơi. nhớ thêm Class trong Menu.vcxspoj. Nó sẽ build lại, chạy mới đúng.

      Bài này mình bỏ ngang rồi, nó có 1 đoạn code dài chạy chuyển cảnh của mấy menu nữa, nhưng mà ngại nên tạm dừng nhé

      Delete
    2. Học từ bài 9 trở đi sẽ hấp dẫn hơn

      Delete
    3. Mình làm như bạn hướng dẫn xóa thư mục debug trong bin(V 3.0) khi run lại vẫn ra bài cũ bạn ơi. Mình đã sửa Menu.vcxspoj

      Delete
    4. Có câu lệnh nào để ReBuild lại project trong cmd không bạn?

      Delete
    5. Ko có Rebuild, và ko phải xóa trong bin, hay publish, hôm trước nhầm

      Xóa Debug trong proj.win32 ( Libs, obj, link ) nằm ở đây nhưng độc lập với bin, và publish

      Delete
    6. Nếu bạn mở project bằng Visual Studio thì có thể click chuột phải vào project chọn "Clean" là được.

      Delete
  2. Làm sao để dùng vật lý cho cái PlayLayer hả anh.
    Cho em hỏi luôn khung vật lý với thằng Sprite động thì làm thế nào ạ

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Các anh cho em hỏi, em đang làm theo tutorial ở đây, em đang làm game đập chuột (bài thứ 26). Em đã code xong bài đó và được yêu cầu làm thêm menu cho game đó. Ví dụ như là có nút New Game để chơi game, Credit để xem thông tin, và sau khi chơi xong có nút Try Again và nút Back để chơi lại và quay lại màn hình menu. Em đã thử add game đập chuột vào nhưng ko được. Em thay cái lớp PlayLayer trong bài này thành lớp HelloWorldScene em đã xóa cái hàm CreateScene trong lớp HelloWorldScene đi để add vào nhưng vẫn ko được
    p/s: em build ok nhưng khi chạy thì bị stop working :(

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. Bạn ơi
    Mình lấy code của bạn và compile theo bạn thì chương trình gặp phải lỗi này không biết bị vấn đề gì? nhờ bạn cho mình chút lời khuyên nhé! cám ơn bạn nhiều

    http://uploads.im/4B2Ht.png

    ReplyDelete