Video - Hướng dẫn cài đặt Cocos2d-x V3.0 FINAL - Install Cocos2d-x v3.0 Final - 100% Working

Người đăng: share-nhungdieuhay on Thứ Tư, 30 tháng 4, 2014

Lần đầu làm Video, có gì sai sót, mọi người bỏ qua. Quay đi quay lại 3-4 lần thôi,

Các bạn chú ý theo dõi kỹ nhé

Đoạn cuối có Bonus 1 tí, Các bạn xem và ủng hộ



Các Video lần sau mình sẽ làm công phu hơn
More about

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

Người đăng: share-nhungdieuhay on Thứ Ba, 29 tháng 4, 2014

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)
More about

Tài liệu tiếng Việt học Cocos2dx

Người đăng: share-nhungdieuhay

Hi all!

Đúng là học thầy không tày học bạn, học bạn không bằng...tự đọc sách. Đọc sách mà cũng không xong thì khỏi học. hêhê

Nói vậy cho vui thôi, khi học bất cứ ngành nghề gì chúng ta đều phải cần tới sự hướng dẫn chỉ dạy từ những cuốn sách, từ thầy giáo hoặc bạn bè, và ngày nay là bác Google.

Sau một thời gian tìm tòi trên mạng, mình cũng tìm được Vô số sách hướng dẫn Cocos2d-x trên mạng NHƯNG, toàn phiên bản cũ 2.x đổ về trước.VÀ có một khó khăn nữa là, 

1/ Sách đó toàn tiếng ANH, TRUNG, HÀN, NHẬT. ( không đến nỗi ko thể đọc)
2/ Trong sách chỉ có một số đoạn code, hướng dẫn, giải thích. Còn lại Source đầy đủ nằm trong đĩa gốc hoặc trên 1 trang tính phí ( bán kèm sách online mà )

Có một cuốn nổi tiếng nhất là Cocos2d-x by Exam mình cũng tìm thấy nhưng cũng mắc phải 2 vấn đề trên, nên mình quyết định là tự mình tìm hiểu Engine vậy. Vì đọc sách với code cũ có khi mất thời gian viết lại code cho Engine mới .

Dù sao mình cũng sẽ chia sẻ với các bạn tài liệu này để tham khảo. bạn nào xài Engine cũ cũng rất hữu ích đấy. Trong sách này có 4 Game, mình mới có 1 game đủ source code. Chia sẻ sau nhé

More about

Tin vui cho anh em, đã ra Cocos2d-x V3.0 FINAL

Người đăng: share-nhungdieuhay

Hix!

Trong thời gian mình miệt mài viết bài về Cocos2d-x V3 RC0, RC1,RC2 thì tại trang chủ đã ra bản Cocos2d-x V3.0 FINAL rồi, vui vãi. Hi vọng là nó sẽ còn được support dài dài

Trong bản FINAL này mọi thứ hầu như đã hoàn thiện tốt phục vụ cho việc làm game của lập trình viên, Thực sự là có quá nhiều thứ hay, nhưng do trình độ có hạn và mới tìm hiểu nên không biết là có gì nổi trội hơn các bản trước không. hehe, Nhưng 1 điều chắc chắn là nó đủ sức làm được những gì 1 game 2D, 2,5D yêu cầu



Tin vui thứ 2 là: trên trang chủ đang tổ chức 1 cuộc thi viết hướng dẫn để quảng bá cho Engine này

Cocos2d-x 3.0 Tutorial Competition On
deadline đến cuối tháng 5. Như vậy là khoảng tháng 7 chúng ta sẽ có những bài Tut chất lượng ( bằng tiếng Anh) để tham khảo rồi. 

Nhưng điều này làm mình cũng hơi e ngại là cùng với chiến dịch quảng bá này liệu mai mốt Engine này có thu phí hay ko?? Haizzz! Nếu thế thì buồn lắm.

Thôi trong thời gian chờ đợi, chúng ta tự mày mò và nghiên cứu những code cũ vậy!
More about

Bài 7 - Menu, từ cơ bản tới phức tạp (Part 1)

Người đăng: share-nhungdieuhay on Chủ Nhật, 27 tháng 4, 2014

Hi, cả lò! (Trời bắt đầu thành cái lò nung tới nơi rồi)

Mọi người nghiên cứu tới đâu rồi nhỉ, còn ai chưa qua được bước cài đặt không? Mình đảm bảo làm theo mình chắc chắn thành công nhé. Xin thông báo với tất cả 1 tin mừng đó là phiên bản Cocos2dx-3 đã ra phiên bản FINAL rồi nhé, nghĩa là bản chính thức, đã khắc phục được tất cả các lỗi. Vậy chúng ta yên tâm học tiếp thôi. Nắm vững được 1 phiên bản thì sau này có ra V4,V5 cũng không khó để tiếp cận.

Ở bài trước, chúng ta đã học qua 1 Bài về Physic cơ bản trong Game và cách tạo chúng = engine Cocos2dx v3. À, trong Engine này sử dụng 2 thư viện Physic để xây dựng game, đó là Chipmunk, và Box 2D. Bài trước là dựa trên Chipmunk nhé, đơn giản, gần gũi hơn Box 2D. Sau này mình sẽ tìm hiểu nốt cái Box 2D và giới thiệu với mọi người. Giờ thì đi tiếp nào, Trong bài này, mình sẽ hướng dẫn mọi người làm mấy cái Menu có thể thao tác được để thực hiện 1 công việc nào đó.

Bắt đầu thôi. Tạo 1 Project mới tên Menu như sau, mở cmd lên gõ vào

>cocos new menu -p com.vn.menu -l cpp -d f:android/project

Sau khi Project mới được tạo, bạn chạy luôn lệnh này giúp mình

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


Đây là biên dịch lần đầu, mục đích là liên kết tới các thư viện của Engine. Lần biên dịch đầu tiên thường lâu là vì thế. Các lần sau thì nhàn hơn nhiều bởi hầu hết chúng ta chỉ thay đổi ở Class và Resource mà thôi.

B1) Copy code và chạy thử
Bạn mở thư mục Classes theo đường dẫn sau F:/android/project/menu/Classes ( có thể khác trên máy bạn)  có chứa 4 file quen thuộc phải không. Nhưng trong bài này chúng ta sẽ không dùng lớp HelloWorldScene nữa mà thay thế bằng 2 lớp khác là MenuLayer và SceneManger.

Bạn xóa 2 file HelloWorldScene.cpp và HelloWorldScene.h, download file nguồn sau tại ĐÂY và copy paste 4 file trong đó vào thư mục Classes. Tiếp theo bạn mở file AppDelegate.cpp, ở dòng #include thứ 2  bạn thay HelloWorldScene.h =  SceneManager.h, 
bỏ dòng auto scene = HelloWorld::createScene();
và director->runWithScene(scene); đi nhé. 
Thêm vào 1 dòng lệnh sau SceneManager::goMenu(); vào bên dưới 2 dòng trên

Xong rồi, trước khi biên dịch chạy thử bạn mở file Menu.vcxproj theo đường dẫn sau F:/android/project/menu/proj.win32/ rồi tìm "HelloWorldScene.cpp" bạn sẽ thấy 4 tên file cơ bản được đặt ở đây khi biên dịch (HelloWorldScene.h, HelloWorldScene.cpp, AppDelegate.cpp, AppDelegate.h )

Vì ở trên bạn đã xóa HelloWorldScene.h và HelloWorldScene.cpp đi rồi nên ở đây bạn cũng phải xóa đi. Đồng thời thêm vào 4 file SceneManager.h, SceneManager.cpp, MenuLayer.h , MenuLayer.cpp vào Menu.vcxproj để trình biên dịch sẽ xử lý thêm 4 file này khi chúng ta biên dịch lại 1 lần nữa để chạy. Cách thêm thì như hình



Chạy thử = lệnh

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

Rất tiếc! LỖI 1 đống nhé. Cũng phải thôi vì mã nguồn có lẽ không phù hợp với phiên bản Engine đang dùng, phải sửa lại đôi chút. Hoặc là tác giả của source bị sai mấy câu lệnh chẳng hạn. Căn cứ vào mấy cái lỗi để sửa thôi

B2) Nghiên cứu file nguồn 1 chút nhỉ

Nhìn vào thông báo lỗi, khá nhiều lỗi luôn, và không phải lỗi nào cũng có thẻ hiểu được. Sau 1 thời gian có kinh nghiệm chắc chắn bạn sẽ fix được các lỗi này thôi. Quả thật mình cũng không biết phải diễn giải các lỗi này ra đây thế nào nữa hì. Tốt nhất là kiểm tra lại mã nguồn của chúng ta xem có sai sót gì không.

Ở phần trên sẽ báo có 8 lỗi: Identifier 'Object' .....

Mở 2 file Header là SceneManager.h, MenuLayer.h , thêm vào đó dồng USING_NS_CC; vào dưới các dòng #include, cả 2 file nhé. compile lại xem, build được luôn, nhưng chạy thử file exe trong F:/android/project/menu/bin thì lại báo lỗi stop working.

Theo kinh nghiệm của mình thì, khi Build không gặp lỗi gì, tức là code đã chuẩn theo phiên bản Engine. Nhưng khi chạy mà báo lỗi Stop working thì có thể do 2 lỗi sau, không tương thích với hệ thống ( build trên 32 mang chạy trên 64 chẳng hạn) và lỗi thứ 2 là do Resource ( file hình ảnh, âm thanh, font, ...) đã bị thiếu. 

Trong trường hợp này mình cố tình ko copy 1 file font "Marker Felt.ttf" vào thư mục Resource nên build ok nhưng chạy bị lỗi. Bạn copy file "Marker Felt.ttf" từ F:/android/project/menu/Resource/font ra ngay bên ngoài thư mục Resource ( cùng cấp với mấy hình ảnh HelloWorld đó)


