Thứ Năm, 31 tháng 7, 2014

Đề thi cũ CTDL 2013

Đề thi cũ môn CTDL cho bạn nào muốn tham khảo kỳ 1,2,3 năm 2013

Kỳ 1 - 2013 

Giữa kỳ: http://1drv.ms/1zyzuys

Cuối kỳ: http://1drv.ms/1zyzyOP

Kỳ 2 - 2013

Giữa kỳ: http://1drv.ms/1qMM38X

Cuối kỳ: http://1drv.ms/1qMM50u

Kỳ 3 - 2013

Giữa kỳ: http://1drv.ms/1zyzL4E


Thứ Tư, 30 tháng 7, 2014

Một số bài cho hai bạn không kiểm tra giữa kỳ

Bài 1. Tìm số phòng họp nhỏ nhất cho các cuộc họp


Đầu vào: Danh sách các cuộc họp với thời điểm bắt đầu và kết thúc
struct meeting
{
int start, end;//thời điểm bắt đầu và kết thúc
}
Đầu ra: đưa ra số phòng ít nhất cần dùng để đảm bảo không cuộc họp trùng giờ được tổ chức cùng phòng

int minNoRoom(struct meeting A[], int n)

trong đó A là mảng chứa danh sách các cuộc họp và n là số lượng phần tử

Chú ý: Các cuộc họp này đã được xếp theo thứ tự tăng dần về thời điểm bắt đầu

Bài 2. Kiểm tra xem hai xâu có phải là bị biến đổi bởi phép xoay hay không


Đầu vào: hai xâu ký tự có cùng độ dài
Đầu ra: nếu hai xâu được tạo ra bởi phép xoay thì trả về là true, ngược lại trả về là false

int checkIsRotation(char *s1, char *s2)

VD.
S1="amazon" S2="azonam" return true
S1="quality" S2="lityqua" return false

Chú ý: Bạn có thể dùng các hàm có sẵn của thư viện string.h

Bài 3. Viết hàm tìm và trả về nút lá sâu nhất trên cây nhị phân


struct BNODE deepestNode(struct BNODE *root)

trong trường hợp có nhiều nút thì chỉ cần trả về 1 nút

Hạn nộp: Thứ 2 tuần tới (4/8/2014)
Mang máy và chương trình tới lớp để bảo vệ!


Thứ Ba, 15 tháng 7, 2014

Hướng dẫn cách Port code từ Cocos2d-x 2 sang Cocos2d-x 3.x ( Update liên tục ...)

Hi mọi người!

Lâu lâu lười viết bài thế, không phải là không còn gì để viết, không còn nguồn để tham khảo. Mà là vì những bài code về sau dung lượng code lớn quá, up lên Blog khá là mất thời gian vì diễn giải khá dài, dù có chia nhỏ từng phần ra cũng hơi oải các bạn ạ. Thời gian để viết Blog cũng đủ cho mình chiến được 1 project tầm trung rồi, vì thế nên các bạn hết sức thông cảm nếu mình có ra bài chậm.

Vậy giải pháp cho vấn đề này như thế nào? Mình xin đưa ra với các bạn 1 vài giải pháp như sau

1/ Nếu bài viết trên Blog, vẫn chia Part 1-2-3 cho tiện, và mình sẽ Copy + Paste chỉ giải thích ( comment ) những đoạn code, phương pháp nào thật sự khó hiểu, hoặc mới chưa từng có trên Blog. Còn lại các bạn nghiên cứu trong từng file .h, .cpp mình sẽ up lên. Trong code cũng chỉ comment đoạn quan trọng, kẻo rối mắt nhé

2/ Code cho phiên bản V3 ngày càng nhiều lên, các bạn có thể tìm trên Github.com bằng các key thích hợp. Tuy nhiên chúng ta không thể bỏ qua 1 nguồn tài nguyên khá lớn từ phiên bản Engine Cocos2dx -2.x được. Sẽ có bạn bảo, code đó làm sao chạy được với Engine 3.x, tất nhiên rồi ( Code 3.1 nhiều khi còn chả chạy được trên V3.2 đó bạn ). Đó là lý do mình viết bài này, chúng ta sẽ Port code từ phiên bản cũ lên phiên bản 3.x rồi Biên dịch = phiên bản mới. Cũng hay đấy chứ.

Lợi ích của việc Port Code này là gì? Theo mình thì có 1 vài lợi ích sau

+ Mở rộng nguồn tài nguyên, chúng ta sẽ có nhiều dự án để thực hành hơn
+ Mã nguồn cũng phong phú hơn do 2.x ra khá lâu rồi
+ Ôn lại được những kiến thức đã học của 3.x. Giúp bạn nắm chắc hơn về cú pháp lệnh của 3.x, sướng nhé
+ Học thêm được một số giải thuật, phương pháp giải quyết bài toán, cấu trúc chương trình mà những người đi trước đã share ( nhiều bộ code full nhé ).
+ Còn gì nữa không nhỉ? tạm thời thế đã :-))

Những ai có thể Port Code?

Những người đã đọc qua 40 bài viết ( có 29 bài học và mấy chú ý ) trong blog này hoàn toàn có thể làm được nhé. Bạn không tự tin ư? Với chính bản thân mình lúc đầu khi bắt tay vào Port code cũng cảm thấy hơi e dè, nhưng chỉ cần qua 1 project thôi là bạn sẽ cảm thấy tự tin lên nhiều. Mình khẳng định chắc chắn đấy.

Như vậy nhé, mình khẳng định lại lần cuối, mọi người hoàn toàn có thể làm được theo những lưu ý dưới đây
( Bài viết sẽ được bổ sung dần dần nhé )

PORT CODE

B1 - Tạo mới Project bằng Engine 3.x, dễ như ăn kẹo

B2 - Không nên copy Class của 2.x đập thẳng vào Class 3.x rồi sửa, rồi build nhé, làm vậy sẽ nhanh chóng bị rối vì rất nhiều lỗi mà ko biết vì sao.

B3 - Ngó nghiêng file AppDelegate.cpp, .h của 2 phiên bản, có đôi chút khác ở phần glview, và phần định hướng Resource, và hàm run scene đầu tiên bạn chỉnh lại 1 chút là được. Phần này ko quá quan trọng, bạn có thể để nguyên của phiên bản 3.x nhé. Có gì mình fix sau

B4 - Trong thư mục Class của 2.x, Tìm 2 file Quan trọng nhất của game - có nhiệm vụ quản lý toàn bộ game, đó là 2 file sẽ được chạy đầu tiên, bạn chỉ cần nhìn trong AppDelegate.cpp là thấy được scene đầu tiên được chạy là của lớp nào thì lớp đó sẽ nằm trong 2 file kia. Thường là thế, không tính đến những cấu trúc file loằng ngoằng do sở thích của người lập trình.

B5 - Trong 2 file quan trọng nhất này, bạn sẽ thấy rất nhiều #Inlude từ các file khác, rất nhiều thuộc tính, nhiều hàm, rối tinh rối mù đúng không. Hãy xem qua để biết được cấu trúc liên kết của các lớp, các hàm trong Project là như nào. Rối quá thì dùng giấy ghi lại thôi.

