coco2d-x3.2使用物理引擎Physicals制作Breakout游戏

HelloWorldScene.h

 1 #ifndef __HELLOWORLD_SCENE_H__
 2 #define __HELLOWORLD_SCENE_H__
 3 
 4 #include "cocos2d.h"
 5 #include "GameOverScene.h"
 6 
 7 USING_NS_CC;
 8 
 9 class HelloWorld : public cocos2d::Layer
10 {
11 public:
12     static cocos2d::Scene* createScene();
13     virtual void onEnter() override;
14     virtual bool init();  
15     
16     CREATE_FUNC(HelloWorld);
17     
18     Sprite* ball;//弹射的球
19     Sprite* paddle;//玩家控制的可移动碰撞块
20     Sprite* edgeSp;//碰撞盒子
21     
22     PhysicsWorld* m_world;
23     
24     void setPhyWorld(PhysicsWorld* world){ m_world = world; };
25     void tick(float dt);
26     
27     bool onTouchBegan(Touch* touch, Event* event);
28     void onTouchMoved(Touch* touch, Event* event);
29     void onTouchEnded(Touch* touch, Event* event);
30     
31     bool onContactBegin(const PhysicsContact& contact);
32     
33 };
34 
35 #endif

HelloWorldScene.cpp

  1 #include "HelloWorldScene.h"
  2 
  3 USING_NS_CC;
  4 
  5 Scene* HelloWorld::createScene()
  6 {
  7     auto scene = Scene::createWithPhysics();
  8     //设置Debug模式,你会看到物体的表面被线条包围,主要为了在调试中更容易地观察
  9     scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
 10     
 11     Vect gravity(0.0f, 0.0f);
 12     //设置重力
 13     scene->getPhysicsWorld()->setGravity(gravity);
 14     
 15     auto layer = HelloWorld::create();
 16     
 17     layer->setPhyWorld(scene->getPhysicsWorld());
 18     
 19     scene->addChild(layer);
 20     
 21     return scene;
 22     
 23 }
 24 
 25 /**
 26 PHYSICSBODY_MATERIAL_DEFAULT常量是默认材质,材质是由结构体PhysicsMaterial定义的,结构体PhysicsMaterial成员有:density(密度)、friction(磨擦系数)和restitution(弹性系数)。
 27 密度可以用来计算物体的质量,密度可以为零或者为正数。
 28 摩擦系数经常会设置在0.0~1.0之间,0.0表示没有摩擦力,1.0会产生强摩擦。
 29 弹性系数的值通常设置到0.0~1.0之间,0.0表示物体不会弹起,1.0表示物体会完全反弹,即称为弹性碰撞。
 30  **/
 31 bool HelloWorld::init()
 32 {
 33     if ( !Layer::init() )
 34     {
 35         return false;
 36     }
 37     
 38     auto visibleSize = Director::getInstance()->getVisibleSize();
 39     auto origin = Director::getInstance()->getVisibleOrigin();
 40     
 41     edgeSp = Sprite::create();
 42     //创建一个盒子,用来碰撞
 43     //矩形的大小、设置材质、设置边的宽度
 44     auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
 45     //设置物体的弹性 0表示完全不反弹。1完全反弹
 46     boundBody->getShape(0)->setRestitution(1.0f);
 47     //设置摩擦力
 48     boundBody->getShape(0)->setFriction(0.0f);
 49     //设置密度
 50     boundBody->getShape(0)->setDensity(1.0f);
 51     edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
 52     edgeSp->setPhysicsBody(boundBody);
 53     this->addChild(edgeSp);
 54     edgeSp->setTag(0);
 55     
 56     //CategoryBitmask, 默认值为 0xFFFFFFFF
 57     //ContactTestBitmask, 默认值为 0x00000000
 58     //CollisionBitmask, 默认值为 0xFFFFFFFF
 59     //如果采用默认的数值,碰撞是可以检测的,但是碰撞事件是不会发出的,so我们的onContactBegin就被屏蔽了
 60     //果想我们的两个物体即发生碰撞又可以检测到,不让它们&的值不等于0就ok了
 61     edgeSp->getPhysicsBody()->setCategoryBitmask(0x01);
 62     edgeSp->getPhysicsBody()->setContactTestBitmask(0x01);
 63     edgeSp->getPhysicsBody()->setCollisionBitmask(0x01);
 64     
 65     ball = Sprite::create("Ball.png", Rect(0, 0, 52, 52));
 66     ball->setPosition(100, 100);
 67     //创建物体,并且物体的形状为圆形,第一参数为半径,第二个参数为物体材质
 68     //第三个参数为边的厚度,就是在Debug模式下看到的物体外面线条的厚度,默认为0
 69     auto ballBody = PhysicsBody::createCircle(ball->getContentSize().width / 2.);
 70     ballBody->getShape(0)->setRestitution(1.0f);
 71     ballBody->getShape(0)->setFriction(0.0f);
 72     ballBody->getShape(0)->setDensity(1.0f);
 73     ballBody->setGravityEnable(false);
 74     Vect force = Vect(1000000.0f, 1000000.0f);
 75     //是对物体施加一个冲量
 76     ballBody->applyImpulse(force);
 77     ball->setPhysicsBody(ballBody);
 78     ball->setTag(1);
 79     this->addChild(ball);
 80     
 81     ball->getPhysicsBody()->setCategoryBitmask(0x01);
 82     ball->getPhysicsBody()->setContactTestBitmask(0x01);
 83     ball->getPhysicsBody()->setCollisionBitmask(0x01);
 84     
 85     paddle = Sprite::create("Paddle.png");
 86     //创建物体,并且物体的形状为矩形
 87     auto paddleBody = PhysicsBody::createBox(paddle->getContentSize(), PHYSICSBODY_MATERIAL_DEFAULT);
 88     paddleBody->getShape(0)->setRestitution(1.0f);
 89     paddleBody->getShape(0)->setFriction(0.0f);
 90     paddleBody->getShape(0)->setDensity(10.0f);
 91     paddleBody->setGravityEnable(false);
 92     paddleBody->setDynamic(false);
 93     paddle->setPosition(visibleSize.width / 2, 50);
 94     paddle->setPhysicsBody(paddleBody);
 95     paddle->setTag(2);
 96     this->addChild(paddle);
 97     
 98     for (int i = 0; i < 4; i++) {
 99         
100         static int padding = 100;
101         
102         // 创建方块并添加到层中
103         auto block = Sprite::create("blocks.png");
104         auto blockBody = PhysicsBody::createBox(block->getContentSize(), PHYSICSBODY_MATERIAL_DEFAULT);
105         blockBody->getShape(0)->setDensity(10.0f);
106         blockBody->getShape(0)->setFriction(0.0f);
107         blockBody->getShape(0)->setRestitution(1.f);
108         blockBody->setDynamic(false);
109         int xOffset = padding + block->getContentSize().width / 2 +
110         ((block->getContentSize().width + padding)*i);
111         block->setPosition(xOffset, 450);
112         block->setPhysicsBody(blockBody);
113         block->setTag(3);
114         this->addChild(block);
115         
116         block->getPhysicsBody()->setCategoryBitmask(0x01);
117         block->getPhysicsBody()->setContactTestBitmask(0x01);
118         block->getPhysicsBody()->setCollisionBitmask(0x01);
119     }
120     
121     this->schedule(schedule_selector(HelloWorld::tick),0);
122     
123     return true;
124 }
125 
126 void HelloWorld::onTouchMoved(Touch* touch, Event* event)
127 {
128     Point touchLocation = this->convertToWorldSpace(this->convertTouchToNodeSpace(touch));
129     paddle->setPositionX(touchLocation.x);
130 }
131 
132 bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
133 {
134     return true;
135 }
136 
137 void HelloWorld::onTouchEnded(Touch* touch, Event* event)
138 {
139     
140 }
141 
142 bool HelloWorld::onContactBegin(const PhysicsContact& contact)
143 {
144     if (ball->getPositionY() <= 50)
145     {
146         auto gameOverScene = GameOverScene::create();
147         gameOverScene->getLayer()->getLabel()->setString("You Lose!");
148         Director::getInstance()->replaceScene(gameOverScene);
149     }
150     
151     auto spriteA = (Sprite*)contact.getShapeA()->getBody()->getNode();
152     auto spriteB = (Sprite*)contact.getShapeB()->getBody()->getNode();
153     int tagA = spriteA->getTag();
154     int tagB = spriteB->getTag();
155     
156     if (tagA == 3)
157     {
158         spriteA->removeFromParentAndCleanup(true);
159     }
160     
161     if (tagB == 3)
162     {
163         spriteB->removeFromParentAndCleanup(true);
164     }
165     
166     return true;
167 }
168 
169 void HelloWorld::tick(float dt)
170 {
171     bool isWin = true;
172     Vector<PhysicsBody*> bodies = m_world->getAllBodies();
173     Vector<PhysicsBody*>::iterator iter;
174     for (iter=bodies.begin();iter!=bodies.end();iter++) {
175         if ((*iter)->getNode()->getTag() == 3)
176         {
177             isWin = false;
178         }
179     }
180     
181     if (isWin == true)
182     {
183         auto gameOverScene = GameOverScene::create();
184         gameOverScene->getLayer()->getLabel()->setString("You Win!");
185         Director::getInstance()->replaceScene(gameOverScene);
186     }
187 }
188 
189 void HelloWorld::onEnter()
190 {
191     Layer::onEnter();
192     
193     auto touchListener = EventListenerTouchOneByOne::create();
194     touchListener->setSwallowTouches(true);
195     
196     touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
197     touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
198     touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
199     _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
200     
201     //添加监听器
202     auto contactListener = EventListenerPhysicsContact::create();
203     //设置监听器的碰撞开始函数
204     contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
205     
206     //添加到事件分发器中
207     _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
208     
209 }