Compile lại xem nào


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

OK nhé


B3) Nghiên cứu Code

Bạn mở 2 file header là SceneManager.h, MenuLayer.h và ngó qua chút: không có gì đặc biệt lắm phải không, ở đó chứa khai báo các hàm hoặc thuộc tính của một lớp. Cách khai báo bạn ôn lại 1 chút trong C++ là hiểu được thôi. Mình sẽ đi vào phần chính ở dưới

(Các bạn theo dõi file CODE nhé, vì nếu chép ra đây thì dài và rối lắm. Chúng ta giải thích là chính thôi)
+ Mở file SceneManager.cpp, trong này có 3 hàm 

void SceneManager::goMenu(), hàm này tạo ra 1 layer ( cái này cũng gọi là lớp nhưng không giống Class nhé. Class là chỉ các đối tượng với thuộc tính và hàm, còn layer giống như 1 mặt phẳng để đặt các thứ khác lên nó, hình dung như thế đi). Sau đó hàm này gọi tiếp 1 hàm void SceneManager::go(Layer* layer)

void SceneManager::go(Layer* layer) thực hiện 2 công việc, truyền layer vừa tạo ở trên cho 1 hàm Scene* SceneManager::wrap(Layer *layer) để xử lý cái layer này,việc xử lý bằng hàm Wrap sẽ trả lại 1 Scene. Sau đó kiểm tra xem có scene nào đang chạy không, nếu có thì thay thế = Scene mới có layer vừa tạo. nếu không có Scene nào đang chạy thì chạy với Scene có layer vừa tạo.

Scene* SceneManager::wrap(Layer *layer) thực hiện công việc là lấy tham số layer truyền vào, đặt lên 1 Scene mới tạo, trả lại giá trị là 1 Scene.

+ Mở file MenuLayer.cpp trong đó cũng lại có 3 hàm

* bool MenuLayer::init(), hàm init luôn trả về bool nhé

Trong này mình sẽ giải thích một số dòng lệnh "lạ"

TTFConfig config_font96("Marker Felt.ttf", 96);

TTFConfig config_font52("Marker Felt.ttf", 52);

//Chình font "Marker Felt.ttf" thành 2 cỡ 96, và 52 (pixel??)

Label *titleLeft = Label::createWithTTF(config_font96, "Menu ");

// Tạo 1 Label ( nhãn )  titleLeft có hiện dòng chữ "Menu" sử dụng font config_font96, các lênh tương tự bên dưới nhé
    
MenuItemFont *startNew = MenuItemFont::create("New Game", CC_CALLBACK_1(MenuLayer::onNewGame, this));

// Tạo biến menu item startNew hiện từ "New Game", khi ấn lên menu item này sẽ gọi hàm onNewGame() của lớp MenuLayer, lệnh dưới tương tụ tạo menu item "Credits"

Menu *menu = Menu::create(startNew, credits, NULL);
// Tạo 1 biến menu có chứa 2 menu item con đã tạo ở trên là startNew  và credits

1 đoạn bên dưới là công việc nhàm chán đặt vị trí trên màn hình = lệnh setPostion(); và đặt các đối tượng vào layer = lệnh this->addChild();

có 1 câu này
 menu->alignItemsVerticallyWithPadding(80.0f); // căn chỉnh theo chiều dọc các đối tượng của biến menu cách nhau 1 khoảng 80 (pixel??)

- 2 hàm bên dưới onNewGame(), onCredits() thực hiện công việc đơn giản là lại gọi hàm tạo 1 Scene mới khi ấn vào 2 menu tạo ở trên

Tổng kết lại, trong bài này học được :

+ Tạo 1 label với font = lệnh
TTFConfig config_font96("Marker Felt.ttf", 96); 
Label *titleLeft = Label::createWithTTF(config_font96, "Menu ");

+ Tạo 1 đối tượng menu item có thể ấn được 
MenuItemFont *startNew = MenuItemFont::create("New Game", CC_CALLBACK_1(MenuLayer::onNewGame, this));

Menu *menu = Menu::create(startNew, credits, NULL);

Xong rồi. 1 bài đơn giản  mà phải diễn giải dài quá các bạn ạ, nếu bài nào mà dài, nhiều đối tượng chắc chết quá



More about

Hướng dẫn Chữ To Trên Facebook

Người đăng: share-nhungdieuhay on Thứ Sáu, 25 tháng 4, 2014

Hôm nay đang rầm rộ trào lưu chữ to trên facebook. Và sau đây mình sẽ hướng dẫn các bạn làm nó.


Đầu Tiên Vào :
https://www.facebook.com/notes/



Tạo 1 Note Mới :D


Tiêu đề: tùy ý
Nội dung : Tùy biến theo ý bạn

<div><div><p><big><big><big><big><b><big><b><b><a href="https://www.facebook.com/dovanhieu2509">Yêu anh đi anh không đòi quà</a></b></b></big></b></big></big></big></big></p></div></div>

Chúc các bạn thành công
More about

Bài 6 - Ball - Physics cơ bản trong Cocos2dx -v3 (Part2)

Người đăng: share-nhungdieuhay on Chủ Nhật, 20 tháng 4, 2014




Hi cả nhà!

Thời gian qua nhanh quá mà chả làm được cái gì, chán ghê. Cũng tại mình vừa vấp phải mấy vấn đề khó giải quyết trong cocos2dx - V3 nên tìm hiểu mãi mới ra. Trong bài này mình cũng trình bày luôn vấn đề đó là gì. Bây giờ chúng ta cùng tiếp tục bài trước về Physics nhé

Ở bài trước chúng ta đã tạo mới 1 Project Ball rồi đúng không, bây giờ là phần code thể hiện physics trong đó.

Let's go!


Các bạn theo đường dẫn sau: Q/android/project/ball/class, mở file HelloWorldScene.h lên. Code của file đó sẽ như vầy:

#ifndef __HELLOWORLD_SCENE_H__

#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

USING_NS_CC;

class HelloWorld : public cocos2d::Layer

{

public:

Sprite* _ball;

PhysicsWorld* m_world;

void setPhyWorld(PhysicsWorld* world){ m_world = world; };

static cocos2d::Scene* createScene();

virtual bool init();

virtual void onAcceleration(Acceleration* acc, Event* unused_event);

bool onContactBegin(const PhysicsContact &contact);

CREATE_FUNC(HelloWorld);

};


#endif // __HELLOWORLD_SCENE_H__

Các bạn không phải sửa đổi gì nhé, mình sẽ giải thích 1 chút về mấy thứ "là lạ trong đó"cho mọi người"

Sprite* _ball; // là 1 con trỏ kiểu Sprite tên là _ball, con trỏ này để quản lý cái gọi là quả bóng trong chương trình chúng ta.

PhysicsWorld* m_world; // Con trỏ kiểu PhysicsWorld tên m_world, gán cho nó các thuộc tính vật lý

void setPhyWorld(PhysicsWorld* world){ m_world = world; }; //hàm gán thuộc tính vật lý cho m_world,

virtual void onAcceleration(Acceleration* acc, Event* unused_event); // hàm này liên quan tới gia tốc kế thì phải
bool onContactBegin(const PhysicsContact &contact); // Hàm này để phát hiện va chạm giữa 2 quả bóng

Tiếp đến các bạn mở file HelloWorldScene.cpp lên nào (file nguồn các bạn down ở bên dưới nhé, vì mình dán vào đây thì bài dài dòng quá), trong đó bạn chú ý một số đoạn sau,

Trong hàm tạo Scene : Scene* HelloWorld::createScene(){}

auto scene = Scene::createWithPhysics(); // Câu lệnh này tạo 1 Scene gắn thuộc tính Physics
---

auto layer = HelloWorld::create(); // Tạo 1 layer của lớp HelloWorld

layer->setPhyWorld(scene->getPhysicsWorld()); // đặt thuộc tính Physics cho biết m_world của đối tượng layer,

scene->getPhysicsWorld() //nghĩa là lấy Physics của scene rồi gán cho m_world của layer

tiếp theo, hàm init()

_ball = Sprite::create("Ball.jpg", Rect(0, 0, 52, 52)); // Tạo 1 quả bóng nằm trong hình vuông 52 pixel

_ball->setPosition(Point(400,600)); // đặt ở vị trí 400, 600

auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width / 2); // Tạo 1 khung body có đặc tính vật lý để phát hiện va chạm, khung này dạng tròn có đường kính = nội dung của _ball chia 2.

ballBody->setContactTestBitmask(0x1); // Cái này rất quan trọng, nếu ko có thì hàm onContactBegin ko có tác dụng, tìm trên mạng mãi mới sửa được lỗi này

_ball->setPhysicsBody(ballBody); // Gán body cho _ball

this->addChild(_ball); // thêm vào layer HelloWorld đã tạo ở trên

ball2 được tạo ra tương tự

tiếp theo, đoạn này sẽ tạo ra 1 khung bao quanh màn hình, khi quả bóng chạm vào sẽ dừng lại. nó giống một bức tường ( 1 cái hộp ) vậy thôi, không cần giải thích nhiều nhé, cứ code mà đập thôi

auto edgeSp = Sprite::create();

auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);

edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));

edgeSp->setPhysicsBody(boundBody);

this->addChild(edgeSp);

edgeSp->setTag(0);

Tiếp theo, quan trọng nè

auto Listener = EventListenerPhysicsContact::create(); // Biến này để "lắng nghe" các tương tác vật lý xảy ra

Listener->onContactBegin=CC_CALLBACK_1(HelloWorld::onContactBegin,this); // gọi hàm onContactBegin, hàm này sẽ xử lý khi va chạm xảy ra, hàm này là hàm chồng lên( gọi là hàm overide của 1 hàm mẫu đã có của thư viện - bạn nào học C++ sẽ hiểu rõ).

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

// dòng này để xử lý ông Listener bên trên kia,