B6 - Bắt đầu làm việc. Trong Class của 3.x, bạn mở file HelloWorldScene.h, nó là file quan trọng đầu tiên đấy. Bắt đầu copy các thuộc tính, các hàm từ bên file .h quan trọng nhất bên 2.x sang nhé ( cứ copy y nguyên nhé, phần sửa đổi cú pháp lệnh, hàm để dành Bước cuối cùng ).

Sau đó trong file HelloWorldScene.cpp,  bạn tạo ra các khai báo hàm rỗng - kế cả hàm hủy và hàm tạo. Rồi build thử, nếu chạy được nghĩa là OK, nếu không được, lỗi có thể do :

+ Lỗi cú pháp, thư viện hàm đã "lỗi thời". Cách sửa trình bày sau
+ Code bị lỗi do thừa thiếu, hoặc có sử dụng đối tượng của lớp khác mà ko #include, hãy comment nó lại để tránh lỗi đã.
+ Lỗi không giải thích nổi, do VS ( mình toàn xài VS ) báo rất khó hiểu, nên phải dựa vào kinh nghiệm để phán đoán và sửa lỗi. Với 3-4 tháng kinh nghiệm là đủ dùng.

B7 - Khi build được thành công với cặp file này ( .h, .cpp) nghĩa là file .h đã OK ( có thể lỗi về cú pháp thì bạn nhảy đến bước cuối cùng - xem rồi sửa theo ) file .cpp thì toàn hàm rỗng OK là đúng rồi. Giờ làm công việc khó khăn hơn là, bắt đầu xử lý các hàm rỗng đó nhé ( Trong Class 3.x)

+ Phần hàm tạo và hàm hủy, khá dễ. Hàm tạo thì khởi tạo giá trị cho các đối tượng, nếu là con trỏ thì cho nó là Null. Hàm hủy thì giải phóng các biến con trỏ ( những biến mà trong project có sử dụng hàm new nhé )