GameOverScene.h

 1 #ifndef __SampleGame1__GameOverScene__
 2 #define __SampleGame1__GameOverScene__
 3 
 4 #include "cocos2d.h"
 5 
 6 class GameOverLayer : public cocos2d::LayerColor
 7 {
 8 public:
 9     GameOverLayer():_label(NULL) {};
10     virtual ~GameOverLayer();
11     bool init();
12     CREATE_FUNC(GameOverLayer);
13     
14     void gameOverDone();
15     
16     CC_SYNTHESIZE_READONLY(cocos2d::LabelTTF*, _label, Label);
17 };
18 
19 class GameOverScene : public cocos2d::Scene
20 {
21 public:
22     GameOverScene():_layer(NULL) {};
23     ~GameOverScene();
24     bool init();
25     CREATE_FUNC(GameOverScene);
26     
27     CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);
28 };
29 
30 #endif

GameOverScene.cpp

 1 #include "GameOverScene.h"
 2 #include "HelloWorldScene.h"
 3 USING_NS_CC;
 4 
 5 
 6 bool GameOverScene::init()
 7 {
 8     if( Scene::init() )
 9     {
10         this->_layer = GameOverLayer::create();
11         this->_layer->retain();
12         this->addChild(_layer);
13         
14         return true;
15     }
16     else
17     {
18         return false;
19     }
20 }
21 
22 GameOverScene::~GameOverScene()
23 {
24     if (_layer)
25     {
26         _layer->release();
27         _layer = NULL;
28     }
29 }
30 
31 bool GameOverLayer::init()
32 {
33     if ( LayerColor::initWithColor( Color4B(255,255,255,255) ) )
34     {
35         auto winSize = Director::getInstance()->getWinSize();
36         this->_label = LabelTTF::create("","Artial", 32);
37         _label->retain();
38         _label->setColor( Color3B(0, 0, 0) );
39         _label->setPosition( Point(winSize.width/2, winSize.height/2) );
40         this->addChild(_label);
41         
42         this->runAction( Sequence::create(
43                                           DelayTime::create(3),
44                                           CallFunc::create(CC_CALLBACK_0(GameOverLayer::gameOverDone, this)),
45                                           NULL));
46         
47         return true;
48     }
49     else
50     {
51         return false;
52     }
53 }
54 
55 void GameOverLayer::gameOverDone()
56 {
57     Director::getInstance()->replaceScene( HelloWorld::createScene() );
58 }
59 
60 GameOverLayer::~GameOverLayer()
61 {
62     if (_label)
63     {
64         _label->release();
65         _label = NULL;
66     }
67 }

游戏中图片:

游戏运行效果:

posted @ 2015-01-25 18:51  小翔momo  阅读(590)  评论(0编辑  收藏  举报