Túm lại đoạn trên đây để phát hiện ra tương tác giữa 2 quả bóng bạn tạo ra, rồi gọi hàm onContactBegin để xử lý.

Bạn mới học thì cứ dập khuôn từng đoạn code, tạm thời đừng hỏi sao phải viết thế, viết khác được không ( Haizzz, ko biết giải đáp thế nào nhỉ). Viết khác được, nhưng hãy nắm chắc cái ban đầu đi đã rồi phát triển sau.

Bây giờ tới hàm onContactBegin{}, format của nó chắc chắn phải viết như sau, sau đó thêm gì thì thêm vào trong 2 dấu ngoặc

bool HelloWorld::onContactBegin(const PhysicsContact &contact)

{

return true;

}

thêm đoạn này vào để xóa 2 quả bóng khi chạm nhau

auto ObjA = (Sprite*)contact.getShapeA()->getBody()->getNode();

auto ObjB = (Sprite*)contact.getShapeB()->getBody()->getNode();

this->removeChild(ObjB,true);

this->removeChild(ObjA,true);

tiếp theo, hàm này this->setAccelerometerEnabled(true); // Gia tốc kế của máy điện thoại

Chạy thử nhé, các bạn đừng quên lệnh này nhé

cocos run -s q:android/project/ball -p win32 

Nếu bạn thấy 2 quả bóng đập vào nhau và biến mất là đã thành công

Bạn thử bỏ dòng lệnh ballBody->setContactTestBitmask(0x1); đi xem, 2 quả bóng có va vào nhau nhưng ko có gì xảy ra phải không. Hehe, mỗi dòng lệnh này mà mình tìm kiếm mất gần tuần. HIX

Vấn đề Physic đã giải quyết xong

Nâng cao lên 1 chút nào

Xóa dòng this->setAccelerometerEnabled(true); và layer->setPhyWorld(scene->getPhysicsWorld());, Xóa tiếp hàm onAcceleration, kết quả ko đổi đúng ko, tốc độ rơi vẫn thế (trên win), 2 quả bóng chạm nhau vẫn biến mất. Lệnh này hình như thiết lập gia tốc kế. Các bạn thử thiết lập và xoay màn hình điện thoại xem nhé. Quả bóng sẽ lăn theo hướng rơi xuống cạnh đáy màn hình

Nhưng thử xóa dòng _ball->setPhysicsBody(ballBody); ball2->setPhysicsBody(ball2Body); Bạn sẽ thấy 2 quả bóng đứng im luôn. Có thể thấy hàm này giống như việc đặt vào quả bóng 1 khối lượng nào đó vậy ( chắc tương đương với bán kính). Quên mất vật nặng nhẹ đều rơi như nhau với gia tốc G mà

Bây giờ thêm lại 2 lệnh setPhysicsBody bên trên, rồi thêm dòng lệnh sau: scene->getPhysicsWorld()->setGravity(Vect(0.0f,-5000.0f)); Bạn sẽ thấy quả bóng rơi rất nhanh, đó, chỗ này chính là thiết lập gia tốc trọng lực, sét càng cao thì rơi càng nhanh.

Như vậy qua bài này, bạn đã biết làm thế nào để thiết lập 1 Physics cơ bản cho chương trình rồi nhé. Sang phiên bản mới ( mình đang xài V3 RC2) bạn chỉ cần nắm mấy lệnh cơ bản sau

auto scene = Scene::createWithPhysics(); // Tạo 1 Scene có thuộc tính Physics ( đã bao gồm gia tốc )

scene->getPhysicsWorld()->setGravity(Vect(0.0f,-3000.0f)); // Thay đổi gia tốc, nhớ là phải có dấu "-"

auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width);

_ball->setPhysicsBody(ballBody);  // thiết lập thuộc tính vật lý ( cụ thể là khối lượng và ranh giới của vật thể )

ballBody->setContactTestBitmask(0x1);  // Thiết lập sự phát hiện va chạm giữa 2 vật

// và đoạn này để lắng nghe sự va chạm nếu có

auto contactListener = EventListenerPhysicsContact::create();

contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

DOWN Mã nguồn và file Resource

Bài 7: Menu - Từ cơ bản tới phức tạp (Part 1)

More about

[ Xử Lý Ảnh] : Phần ngày 2-4-2014

Người đăng: share-nhungdieuhay on Thứ Hai, 14 tháng 4, 2014

3.6.4 . Dùng đạo hàm cấp 1 tăng độ nét của ảnh .

Công thức :
đạo hàm cấp 1 của 1 ảnh có tên gọi là Gradian Laplace.
Người ta quan tâm đến độ lớn của đạo hàm cấp 1 :
 Độ lớn vec tơ đạo hàm cấp  của
ký hiệu là M(x,y) :

Thường được gọi là gradient image :  
Lấy căn bậc 2 ta được : 
g(x), g(y) là ảnh. M(x,y) cũng là ảnh .

Ký hiệu cửa sổ 3x3 của ảnh :

gx=z8-z5 hoặc gx=z9-z9
gy= z6-z5 hoặc gy= z8-z6

Mặt nạ đạo hàm nên có kích thước là lẽ để có phần tử trung tâm nên Sobel mở rộng định nghĩa đạo hàm: 

để đầu ra bằng 0 ảnh trong miền bằng phẳng.

3.7 (không cần )

3.8. Dùng kỹ thuật mờ để biến đổi độ sáng và lọc trong không gian.

3.8.1. Nhắc lại lý thuyết tập hợp.


More about

Bài 5: Ball - Physics cơ bản trong Cocos2dx - V3.1 ( Part 1)

Người đăng: share-nhungdieuhay on Chủ Nhật, 13 tháng 4, 2014

Hi cả nhà!
Chán quá đi, dạo này tình hình sức khỏe đi xuống quá. Sáng nay uống 1 nhúm thuốc các thể loại giờ nôn nao chóng mặt vãi ( Sốc cmn thuôc rồi). Lần trước có 1 lần cũng uống quá liều, may chưa tiêu.

Tay chân mặt mũi, trí óc không mỏi, mà mắt mỏi và choáng quá. Thôi cố viết xong bài này rồi đi nghỉ.

Vậy là chúng ta đã đi qua được 2 bài quan trọng là cài đặt Cocos2dx và HelloWorld trong các phần trước rồi. Các bạn vẫn còn hào hứng cùng tôi đi tiếp không nào. Haizzz, chắc có một số người rớt lại phía sau hoặc bỏ cuộc rồi không biết chừng. Dù thế nào, dù 1 mình tôi cũng sẽ đi tới cùng. :))

Tôi xin nhắc lại với các bạn là: 
1/ Những gì tôi viết trong này hoàn toàn là tham khảo từ các bài code ví dụ trên mạng nước ngoài, nên có thể sẽ không theo 1 hệ thống nào cả, vì tôi ko phải là nhà viết sách chuyên nghiệp, nên không thể hệ thống lại được theo cách tốt nhất. Tôi sẽ ưu tiên cho các bài ngắn dễ hiểu, rồi đến bài dài khó hiểu, vậy thôi, hoặc theo thứ tự thời gian các bài code tôi sưu tầm được.

2/ Vì phiên bản Cocos2dx v3.0 (giờ đã là 3.2 RC0 ) này là phiên bản mới nhất nên chẳng có sách nào đâu. À, có đấy nhưng bằng tiếng Hàn + Trung, đang trong quá trình chuẩn bị dịch sang Anh, nhưng mà chắc chắn là phải mua = tiền, nhưng cũng ko biết mua ở đâu nữa, và chắc phải 1-2 năm nữa Việt Nam mình mới có. Hehê, lúc đó thì chúng nó lại ra phiên bản 4, rồi 5 và rồi chúng ta lại chờ sách. Sao luẩn quẩn vậy? chả lẽ chúng ta cứ phải chờ đợi vào người khác?

3/ Các sách cũ hơn thì hầu như không dùng được vì hồi trước tiền thân của Cocos2d - X ( nhớ là có chữ X nhé ) là Cocos2d - iphone ( cho riêng Iphone ) nên các Sách trước đây viết cho lập trình viên Iphone, các bạn nhé. Code là Oject -C chứ không phải C++ như Cocos2d - X ( đa nền ) như bây giờ. Bạn vẫn có thể sử dụng code Object - C đó để port sang code C++ , nhưng khi đó trình độ và kinh nghiệm ít nhất cũng phải 6 tháng học cocos2d-x nhé. Thôi thì chịu khó học cái mới mẻ đi.

Dài dòng lắm rồi, túm lại là, có cái để học, để làm là tốt lắm rồi, không lại rảnh rỗi sinh nông nổi thì chết.

Bắt đầu thôi

Đầu tiên bạn tạo 1 Project mới cho mình bằng CMD như sau

>cocos new Ball -p com.vn.Ball -l cpp -d Q:/android/project

Giải thích chút, lệnh trên sẽ tạo 1 Project tên Ball trong thư mục Q:/android/project

-p com.vn.Ball là cú pháp package. bạn có thể thay đổi 1 chút nhưng nhất thiết phải có 2 cái dấu chấm (.) như trên nha. Tốt nhất là làm theo mình.
-l cpp: là lựa chọn ngôn ngữ C++
- d Q:/android/project: là thư mục lưu Project thôi

OK, rồi. Bạn thấy đó cái Project Ball lần này cũng chẳng khác gì  cái Project HelloWorld hôm trước cả đâu, không tin bạn vào kiểm tra xem, cấu trúc thư mục rồi file nguồn cũng giống hệt nhau mà. Bạn tự kiểm tra nhé. Nhưng rồi chúng ta sẽ làm cho nó khác đi một chút, đó là thêm physics ( tạm gọi là thuộc tính vật lý đi) vào trong chương trình Ball này.

Physics là gì, tại sao phải thêm Physics?

