In previous part, we studied about Box2D, and build a small app using physics Box2D. In this lesson, we come to advanced a bit, control the ball, make it collide with the screen với màn hình as follow:
+ Make the ball move by vector + force
+ Predict the direction the ball moves
Step 1 - Make the ball move by vector + force
* Open file HelloWorldScene.h, in Public area, add the following code block:
// You can see the meanings of variables in the below block
bool existBall;
float ballX;
float ballY;
int dragOffsetStartX;
int dragOffsetEndX;
int dragOffsetStartY;
int dragOffsetEndY;
float powerMultiplier; // Force
Sprite *points[32];
void defineBall(); // Create the ball follow Box2D
+ Make the ball move by vector + force
+ Predict the direction the ball moves
Step 1 - Make the ball move by vector + force
* Open file HelloWorldScene.h, in Public area, add the following code block:
// You can see the meanings of variables in the below block
bool existBall;
float ballX;
float ballY;
int dragOffsetStartX;
int dragOffsetEndX;
int dragOffsetStartY;
int dragOffsetEndY;
float powerMultiplier; // Force
Sprite *points[32];
void defineBall(); // Create the ball follow Box2D
void simulateTrajectory(b2Vec2 coord);
// Catch the touch events
bool onTouchBegan(Touch* touch, Event* event);
void onTouchMoved(Touch* touch, Event* event);
void onTouchEnded(Touch* touch, Event* event);
* Open file HelloWorldScene.cpp, Delete all old code but these:
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
// Delete all here
return true;
+ Add the following code block into the deleted place:
b2Vec2 gravity = b2Vec2(0.0f, -10.0f); // Vector of acceleration
world = new b2World(gravity); // Create world
// Create the ball, save the coordinate of the beginning point and end point
dragOffsetStartX = 0;
dragOffsetEndX = 0;
dragOffsetStartY = 0;
dragOffsetEndY = 0;
existBall= false;
ballX = 500;
ballY = 200;
powerMultiplier = 10; // The value of force is 10
ball =Sprite::create("ball.png");
ball->setPosition(Point(ballX,ballY));
this->addChild(ball);
// Build the frame around three sides of the screen
addWall(visibleSize.width ,10,(visibleSize.width / 2) ,0);// Floor
addWall(10 ,visibleSize.height ,0,(visibleSize.height / 2) ); // Left
addWall(10 ,visibleSize.height ,visibleSize.width,(visibleSize.height / 2) ); // Right
// Catch the touch event
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
scheduleUpdate(); // Update Scene by Time
+ Build the function addWall as follow, like the previous part, is also building physics body by Box2D
void HelloWorld::addWall(float w,float h,float px,float py) {
b2PolygonShape floorShape; // the floor shape
floorShape.SetAsBox(w/ SCALE_RATIO,h/ SCALE_RATIO); // square, or rectangle
b2FixtureDef floorFixture;
floorFixture.density=0;
floorFixture.friction=10;
floorFixture.restitution=0.5;
floorFixture.shape=&floorShape;
b2BodyDef floorBodyDef;
floorBodyDef.position.Set(px/ SCALE_RATIO,py/ SCALE_RATIO);
b2Body *floorBody = world->CreateBody(&floorBodyDef);
floorBody->CreateFixture(&floorFixture);
}
+ The function defineBall(), declare again to create physics body for the ball of previous part and convert it as private function
void HelloWorld::defineBall(){
bodyShape.m_radius = 45 / SCALE_RATIO;
fixtureDef.density=10;
fixtureDef.friction=0.8;
fixtureDef.restitution=0.6;
fixtureDef.shape=&bodyShape;
bodyDef.type= b2_dynamicBody;
bodyDef.userData=ball;
bodyDef.position.Set(ball->getPosition().x/SCALE_RATIO,ball->getPosition().y/SCALE_RATIO);
ballBody = world->CreateBody(&bodyDef);
ballBody->CreateFixture(&fixtureDef);
ballBody->SetGravityScale(10);
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
// Save the coordinate of first touch point
dragOffsetStartX = touch->getLocation().x;
dragOffsetStartY = touch->getLocation().y;
Point touchLocation = touch->getLocation(); // Get the coordinate of touch point
// Save
ballX = touchLocation.x;
ballY = touchLocation.y;
// Check if the touch point doesn't have the ball, delete body of the ball created in defineBall() function
if (existBall){
world->DestroyBody(ballBody);
}
ball->setPosition(Point(ballX ,ballY)); // Set new position ballX ,ballY
return true;
}
+ The function onTouchEnded
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
existBall = true;
HelloWorld::defineBall(); // Create body of the ball at the last touch point
Point touchLocation = touch->getLocation(); // Get the touch point
// Save the last touch point
dragOffsetEndX = touchLocation.x;
dragOffsetEndY = touchLocation.y;
// The distance of moving the ball
float dragDistanceX = dragOffsetStartX - dragOffsetEndX;
float dragDistanceY = dragOffsetStartY - dragOffsetEndY;
// Create the movement of body with an unchanging velocity with direction and the size = vector with the last point, the first point, multiply with a force = 10 = powerMultiplier
ballBody->SetLinearVelocity(b2Vec2((dragDistanceX*powerMultiplier)/SCALE_RATIO,(dragDistanceY*powerMultiplier)/SCALE_RATIO));
}
+ The function onTouchMoved
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
}
Build and run. Pull the ball and release, you will see that the ball shoot out and collide with the wall of the screen.
Step 2 - Predict the direction of the movement of the ball
You need to build two functions as follow:
+ onTouchMoved
void HelloWorld::onTouchMoved(Touch* touch, Event* event)
{
Point touchLocation = touch->getLocation();
// Save the last point
dragOffsetEndX = touchLocation.x;
dragOffsetEndY = touchLocation.y;
// The distance of the movement of the ball
float dragDistanceX = dragOffsetStartX - dragOffsetEndX;
float dragDistanceY = dragOffsetStartY - dragOffsetEndY;
// Call the function to simulate the path of the ball, vector multiply with a force = 10 = powerMultiplier HelloWorld::simulateTrajectory(b2Vec2((dragDistanceX * powerMultiplier)/SCALE_RATIO,(dragDistanceY * powerMultiplier)/SCALE_RATIO));
}
+ simulateTrajectory
void HelloWorld::simulateTrajectory(b2Vec2 coord){
//Định nghĩa physics body bóng HelloWorld::defineBall();
// Tạo chuyển động cho body với 1 vận tốc không đổi có phương và độ lớn = vector truyền vào
ballBody->SetLinearVelocity(b2Vec2(coord.x,coord.y));
// Duyệt mảng point for (int i = 1; i <= 31; i++){
//Trong hàm Step, Giá trị đối số phải bằng gia tốc 10 và powerMultiplier (=10) world->Step(deltaTime,10,10);
points[i]->setPosition(Point(ballBody->GetPosition().x*SCALE_RATIO,ballBody->GetPosition().y*SCALE_RATIO));
world->ClearForces();
}
world->DestroyBody(ballBody);
}
+ In init() function, add a code block
// Initialize a Sprite array including 31 points, to demon the path of the movement of the ball
for (int i = 1 ; i <= 31; i++){
points[i] =Sprite::create("dot.png");
this->addChild(points[i]);
}
Build and run. When you drag the ball, you will see the dot path to show the direction of its movement. When you release, the ball fly right the direction, it means you're successful
Done for this lesson. Conclusion, in this lesson, you know how to:
+ Create the force for an object moving
+ Show the path of its movement in world
Expand this lesson, you can create the billiard game.
P/S: You can see that in Box2D, sprite is depended to Body, setting and moving body first, then display sprite follow the position of body. In Chipmunk is contrary, setting position Sprite first, then place body after. You can reference the previous lessons of Physics.
Source Link: http://laptrinhgamecocos2dx.blogspot.com/2014/05/bai-16-box2d-mot-thu-vien-vat-ly-khac-cua-cocos2d-x.html
[ttaiit.blogspot.com translated]
0 comments:
Post a Comment