+ Hàm createScene() đển nguyên, trừ phi bên 2.x có thêm cú pháp khác
2.x nó thế này
CCScene* GameLayer::scene()
{
    CCScene * scene = NULL;
    do 
    {
    } while (0);
    return scene;
// Thường ko copy gì cả nhé

+ Hàm init (), bạn để nguyên như vậy, copy thêm các câu lệnh và hàm nằm trong khối lệnh sau ( trong file 2.x )

bool GameLayer::init() // init của v 2.x
{
   bool bRet = false;
    do 
    {
    CC_BREAK_IF(! CCLayer::init()); // không copy

// Copy các hàm, lệnh ở đoạn này
    bRet = true; // Không copy

    } while (0);
    return bRet;
}

B8 - Rồi, build thử xem có lỗi gì không, khả năng là có lỗi cao, vì trong hàm init sẽ có gọi đến 1 số hàm khác của project, thậm chí gọi tới đối tượng của lớp khác. Bạn hãy comment hết lại những hàm, code phát sinh lỗi. Build cho tới khi thành công thì bắt đầu công đoạn tiếp theo.

B9 - Khi đã build thành công ở bước 8, bạn mở comment từng hàm 1 trong hàm init ( Các hàm này đểu được khai báo rỗng cả rồi nên ko sợ lỗi ) Khi mở hàm nào, hãy copy code từ hàm tương ứng bên 2x chuyển sang, và chú ý xem trong hàm mới copy đó, có gọi tới hàm nào khác không thì bước tiếp theo là copy code của Hàm được gọi đó vào.

Cứ theo từng bước như thế, bạn sẽ mở hết các hàm.

B10 - Trong quá trình mở hàm, bạn sẽ gặp phải các đối tượng của lớp khác, khi này bạn sẽ làm như sau. Copy 2 file .h, .cpp của lớp đó từ 2.x sang 3.x của mình, Nhớ comment lại code, hàm, của 2 file đó rồi thực hiện mở comment như các bước trên. ( Nhớ phải thêm Class mới = VS hoặc Android.MK nhé )

Cứ làm tuần tự như vậy cho đến khi copy mở hết code, hàm từ 2.x sang 3.x. Tất nhiên không chỉ đơn giản như vậy, vì trong code, hàm của 2.x có cú pháp đã lỗi thời không phù hợp với 3.x nên báo lỗi ngay. Vậy thì bạn chỉ việc làm theo các lưu ý của bước cuối cùng sau đây là OK thôi

B11 - Chuyển đổi cú pháp code, cập nhật tham số hàm. QUAN TRỌNG

Vì sang 3.x thư viện có sửa đổi nhiều nên nhiều lớp cũ, hàm cũ không thể dùng được, hãy tham khảo trong bài cpp-test để lấy đúng nguyên mẫu của hàm đó, sửa đổi là xong, Tất cả mình sẽ trình bày bên dưới:

1/ Hầu như các prefix CC đều được loại bỏ khỏi lớp nhé, nêu bạn xóa cái CC này đi cho gọn, thoáng

Ví dụ CCSprite => Sprite  ,v.v...

2/ Thay đổi tên 1 số lớp
Ví dụ cpp, hoặc Point, CCPointMake => Vec2

CCPointZero => Vec2::ZERO

3/ Hàm Touch đơn

Không nhớ 2.x nó thế nào

Chuyển thành

bool onTouchBegan(Touch* touch, Event* event);

4/ Touch đa điểm

2.x void ccTouchesBegan(CCSet* pTouches, CCEvent* event);

3.x void onTouchesBegan(const std::vector<Touch*>& touches, Event *event); 

5/ dạng share

2.x _screenSize = CCDirector::sharedDirector()->getWinSize();

3.x _screenSize = Director::getInstance()->getWinSize();

Đại loại có dạng share ở dầu lệnh static bạn có thể dùng getInstane , hãy chỉ chuột vào lệnh sharedDirector() nó sẽ hiện bảng lệnh nào dùng để thay thế ( VS + VAX nhé )

6/ Hàm callback là dạng hàm được gọi khi thực hiện event nào đó, ví dụ click chuột menu, hoặc trong action sequence hay gặp

2.x (CCObject* pSender)

3.x (Ref* pSender)

7/ Menu
2.x
CCMenuItemSprite * starGametItem = CCMenuItemSprite::create(
                                                                menuItemOff,
                                                                menuItemOn,
                                                                this,
                                                                menu_selector(GameLayer::startGame));
   
3.x
MenuItemSprite * starGametItem = MenuItemSprite::create(
                                                                menuItemOff,
                                                                menuItemOn,
                                                                CC_CALL_BACK_x(GameLayer::startGame,this));
x = 0,1,2,3 tùy thuộc vào số tham số của hàm được gọi

8/ CCArray

Chuyển sang dùng Vector, ví dụ vector<T> vec; hoặc Vector<T> Vec, hai thằng này có vẻ giống nhau nhé, nhưng hàm của chúng có khác nhau đấy.

9/ spriteFrameByName
2.x
CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName()
3.x
SpriteFrameCache::getInstance()->getSpriteFrameByName("")
10/ Create

CCSprite::spriteWithFile() -> Sprite::create();

11/ Action

runAction(CCSequence::actions(CCDelayTime::actionWithDuration(0.5f),
 CCCallFunc::actionWithTarget(this, callfunc_selector(HelloWorld::resetGame)),NULL));

3.x

runAction(Sequence::create(DelayTime::create(0.5f),
  CallFuncN::create(CC_CALL_BACK_x(HelloWorld::resetGame,this)),NULL));
CC_CALL_BACK_x, x  = 0,1,2,3  tùy vào số tham số của resetGame

=> Các action đều chuyển về ::create

12/ CGFloat

=> float
   

13/ Debug Box2D

void draw() - 2.x
virtual void draw(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override; - 3.1

3.2
virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;
Tạm thời như vậy thôi nhỉ, còn 1 vài đoạn code đặc biệt nữa, mình không nhớ hết, vì giờ lục lại các bài code hơi bị nhiều. Có gì mình sẽ bổ sung sau. OK?

Vậy là trong bài này chúng ta đã học được cách để Port code từ phiên bản 2.x sang 3.x mà không quá khó khăn rồi.

Nếu bạn làm theo các bước trên đặc biệt chú ý bước cuối cùng quan trọng thì sẽ không Project 2.x nào làm khó được bạn, Mình đã làm 2-3 project 2.x rồi, thành công cả. Hì

Có thể tóm gọn lại như sau

+ Làm theo từng bước: Sửa cú pháp trước =>Copy file =>đóng - mở comment = > Copy code => đóng - mở comment => Debug => mở từng hàm => Debug => đóng mở comment chỗ lỗi => Debug => KẾT QUẢ

Thế thôi nhỉ, Hẹn gặp lại ở bài sau!

Thứ Sáu, 11 tháng 7, 2014

Bài 28 - Box2D - Physics Body cho những vật tĩnh có hình khối phức tạp

Hi, tất cả!

Ở mấy bài trước ( 15-16 gì đó) chúng ta đã cùng nhau nghiên cứu về cách sử dụng Box2D để tạo môi trường vật lý trong Game 2D. Trong bài đó, đối tượng của chúng ta chỉ là một quả bóng hình tròn bán kính R, nên việc đặt body cho nó là quá dễ dàng. Vậy còn đối với những đối tượng có hình dáng bất kỳ thì sao ( chỉ xét những vật tĩnh, ko xét animation nhé) ? Làm thế nào để đặt body cho chúng. Đó sẽ chính là nội dung trong bài hôm nay của chúng ta.

Trong bài này chúng ta sẽ buộc phải sử dụng 2 công cụ PhysicsEditor và TexturePacker ( có thể sử dụng ShoeBox, hoặc SpritePacker để thay thế nếu TexturePacker crack bị lỗi - Win 64 của mình ko bị lỗi sau crack, 32 thì dính chưởng : ((

Đồng thời bạn cũng sẽ được cung cấp 1 bộ thư viện để phân tích file ảnh + file thông số physics được tạo ra bởi 2 phần mềm kể trên. Do đó, hầu như bạn chẳng phải viết code gì nặng nhọc đâu, chỉ việc sử dụng cái thư viện đó để phân tích file nạp vào rồi thiết lập được body ngay. Để hiểu sâu bạn có thể tìm hiểu thư viện đó ( chỉ gồm 1 file .h và .cpp ) sẽ rất có ích nếu bạn có ý định sử dụng Box2D về sau.

Nội dung trong bài gồm các phần sau đây:

+ Sử dụng PhysicsEditor + TexturePacker để thiết kế body cho các đối tượng có hình khối phức tạp
+ Nạp vào game
+ Phương pháp Debug - vẽ khung của đối tượng 1 cách trực quan
+ Test thử

OK, ngắn gọn như vậy thôi, triển nào

À, bài này mình tìm được trên trang codeandweb - trang chủ của PhysicsEditor và TexturePacker

Đây https://www.codeandweb.com/physicseditor/tutorials

Nhưng chủ yếu là Cocos2D, và các Engine khác ( phân biệt đối xử thật ). Lúc đầu cũng khá hì hụi để tìm code trên Github, nhưng khá cũ. Đành sửa và port sang bản 3.x vậy. Các bạn đọc hết 27 bài trước đây trong Blog này thì mình tin là việc port Code từ 2.x sang 3.x thật dễ dàng. Mình muốn chia sẻ 1 điều là, khi tự mình nghiên cứu tìm tòi cách để làm 1 cái gì đó thì kết quả đạt được sẽ rất ý nghĩa, vui và nhớ lâu hơn.

À, các bạn nhớ ôn lại:
+ Cách Import Box2D ( Cũng như các thư viện khác ) ở bài 15, 23,24
+ Cách khai báo Class mới, cũng ở các bài trên
+ Hãy đọc bài chú ý khi biên dịch cho cả Win + Android ( Side bar bên phải có dấu tam giác to đùng )

B1 - Sử dụng PhysicsEditor + TexturePacker 

TexturePacker 

Phầm mềm này rất dễ sử dụng, chức năng chính của nó là đóng gói ( pack ) nhiều ảnh đơn thành 1 bức ảnh to + 1 file thông số đi kèm. File ảnh to xuất ra có thể là png hoặc các dạng nén khác. Mục đích là để giảm tải bộ nhớ, dung lượng game, vậy thôi. Đơn giản vô cùng.

Mở chương trình lên, để các thông số mặc định không sửa đổi gì, import ảnh vào thông qua nút + SPrite hoặc + thư mục, trỏ tới THƯ MỤC ẢNH chứa các ảnh sử dụng trong chương trình này. Nhấn Publish, được 2 file, quăng vào Resource của project. Phần này khá đơn giản nên mình ko minh họa bằng hình ảnh nhé.

PhysicsEditor

Mở phần mềm lên, Import hình ảnh vào thông qua nút Open hoặc nút AddSprites, và cũng trỏ  vào THƯ MỤC ẢNH ở trên ( quan trọng nhé ).




Bây giờ bạn để ý tới 3 khu vực quan trọng nhất
+ Trái : là các hình ảnh bạn import vào
+ Giữa là khu vực bạn sẽ vẽ, hoặc auto tracer shape cho hình ảnh thông qua các hình tròn, đa giác, nút auto, flip ngay bên dưới nút AddSprites
+ Phải: Thiết lập chế độ xuất ra - Exporter ( Box2D, Engine xx) và các thông số vật lý cơ bản của Box2D ( dynamic, friction, density, bitmask, v..v...). Bạn chọn mục Exporter là Box2D generic (PLIST) nhé

Lưu ý 1 chút: để tạo shape dạng Polygon, bạn chọn công cụ đa giác, sẽ hiện 1 tam giác đỏ, để thêm đỉnh mới bạn click đúp, rồi kéo các đỉnh khớp với đối tượng

Thực hành luôn, bạn nhấn vào nút Shape Tracer ( nút thứ 3, sau hình đa giác ) nhé sẽ hiện lên bảng Tracer

Bạn để các thông số như hình





 Để ý là
+ Thông số Telerance càng cao thì Vertexer càng nhỏ và Shape càng thiếu chính xác, với hình ko quá phức  tạp bạn để Vertexes vừa phải thôi nhé. Chỉnh sao sao cái Shape tạo ra ( màu đỏ khớp tương đối với hình ảnh của chúng ta là được).

Sau khi tạo Shape xong cho các ảnh trong này, bạn nhấp chuột vào nút Publish, đặt tên file và chọn nơi lưu là Resource của project

Tuy 2file Plist tạo bởi Physics Editor và TexturePacker khá giống nhau nhưng nội dung chúng lưu khác nhau nhé: 1 thằng lưu thông số hình ảnh, 1 thằng lưu thông số hình khối. Bạn mở 2 file lên để so sách sự khác biệt. Và Physics Editor chỉ tạo ra 1 file Plist, còn TexturePacker tạo ra 2 file là: Plist + ảnh Png ( hoặc dạng khác tùy mình chọn ).

B2 - Nạp vào game + Debug drawing Box2D

Ở bước này, bạn tạo 1 project, giả sử tên là newbox2d chẳng hạn, nhớ Import thư viện Box2D vào theo bài 15, 23,24

Mở thư mục cpp-tests trong thư mục Engine  lên, copy các file sau vào Class Project của chúng ta:

+ VisibleRect.h, .cpp theo đường dẫn Q:\ANDROID\Cocos2dx3\tests\cpp-tests\Classes
+ GLES-Render.h, .cpp theo đường dẫn Q:\ANDROID\Cocos2dx3\tests\cpp-tests\Classes\Box2DTestBed
Download và copy 2 file này vào thư mục Class (Tất cả down ở cuối bài)

OK, các bạn không phải làm gì với các file ở trên, vì mình sử dụng chúng làm thư viện hỗ trợ thôi, các bạn thích thì có thể ngó nghiêng qua, không thì thôi, vào phần chính luôn, đó là file HelloWorldScene.h và .cpp

À, các bạn nhớ thêm các class trên vào file. newbox2d.vcxproj trong proj.win32 ( nếu build win )

hoặc trong file Android.MK ( nếu build Apk )

OK, giờ thì tập trung vào file HelloWorldScene.h

Các bạn mở lên, Paste full code sau vào

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

// Nhớ include Box2D, và các mở rộng
#include "cocos2d.h"
#include "Box2D/Box2D.h"
#include "GLES-Render.h"
#include "GB2ShapeCache-x.h"
#include "VisibleRect.h"

USING_NS_CC;

class HelloWorld : public cocos2d::Layer
{
public:

    static cocos2d::Scene* createScene();

    virtual bool init();  
    
    void menuCloseCallback(cocos2d::Ref* pSender);
void addNewSpriteWithCoords(Point p); // Tạo đối tượng tại Point xác định
// Touch, nên để cả 3 hàm, mặc dù chỉ dùng 1 hàm thôi
bool onTouchBegan(Touch* touch, Event* event);
void onTouchMoved(Touch* touch, Event* event);
void onTouchEnded(Touch* touch, Event* event);

// Hàm vẽ để Debug khung body của đối tượng, lưu ý: Hàm này chỉ đúng với Engine 3.0,3.1.x nhé, Ai dùng Engine 3.2 RC0 trở lên ( ko xét alpha,beta) thì phải sửa thành.

// virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;

// Kẻo lỗi tùm lum

virtual void draw(Renderer *renderer, const Mat4 &transform, bool transformUpdated) override;

void update(float dt);
    
    CREATE_FUNC(HelloWorld);

private:

// World và đối tượng Debug Draw
b2World* world;
GLESDebugDraw *m_debugDraw;
};

#endif // __HELLOWORLD_SCENE_H__

Giờ thì tới lượt file HelloWorldScene.cpp

Phần Include, thêm code sau

USING_NS_CC;
using namespace std;
 // Nếu ko dùng namespace này, khai báo string str sẽ lỗi
#define PTM_RATIO 32  

Hàm init()

bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
    
// Lớp Point đã được thay = Vec2 từ V3.1
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
  
setTouchEnabled( true );
Size screenSize = Director::getInstance()->getWinSize();

// Khởi tạo world của Box2D
b2Vec2 gravity;
gravity.Set(0.0f, -10.0f);
bool doSleep = true;  
world = new b2World(gravity);
world->SetAllowSleeping(doSleep);    
world->SetContinuousPhysics(true);

//-----------DEBUG------------và phải có hàm Draw ở phía dưới nữa
// Debug khung body
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
world->SetDebugDraw(m_debugDraw);

// Các tham số để vẽ, bạn mở dần từng comment ra để thấy sự thay đổi
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
//flags += b2Draw::e_jointBit;
//flags += b2Draw::e_aabbBit;
// flags += b2Draw::e_pairBit;
// flags += b2Draw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);
//-------------End Debug------------

//Tạo Ground bao quanh màn hình
b2BodyDef groundBodyDef;


groundBodyDef.position.Set(screenSize.width/2/PTM_RATIO, 
screenSize.height/2/PTM_RATIO); 

b2Body* groundBody = world->CreateBody(&groundBodyDef);

b2PolygonShape groundBox;

// bottom
groundBox.SetAsBox(screenSize.width/2/PTM_RATIO, 0, b2Vec2(0, -screenSize.height/2/PTM_RATIO), 0);
groundBody->CreateFixture(&groundBox, 0);

// top
groundBox.SetAsBox(screenSize.width/2/PTM_RATIO, 0, b2Vec2(0, screenSize.height/2/PTM_RATIO), 0);
groundBody->CreateFixture(&groundBox, 0);

// left
groundBox.SetAsBox(0, screenSize.height/2/PTM_RATIO, b2Vec2(-screenSize.width/2/PTM_RATIO, 0), 0);
groundBody->CreateFixture(&groundBox, 0);

// right
groundBox.SetAsBox(0, screenSize.height/2/PTM_RATIO, b2Vec2(screenSize.width/2/PTM_RATIO, 0), 0);
groundBody->CreateFixture(&groundBox, 0);

//---------------------------------------

// Nạp vào game file hình ảnh đóng gói và thông số của nó tạo bởi TexturePacker
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("INFOR.plist");
auto spriteSheet = SpriteBatchNode::create("INFOR.png");
this->addChild(spriteSheet);

// Nạp vào file thông số hình khối tạo bởi Physics Editor
GB2ShapeCache::sharedGB2ShapeCache()->addShapesWithFile("shapedefs.plist");

// Bắt sự kiện Touch

auto touchListener = EventListenerTouchOneByOne::create();
touchListener->setSwallowTouches(true);
touchListener->onTouchBegan= CC_CALLBACK_2(HelloWorld::onTouchBegan,this);
touchListener->onTouchMoved=CC_CALLBACK_2(HelloWorld::onTouchMoved,this);
touchListener->onTouchEnded=CC_CALLBACK_2(HelloWorld::onTouchEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener,this); 

// Cập nhật Scene
schedule( schedule_selector(HelloWorld::update) );

    return true;
}

3 Hàm Touch

void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
// Lấy tọa độ điểm touch và tạo ra đối tượng tại tọa độ đó
auto touchPoint = touch->getLocation(); 
touchPoint = this->convertToNodeSpace(touchPoint);
addNewSpriteWithCoords( touchPoint );
}

bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
return true;
}

void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
}

Hàm addNewSpriteWithCoords

// Chuỗi string lưu tên các file ảnh nằm trong pack
string names[] = {
"hotdog",
"drink",
"icecream",
"icecream2",
"icecream3",
"hamburger",
"orange"
};

void HelloWorld::addNewSpriteWithCoords(Point p)
{
string name = names[rand()%7]; // Random 0-6

// Trả về xâu ký tự ví dụ: "orange.php" - = phương thức c_str()
Sprite *sprite = Sprite::createWithSpriteFrameName((name+".png").c_str());

sprite->setPosition(p);
addChild(sprite);

// Tạo b2BodyDef
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
bodyDef.userData = sprite;

b2Body *body = world->CreateBody(&bodyDef);

// Tạo fixture cho body, bằng cách sử dụng GB2ShapeCache

GB2ShapeCache *sc = GB2ShapeCache::sharedGB2ShapeCache();
sc->addFixturesToBody(body, name.c_str()); 
sprite->setAnchorPoint(sc->anchorPointForShape(name.c_str())); // Đặt cùng 1 điển neo
}

Hàm update, chỉ việc copy lại ở những bài trước thôi, nếu có thay đổi thì đổi giá trị của velocityIterations + positionIterations 


void HelloWorld::update(float dt)

{

int velocityIterations = 8;
int positionIterations = 1;
world->Step(dt, velocityIterations, positionIterations);

for (b2Body *body = world->GetBodyList(); body != NULL; body = body->GetNext())   
if (body->GetUserData()) 
{  
Sprite *sprite = (Sprite *) body->GetUserData();  
sprite->setPosition(Point(body->GetPosition().x * PTM_RATIO,body->GetPosition().y * PTM_RATIO));  
sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(body->GetAngle())); 

}  
world->ClearForces(); 
world->DrawDebugData();   

}