Đơn giản lắm các bạn ơi. Physics là sự mô phỏng các hiện tượng vật lý trong game sao cho giống với ngoài đời thực. Sự mô phỏng này có thể giống nhiều hay ít tùy thuộc vào ý tưởng game, và quyết định của lập trình viên.

Các physic cơ bản bạn đễ nhận thấy là: Hình ảnh, Âm thanh, gia tốc rơi, chuyển động 1 vật, Va chạm nhau...

Hẹn các bạn bài sau nhé, nay mỏi mắt quá, sẽ sớm lên sóng thôi.


More about

Bài 4: Hello World. Bài code đầu tiên

Người đăng: share-nhungdieuhay on Thứ Sáu, 11 tháng 4, 2014

Hi mọi người!

Dạo này không hiểu sao ốm yếu quá, ít có thời gian nghiên cứu. Nay sức khỏe đã tạm ổn, mình sẽ tiếp tục giới thiệu với các bạn bài đầu tiên về code. Mà không biết còn ai thắc mắc về cách cài đặt không?

Hiện tại đến thời điểm mình sửa bài này (7-11-2014, đã có Cocos2d-x 3.2 RC0) rồi. Và mình khuyên các bạn là chỉ nên tải và sử dụng các phiên bản có đuôi RC.x trở lên cho tới stable ( thường là ko ghi gì sau đuôi ví dụ 3.1.1 ) chứ ko nên sử dụng các bản Alpha.x hoặc Beta.x vì chúng vẫn còn trong giai đoạn thử nghiệm sẽ mắc nhiều lỗi không đáng có. Và khi mình update các phiên bản ( chỉ việc copy vào thư mục chưa Engine thôi - nội dung trong thư mục engine cũ thì xóa đi ) hầu như không gặp bất kỳ lỗi nào khi compile, run cả trên Win, hoặc Android. Chỉ gặp các lỗi liên quan tới code do thư viện của cocos2d-x có thay đổi 1 chút xíu ở phiên bản mới, sai đâu thì IDE sẽ báo ở đó để biết cách sửa thôi.

=> Cách cài đặt của các phiên bản Engine thế hệ 3.x là giống nhau ( tới thời điểm này ) nhé

Nếu các bạn đã từng học qua các loại ngôn ngữ lập trình, hẳn đã quen với loại bài viết Hello World, Your First Application rồi nhỉ. Ai đã tìm hiểu 1 chút rồi thì có thể xem nhanh qua phần này. Mình bắt đầu nhé.

A - Tạo và chạy thử Project

Đầu tiên, tạo một Project mới với tên Hello World bằng lệnh sau trong cmd

Run/cmd
>cocos new HelloWorld -p com.vn.HelloWorld -l cpp - d q:/android/myproject

Đợi khoảng 5 phút để nó tạo Project mới cho chúng ta

Xong rồi, vào Project mới tạo theo đường dẫn

Q:/android/myproject/helloworld, cấu trúc thư mục trong đó như sau:

Classes <- Quan trọng nhất nhé, nó chứa mã nguồn cpp hay lua tùy thuộc việc bạn chọn ngôn ngữ nào khi dùng lệnh new ở phía trên.
cocos2d <- thư viện của engine Cocos2d - x.
proj.android <- dành cho việc build ứng dụng apk cho Android mobile.
proj.ios_mac  <- dành cho việc build ứng dụng cho Iphone và Mac OS ( Chỉ chạy được trên máy của Apple, hoặc máy cài Mac OS.
proj.linux <- dành cho việc build ứng dụng trên máy Linux.
proj.win32 <- dành cho việc build ứng dụng trên hệ điều hành Window 7, 8
proj.wp8-xaml <- dành cho việc build ứng dụng chạy trên Window phone 8
Resources <- chứa ảnh, font chữ, Map, định nghĩa vật lý,v.v...
.cocos-project.json <- chỉ định việc build project với ngôn ngữ nào, lua hay cpp.
CMakeLists.txt <- Danh sách thư viện phục vụ việc build project.

Tiếp theo chúng ta build và run thử trên Window nhé. Lệnh sau

>cocos run -s q:/android/myproject/helloworld -p win32

(gõ cocos run -h để được help)

Lưu ý: 
1/ Win mình xài là Win 7 32 bít, bạn nào xài XP, Win 7 -  64, Win 8 all, thì mình ko biết nhé. Các bạn thử xem thành công không. (Đã cài đặt và chạy trên win 7 - 64 ngon lành cành đào nhé.). Đã có nhiều bạn chạy Win8 OK rồi nhé

2/ Mình ko chắc xài máy ảo VMWare có chạy được không nhé

3/ Bạn có thể build thành ứng dụng .apk để chạy trên máy ảo Android, hoặc chơi máy thật luôn cho máu

>cocos compile -s q:/android/myproject/helloworld -p android --ap 16
--ap 16 là chỉ định dành cho android 4.1.2 trở lên

cài vào máy ảo

>adb install q:/android/myproject/helloworld/bin/debug/android/helloworld-debug-unligned.apk
hoặc
>cocos run -s q:/android/myproject/helloworld -p android --ap 16

Nếu không báo lỗi nào và xuất hiện ảnh như thế này, nghĩa là bạn đã thành công rồi đó. Mình cam đoan nếu các bạn cài đặt như bài trước của mình thì chắc chắn sẽ thành công.



B - Tìm hiểu Code

Bên trên mới là phần tạo và chạy thử thôi, còn trong phần này chúng ta cùng tìm hiểu những dòng lệnh đầu tiên
Các bạn vào thư mục Classes của Project, trong đó có 4 file
AppDelegate.h, AppDelegate.cpp
HelloWorldScene.h, HelloWorldScene.cpp

Mới đầu mình chỉ nên tìm hiểu 2 file HelloWorldScene.h, HelloWorldScene.cpp thôi nhé. 2 file bên trên có chức năng theo dõi thông số của ứng dụng thôi. Nhưng bạn không thể xóa 2 file này nhé

file HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();  
    
    void menuCloseCallback(cocos2d::Ref* pSender);
    
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__

cấu trúc rất giống 1 chương trình C++ phải không, thì nó chính là C++ mà, hehee

Trước khi tìm hiểu code, các bạn nên đọc qua, hoặc ôn lại kiến thức C++ chú nhé. Mình sẽ cố gắng giải thích các hàm chức năng hoặc các điểm mới trong cocos2dx 3 thôi

static cocos2d::Scene* createScene();  //tạo ra một cảnh mới
virtual bool init(); //Khởi tạo 1 đối tượng của lớp HelloWorld
void menuCloseCallback(cocos2d::Ref* pSender); //Nút Tắt ứng dụng
CREATE_FUNC(HelloWorld); //Chưa rõ lắm, nhưng tạm coi là cần phải có đi

file tiếp theo HelloWorldScene.cpp

#include "HelloWorldScene.h"

USING_NS_CC;

// hàm tạo 1 cảnh mới trả về con trỏ Scene*
Scene* HelloWorld::createScene()
{
  
    auto scene = Scene::create();  // tạo 1 đối tượng Scene
    
    auto layer = HelloWorld::create(); // tạo đối tượng HelloWorld

// thêm đối tượng HelloWorld vào Scene
    scene->addChild(layer);

// trả về con trỏ scene
    return scene;
}

// khởi tạo đối tượng HelloWorld
bool HelloWorld::init()
{
    //////////////////////////////
    // kiểm tra khởi tạo lỗi
    if ( !Layer::init() )
    {
        return false;
    }
    
// Lấy kích thước màn, và điểm tọa độ gốc
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Point origin = Director::getInstance()->getVisibleOrigin();


    //tạo nút đóng ứng dụng

    auto closeItem = MenuItemImage::create(
                                           "CloseNormal.png",
                                           "CloseSelected.png",
                                           CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
    
// Đặt vị trí nút đóng tại điểm tính theo công thức bên dưới
closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
                                origin.y + closeItem->getContentSize().height/2));

    // Tạo menu chứa nút đóng ở bên trên, đặt vị trí
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Point::ZERO);
    this->addChild(menu, 1); // thêm menu vào đối tượng HelloWorld

    /////////////////////////////
   // Tạo 1 dòng Text với font arial cỡ 24 pixel
    
    auto label = LabelTTF::create("Hello World", "Arial", 24);
    
    // đặt vị trí Text
    label->setPosition(Point(origin.x + visibleSize.width/2,
                            origin.y + visibleSize.height - label->getContentSize().height));

    // Thêm text vào đối tượng HelloWorld
    this->addChild(label, 1);

    // tạo 1 đối tượng loại sprite ( là các đối tượng có thể di chuyển trong game)
    auto sprite = Sprite::create("HelloWorld.png");

    // Đặt sprite lên vị trí giữa màn hình
    sprite->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    // Thêm đối tượng Sprite vào HelloWorld
    this->addChild(sprite, 0);
    
   // giá trị trả về của hàm init()
    return true;
}

// Hàm đóng ứng dụng
void HelloWorld::menuCloseCallback(Ref* pSender)
{

Director::getInstance()->end(); // Kết thúc chương trình.

// Nếu là IOS thì gọi lệnh exit(0);#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

exit(0);

#endif

}

Tới đây, hẳn mọi người đã biết cách tạo và chạy thử 1 project thế nào rồi phải không. Lại còn biết được 1 phần code đơn giản nữa cơ đấy. Trong các bài sau nâng cao hơn sẽ giúp các bạn hiểu sâu hơn về Cocos2dx trong lập trình Game di động.
Bye bye!


More about

Một số chú ý khi biên dịch project cocos2dx trên window

Người đăng: share-nhungdieuhay on Thứ Năm, 10 tháng 4, 2014

Hi mọi người!

