chapter8 實驗手冊
《chapter8 實驗手冊》由會員分享,可在線閱讀,更多相關(guān)《chapter8 實驗手冊(14頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1、第八章 碰撞檢測與運動模擬 基于Box2D的游戲?qū)嵗? (一)基礎(chǔ)知識 物理模擬、精靈的繪制與移動、觸摸事件的應(yīng)用 (1) 繪制游戲界面 (2) 通過單點觸摸屏幕,球桿瞄準(zhǔn)目標(biāo) (3) 設(shè)置能量條(觸屏檢測) (4) 球桿擊球 (5) 碰撞檢測(物理模擬) (二)游戲配置文件 游戲需要新建一個Config.h的頭文件,此文件用來定義游戲中需要的參數(shù)。 #include "cocos2d.h" USING_NS_CC; using namespace cocos2d; #define PTM_RATIO 32 // 定義32像素代表1米 static c
2、onst int SLIDER_BG_TAG = 1000; static const int SLIDER_TAG = 1001; static const int DASH_LINE_TAG = 1002; static const int MAIN_BILLIARDS_TAG = 1003; static const int AIM_ICON_TAG = 1004; static const int AIM_GAN_TAG = 1005; static const int MAX_SPEED = 2600; static const std::string ball
3、[5] = { "Chapter07/Ball/3.png", "Chapter07/Ball/4.png", "Chapter07/Ball/5.png", "Chapter07/Ball/6.png", "Chapter07/Ball/10.png" }; static const Vec2 ballPos[] = { Vec2(300,500), Vec2(500,300), Vec2(100,600), Vec2(600,100), Vec2(800,500) }; (三)物理場景的繪制 由PhysicsScene.h類實現(xiàn)
4、,這里具體給出其實現(xiàn),定義均在實現(xiàn)文件中實現(xiàn)了。 PhysicsScene.cpp #include "PhysicsScene.h" PhysicsScene::PhysicsScene(){} PhysicsScene::~PhysicsScene(){} bool PhysicsScene::init() { if (!Layer::init()) { return false; } // physics scene Size visibleSize = Director::getInstance()->getVisibleSize();
5、 Vec2 origin = Director::getInstance()->getVisibleOrigin(); // 定義世界的邊界 auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT,5.0f); auto edgeNode = Node::create(); edgeNode->setPosition(Vec2(visib
6、leSize.width/2,visibleSize.height/2)); edgeNode->setPhysicsBody(body); this->addChild(edgeNode); // 屏幕觸摸 auto listener = EventListenerTouchOneByOne::create(); listener->onTouchBegan = CC_CALLBA
7、CK_2(PhysicsScene::onTouchBegan, this); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this); return true; } Scene* PhysicsScene::createScene() { // 創(chuàng)建物理世界 auto scene = Scene::createWithPhysics(); // 繪制調(diào)試遮罩 // scene->getPhysicsWor
8、ld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); auto layer = PhysicsScene::create(); scene->addChild(layer); return scene; } bool PhysicsScene::onTouchBegan(Touch *touch, Event *unused_event) { Vec2 location = touch->getLocation(); addNewSpriteAtPosition(location); return fal
9、se; } void PhysicsScene::addNewSpriteAtPosition(Vec2 p) { int picpath = rand() % 11; auto sp = Sprite::create(StringUtils::format("Chapter07/Ball/%d.png",picpath)); sp->setTag(1); auto body = PhysicsBody::createCircle(sp->getContentSize().width / 2); // auto body = PhysicsBody::cre
10、ateBox(sp->getContentSize()); sp->setPhysicsBody(body); sp->setPosition(p); this->addChild(sp); } (四)物理物體的封裝,桌球的實現(xiàn) 由BilliardSprite.h類實現(xiàn),這里具體給出其實現(xiàn),定義均在實現(xiàn)文件中實現(xiàn)了。 BilliardSprite.cpp #include "BilliardSprite.h" BilliardSprite::BilliardSprite(){} void BilliardSpri
11、te::update(float t) { _sprite->setPosition(Vec2( _body->GetPosition().x * PTM_RATIO, _body->GetPosition().y * PTM_RATIO)); _sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(_body->GetAngle())); } BilliardSprite::~BilliardSprite() { if (_name != NULL) { _name = NULL; } } Bi
12、lliardSprite* BilliardSprite::create(char* name, bool isStatic, bool isBullet, b2World* world, std::string picPath, Vec2 position, float density /*= 1.0*/, float friction /*= 0.1*/, float restitution /*= 0.78 */) { BilliardSprite *pRet = new(std::nothrow) B
13、illiardSprite(); if (pRet && pRet->init(name, isStatic, isBullet, world, picPath, position, density, friction, restitution)) { pRet->autorelease(); return pRet; } else { delete pRet; pRet = NULL; return NULL; } } bool BilliardSprite::init(char* name, bool isStatic,
14、 bool isBullet, b2World* world, std::string picPath, Vec2 position, float density /*= 1.0*/, float friction /*= 0.1*/, float restitution /*= 0.78*/) { if (!Sprite::init()) { return false; } _name = name; // 創(chuàng)建精靈 _sprite = Sprite::create(picPath); th
15、is->addChild(_sprite); // bodyDef b2BodyDef bodyDef; if (!isStatic) { bodyDef.type = b2_dynamicBody; } if (isBullet) { bodyDef.bullet = true; } bodyDef.position.Set(position.x / PTM_RATIO,position.y / PTM_RATIO); // 創(chuàng)建body _body = world->CreateBody(&bodyDef); _bo
16、dy->SetUserData(this); b2CircleShape circle; circle.m_radius = (_sprite->getContentSize().width / 2 ) / PTM_RATIO; if (isStatic) { // 靜態(tài) _body->CreateFixture(&circle,0.0f); } else { // 動態(tài) b2FixtureDef fixtureDef; fixtureDef.shape = &circle; fixtureDef.density = densit
17、y; fixtureDef.friction = friction; fixtureDef.restitution = restitution; _body->CreateFixture(&fixtureDef); } this->scheduleUpdate(); return true; } (五)碰撞監(jiān)聽 由GameContactListener.h類實現(xiàn),這里具體給出其實現(xiàn),定義均在實現(xiàn)文件中實現(xiàn)了。 GameContactListener.cpp #include "GameContactListener.h" #include "B
18、illiardSprite.h"
GameContactListener::GameContactListener(){}
GameContactListener::~GameContactListener(){}
void GameContactListener::BeginContact(b2Contact*contact)
{
CCLOG("%s",static_cast
19、ic_cast
20、 void GameContactListener::PostSolve(b2Contact* contact,const b2ContactImpulse* impulse) { // handle post-solve event } void GameContactListener::deleteBody(){} (六)初始化物理世界 PhysicsBox2dScene.cpp文件中 void PhysicsBox2dScene::initPhysics() { Size s = Director::getInstance()->getVisibleS
21、ize(); _ContactListener = new GameContactListener(); // gravity b2Vec2 gravity; gravity.Set(0.0f, 0.0f); // create world _world = new b2World(gravity); _world->SetContactListener(_ContactListener); // 碰撞 // allow sleep _world->SetAllowSleeping(true); // physics test 避
22、免碰撞檢測不連續(xù)產(chǎn)生碰撞穿透 _world->SetContinuousPhysics(true); // ground b2BodyDef groundBodyDef; // left down groundBodyDef.position.Set(0, 0); // create ground b2Body* groundBody = _world->CreateBody(&groundBodyDef); groundBody->SetUserData("boundary"); // shape b2EdgeShape groundB
23、ox; // down groundBox.Set(b2Vec2(0,0),b2Vec2(s.width/PTM_RATIO,0)); groundBody->CreateFixture(&groundBox,0); // up groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO)); groundBody->CreateFixture(&groundBox,0); // left groundBox.Set(b2Vec2
24、(0,s.height/PTM_RATIO),b2Vec2(0,0)); groundBody->CreateFixture(&groundBox,0); // right groundBox.Set(b2Vec2((s.width - 60)/PTM_RATIO,s.height/PTM_RATIO),b2Vec2((s.width - 60)/PTM_RATIO,0)); groundBody->CreateFixture(&groundBox,0); } (七)初始化場景 初始化: PhysicsBox2dScene::PhysicsBox2dScene(
25、) { _world = NULL; _aim = false; _angle = 0.0f; _curPower = 0.0f; _powerEnd = false; _sliderSpeed = 0.0f; _aimPos = Vec2(-1,-1); _canAim = true; } 在PhysicsBox2dScene.cpp文件中init函數(shù)中初始化場景: 1、繪制能量條 // slider bg auto slider_bg = Sprite::create("Chapter07/slider/bg-f.png"); sli
26、der_bg->setPosition(Vec2(visibleSize.width - 30, visibleSize.height/2)); this->addChild(slider_bg, 2, SLIDER_BG_TAG); // init power slider rect _powerRect = Rect(visibleSize.width - 58, 0, 58,visibleSize.height); // slider auto slider = Sprite::create("Chapter07/slider/fg-f.png")
27、; this->addChild(slider, 3, SLIDER_TAG); slider->setVisible(false); // slider left auto slider_left = Sprite::create("Chapter07/slider/bg-left.png"); slider_left->setPosition(Vec2(visibleSize.width - 60, visibleSize.height/2)); this->addChild(slider_left, 2); 2、繪制非物理世界邊界 // slider
28、 left auto slider_left = Sprite::create("Chapter07/slider/bg-left.png"); slider_left->setPosition(Vec2(visibleSize.width - 60, visibleSize.height/2)); this->addChild(slider_left, 2); // boundary left auto boundary_left = Sprite::create("Chapter07/slider/bg-left.png"); boundary_left->se
29、tPosition(Vec2(3, visibleSize.height/2)); this->addChild(boundary_left); // boundary right auto boundary_right = Sprite::create("Chapter07/slider/bg-left.png"); boundary_right->setPosition(Vec2(visibleSize.width - 2, visibleSize.height/2)); this->addChild(boundary_right, 2); 3、初始化瞄準(zhǔn)區(qū)域
30、(物理世界大?。? // init aim rect _aimRect = Rect(0, 0, visibleSize.width - 60, visibleSize.height); 4、初始化物理世界 // init physics world this->initPhysics(); 5、初始化桌球 // 白球 _mainBilliards = BilliardSprite::create("main", false, true, _world, "Chapter07/Ball/8.png", Vec2(200,visibleSize.height/2));
31、 this->addChild(_mainBilliards, 10, MAIN_BILLIARDS_TAG); for (int i=0;i<5;i++) { auto ballSprite = BilliardSprite::create("ball",false, false, _world, ball[i], ballPos[i]); this->addChild(ballSprite); } 6、初始化添加瞄準(zhǔn)線、瞄準(zhǔn)圖片和球桿 // dash line auto dashLine = Sprite::create("Chapter07/aim/do
32、t_line.png"); this->addChild(dashLine, 2, DASH_LINE_TAG); dashLine->setAnchorPoint(Vec2(0.5, 0)); dashLine->setVisible(false); // aim icon auto aim_icon = Sprite::create("Chapter07/aim/aim.png"); this->addChild(aim_icon, 10, AIM_ICON_TAG); aim_icon->setScale(0.4f); aim_icon->setVis
33、ible(false); // 球桿 auto aim_gan = Sprite::create("Chapter07/aim/gan-f.png"); this->addChild(aim_gan, 10, AIM_GAN_TAG); aim_gan->setAnchorPoint(Vec2(0.5, 0)); aim_gan->setScale(0.6f); aim_gan->setVisible(false); (八)能量條的控制 1、能量條區(qū)域觸摸響應(yīng)事件的設(shè)置 設(shè)置觸摸開始時響應(yīng)的事件: bool PhysicsBox2dScene::on
34、TouchBegan(Touch *touch, Event *unused_event) { if (_aimRect.containsPoint(touch->getLocation()) && _canAim) { _aim = true; auto start_p = changePos(_mainBilliards->getPosition()); auto end_p = touch->getLocation(); updateLine(start_p, end_p); } _powerEnd = false; r
35、eturn true; } 設(shè)置觸摸移動時響應(yīng)的事件,分為兩種情況,一種是當(dāng)觸摸移動的區(qū)域的是非物理世界時,改變的是能量條的狀態(tài);另一種情況是當(dāng)觸摸移動的區(qū)域的是物理世界區(qū)域時,改變的是球桿瞄準(zhǔn)的方向: void PhysicsBox2dScene::onTouchMoved(Touch *touch, Event *unused_event) { auto slider_bg = (Sprite*)getChildByTag(SLIDER_BG_TAG); if (_powerRect.containsPoint(touch->getStartLocation()) &&
36、 _aim) { _curPower = touch->getStartLocation().y - touch->getLocation().y; if (_curPower<0) { _curPower = 0; } else if( _curPower > slider_bg->getContentSize().height ) { _curPower = slider_bg->getContentSize().height; } updatePowerSlider(_curPower); } else if (_
37、aimRect.containsPoint(touch->getStartLocation()) && _canAim) { if (_aimRect.containsPoint(touch->getLocation())) { auto start_p = changePos(_mainBilliards->getPosition()); auto end_p = touch->getLocation(); updateLine(start_p, end_p); } } } 設(shè)置觸摸結(jié)束時響應(yīng)的事件: void PhysicsBox
38、2dScene::onTouchEnded(Touch *touch, Event *unused_event) { if (_powerRect.containsPoint(touch->getLocation()) && _aim) { auto slider_bg = (Sprite*)getChildByTag(SLIDER_BG_TAG); _sliderSpeed = _curPower / slider_bg->getContentSize().height * 50.0f; // 擊球 auto start_p = changePos(_m
39、ainBilliards->getPosition()); auto end_p = _aimPos; auto v = changePos((end_p - start_p).getNormalized()); float q = _curPower / slider_bg->getContentSize().height; // 設(shè)置白球速度 _mainBilliards->SetLinearVelocity(b2Vec2(v.x * q * MAX_SPEED, v.y * q * MAX_SPEED)); auto dash_line = (
40、Sprite*)getChildByTag(DASH_LINE_TAG); dash_line->setVisible(false); auto aim_icon = (Sprite*)getChildByTag(AIM_ICON_TAG); aim_icon->setVisible(false); auto aim_gan = (Sprite*)getChildByTag(AIM_GAN_TAG); aim_gan->setVisible(false); // 擊球運動后,在所有物體都靜止之前無法再進(jìn)行瞄準(zhǔn)和擊球 _canAim = false;
41、 _aim = false; _powerEnd = true; // 進(jìn)度條可以消除 } } 2、為控制條添加監(jiān)聽 在PhysicsBox2dScene.cpp文件中init函數(shù)中 // add touch listener auto listener = EventListenerTouchOneByOne::create(); listener->onTouchBegan = CC_CALLBACK_2(PhysicsBox2dScene::onTouchBegan, this); listener->onTouchMoved = CC_CA
42、LLBACK_2(PhysicsBox2dScene::onTouchMoved, this); listener->onTouchEnded = CC_CALLBACK_2(PhysicsBox2dScene::onTouchEnded, this); Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this); (九)改變球桿方向 b2Vec2 PhysicsBox2dScene::changePos(Vec2 pos) { r
43、eturn b2Vec2(pos.x/PTM_RATIO, pos.y/PTM_RATIO); } cocos2d::Vec2 PhysicsBox2dScene::changePos(b2Vec2 pos) { return Vec2(pos.x*PTM_RATIO, pos.y*PTM_RATIO); } (十)更新瞄準(zhǔn)線的位置和球桿位置 void PhysicsBox2dScene::updateLine(Vec2 start_p, Vec2 end_p) { _aimPos = end_p; // update line _angle = (_
44、aimPos - start_p).getNormalized().getAngle() ; auto dashLine = (Sprite*)getChildByTag(DASH_LINE_TAG); dashLine->setPosition(start_p); dashLine->setTextureRect(Rect(0,0,2,abs((end_p - start_p).getLength()))); dashLine->setRotation(CC_RADIANS_TO_DEGREES(-_angle) + 90.0f); dashLine->setVisibl
45、e(true); // update aim icon auto aim_icon = (Sprite*)getChildByTag(AIM_ICON_TAG); aim_icon->setPosition(_aimPos); aim_icon->setVisible(true); // 計算球桿位置 auto aim_gan_pos = Vec2( (((end_p - start_p).getLength() + 45) * start_p.x - 45 * end_p.x) / (end_p - start_p).getLength(), ((
46、(end_p - start_p).getLength() + 45) * start_p.y - 45 * end_p.y) / (end_p - start_p).getLength()); auto aim_gan = (Sprite*)getChildByTag(AIM_GAN_TAG); aim_gan->setPosition(aim_gan_pos); aim_gan->setRotation(CC_RADIANS_TO_DEGREES(-_angle) - 90.0f); aim_gan->setVisible(true); } (十一)實現(xiàn)碰撞檢測
47、(物理模擬) 1、碰撞檢測(物理模擬)的實現(xiàn)函數(shù) void PhysicsBox2dScene::update(float delta) { float timeStep = 1.0f / 60.0f; // 時間同步 int32 velocityIterations = 8; // 速度迭代次數(shù) int32 positionIterations = 1; // 位置迭代次數(shù) _world->Step(timeStep,velocityIterations,positionIterations); _ContactListener->deleteBo
48、dy(); // 循環(huán)判定游戲輸贏 for (b2Body* Cur = _world->GetBodyList(); Cur; Cur = Cur->GetNext() ) { if ( Cur->GetType() == b2_dynamicBody && Cur->IsAwake() == true ) { // 模擬阻力 Cur->SetLinearVelocity(b2Vec2(Cur->GetLinearVelocity().x * 0.989, Cur->GetLinearVelocity().y * 0.989)); if( ab
49、s(Cur->GetLinearVelocity().x) < 0.5f && abs(Cur->GetLinearVelocity().y) < 0.5f ) { Cur->SetAwake(false); } } } if (_powerEnd) { // 滑塊消失 if (_curPower !=0) { _curPower -= _sliderSpeed; } else if (_curPower <= 0) { _curPower = 0.0f; } updatePowerSli
50、der(_curPower); } // 所有球靜止才可以進(jìn)行瞄準(zhǔn) int awak = 0; for (b2Body* Cur = _world->GetBodyList(); Cur; Cur = Cur->GetNext() ) { if ( Cur->GetType() == b2_dynamicBody && Cur->IsAwake() == true ) { awak ++; } } if (awak == 0) { _canAim = true; } } 2、在PhysicsBox2dScene.cpp文件中init函數(shù)中添加定時刷新函數(shù),實現(xiàn)物理模擬,碰撞檢測 // main loop this->scheduleUpdate(); (十二)游戲運行效果如圖。
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。