Và đây là hàm Draw để Debug cho Box2D ( V3.0, 3.1 thì như bên dưới ). V3.2 RC0 trở lên thì thay đổi 1 chút ở phần tham số vào virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags). Các bạn chú ý. Nội dung hàm mình ko giải thích nhé, lấy từ thư viện ra thôi.

void HelloWorld::draw(Renderer *renderer, const Mat4 &transform, bool transformUpdated)
{
GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION );
Director* director = Director::getInstance();
CCASSERT(nullptr != director, "Director is null when seting matrix stack");
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
world->DrawDebugData();
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}

OK rồi đó, Build thử xem cơm cháo thế nào

Cũng khá hay phải không nào.
Trong bài này chúng ta đã được nghâm cứu các vấn đề sau:

+ Cách sử dụng Physics Editor và TexturePacker ( có thể = ShoeBox hoặc SpritePacker thay thế )
+ Phân tích body của 1 Sprite phức tạp = thư viện GB2ShapeCache
+ Debug drawing trong Box2D


Mình kết thúc bài này ở đây nhé, chào và hẹn các bạn ở bài sau!

Thứ Năm, 10 tháng 7, 2014

Cách build Project cpp-tests của Cocos2d-x V3.x ra EXE (publish not debug)

Hi các bạn!