Mình đã trở lại và bớt ăn hại hơn. Vì, sau 1 thời gian nghiên cứu mày mò, công việc tiến triển khá thuận lợi. Quả thật để sử dụng tốt được Engine dạng mã mở như thế này đã tiêu tốn của mình khá nhiều thời gian, công sức. Có sẵn code toturial rồi mà khi biên dịch còn lỗi tùm lum, tìm rất khổ. Mình tổng kết vào đây những lỗi phổ biến khi biên dịch để các bạn chú ý. Có lỗi nào là cập nhật ngay lỗi đó.

Vì mình làm trên Window nên build file trực tiếp trên ra file exe ( bắt buộc cài VS 2012 trở nên nhé). Không nên xài bản Express các bạn nhé. Crack đầy ra đấy, xài bản miễn phí Express làm gì.

Lệnh CMD

WIN
>cocos compile -s q:/android/myproject/test -p win32
>cocos run -s q:/android/myproject/test -p win32

Android
>cocos compile -s q:/android/myproject/test -p android --ap 1x 
( x từ 0 đến 9 - bắt buộc SDK Manager phải cài bản API 10 ) . --ap ( có 2 dấu ngang)

Lưu ý quan trọng

1 dự án Mẫu bao gồm 4 file cơ bản

AppDelegate.h
AppDelegate.cpp

HelloWorldScene.h
HelloWorldScene.cpp

1/ Cấu trúc file
Trong Window
và 1 file quan trọng là test.vcxproj theo đường dẫn Q:\ANDROID\MyProject\Test\proj.win32 mở và tìm AppDelegate hoặc HelloWorldScene. Bạn sẽ thấy tên 4 file cần để biên dịch nằm ở đây. Nếu thêm 1 file nào mới bạn phải add vào theo đúng cú pháp. nếu thừa hoặc thiếu 1 file nào đó trong này cũng sẽ báo lỗi.

Nếu bạn Build cho Android: Bạn cũng phải bổ sung thêm file mới vào file Android.mk nằm trong đường dẫn sau

ProjectName\proj.android\jni\Android.mk

Trong các file (.h) nên có dòng lệnh USING_NS_CC; ở dưới phần #include, để tránh một số lỗi ( điển hình là PhysicsContact.

2/ Số lưu ý về Function

contactListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this);

CC_CALLBACK_1 chứ ko phải là CC_CALLBACK_2

bool GameScene::onContactBegin(const PhysicsContact& contact)
chứ ko phải

bool GameScene::onContactBegin(EventCustom* event, const PhysicsContact& contact)


3/ Build Android

Bạn mở file Android.MK trong prj.android, thêm vào Class mới tạo như sau ( ví dụ file GameOverScene.cpp)









Chú ý dấu "\" ở dòng gần cuối cùng
Dòng cuối cùng ko cần dấu này

4/ Vòng lặp For cho Vector

vector<T> vec;
for(auto i : vec){} // Chuẩn C++ 11

5/ Phiên bản 3.1

Khi bạn download bản Cocos2d-x 3.1 mới nhất về, nếu build các Project cũ sẽ bị lỗi, nhiều lỗi là khác

Bạn cần phải tạo Project mới với v3.1, sau đó copy  Class+ Resource của Project cũ đè vào build là OK

6/ Build project trên Window, file chạy ở đâu?

Nhiều bạn hỏi mình build game trên win xong click ko chạy?

Đó là do các bạn build game trên win xong lại vào thư mục Proj.win32/Debug.win32 để chạy file Exe trong đó. Vâng, bạn có build 1000 lần thì cũng ko thể chạy nổi vì trong đó KHÔNG CÓ RESOURCE cho game nên Force Stop ngay

=> Các bạn phải vào thư mục PUBLISH ( ngang hàng Proj.win32, Class,.. ) đối với Engine 3.1, hoặc vào thư mục BIN ( cũng ngang hàng Proj.win32, Class,...) với Engine 3.0. Hãy nhớ kỹ!

7/ Chỉnh Độ phân giải (Resolution) trên Window

Khi bạn build ra Android, hoạc IOS, thì tỉ lệ khung hình ( độ phân giải - Resolution ) bạn chỉnh trong file AppDelegate.cpp ( game Sushi) rất dễ dàng. Tuy nhiên, và thường thì bạn sẽ build trên win trước để test game. vậy làm sao chỉnh độ phân giải??

Hãy làm như sau, tìm file CCGLView.cpp theo đường dẫn ( Nằm trong game nhé, không phải trong Engine)

YOURGAME\cocos2d\cocos\platform\desktop mở file CCGLView.cpp

search "960" sẽ thấy 1 dòng thế này ( dòng 288 thì phải )

if(ret && ret->initWithRect(viewName, Rect(0, 0, 960, 640), 1)) {

Đây chính là kích thước màn hình game trên Desktop, giờ thì chỉnh bao nhiêu tùy bạn thôi, tùy thuộc game ngang hay dọc mà chỉnh dài x rộng cho hợp lý.
Bạn chưa tin ư? Hãy nhìn, đã đủ 7 cột, 9 hàng chưa ( ở cuối bài 23 bạn build ra không đủ 7 cột, 9 hàng là do chưa chỉnh Resolution )


( Lại bảo ko đúng đi )

8/ Phân biệt các loại Macro CC_CALLBACK_x

Chắc có nhiều bạn từng thắc mắc cái dòng Macro ở trên vẫn hay dùng trong code nghĩa là gì, khi nào dùng phải không.

Xin trả lời: Mình thấy dùng trong mấy trường hợp sau đây

+ Trong menu để gọi tới hàm thực hiện khi nhấn 1 nút, ví dụ
    MenuItemFont *startNew = MenuItemFont::create("New Game", CC_CALLBACK_1(MenuLayer::onNewGame, this));

+ Trong đối tượng bắt sự kiện ( ví dụ Touch, Contact )
    contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);

+ Trong Action Sequence

asteroid->runAction(Sequence::create(
MoveBy::create(randDuration, Point( - winSize.width - asteroid->getContentSize().width, 0)), 
CallFuncN::create(CC_CALLBACK_1(HelloWorld::setInvisible,this)), 
NULL
));   

Vậy dùng khi nào, ý nghĩa của các số 1,2

Thật ra có 4 Macro CC_CALLBACK_0, CC_CALLBACK_1, CC_CALLBACK_2, CC_CALLBACK_3

Số 0,1,2,3 chính là số tham số truyền vào của hàm được gọi.

Ví dụ hàm setInvisible(float af) thì khi gọi phải dùng CC_CALLBACK_1 ( vì có 1 tham số )

setInvisible(float af, int b)  thì khi gọi phải dùng CC_CALLBACK_2 ( vì có 2 tham số )

tương tự các trường hợp còn lại, và không có thấy CC_CALLBACK_4 à


Update thêm nhiều lắm!

Chúc các bạn sẽ có nhiều game hay!


More about

[LTM] Chương 8.1: Network Program with Java-TCP

Người đăng: share-nhungdieuhay on Thứ Tư, 9 tháng 4, 2014


Objectives

  • Giao tiếp Socket
  • Đặc điểm, cấu trúc Socket
  • TCP Socket
  • UDP Socket 
  • Thiết kế giải thuật server/client
  • Các lớp trong gói java.net 
  • Ứng dụng client/server qua TCP socket 
  • Ứng dụng client/server qua UDP socket 



Giới thiệu

  • Trong quá trình truyền tin có thể xảy ra nhiều sự cố:
  • một hay nhiều gói bị mất hay bị hỏng 
  • cần phải truyền lại hay không hoặc 
  • các gói tin đến không theo đúng trình tự. 
  • Cần xử lý;
  • việc phân chia dữ liệu thành các gói, 
  • tạo các header, phân tích header của các gói đến, 
  • quản lý danh sách các gói đã nhận được/ chưa nhận được…
  • => nhiều công việc cần phải thực hiện, và đòi hỏi rất nhiều phần mềm phức tạp để xử lý.
  • => Socket

  • Socket API – Socket Application Programming Interface: 
  • là một cuộc cách mạng của Berkeley UNIX. 
  • được giới thiệu ở BSD4.1 UNIX, 1981 
  • Xuất phát từ ý tưởng quan trọng nhất của UNIX: 
  • tất cả các thao tác vào/ra giống như vào ra tệp tin 
  • Socket xem một liên kết mạng như là một luồng mà có thể đọc dữ liệu ra hay ghi dữ liệu vào từ luồng này. 
  • Nó che dấu người lập trình khỏi các chi tiết mức thấp của mạng như môi kiểu đường truyền, các kích thước gói, yêu cầu truyền lại gói, các địa chỉ mạng... 


KHÁI NIỆM VỀ SOCKET

  • Socket: “cơ chế ổ cắm”
  • Các máy có khả năng kết nối được với nhau.
  • Dùng cơ chế client/server
  • Cung cấp hai dịch vụ chính chuyển dữ liệu thông qua socket API:
  • unreliable datagram (UDP)
  • reliable, byte stream-oriented (TCP)

Socket trong TCP/IP Model



Socket

  • socket được định nghĩa trong hệ điều hành bằng một cấu trúc, được xem như điểm nối để hai procceses giao tiếp với nhau.
  • Cấu trúc socket gồm 5 fields:


  1. Family : xác định protocol group
  2. Type : xác loại socket, stream, datagram hay raw socket.
  3. Protocol : kieu gthuc. thường gán giá trị bằng 0
  4. Local Socket Address và 
  5. Remote Socket Address : là địa chỉ socket của process cục bộ và từ xa.

Cấu trúc socket

Địa chỉ của một socket
Địa chỉ của một socket trên mạng TCP/IP gồm có hai phần:

  • Địa chỉ IP: một số nguyên 32 bits xác định duy nhất một card mạng trên máy tính (host)
  • Cổng dịch vụ: một số nguyên 16 bits xác định điểm kết nối với một ứng dụng trên một host. 
  • Các ứng dụng thương mại hay các dịch vụ thông dụng sử dụng các cổng dịch vụ chuẩn đã được đăng ký


