Vào một lúc nào đó ta cần di chuyển
một vật nào đó (có thể là nhân vật,quái thú….) theo đường cong ? Lúc nào đó việc
áp dụng các Action MoveTo,MoveBy … có vẻ sẽ gặp nhiều khó khăn ? Vì thường những
Action này áp dụng để di chuyển vật theo đường thẳng ! Dưới đây tôi xin giới thiệu
các bạn một phương pháp di chuyển theo đường cong đó là dùng Action Bezier
trong cocos2d-x ( cocos2d::BezierTo , cocos2d::BezierBy ).
Các bạn copy nhớ ghi nguồn :
Viết bởi : Nguyễn Hoàng Thiên Phước .
Link : https://hoangthienphuoc.blogspot.com/2016/10/su-dung-action-bezier-e-tao-uong-cong.html
Các bạn copy nhớ ghi nguồn :
Viết bởi : Nguyễn Hoàng Thiên Phước .
Link : https://hoangthienphuoc.blogspot.com/2016/10/su-dung-action-bezier-e-tao-uong-cong.html
❶ Đường cong Bezier Là Gì ?
Về định nghĩa nghiên về mặt lý thuyết chi tiết các bạn có thể
tham ở wikipedia . Ở đây tôi chỉ
khái quát cho các bạn hiểu , và việc áp dụng nó trong cocos2d-x . Các bạn hãy
xem hình bên dưới :
Hình 1
Đây chính là đường cong Bezier ( Bậc 2 ) nó được tạo thành từ 3 điểm P0 , P1 và P2. Nhìn vào hình các bạn sẽ thấy có 1 điểm chạy từ đoạn P0->P1, và điểm thứ 2 chạy từ P1->P2 . Tương ứng với mỗi lần sẽ sinh ra 1 điểm ta gọi là B(t) cái chấm tròn màu đen di chuyển ấy ! cứ liên tục như vậy -> nó sẽ tạo ra đường cong Bezier.
✿Ghi chú thêm : Nếu muốn đường cong của mình đều,đẹp như nửa hình tròn, hay nửa hình eclipse … thì các bạn nên thiết lập 3 điểm đó, là 3 đỉnh của một tam giác đều , hoặc tam giác cân !
❷ Cách Thức Sử Dụng Ra Sao ?
Ok ! Đến đây các bạn có thể hiểu sơ sơ cách thức hoạt động của nó rồi đúng ko !
Vậy việc áp dụng thì sao ? Haha … Việc sử dụng của nó rất đơn giản , cũng giống như các Action khác thôi !
cocos2d::BezierTo::create(float t, const ccBezierConfig& c);
Nhìn vào hàm create ta thấy nó cần hai tham số :
✚ Một là tham số t kiểu float là khoảng thời gian (duration ) Action thực hiện.
✚ Hai là tham số c kiểu ccBezierConfig.
Oh ! Vậy ccBezierConfig là kiểu gì ? Các bạn hãy xem cấu trúc sau :
/** @struct Bezier
configuration structure
*/
typedef struct _ccBezierConfig {
//! end position of the bezier
Vec2 endPosition;
//! Bezier control point 1
Vec2 controlPoint_1;
//! Bezier control point 2
Vec2 controlPoint_2;
} ccBezierConfig;
☛ Tương ứng với hình 1 :
☛Ở đây điểm :
controlPoint_1 tương ứng với điểm P0,
controlPoint_2 tương ứng với điểm P1 ,
endPosition tương ứng với điểm P2.
OK ! Đọc 100 bài báo lý thuyết suông không bằng ta làm cái demo nhỏ nhỏ ! (•‿•) !
Đến đây ta sẽ bắt đầu thực hành nào ! Đầu tiên tôi sẽ nói cho các bạn biết là mình sẽ làm những gì ?
Đơn giản chỉ là làm đường cong giống như hình 1 và hình 2 là được ! ( Xem hình 3 )
cocos2d::ccBezierConfig bezier;
(¬‿¬) Download Source ( Link Github )
Tiếp theo , BezierBy khác với BezierTo ra sao ? Nếu BezierTo là di chuyển “đến” -> thì BezierBy nó là di chuyển “thêm” !
Và lúc này điểm mà nó di chuyển đến sẽ là (400,300) ! Sau khi thực hiện Action BezierBy !
Bây giờ mình sẽ dời tọa độ của các điểm RED,GREEN,BLUE ... đến những vị trí mới đã tính toán ?
Y như mong đợi haha!
❹ Ứng Dụng Thực Tế
Mô tả hiệu ứng chết của nhân vật ....
Character
sprite->runAction(Spawn::create(BezierBy::create(1.5f, config),FadeOut::create(2.0f),NULL));
Hình 2
controlPoint_1 tương ứng với điểm P0,
controlPoint_2 tương ứng với điểm P1 ,
endPosition tương ứng với điểm P2.
Các bạn thấy quen quen rồi đúng không ? ◕‿◕ hehe....
OK ! Đọc 100 bài báo lý thuyết suông không bằng ta làm cái demo nhỏ nhỏ ! (•‿•) !
Đến đây ta sẽ bắt đầu thực hành nào ! Đầu tiên tôi sẽ nói cho các bạn biết là mình sẽ làm những gì ?
Đơn giản chỉ là làm đường cong giống như hình 1 và hình 2 là được ! ( Xem hình 3 )
Hình 3
❖Quy định nhỏ :
✚Điểm màu đỏ là controlPoint_1 (P0) ->
tọa độ (200,200)
✚Điểm màu xanh dương là controlPoint_2(P1)
->
tọa độ (250,300)
✚Điểm màu xanh lá là điểm endPosition(P2) ->
tọa độ (300,200)
Ở đây 3 điểm của mình sẽ tạo thành tam giác cân(Isosceles Triangle) để cho đường cong của mình nó đẹp xíu!haha….
Ở đây 3 điểm của mình sẽ tạo thành tam giác cân(Isosceles Triangle) để cho đường cong của mình nó đẹp xíu!haha….
cocos2d::ccBezierConfig bezier;
bezier.controlPoint_1 = Point(200, 200);
bezier.controlPoint_2 = Point(250, 300);
bezier.endPosition = Point(300,
200);
Sau đó chúng ta sẽ hiển
thị 3 điểm đó lên màn hình ( mục đích để nhận biết thôi chứ không có ý gì
khác ) Ở đây tôi dùng một sprite kích cỡ
20x20 pixel ( hoặc có thể khác tùy các bạn ) tên là “point.png”.
auto controlPoint_1 = Sprite::create("point.png");
controlPoint_1->setColor(Color3B::RED);
controlPoint_1->setPosition(bezier.controlPoint_1);
addChild(controlPoint_1);
auto controlPoint_2 = Sprite::create("point.png");
controlPoint_2->setColor(Color3B::BLUE);
controlPoint_2->setPosition(bezier.controlPoint_2);
addChild(controlPoint_2);
auto endPosition = Sprite::create("point.png");
endPosition->setColor(Color3B::GREEN);
endPosition->setPosition(bezier.endPosition);
addChild(endPosition);
Đến đây chắc các bạn
đã nắm bắt đc vấn đề rồi đúng không ? Ok
! tiếp nào ! Bây giờ vẽ một sprite di chuyển theo đường cong thôi ! Tôi xài một
ảnh kích cở 10x10 pixel ( tên là “10x10.png”
luôn nha ) !
auto sprTest = Sprite::create("10x10.png");
sprTest->setPosition(100, 100);
sprTest->runAction(BezierTo::create(2, bezier));
addChild(sprTest);
Hình 4
Để làm được đường màu
trắng ( Hiển thị lên đường cong cho
mình dễ nhận biết ! ) . Các bạn code thêm trong hàm update void HelloWorld::update(float delta) nha ! Tôi dùng một sprite
tên là “1x1.png” để vẽ lên !
auto sprTest = (Sprite*) this->getChildByName("sprTest");
//cocos2d::log("x=%f,y=%f",
sprTest->getPositionX(), sprTest->getPositionY());
auto point = Sprite::createWithTexture(cocos2d::TextureCache::getInstance()->addImage("1x1.png"));
point->setPosition(sprTest->getPosition());
addChild(point);
Bổ sung thêm sprTest->setName("sprTest"); trên đoạn code
mô tả sprTest nha !
Bên file <HelloWorldScene.h> thêm void update(float delta) override;
Bên file <HelloWorldScene.cpp> thêm scheduleUpdate() trong bool HelloWorld::init() và thêm hàm void HelloWorld::update(float delta){ //.... }
Bên file <HelloWorldScene.h> thêm void update(float delta) override;
Bên file <HelloWorldScene.cpp> thêm scheduleUpdate() trong bool HelloWorld::init() và thêm hàm void HelloWorld::update(float delta){ //.... }
(¬‿¬) Download Source ( Link Github )
❸ BezierTo Và BezierBy
Phía trên tôi
dùng là BezierTo , có nghĩa là di chuyển mục tiêu của mình theo đường cong
Bezier đến một
điểm đích xác định !
Ví dụ : Node của mình ( sprTest ) ban đầu tại vị trí (100,100) và Action BezierTo có điểm endPosition tại vị trí (300,200) , sau khi thực hiện hành động nạy node của mình sẽ ở tại vị trí endPosition (300,200). Quá dễ hiểu :v
Ví dụ : Node của mình ( sprTest ) ban đầu tại vị trí (100,100) và Action BezierTo có điểm endPosition tại vị trí (300,200) , sau khi thực hiện hành động nạy node của mình sẽ ở tại vị trí endPosition (300,200). Quá dễ hiểu :v
Tiếp theo , BezierBy khác với BezierTo ra sao ? Nếu BezierTo là di chuyển “đến” -> thì BezierBy nó là di chuyển “thêm” !
Có nghĩa là
sao ? Có nghĩa là từ chổ nó đang đứng nó sẽ di chuyển thêm 1 đoạn !
Ví dụ : sprTest mình đang đứng
ở chổ (100,100) , controlPoint_1 (200,200) , controlPoint_2 (250,300) , endPosition (300,200) nếu thực hiện Action BezierBy thì :
controlPoint_1 + sprTest =
(200,200) + (100,100) = (300,300)
controlPoint_2 + sprTest = (250,300)
+ (100,100) = (350,400)
endPosition + sprTest = (300,200) + (100,100) = (400,300)
Và lúc này điểm mà nó di chuyển đến sẽ là (400,300) ! Sau khi thực hiện Action BezierBy !
Hình 5
//.............
controlPoint_1->setPosition(300,300);
//.............
controlPoint_2->setPosition(350,400);
//.............
endPosition->setPosition(400,300);
endPosition->setPosition(400,300);
//.............
sprTest->runAction(BezierBy::create(2, bezier));
Hình 6
❹ Ứng Dụng Thực Tế
Mô tả hiệu ứng chết của nhân vật ....
Character
ccBezierConfig config;
config.controlPoint_1 = Vec2(60, 50);
config.controlPoint_2 = Vec2(-60, 100);
config.endPosition = Vec2(60, 150);
Sprite *sprite = Sprite::create("character.png");
sprite->setPosition(Vec2(visibleSize.width/2,visibleSize.height/2));
this->addChild(sprite);
sprite->runAction(Spawn::create(BezierBy::create(1.5f, config),FadeOut::create(2.0f),NULL));
Biểu tượng Public
cocos2d-x
Biểu tượng Public
cocos2d
Biểu tượng Public
action bezier cocos2d-x