Dạo này mình tập trung nghiên cứu mấy project game lớn lớn 1 chút để tích kinh nghiệm và đào sâu hơn các thư viện mẫu của Engine nên cũng ít viết bài hơn. Mọi người thông cảm nhé. Càng đào sâu đọc kỹ càng thấy những hiểu biết trước đây có nhiều điểm chưa đúng, hoặc không còn đúng vào thời điểm hiện tại. Như thế là tốt, chứ cứ bảo thủ với kiến thức cũ của mình thì nguy. Chính vì thế mình đang chỉnh sửa lại những bài viết cũ trên Blog.

Trong 1 bài ngắn ngắn này mình sẽ chỉ cho các bạn cách Publish Project cpp-test của Engine ra file chạy Exe trong Window - có thể mở trực tiếp nhiều lần ko cần dùng VS. Không xét việc build APK nhé, bạn làm việc nhiều trên máy tính để code hơn mà.

Các bạn biết đấy, 1 project bình thường tạo bởi Engine, bạn có thể build ra exe bằng 2 cách :

+ Dùng lệnh cmd của window
+ Dùng VS2012, 2013 để tạo bản Release hoặc Debug

Nhưng với cách tạo Release hoặc Debug mình chạy trực tiếp file exe sẽ lỗi do thiếu Resource, và rất nhiều lib,obj, log, linh tinh khác trong thư mục. Mỗi lần chạy lại phải mở VS lên khá bất tiện. Có thể mình chưa biết cách Publish trong VS chăng. Có ai biết không - Cách build 1 lần rồi mở file Exe lên chạy cho các lần khác đó?

Với 1 bản Publish bạn sẽ dễ dàng sử dụng mọi lúc mọi nơi trên window, kể cả vác sang máy khác để chạy thử mà ko phải mở VS lên.

Thông thường khi bạn down Engine về, bạn build Project cpp-test bằng cách sau

+ Mở file cocos2d-win32.vc2012.sln theo đường dẫn Q:\ANDROID\Cocos2dx3\build, rồi cứ thế Debug và chạy thử, lần nào muốn xem ví dụ mẫu bạn cũng sẽ phải làm như vậy khá bất tiện nhỉ. Mình chuyển chế độ Release cũng vẫn phải làm vậy là sao. Nên loay hoay tìm ra cách build cmd cho cpp-tests kia. đơn giản thôi, chẳng cao siêu gì, nhưng có thể có người chưa biết như mình chẳng hạn.

Cách của mình là như thế này

+ Dùng lệnh cmd của window buil Project cpp-test như là 1 project thông thường các bạn tạo ra, nhưng trước hết các bạn phải chỉnh sửa 2 file sau.

1/ Copy file cocos2d-win32.vc2012.sln ở trên vào Project cpp-test theo đường dẫn Q:\ANDROID\Cocos2dx3\tests\cpp-tests\proj.win32, đổi tên lại thành cpp-tests.sln

2/ Quan trọng đây : Sửa path của các Libs trong file đó theo đúng đường dẫn mới ( do mình copy và thả vào thư mục khác với thư mục build mà ). Có chút kinh nghiệm là sửa được thôi. Mà DOWNLOAD file của mình cho nhanh . Trong này mình đã bỏ đi Lib và Project test khác nhé chỉ để cpp-tests thôi

3/ Mở file .cocos-project.json Xóa hết ( tốt hơn là lưu Save As đề phòng ) config trong đó và paste

{
    "project_type": "cpp"
}

Save lại

OK, giờ thì BUILD thử bằng commend sau

>cocos run -s (chỗ này bạn kéo thả thư mục cpp-tests vào đây nhé, vì path dài ngại gõ) -p win32