Cấu trúc địa chỉ socket
struct sockaddr_in
{
u_char sin_len;
u_short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};

Các hàm socket (in System Calls Interface ) 


  1. Hàm socket() để tạo mới một socket
  2. Hàm bind() Đăng ký socket đã khởi tạo với địa chỉ socket local. Trả về 0 nếu thành công, -1: thất bại.
  3. Hàm connect() để client kết nối đến server
  4. Hàm listen() đặt socket ở trạng thái chờ, lắng nghe kết nối từ phía client
  5. Hàm accept() : chấp nhận kết nối từ client đến
  6. Hàm read() để đọc dữ liệu từ socket vào bộ nhớ
  7. Hàm write() để ghi dữ liệu từ bộ nhớ -> socket
  8. Hàm sendto() để gởi dữ liệu đến một socket từ xa
  9. Hàm recvfrom(): nhận dữ liệu đến từ 1 socket từ xa


Các loại Socket

  1. Stream Socket: dùng cho connection-oriented protocol như TCP.
  2. Datagram Socket: dùng cho connectionless protocol như UDP.
  3. Raw Socket: dùng cho một số protocol của một số ứng dụng đặc biệt, dùng các dịch vụ trực tiếp của lớp IP.

TCP socket – đặc điểm

  1. Có thể sử dụng để liên lạc theo mô hình client/server
  2. Có 1 đường kết nối ảo giữa 2 phía Server/client
  3. Một trong 2 phía phải đợi tiến trình kia yêu cầu kết nối
  • Server lắng nghe và chấp nhận yêu cầu kết nối
  • Mỗi thông điệp gửi đều có xác nhận trở về
  • Các gói tin chuyển đi tuần tự

TCP socket – hoạt động

  • Client phải kết nối đến server 
  • server process phải chạy trước (phần tử thụ động)
  • server phải tạo một socket để lắng nghe và chấp nhận các kết nối từ client
  • Client kết nối đến server bằng cách:
  • Khởi tạo TCP socket ở local
  • Xác định IP address, port number của server process và kết nối đến
  • Sau khi client khởi tạo socket, nó sẽ thiết lập kết nối đến server
  • Khi server nhận yêu cầu kết nối, nó sẽ chấp nhận yêu cầu và khởi tạo socket mới để giao tiếp với client.
  • Cho phép server chấp nhận nhiều client tại một thời điểm.

TCP socket - hoạt động

UDP socket – đặc điểm

  1. Cung cấp cơ chế truyền không tin cậy các nhóm  bytes (datagrams) giữa client và server.
  2. Không cần thiết lập kết nối giữa client với server.
  3. Client phải gởi kèm địa chỉ IP và port đích
  4. Server khi nhận dữ liệu sẽ phân tích địa chỉ của client để truyền lại.

--

  • Thông điệp có thể gửi nhiều lần
  • Người gửi không chắc chắn thông điệp tới người nhận
  • Thông điệp sau có thể đến đích trước thông điệp gửi trước nó


UDP socket – hoạt động

Số hiệu cổng của socket

  • Một trong 2 quá trình phải công bố số hiệu cổng của socket mà mình sử dụng
  • Mỗi cổng giao tiếp thể hiện 1 địa chỉ xác định trong hệ thống
  • Có thể nhận dữ liệu gửi đến cổng giao tiếp này từ các quá trình khác.

Viết các ứng dụng Socket

  • Thiết kế giải thuật cho client/Server.
  • Công cụ viết
  • Dùng các class trong Java
  • Example


Thiết kế giải thuật cho client/Server

  • Giải thuật cho chương trình client/Server dùng TCP
  • Giải thuật cho chương trình client/Server dùng UDP
  • Chương trình server có hai loại: 

        1. Lặp (iterative)
        2. Đồng thời (concurrent).

  •  Hai dạng giao thức chương trình server: 

       1.Connection-oriented  (TCP)
       2.Connectionless. (UDP)

Giải thuật cho client/Server TCP
 Client

  1. Xác định địa chỉ server.
  2. Tạo socket.
  3. Kết nối đến Server
  4. Gởi/nhận dữ liệu theo giao thức đã thiết kế.
  5. Đóng socket.

Server

  1. Tạo socket 
  2. Đăng ký với hệ thống
  3. Lắng nghe kết nối
  4. Chấp nhận kết nối 
  5. Gửi nhận dữ liệu theo đúng giao thức đã thiết kế.
  6. Đóng  kết nối sau khi đã hoàn thành và trở lại trạng thái lắng nghe chờ kết nối mới


Giải thuật cho client/Server UDP
 Client

  1. Xác định địa chỉ server.
  2. Tạo socket.
  3. Gởi/nhận dữ liệu theo giao thức đã thiết kế.
  4. Đóng socket.

Server

  1. Tạo socket 
  2. Đăng ký với hệ thống
  3. Lặp công việc đọc dữ liệu từ client gửi đến và gửi trả kết quả cho client theo đúng giao thức lớp ứng dụng đã thiết kế.
  4. Đóng Socket


Thiết kế giải thuật cho Server – concurrent, connection-oriented (TCP)

  • Tạo socket và đăng ký với hệ thống
  • Đặt socket ở chế độ chờ, lắng nghe kết nối.
  • Khi có request từ client, Server sẽ:
  • chấp nhận kết nối, 
  • tạo một process con để xử lý. 
  • Quay lại trạng thái chờ, lắng nghe kết nối mới
  • Công việc của process con:
  • Nhận thông tin kết nối của client
  • Giao tiếp với client theo giao thức lớp ứng dụng đã thiết kế
  • Đóng kết nối và kết thúc process con.
  • Đóng socket

Thiết kế giải thuật cho Server – concurrent, connectionless (UDP) 

  • Tạo socket và đăng ký với hệ thống
  • Lặp công việc nhận dữ liệu từ client, đối với một dữ liệu nhận:
  • tạo mới một process để xử lý. 
  • Tiếp tục nhận dữ liệu mới từ client
  • Công việc của process mới:
  • Nhận thông tin của process cha chuyển đến, lấy thông tin socket
  • Xử lý và gửi thông tin về cho client theo giao thức lớp ứng dụng đã thiết kế
  • Kết thúc

Thiết kế giải thuật server – multi-protocol Server (TCP/UDP)

  • Dùng một chương trình, mở một master socket cho cả TCP và UDP.
  • Dùng hàm hệ thống (select) để chọn lựa TCP socket hay UDP socket sẵn sàng.
  • Tùy vào protocol (TCP, UDP) để xử lý gửi nhận thông điệp theo đúng giao thức của lớp ứng dụng
  • Ref RFC 1060

Lập trình mạng trên Java
Gói java.net cung cấp các lớp

  1.  InetAddress
  2. URL
  3.  URLConnection
  4.  ServerSocket
  5.  Socket
  6. DatagramSocket
  7. DatagramPacket
InetAddress class


  • Phục vụ việc quản lý địa chỉ theo IP và tên.
  • Cung cấp các phương thức thông dụng nhất dùng để chuyển đổi và truy xuất IP 
  • Nó bao gồm hai trường thông tin: (không thể truy xất chúng trực tiếp)
  • hostName (một đối tượng kiểu String) và 
  • address (một số kiểu int). 
  • Lớp InetAddress không có các constructor cho lớp InetAddress
  • Có các phương thức:

Tất cả các phương thức này đều thực hiện kết nối tới server DNS cục bộ để biết được các thông tin trong đối tượng InetAddress:
1. public static InetAddess getLocalHost()throws UnknownHostExceptiongetByName 
Trả về InetAddress là IP của local
2. public static InetAddess getByName(String hostname) throws UnknownHostException: 
Nhận tên host và trả về InetAddress (name và IP address)
3. public static InetAddess [] getAllByName (String hostname) throws UnknownHostException
Nhận địa chỉ host dạng String và trả về tất cả InetAddress tương ứng với host (name và IP address)



  • Nhận các trường thông tin của một đối tượng InetAddress: 
  • Chỉ có các lớp trong gói java.net có quyền truy xuất tới các trường của lớp InetAddress. bằng các phương thức:


public byte[] getAddress()
Trả về một địa chỉ IP dưới dạng một mảng các byte.
public String getHostAddress()
Trả về một địa chỉ IP dưới dạng String "%d.%d.%d.%d"
public String getHostName()
Trả về một xâu biểu diễn hostname của một đối tượng InetAddress. Nếu máy không có hostname, thì sẽ trả về "%d.%d.%d.%d"



Ex:  In địa chỉ IP và name  củalocalhost
import java.net.*;
public class HostInfo {
public static void main(String args[]) {
try {
InetAddress myHost = InetAddress.getLocalHost(); System.out.println(myHost.getHostAddress());
System.out.println(myHost.getHostName());
} catch (UnknownHostException ex) {
System.err.println("Cannot find local host");}
}
}