Kết quả sẽ ra thư mục Publish nằm trong thư mục Cpp-tests với đầy đủ Resource, dll, EXE.
Khi nào bạn cần chạy thử các ví dụ chỉ việc vào đây, hoặc tạo shortcut ngoài desktop mà run thôi. đỡ phải dùng đến VS nữa, và cũng ko phải tạo APK chạy trên điện thoại.

Bạn hoàn toàn có thể mang thư mục Publish này lên máy window khác để chạy nhé



Có thể có cách khác nữa nhưng mình chỉ biết các này thôi, ai biết cách ngắn gọn hơn thì share với

+ Bạn cũng có thể build lua-tests với cách tương tự nhưng nhớ chú ý file json là .lua nhé

Chào và hẹn gặp lại các bạn ở bài sau

Thứ Ba, 8 tháng 7, 2014

Bài tập lớn CTDLGT học kỳ hè 20133

Một số BTL cho kỳ hè 2013

Bài 1. Thống kê từ file log


Dữ liệu log về quảng cáo trong 1h được ghi ra các file log, mỗi trường được ngăn cách nhau bởi dấu tab (\t)
Nội dung các trường theo thứ tự

0 time create
1 browser code
2 browser version
3 os code
4 os version
5 device code
6 bannerId
7 ip
8 geoId
9 domain
10 path
11 ref url
12 click or view
13 cookie create time
14 guid
15 appid
16 sdk version
17 zoneId
18 campaign id
21 screen width
22 screen height
24 manufactory id

Cần thống kê:

  • Số lượng thiết bị (Device) (Các thiết bị không xác định sẽ được gom lại thành 1 nhóm)
  • Thống kê Pageview theo domain và theo từng page 


Dữ liệu các bạn có thể tài về từ

https://drive.google.com/folderview?id=0B5nb3v94xY_WSFFxMmRiQ1hDN3M&usp=sharing

Bài 2. Cài đặt thuật toán Seamcarving dùng để resize lại ảnh


Mô tả thuật toán này các bạn có thể tìm tại
https://drive.google.com/folderview?id=0B5nb3v94xY_WSFFxMmRiQ1hDN3M&usp=sharing

Với ảnh màu RGB bạn có thể chọn một trong những cách sau đây


  • Chuyển về ảnh mức xám
  • Xử lý các thành phần màu RAG như 1 số nguyên 3 Byte
  • xử lý từng thành phần màu R,G,B riêng rẽ

Bài 3. Xây dựng gợi ý khi gõ văn bản



Khi gõ một hoặc một số ký tự, chương trình sẽ tự động suggest nốt phần còn lại của từ

Ý tưởng: Dùng prefix Tree

Yêu cầu: Xây dựng prefix tree và áp dụng để suggest một số từ thông dụng cho từ điển tiếng Anh
(Từ điển có thể tải về từ https://drive.google.com/folderview?id=0B5nb3v94xY_WSFFxMmRiQ1hDN3M&usp=sharing), file mword10.zip, dùng file COMMON.TXT hoặc COMPOUND.TXT


Bài 4. Xây dựng thuật toán sinh màn chơi SODOKU theo các mức khó

Cài đặt thuật toán mô tả trong bài báo sau

http://zhangroup.aporc.org/images/files/Paper_3485.pdf

Tham khảo thêm tại


Bài 5. Xây dựng chương trình tự động suggest và sửa lỗi chính tả (tiếng Anh)

Với một văn bản tiếng Anh được nhập từ bàn phím, hoặc file, chương trình sẽ làm những việc sau:


  1. Phát hiện những từ sai chính tả (VD: Đầu dòng, đoạn phải viết hoa, những từ ko có trong từ điển), và đánh dấu bằng màu khác hoặc tô đậm
  2. Với những từ không có trong từ điển, chương trình có thể gợi ý những cách sửa (đưa ra 1 vài gợi ý dựa trên thuật toán tìm khoảng cách sửa đổi gần nhất của 2 xâu - Levenshtein Edit Distance)


(Từ điển có thể tải về từ https://drive.google.com/folderview?id=0B5nb3v94xY_WSFFxMmRiQ1hDN3M&usp=sharing), file mword10.zip, dùng file COMMON.TXT

Tham khảo

Bài 6: Thuật toán sinh mê cung



Yêu cầu: Sinh mê cung kích thước nxn bất kỳ
Đầu ra: Vẽ minh họa mê cũng sinh được (với trường hợp n nhỏ thì hiển thị trên màn hình, còn n lớn có thể ghi ra file), dùng các ký hiệu VD. _, | để minh họa

Tham khảo


Demo


Bài 7: Đưa ra từ gợi ý dựa trên n-gram (+2 điểm)


http://en.wikipedia.org/wiki/N-gram
n-gram là chuỗi n từ được đi liền với nhau (có thể có nghĩa hoặc không có nghĩa)

Ví dụ: với xâu "In the fields of computational linguistics and probability, an n-gram is a contiguous sequence of n items from a given sequence of text or speech. The items can be phonemes, syllables, letters, words or base pairs according to the application. The n-grams typically are collected from a text or speech corpus."

1-gram là các từ đứng rời In, the, fields, of, computational,....
2-gram là các cặp 2 từ liền nhau: In the, the fields, fields of, of computational,....
3-gram là các nhóm 3 từ liền nhau: In the fields, the fields of, fields of computational,....

tương từ với 4-gram, 5-gram

Đầu vào: là tập văn bản reuters21578 http://www.daviddlewis.com/resources/testcollections/reuters21578/
format của các văn bản này các bạn xem thêm tại: http://www.daviddlewis.com/resources/testcollections/reuters21578/readme.txt

Yêu cầu:

  1. Lọc lấy tiêu đề và nội dung của các bài viết
  2. Tách và sinh ra các n-gram (1,2,3,4,5-gram)
  3. Thống kê tần số xuất hiện của các gram (không phân biệt hoa thường, và có phân biệt hoa thường)
  4. Gợi ý từ dựa trên các n-gram thống kê được
VD. Với dữ liệu mẫu là 3 gram ở trên thì khi người dùng gõ vào từ "In" ta có thể gợi ý các cặp là "In the", "In the fields".

Trong thực tế thì ta có thể chọn các cặp n-gram có tần số xuất hiện lớn nhất để đưa ra trước, nhưng vì tần số xuất hiện này còn tỉ lệ với độ dài gram. Do đó việc đưa ra các từ gợi ý dựa trên (tần số xuất hiện của gram)/(tổng số các n-gram).

Ví dụ. Có 2500 2-gram và 1000 3-gram

cụm 2-gram "In the" có tần số xuất hiện 15 lần thì tỉ lệ của nó sẽ là 15/2500
cụm 3-gram "In the fields" có tần số xuất hiện 7 lần thì tỉ lệ là 7/1000

Vậy khi đưa ra gợi ý ta sẽ đưa ra cụm "In the fields" trước cụm "In the"

Chú ý: Các cụm gram này dừng tại các dấu câu.

VD. câu "In the fields of computational linguistics and probability, an n-gram is a contiguous sequence of n items from a given sequence of text or speech.

được tách thành 2 phần

"In the fields of computational linguistics and probability"
"an n-gram is a contiguous sequence of n items from a given sequence of text or speech"

để đảm bảo các n-gram không chứa các dấu như , . : ? ! ;

Tham khảo thêm tại
  • http://en.wikipedia.org/wiki/N-gram
  • http://nlpwp.org/book/chap-ngrams.xhtml
  • http://www.ngrams.info/
  • https://drive.google.com/folderview?id=0B5nb3v94xY_WSFFxMmRiQ1hDN3M&usp=sharing

Bài 8: Xây dựng chương trình kiểm tra một biểu thức dạng trung tố có hợp lệ


Một biểu thức dạng trung tố

  • Toán tử có thể 1 ngôi hoặc 2 ngôi, chỉ gồm 1 ký tự
  • Toán hạng: nếu là số thì có thể có 1 hoặc nhiều chữ số được viết liên nhau, nếu là chữ cái thì chỉ có 1 ký tự
  • Các toán tử và toán hạng được viết liền nhau, giữa chúng không có khoảng cách trống
  • Chỉ có một loại dấu ngoặc tròn
Ví dụ một số biểu thức hợp lệ

A=a+345-23*12+(a-34/2)
B=b+(45+a/3+(52-4*a))
C=|45+a*(2-7/b)|/23*a

Hãy viết chương trình kiểm tra biểu thwucs hợp lệ, với biểu thức có thể được nhập vào từ file hoặc từ bàn phím

Thứ Hai, 7 tháng 7, 2014

Bài 9: Ví dụ tổng hợp CheckBox, RadioButton, Button, EditText...

     Trong bài trước, các bạn đã tìm hiểu và nắm bắt được các control CheckBox, RadioButton. Trong bài này, chúng ta cùng làm ví dụ tổng hợp CheckBox, RadioButton, Button, Editext... giúp chúng ta củng cố lại kiến thức đã học.

- Ví dụ: đăng ký thông tin tìm bạn bốn phương. Yêu cầu nhập họ tên, email, giới tính và một vài thông tin khác. Ứng dụng sẽ có 2 nút là OK và Clear. Khi nhấn vào nút Ok sẽ hiện ra một hộp hội thoại AlertDialog để thông báo các thông tin đã được nạp vào. Nút Clear để xóa trắng các trường thông tin.
- Các bạn xem giao diện sau để dễ hình dung và thiết kế giao diện:
Ví dụ tổng hợp CheckBox, RadioButton, Button, Editext...
- Chúng ta sử dụng CheckBox để xác định giới tính, và RadioButton để nhập đối tượng quan tâm. Các bạn cần nhóm 2 CheckBox lại vào một RadioGroup để tiện xử lý. Sau đây là code của chương trình.
+activity_main.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:context="com.example.checkboxradiobutton.MainActivity$PlaceholderFragment" >

    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#008000"
        android:textColor="#FFFFFF"
        android:textSize="20sp"
        android:gravity="center"
        android:text="Đăng ký tìm bạn bốn phương"/>
   
    <TableLayout android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:stretchColumns="*">
        <TableRow android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5sp"
            android:layout_marginLeft="5sp">
           
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Họ tên: "/>
            <EditText
                android:id="@+id/edtHoTen"
                 android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="8"
                android:inputType="text">
                <requestFocus/>
            </EditText>
        </TableRow>
        <TableRow android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5sp"
            android:layout_marginLeft="5sp">
           
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Email liên lạc: "/>
            <EditText
                android:id="@+id/edtEmail"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="8"
                android:inputType="text">
            </EditText>
        </TableRow>
        <TableRow android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5sp"
            android:layout_marginLeft="5sp">
           
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:text="Giới tính "/>
            <RadioGroup android:id="@+id/rgGioiTinh"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <RadioButton android:id="@+id/rbNam"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Nam"
                    android:checked="true"/>
                <RadioButton android:id="@+id/rbNam"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Nữ"/>
            </RadioGroup>
        </TableRow>
       
        <TableRow android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5sp"
            android:layout_marginLeft="5sp">
           
            <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Năm sinh "/>
           
            <EditText
                android:id="@+id/edtNamSinh"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="8"
                android:inputType="number">
            </EditText>
        </TableRow>
    </TableLayout>
   
    <TextView
        android:layout_marginTop="10sp"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textColor="#9230f3"
        android:text="Đối tượng quan tâm"/>
   
    <RadioGroup android:id="@+id/rgDoiTuong"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
       
        <CheckBox android:id="@+id/cbNam"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Nam"/>
        <CheckBox android:id="@+id/cbNu"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Nữ"/>
        <CheckBox android:id="@+id/cbGay"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Gay"/>
        <CheckBox android:id="@+id/cbLes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Les"/>
    </RadioGroup>
   
    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button android:id="@+id/btnOK"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="OK"/>
           <Button android:id="@+id/btnClear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Clear"/>
    </LinearLayout>
</LinearLayout>
   
</ScrollView>

Chúng ta sử dụng ScrollView bao trùm ngoài LinearLayout, ScrollView sẽ giúp chúng ta kéo được màn hình nếu ứng dụng của chúng ta vượt quá chiều dài màn hình. Tuy nhiên, bên trong ScrollView chỉ cho phép 1 control nên chúng ta bao toàn bộ các control khác trong LinearLayout. Các bạn cần chú ý và ghi nhớ đặc điểm này của ScrollView vì nếu không làm như vậy sẽ nhận được báo lỗi.

+MainActivity.java:

package com.example.checkboxradiobutton;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

    Button btnOK, btnClear;
    EditText edtHoten, edtEmail, edtNamSinh;
    RadioGroup rgGioiTinh;
    CheckBox cbNam, cbNu, cbGay, cbLes;
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        getControlView();
       
        btnOK.setOnClickListener(new OnClickListener() {
           
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                xuLyNhap();
            }
        });
        btnClear.setOnClickListener(new OnClickListener() {
           
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                xuLyXoa();
            }
        });
       
    }
    private void getControlView() {
        // TODO Auto-generated method stub
        btnOK = (Button)findViewById(R.id.btnOK);
        btnClear = (Button)findViewById(R.id.btnClear);
        edtHoten = (EditText)findViewById(R.id.edtHoTen);
        edtEmail = (EditText)findViewById(R.id.edtEmail);
        edtNamSinh = (EditText)findViewById(R.id.edtNamSinh);
        rgGioiTinh = (RadioGroup)findViewById(R.id.rgGioiTinh);
        cbNam = (CheckBox)findViewById(R.id.cbNam);
        cbNu = (CheckBox)findViewById(R.id.cbNu);
        cbLes = (CheckBox)findViewById(R.id.cbLes);
        cbGay = (CheckBox)findViewById(R.id.cbGay);
    }
   
    protected void xuLyNhap() {
        // TODO Auto-generated method stub
        String hoTen = edtHoten.getText().toString();
        String email = edtEmail.getText().toString();
        String namsinh = edtNamSinh.getText().toString();
        if(hoTen==null || hoTen.equalsIgnoreCase("") ){
            Toast.makeText(getBaseContext(), "Bạn phải nhập họ tên", Toast.LENGTH_LONG).show();
            return;
        }
        if(email==null || email.equalsIgnoreCase("")){
            Toast.makeText(getBaseContext(), "Bạn phải nhập email", Toast.LENGTH_LONG).show();
            return;
        }
        if(namsinh==null || namsinh.equalsIgnoreCase("")){
            Toast.makeText(getBaseContext(), "Bạn phải nhập năm sinh", Toast.LENGTH_LONG).show();
            return;
        }
       
        String gioiTinh;
        if(rgGioiTinh.getCheckedRadioButtonId()==R.id.rbNam){
            gioiTinh = "Nam";
        }else{
            gioiTinh = "Nữ";
        }
       
        String doiTuongQuanTam = "";
        if(cbNam.isChecked()){
            doiTuongQuanTam += "Nam"+"; ";
        }
        if(cbNu.isChecked()){
            doiTuongQuanTam += "Nữ"+"; ";
        }
        if(cbLes.isChecked()){
            doiTuongQuanTam += "Les"+"; ";
        }
        if(cbGay.isChecked()){
            doiTuongQuanTam += "Gay"+"; ";
        }
       
        if(doiTuongQuanTam == null || doiTuongQuanTam.equalsIgnoreCase("") ){
            Toast.makeText(getBaseContext(), "Bạn cần chọn đối tượng quan tâm", Toast.LENGTH_LONG).show();
            return;
        }
       
        AlertDialog.Builder ad = new AlertDialog.Builder(this);
        ad.setTitle("Thông tin cá nhân");
        ad.setPositiveButton("Close", new DialogInterface.OnClickListener() {
           
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO Auto-generated method stub
                dialog.cancel();
            }
        });
        String message = "";
        message += "Họ tên: "+hoTen + "\n";
        message += "Email: "+email + "\n";
        message += "Giới tính: "+gioiTinh + "\n";
        message += "Năm sinh: "+namsinh + "\n";
        message += "Đối tượng quan tâm : "+doiTuongQuanTam + "\n";
       
        ad.setMessage(message);
        ad.create().show();
    }

    protected void xuLyXoa() {
        // TODO Auto-generated method stub
        edtHoten.setText("");
        edtNamSinh.setText("");
        edtEmail.setText("");
        cbNam.setChecked(false);
        cbNu.setChecked(false);
        cbLes.setChecked(false);
        cbGay.setChecked(false);
       
    }
}