Ex: In IP của www.google.com
import java.net.*; 
class Print_IP{ 
public static void main (String args[]) { 
try { 
InetAddress[] addresses = 
InetAddress.getAllByName("www.google.com"); 
for (int i = 0; i < addresses.length; i++) { 
System.out.println(addresses[i]); 

} catch (UnknownHostException e) { 
System.out.println("Could not find www.google.edu.vn"); 

     } 
}



URL  

  • URL(Uniform Resource Locator)  là địa chỉ định vị tài nguyên trên mạng, 
  • Một URL  thường bao gồm 3 phần: 
  1. Protocol
  2. Hostname
  3. Filename. 
  4. (port)
  • Java đóng gói tất cả vào một lớp URL. 
  • Đối tượng URL được tạo ra bằng một trong những phương thức khởi tạo sau:

URL  class - Constructors
public URL(String spec) throws MalformedURLException 
Tạo một đối tượng URL từ địa chỉ định vị là một chuỗi. (simple)
public URL(String pro, String host, int port, String file) throws MalformedURLException 
Tạo một địa chỉ định vị tuyệt đối với đầy đủ nghi thức(protocol), máy chủ(server), cổng(port), đường dẫn(file) tới tập tin cần lấy trên máy chủ. 
public URL(String protocol, String host, String file) throws MalformedURLException 
Tạo một  địa chỉ  định vị tuyệt  đối với  đầy  đủ protoccol, server, path file 

Phân tích một URL thành các thành phần

public final Object getContent() throws IOException :lấy về nội dung mà kết nối theo địa chỉ URL có được.
String getFile() :Lấy về tên tập tin hay tài liệu nằm trong chuỗi địa chỉ URL có được. 
String getHost() :Lấy tên máy chủ (thường là thành phần thức 2 của chuỗi URL) 
String getPort() :Lấy về số hiệu cổng. 
String getProtocol() :Lấy về tên giao thức(thường là thành phần đầu tiên trong chuỗi URL) 
String getRef() :Lấy về nội dung chuỗi tham khảo thêm trong chuỗi URL (được đặt sau dấu #  của chuỗi) 
URL class - ex
import java.net.*;
import java.io.*;

public class GetURLInfor {
    public static void main(String[] args) throws Exception {

        URL aURL = new URL("http://google.com:80/docs/books/tutorial"
                           + "/index.html?name=networking#DOWNLOADING");

        System.out.println("protocol = " + aURL.getProtocol());
        System.out.println("authority = " + aURL.getAuthority());
        System.out.println("host = " + aURL.getHost());
        System.out.println("port = " + aURL.getPort());
        System.out.println("path = " + aURL.getPath());
        System.out.println("query = " + aURL.getQuery());
        System.out.println("filename = " + aURL.getFile());
        System.out.println("ref = " + aURL.getRef());
    }
}

Tìm kiếm dữ liệu từ một URL
public final InputStream openStream() throws IOException: 
kết nối tới một tài nguyên được tham chiếu bởi một URL, thực hiện mở luồng nhập để đọc thông tin trả về từ máy chủ  
public URLConnection openConnection() throws java.io.IOException: 
Mở một socket tới một URL xác định và trả về một đối tượng URL. 
public final Object getContent() throws java.io.IOException: 
Cung cấp cách tải dữ liệu được tham chiếu bởi một URL

URL class: ex get text
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
public class getText {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("http://tintuconline.com.vn/vn/index.html");
    BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
    String str;
    while ((str = in.readLine()) != null) {
      System.out.println(str); 
    }
    in.close();
  }
}
URLConnection class

  • URLConnection là một lớp trừu tượng biểu diễn một liên kết tích cực tới một tài nguyên được xác định bởi 1 URL. 
  • Ý nghĩa của lớp URLConnection:
  • Cung cấp nhiều khả năng điều khiển hơn thông qua việc tương tác với một server chứ không phải lớp URL: 
  • kiểm tra các headerMIME được gửi bởi một Http Server. 
  • tải về các tệp nhị phân. 
  • gửi dữ liệu trở lại Web server bằng lệnh POST. 
  • Là một phần của cơ chế quản trị giao thức
  • phân tích các chi tiết xử lý một giao thức với việc xử lý các kiểu dữ liệu cụ thể, 
  • cung cấp các giao diện người dùng, và thực hiện các công việc khác mà một trình duyệt thường làm.

Mở các URLConnection  
Một chương trình sử dụng lớp URLConnection trực tiếp theo một dãy các bước cơ bản sau:

  • Xây dựng một đối tượng URL. 
  • Gọi phương thức openConnection() của đối tượng URL để tìm kiếm một đối tượng URLConnection cho URL đó. 
  • Cấu hình đối tượng URL. 
  • Đọc các trường header. 
  • Nhận một luồng nhập và đọc dữ liệu. 
  • Nhận một luồng xuất và ghi dữ liệu. 
  • Đóng liên kết. 

Ex, xây dựng 1 URLConnection 
u= new URL("http://www.microsoft.com"); 
URLConnection uc; 
uc=u.openConnection();
Methods: read/write data 
public Object getContent() throws IOException 
chỉ làm việc khi Java có một trình quản lý nội dung cho kiểu nội dung. tải về đối tượng được chọn bởi URL của URLConnection này.
public InputStream getInputStream()  
luồng này cho phép tự đọc và phân tích dữ liệu.
public OutputStream getOutputStream() 
ghi dữ liệu vào một URLConnection. Trả về một luồng OutputStream trên đó có thể ghi dữ liệu để truyền tới một server.
Phải gọi phương thức setDoOutput() trước khi yêu cầu một luồng xuất. (URLCon. ko cho phép xuất default)

Đọc dữ liệu từ một server

Các bước tối thiểu cần để tìm kiếm dữ liệu từ một URL bằng cách sử dụng đối tượng URLConnection:
Bước 1: Xây dựng một đối tượng URL.
Bước 2: Gọi phương thức openConnection() của lớp URL để tìm kiếm một đối tượng URL Connection cho đối tượng URL đó.
Bước 3: Gọi phương thức getInputStream().
Bước 4: Đọc từ luồng nhập bằng cách sử dụng API.
Ex, get source web hcmute.edu.vn
import java.net.*; 
import java.io.*; 
public class  getText { 
 public static void main(String[] args) throws MalformedURLException { 
  String thisLine; 
  URL u; 
  URLConnection uc; 
    u =new URL("http://www.hcmute.edu.vn"); 
    try{ 
     uc=u.openConnection(); 
     DataInputStream theHtml = new DataInputStream(uc.getInputStream()); 
     try{ 
     while((thisLine=theHtml.readLine())!=null) 
                System.out.println(thisLine); 
            } catch(Exception e)    { 
         System.err.println(e); } 
       }        catch(Exception e)    { 
       System.err.println(e);   } 
    }  
 }
Ex: send data to server
try{ 
   URL u = new URL(http://www.hcmute.edu.vn); 
   URLConnection uc = u.openConnection(); 
   uc.setDoOutput(true); 
    DataOutputStream dos = new DataOutputStream(uc.getOutputStream()); 
  dos.writeByte(“Here is some data”); 
}  catch(Exception e)  { 
System.err.println(e); 


Phân tích Header

HTTP Server cung cấp một số lượng thông tin đáng kể trong các header MIME trước mỗi đáp ứng.
Thông tin trong các header MIME có thể:

  • cơ chế mã hóa nội dung được sử dụng, 
  • chiều dài của nội dung được trả về bằng byte
  • ngày và giờ truy nhập cuối 
  • ngày hết hạn của nội dung, 
  • ngày mà nội dung được sửa đổi lần cuối. 

Có thể truy vấn một URLConnection để tìm ra thông tin MIME nào mà server đã cung cấp.
Ngoài HTTP, rất ít giao thức sử dụng các header MIME.

Methods

public String getContentType() 
trả về kiểu nội dung MIME của dữ liệu. Nó phụ thuộc vào web server gửi một header MIME tương ứng. Các kiểu nội dung phổ biến khác bao gồm: text/plain, image/gif, image/jpeg.
public int getContentLength() 
cho biết nội dung có kích thước bao nhiêu byte.
public String getContentEncoding() 
trả về String cho ta biết cách thức mã hóa. Nếu nội dung được gửi không được mã hóa (như trong trường hợp của HTTP server),
public long getDate() 
trả về một số nguyên kiểu long cho bạn biết tài liệu đã được gửi khi nào. Ta có thể chuyển đổi nó sang một đối tượng kiểu java.util.Date.
public long getExpiration() 
public long getLastModified() 
URL class - ex
public class GetURLInfor {
public static void printinfo(URL url) throws IOException {
    URLConnection c = url.openConnection(); // Get URLConnection from URL
    c.connect(); // Open a connection to URL
    System.out.println("  Content Type: " + c.getContentType());
    System.out.println("  Content Encoding: " + c.getContentEncoding());
    System.out.println("  Content Length: " + c.getContentLength());
    System.out.println("  Date: " + new Date(c.getDate()));
if (c instanceof HttpURLConnection) {
      HttpURLConnection h = (HttpURLConnection) c;
      System.out.println("  Request Method: " + h.getRequestMethod());
      System.out.println("  Response Message: " + h.getResponseMessage());
      System.out.println("  Response Code: " + h.getResponseCode());    }
  }
 public static void main(String[] args) {
    try {
      printinfo(new URL(args[0]));
    } catch (Exception e) {      System.err.println(e + " Not found URL");
      System.err.println("Usage: java GetURLInfo <url>");     }
  }
}

Socket trong Java
Java cung cấp lớp (trong thư viện java.net)

  •  ServerSocket  (thường dùng cho server) và
  •  Socket  (thường dùng cho  client) có thể được sử dụng cho server
  • Có các phương thức tương ứng với các thao tác của  server và client 

Socket class
Dùng để tạo kết nối từ phía client tới Server
Các phương thức hỗ trợ:

  • Tạo Socket
  • Nhận thông tin từ Socket
  • Lấy các thông tin về Socket dạng Stream
  • Đóng Socket
  • Đóng luồng nhập/xuất từ SOcket


Tạo Socket
Các phương thức tạo Socket:
1. public Socket(String host, int port) throws UnknownHostException, IOException: 
Tạo 1 socket TCP với host và port x/đ
2. public Socket(InetAddress address, int port) throws IOException: 
Tạo 1 socket TCP với 1 host có address được x/đ bởi 1 object InetAddress  và port x/đ


3. public Socket(InetAddress address, int port, InetAddress interface, int localPort) throws IOException, UnknownHostException: Socket tao ra kết nối tới host ở xa thông qua một giao tiếp mạng và số hiệu cổng cục bộ
4. public Socket(String host, int port, InetAddress interface, int localPort) throws IOException, UnknownHostException
5. public Socket(String host, int port, boolean stream): stream qui định kiểu kết nối (T/F)
Nhận các thông tin về Socket
InetAddress getInetAddress() :
trả về địa chỉ (IP và hostname) của host mà socket  kết nối đến.
int getPort() :
trả về port của host mà socket kết nối đến.
InetAddress getLocalAddress() : 
trả về địa chỉ của host cục bộ.
int getLocalPort() : 
trả về port trên host cục bộ.

Ex:Kết nối đến 1 số web server

import java.net.*;
import java.io.*;
public class getSocketInfo {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
try {
Socket Sk = new Socket(args[i], 80);
System.out.println( "From port " + Sk.getLocalPort() + " of " + Sk.getLocalAddress());
System.out.println("Connected to " + Sk.getInetAddress() + " on port " + Sk.getPort());
} catch (UnknownHostException e) {
System.err.println("I can't find " + args[i]);
} catch (SocketException e) {
System.err.println("Could not connect to " + args[i]);
} catch (IOException e) {
System.err.println(e); }
} // end for
  } // end main
} // end getSocketInfo


Đọc /ghi dữ liệu với Socket dạng Stream
Việc nhận dữ liệu /ghi dữ liệu với socket được tiến hành thông qua luồng

Các phương  thức truy xuất luồng dữ liệu nhập/xuất

public OutputStream getOutputStream() throws IOException
Trả về một output stream cho việc ghi (các byte) dữ liệu từ ứng dụng đến một socket.
public InputStream getInputStream() throws IOException
Trả về một input stream cho việc đọc (các byte) dữ liệu từ một socket  vào chương trình.
Ex, Lấy các thông tin về Socket dạng Stream
Socket clientSk = new Socket("localhost", 9999);
//Tạo luồng đọc vào từ bàn phím
BufferedReader inFromUser =
new BufferedReader(new InputStreamReader(System.in));
//Tạo luồng để ghi dữ liệu từ client đến server(sk)
DataOutputStream outToServer =
New DataOutputStream(clientSk.getOutputStream());
//Hoac PrintWriter, dung println() de ghi
PrintWriter outToServer = new PrintWriter(new BufferedWriter(new OutputStreamWriter( clientSk.getOutputStream())), true);

// Tạo luồng để đọc dữ liệu từ server(sk) gửi về client
BufferedReader inFromServer = new BufferedReader( new
InputStreamReader(clientSk.getInputStream()));

Đóng Socket 

Phương thức:
public void close() throws IOException 
Khi một Socket đã bị đóng lại:

  • Có thể truy xuất tới các trường thông tin qua các phương thức: getInetAddress(), getPort(), getLocalHost(), và getLocalPort(). 
  • Dùng phương thức getInputStream() hoặc getOutputStream() thì ngoại lệ IOException được đưa ra. 

Đóng luồng nhập/ xuất
Đóng luồng nhập/ xuất từ socket:

  • public void shutdownInput() throws IOException 
  • public void shutdownOutput() throws IOException 

Các phương thức này không thực sự ngắt liên kết. Tuy nhiên, nó chỉ điều chỉnh luồng kết nối tới nó
Kiểm tra các luồng nhập và luồng xuất mở hay đóng

  • public boolean isInputShutdown() 
  • public boolean isOutputShutdown() 

ServerSocket class
Lớp ServerSocket:

  • các constructor để tạo các đối tượng ServerSocket mới, 
  • các phương thức để lắng nghe các liên kết trên một cổng xác định, và 
  • các phương thức trả về một Socket khi liên kết được thiết lập, 

=> có thể gửi và nhận dữ liệu.

Server – Hoạt động

1. Một ServerSocket mới được tạo ra trên một cổng xác định bằng cách sử dụng một constructor ServerSocket.
2. ServerSocket lắng nghe liên kết đến trên cổng đó bằng cách sử dụng phương thức accept().
Phương thức accept() phong tỏa cho tới khi một client thực hiện một liên kết, phương thức accept() trả về một đối tượng Socket mà liên kết giữa client và server.
3. Tùy thuộc vào kiểu server, hoặc phương thức getInputStream(),
getOutputStream() hoặc cả hai được gọi để nhận các luồng vào ra để truyền tin với client.
4. server và client tương tác theo một giao thức thỏa thuận sẵn cho tới khi ngắt liên kết.
5. Server, client hoặc cả hai ngắt liên kết
6. Server trở về bước hai và đợi liên kết tiếp theo.

Tạo Socket cho Server

public ServerSocket(int port) throws IOException, BindException 
Tạo một socket cho server trên cổng xác định.
Nếu port = 0, hệ thống chọn một cổng ngẫu nhiên.khó x/đ
public ServerSocket(int port, int queuelength, InetAddress bindAddress) throws IOException  
Tạo một đối tượng ServerSocket trên port xác định với queuelength xác định. ServerSocket chỉ gán cho địa chỉ IP cục bộ bindAddress xác định.
Constructor này hữu ích cho các server chạy trên các hệ thống có nhiều địa chỉ IP
ex
public class portSrv  { 
 public static void main(String[] args)   { 
for(int i=0;i<=1024;i++)   { 
   try{ 
 ServerSocket ss= new ServerSocket(i); 
    ss.close(); 
   
   catch(IOException e)    { 
   System.out.print("Co 1 server tren cong "+i); 
   
 
  } 
}
Chấp nhận và ngắt liên kết 
Socket accept() throws IOException :
Lắng nghe một kết nối đến socket này và chấp nhận nó.
nó dừng quá trình xử lý và đợi cho tới khi client được kết nối
void close() throws IOException : Đóng socket.
Ta sử dụng các phương thức getInputStream() và getOutputStream() để truyền tin với client.
Methods
Các phương thức trong ServerSocket

  • InetAddress getInetAddress() : trả về địa chỉ của socketserver
  • int getLocalPort() : Trả về port mà server đang lắng nghe. 
  • void setSoTimeout(int timeout) throws SocketException
  • Enable/disable SO_TIMEOUT với khai báo timeout (milliseconds)

Ex: DateTime Server
import java.net.*; 
import java.io.*; 
class ScanPort  { 
 public static void main(String[] args)   { 
   try{ 
   ServerSocket theServer = new ServerSocket(5776); 
while(true) { 
  Socket con = theServer.accept(); 
  PrintStream p = new PrintStream(con.getOutputStream()); 
  p.println(“Connected to this Server "); 
  con.close(); 

} catch(IOException e) { 
  System.err.println(e); 



Tương tác giữa client/server qua socket TCP

Lập trình Socket cho giao thức TCP 

  • Cấu trúc chương trình Client
  • Cấu trúc chương trình Server



Cấu trúc chương trình client

Cấu trúc chương trình server

Ex: viết ứng dụng client/ server bằng TCP Socket
1) client đọc các dòng văn bản do người dùng gõ từ bàn phím (inFromUser stream) , gửi tới server qua socket (outToServer stream)
2) server đọc các dòng gửi từ socket
3) server chuyển sang chữ hoa và gửi trả lại cho client
4) client đọc và in lại dòng văn bản nhận được từ socket (inFromServer stream)
TCP client
class TCPClient_upcase { 
public static void main(String argv[]) throws Exception { 
String sentence; 
String modifiedSentence;
Socket clientSocket = new Socket("localhost", 9999); //Create Socket
//Create inputStream for reading data from keyboard
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in)); 
sentence = inFromUser.readLine();
// Create OutputStream for writing byte to Server socket
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
outToServer.writeBytes(sentence + '\n');
// Create inputStream for reading data from Serversocket
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
modifiedSentence = inFromServer.readLine(); 
//View data that received from server
System.out.println("FROM SERVER: " + modifiedSentence);
clientSocket.close(); 

}
TCP Server
class TCPServer_upcase { 
public static void main(String argv[]) throws Exception { 
String clientSentence; 
String upSentence;
System.out.println("Hello, wellcome to Server. Waiting.... ");
ServerSocket welcomeSocket = new ServerSocket(9999); //Create Server Socket
while(true) { 
//Create connection
Socket connectionSocket = welcomeSocket.accept();
//Create InputStream for reading data from socket client
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));
clientSentence = inFromClient.readLine();
// Create OutputStream for writing data to socket client
DataOutputStream  outToClient = new DataOutputStream(connectionSocket.getOutputStream());
//Process: upcase
upSentence = clientSentence.toUpperCase() + '\n';
outToClient.writeBytes(upSentence); 
System.out.println("Done!!!"); } 
}
}
output
D:\Practice_Java\TCP-UDP\bin




Using GUI in TCP Socket



Exercise: Print Primes
TCPSever_SNT, TCPClient_SNT
MultiThread trong các chương trình Server
Đa tuyến hay được ứng dụng trong các chương trình Server:

  • cho phép các server làm việc với nhiều client đồng thời. 
  • Server này được gọi là server tương tranh (concurrent server):
  • server tạo ra một tuyến đoạn để quản lý từng yêu cầu, 
  • sau đó tiếp tục lắng nghe các client khácMô  hình

Example
Thread_TCPServer.java
  Thread_TCPClient.java
Sample:Chuoi, Server, Client (Object)
Prime: (Object: int+ Str)
Array_Object (Socket+Object)
MultiServer: (MultiSrv, cuoiky.cuoiky)
Str_Client_Loop,
Str_Server1_Loop,
Str_Server2_Loop



I/O Stream in Read/ write from/to socket
DataOutputStream : dùng
- writeBytes(str) để ghi string;
- writeInt(num) để ghi số (với all dữ liệu nguyên thủy)…
DataInputStream:
- readLine(): để đọc string
- readInt(num) để đọc số (với all dữ liệu nguyên thủy)…
PrintWriter: dùng
- println(str) de ghi string
InputStreamReader: dùng read(char []) để đọc vào mảng char. Sau đó in char[] (or->String)
BufferredReader: dùng readLine(): để đọc string
ObjectI/Ostream: Object: serializable

More about