Các bạn lưu ý đoạn code xử lý CheckBox, RadioButton và tạo hộp hội thoại AlertDialog. Đây đều là các control rất cơ bản và thường được sử dụng thường xuyên trong các ứng dụng Android. Việc nắm vững các kiến thức về những loại control này là rất quan trọng. Các bạn nên tự mình code lại bài tập này sau khi đã đọc kỹ và tự mầy mò tạo ra thêm các ví dụ khác về các control này nhé.

>>>Bài 10:Thêm một ví dụ về TextView, EditText, CheckBox, Button và ImageButton trong Android

Bài 8: Cách sử dụng Checkbox, Radio Button trong Android

     Trong bài tập này, chúng ta cùng tìm hiểu về 2 thành phần: CheckBox RadioButton. Đây là 2 control thường xuyên được chúng ta sử dụng trong các chương trình.



- Một số phương thức thường sử dụng của CheckBox RadioButton:
 + Phương thức setChecked dùng để thiết lập việc checked. Nếu bạn gọi setChecked(true) thì có nghĩa là bạn cho phép CheckBox hoặc RadioButton được checked, và ngược lại setChecked(false) sẽ unchecked 2 control này.
 + Phương thức isChecked: Trả về một giá trị boolean: True hoặc False. Nếu control đang được check sẽ trả về giá trị True, và ngược lại unchecked trả về là False

- Cả CheckBox và RadioButton thường được thiết kế trong một RadioGroup. RadioGroup nhóm các CheckBox và RadioButton lại và thường dùng cho một mục đích nào đó. Tuy nhiên, CheckBox cho phép chúng ta checked nhiều đối tượng còn RadioButton thì tại một thời điểm chỉ cho phép ta checked 1 đối tượng trong cùng một group mà thôi.

- Các bạn xem hình sau để hiểu rõ hơn về CheckBox. Đây là ví dụ khi bạn muốn người sử dụng chọn lựa nhiều trường hợp do bạn đưa ra trong CheckBox.
CheckBox trong android
- Bạn cũng có thể thiết lập trạng thái checked cho CheckBox trong xml như sau :

<CheckBox android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Brazil"
            android:checked="true"/>

- Nếu bạn chỉ muốn người sử dụng chọn 1 trong các trường hợp mà bạn đưa ra thì bạn sử dụng RadioButton. RadioButton chỉ cho phép chọn 1 trong RadioGroup.
RadioButton trong Android
 - Các bạn xem cách thiết kế một RadioGroup
<RadioGroup android:id="@+id/rg1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
       
        <RadioButton android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Brazil"/>
       
        <RadioButton android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Đức"/>
       
        <RadioButton android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Italia"/>
       
        <RadioButton android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Việt Nam"/>
       
    </RadioGroup>
 
- Dựa vào ví dụ thiết kế trên, các bạn đã hình dung và biết cách sử dụng RadioGroup để gom nhóm các RadioButton hoặc CheckBox vào thành một nhóm nào đó. Bởi vì RadioButton mà cùng một nhóm thì tại cùng thời điểm chỉ có 1 RadioButton được checked nên bạn có thể tạo nhiều nhóm RadioGroup để xử lý với các mục đích khác nhau

- Chúng ta có 2 cách để xử lý RadioButton nào được checked:
 + C1: Dựa vào RadioGroup để biết ID nào của RadioButton được checked. Dựa vào ID này chúng ta sẽ xử lý code theo những gì chúng ta mong muốn

        RadioGroup rg = (RadioGroup) findViewById(R.id.rg1);
        int idRadioButtonChecked = rg.getCheckedRadioButtonId();
        switch (idRadioButtonChecked) {
        case R.id.rbBrazil:
            break;
        case R.id.rbDuc:
            break;
        case R.id.rbItalia:
            break;
        case R.id.rbVietNam:
            break;
        }
 + C2: Check trực tiếp xem RadioButton đó có được cheked hay không
        RadioButton rbDuc = (RadioButton)findViewById(R.id.rbDuc);
        if(rbDuc.isChecked()){
            //Xử lý với trạng thái checked
        }else{
            //Xử lý với trạng thái unchecked
        }

      Qua bài tập này, các bạn đã hiểu và biết cách sử dụng 2 control CheckBox và RadioButton. Trong bài tập sau, mình sẽ demo thêm ví dụ về CheckBox, RadioButton, Button, Editext để các bạn nắm vững hơn kiến thức về các control cơ bản này. Hẹn gặp lại các bạn ở các bài tiếp theo !

>>>Bài 9: Ví dụ tổng hợp CheckBox, RadioButton, Button, EditText...

Bài đăng phổ biến