笔记:利用 Cocos2dx 3.2 与 Box2D制作一个跑酷游戏(上)

最近写lua写得没有力气了,所以想让脑袋放松一下,刚好看到有人在用swift做游戏:

Swift游戏实战-跑酷熊猫 

于是脑子一短路,就想到了利用这些素材来做一个游戏。

本来不想记笔记的,但是由于选择物理引擎的时候遇到诸多问题,所以选择记录下来,目前只做了个雏形,需要再完善一点。

需要知识:

1 cocos2dx-3.2 基本知识

2 box2d有一定的了解。

由于比较简单,所以把所有代码给上了先,然后再简单介绍下遇到的问题之类的东西。

首先是主角,熊猫类:

Panda.h
 1 #ifndef __PANDA_H__
 2 #define __PANDA_H__
 3 
 4 #include "cocos2d.h"
 5 USING_NS_CC;
 6 
 7 class Panda : public cocos2d::Node
 8 {
 9 public:
10     Vector<SpriteFrame*> run_frames;
11     Vector<SpriteFrame*> jump_effect_frames;
12     Vector<SpriteFrame*> roll_frames;
13     Vector<SpriteFrame*> jump_frames;
14     Animation * run_anim;
15     Animation * jump_anim;
16     Animation * jump_effect_anim;
17     Animation * roll_anim;
18     Sprite * shape;
19     Animation * anim;
20     int cur_state;//current state
21     // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
22     virtual bool init();  
23     //play status RUM||ROLL||JUMP etc
24     void play(unsigned int state);
25 
26     void updateState();
27     // implement the "static create()" method manually
28     CREATE_FUNC(Panda);
29 
30     int getCurrentState();
31     //panda 4 states
32     enum {
33         RUN = 1,
34         JUMP = 2,
35         JUMP2 = 3
36     };
37 };
38 
39 #endif // __PANDA_H__

 1 #include "Panda.h"
 2 #include "cocos2d.h"
 3 
 4 USING_NS_CC;
 5 
 6 bool Panda::init()
 7 {
 8     if(!Node::init())
 9         return false;
10     
11     run_frames = Vector<SpriteFrame*>(8);
12     roll_frames = Vector<SpriteFrame*>(8);
13     jump_effect_frames = Vector<SpriteFrame*>(4);
14     jump_frames = Vector<SpriteFrame*>(8);
15     char str[40] = {0};
16     for(int i=1; i<=8;i++)
17     {
18         sprintf(str,"jump.atlas/panda_jump_0%d.png",i);
19         auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(str);
20         if( frame != NULL )
21         {
22             jump_frames.pushBack(frame);
23         }
24 
25         sprintf(str,"roll.atlas/panda_roll_0%d.png",i);
26         auto frame_0 = SpriteFrameCache::getInstance()->getSpriteFrameByName(str);
27         if( frame_0 != NULL )
28         {
29             roll_frames.pushBack(frame_0);
30         }
31 
32         sprintf(str,"run.atlas/panda_run_0%d.png",i);
33         auto frame_1 = SpriteFrameCache::getInstance()->getSpriteFrameByName(str);
34         if( frame_1 != NULL )
35         {
36             run_frames.pushBack(frame_1);
37         }
38 
39         sprintf(str,"jump_effect.atlas/jump_effect_0%d.png",i);
40         auto frame_2 = SpriteFrameCache::getInstance()->getSpriteFrameByName(str);
41         if( frame_2 != NULL )
42         {
43             jump_effect_frames.pushBack(frame_2);
44         }
45     }
46 
47     run_anim = Animation::createWithSpriteFrames(run_frames,0.05f);
48     run_anim->retain();
49     roll_anim = Animation::createWithSpriteFrames(roll_frames,0.05f);
50     roll_anim->retain();
51     jump_anim = Animation::createWithSpriteFrames(jump_frames,0.05f);
52     jump_anim->retain();
53     jump_effect_anim = Animation::createWithSpriteFrames(jump_effect_frames,0.05f);
54     jump_effect_anim->retain();
55     shape= Sprite::createWithSpriteFrameName("run.atlas/panda_run_01.png");
56     addChild(shape);
57     return true;
58 }
59 
60 void Panda::play(unsigned int state)
61 {
62     Action * animate;
63     switch(state)
64     {
65     case RUN:
66         cur_state = Panda::RUN;
67         animate = RepeatForever::create(Animate::create(run_anim));
68         animate->setTag(100);
69         shape->runAction(animate);
70         break;
71     case JUMP:
72         cur_state = Panda::JUMP;
73         animate = Animate::create(jump_anim);
74         animate->setTag(200);
75         shape->stopActionByTag(100);
76         shape->runAction(animate);
77         break;
78     case JUMP2:
79         animate = Sequence::create(Animate::create(jump_effect_anim),Animate::create(roll_anim));
80         animate->setTag(300);
81         cur_state = Panda::JUMP2;
82         shape->runAction(animate);
83         break;
84     }
85 }
86 
87 int Panda::getCurrentState()
88 {
89     return cur_state;
90 }
91 
92 void Panda::updateState()
93 {
94     if (shape->getActionByTag(200) == nullptr && shape->getActionByTag(300) == nullptr)
95     {
96         play(Panda::RUN);
97     }
98 }
Panda.cpp

然后是场景类,里面有一些逻辑处理:

 1 #ifndef __GAMEMAIN_H__
 2 #define __GAMEMAIN_H__
 3 
 4 #include "cocos2d.h"
 5 #include "Panda.h"
 6 #include "Box2DBox2D.h"
 7 #include "GLES-Render.h"
 8 
 9 USING_NS_CC;
10 //whether show assets
11 #define SHOW_DEBUG true
12 //draw scale of physics world
13 #define DRAW_SCALE 30.0f
14 #define ALL_ALHA 0.5f
15 
16 class GameMain : public cocos2d::Layer
17 {
18 public:
19     //physic engine related
20     b2World * world;
21     Map<b2Body,Sprite> * map;
22     b2Body * panda_body;
23     //objects move speed
24     float speed;
25     Sprite * far_bg;
26     Sprite * middle_bg_0;
27     Sprite * middle_bg_1;
28     Size cSize;
29     Size visibleSize;
30     Layer * platform_container;
31     Panda * panda;
32     GLESDebugDraw * debugDraw;
33     // there's no 'id' in cpp, so we recommend returning the class instance pointer
34     static cocos2d::Scene* createScene();
35 
36     // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
37     virtual bool init();  
38 
39     virtual void onEnter();
40     
41     virtual void onExit();
42 
43     void update(float dt);
44 
45     virtual bool onTouchBegan(Touch * touch, Event * event);
46     virtual void onTouchEnded(Touch * touch, Event * event);
47     virtual void onTouchMoved(Touch * touch, Event * event);
48 
49     virtual bool onContactBegin(const PhysicsContact& contact);
50     // implement the "static create()" method manually
51     CREATE_FUNC(GameMain);
52 
53      //
54     // Overrides
55     //
56     virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;
57 private:
58     void create_ground();
59     void gen_step(const std::string& res, float posX, float posY);
60     void init_physics_world();
61 };
62 
63 #endif // __HELLOWORLD_SCENE_H__
GameMain.h
  1 #include "GameMain.h"
  2 #include "cocos2d.h"
  3 #include "Box2DBox2D.h"
  4 #include "GLES-Render.h"
  5 USING_NS_CC;
  6 
  7 Scene* GameMain::createScene()
  8 {
  9     auto scene = Scene::create();
 10     auto layer = GameMain::create();
 11     scene->addChild(layer);
 12     return scene;
 13 }
 14 
 15 
 16 bool GameMain::init()
 17 {
 18     if ( !Layer::init() )
 19     {
 20         return false;
 21     }
 22     speed = 5.0f;
 23     auto listener = EventListenerTouchOneByOne::create();
 24     listener->onTouchBegan = CC_CALLBACK_2(GameMain::onTouchBegan,this);
 25     listener->onTouchEnded = CC_CALLBACK_2(GameMain::onTouchEnded,this);
 26     listener->onTouchMoved = CC_CALLBACK_2(GameMain::onTouchMoved,this);
 27 
 28     Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
 29 
 30     visibleSize = Director::getInstance()->getVisibleSize();
 31     Vec2 origin = Director::getInstance()->getVisibleOrigin();
 32     SpriteFrameCache::getInstance()->addSpriteFramesWithFile("panda.plist");//add panda animate
 33     SpriteFrameCache::getInstance()->addSpriteFramesWithFile("scene.plist");//add scene resources
 34 
 35     middle_bg_0 = Sprite::create("bbg_snow_bone.jpg");
 36     cSize = middle_bg_0->getContentSize();
 37     middle_bg_0->setPosition(visibleSize.width*0.5, visibleSize.height*0.5);
 38     middle_bg_0->setVisible(SHOW_DEBUG);
 39     addChild(middle_bg_0);
 40 
 41     init_physics_world();
 42 
 43     //gen_step();
 44     create_ground();
 45 
 46     //init panda and its physics data
 47     Point p(visibleSize.width/2,visibleSize.height/2);
 48     b2BodyDef bodyDef;
 49     bodyDef.type = b2_dynamicBody;
 50     bodyDef.position.Set(p.x/DRAW_SCALE, p.y/DRAW_SCALE);
 51     panda_body = world->CreateBody(&bodyDef);
 52     b2MassData massdata;
 53     massdata.mass = 100.0f;
 54     panda_body->SetMassData(&massdata);
 55 
 56     b2PolygonShape shape;
 57     shape.SetAsBox(50.0f/DRAW_SCALE, 100.0f/DRAW_SCALE);
 58 
 59     b2FixtureDef fixtureDef;
 60     fixtureDef.shape = &shape;
 61     fixtureDef.density = 1.0f;
 62     fixtureDef.friction = 0.3f;
 63     panda_body->CreateFixture(&fixtureDef);
 64 
 65     panda = Panda::create();
 66     panda->setPosition(visibleSize.width/2, visibleSize.height/2);
 67     Size panda_size = Size(50.0f,100.0f);
 68     panda->play(Panda::RUN);
 69     this->addChild(panda);
 70     panda_body->SetUserData(panda);
 71     panda->setVisible(SHOW_DEBUG);
 72     
 73     gen_step("platform_l.png",51.0,100.0f);
 74     gen_step("platform_m.png",196.0f,100.0f);
 75     gen_step("platform_r.png",392.0f,100.0f);
 76     return true;
 77 }
 78 
 79 void GameMain::init_physics_world()
 80 {
 81     b2Vec2 gravity;
 82     gravity.Set(0.0f,-10.0f);
 83     world = new b2World(gravity);
 84     world->SetAllowSleeping(true);
 85     world->SetContinuousPhysics(true);
 86     debugDraw = new GLESDebugDraw(DRAW_SCALE);
 87     uint32 flags = 0;
 88     flags += GLESDebugDraw::e_shapeBit;
 89     flags += GLESDebugDraw::e_aabbBit;
 90     flags += GLESDebugDraw::e_centerOfMassBit;
 91     debugDraw->SetFlags(flags);
 92     world->SetDebugDraw(debugDraw);
 93 }
 94 
 95 void GameMain::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
 96 {
 97     world->DrawDebugData();
 98     Layer::draw(renderer,transform,flags);
 99 }
100 
101 void GameMain::create_ground()
102 {
103     b2BodyDef ground_def;
104     ground_def.position.Set(visibleSize.width/2/DRAW_SCALE, visibleSize.height/2/DRAW_SCALE);
105 
106     b2Body * ground_body = world->CreateBody(&ground_def);
107 
108     /***/
109     //bottom
110     b2PolygonShape ground_shape;
111     ground_shape.SetAsBox(visibleSize.width/2/DRAW_SCALE,0,b2Vec2(0,-visibleSize.height/2/DRAW_SCALE),0);
112     ground_body->CreateFixture(&ground_shape,0);
113     //top
114     ground_shape.SetAsBox(visibleSize.width/2/DRAW_SCALE,0,b2Vec2(0,visibleSize.height/2/DRAW_SCALE),0);
115     ground_body->CreateFixture(&ground_shape,0);
116     //left
117     ground_shape.SetAsBox(0,visibleSize.height/2/DRAW_SCALE,b2Vec2(-visibleSize.width/2/DRAW_SCALE,0),0);
118     ground_body->CreateFixture(&ground_shape,0);
119     //right 
120     ground_shape.SetAsBox(0,visibleSize.height/2/DRAW_SCALE,b2Vec2(visibleSize.width/2/DRAW_SCALE,0),0);
121     ground_body->CreateFixture(&ground_shape,0);
122 }
123 
124 bool GameMain::onTouchBegan(Touch * touch, Event * event)
125 {
126     Sprite * ball = Sprite::create("apple.png");
127     ball->setVisible(SHOW_DEBUG);
128     Size contentSize = ball->getContentSize();
129     addChild(ball);
130     b2BodyDef ballDef;
131     ballDef.type = b2_dynamicBody;
132     ballDef.position.Set(touch->getLocation().x/DRAW_SCALE, touch->getLocation().y/DRAW_SCALE);
133     b2Body * ballBody = world->CreateBody(&ballDef);
134     ballBody->SetUserData(ball);
135     b2MassData massData;
136     massData.center = b2Vec2(contentSize.width/2/DRAW_SCALE,contentSize.height/2/DRAW_SCALE);
137     massData.mass = 50;
138     b2CircleShape ballShape;
139     ballShape.ComputeMass(&massData,1.5f);
140     ballShape.m_radius=45.0f/DRAW_SCALE;
141     b2FixtureDef ballFixture;
142     ballFixture.density = 10.0f;
143     ballFixture.friction = 1.0f;
144     ballFixture.restitution = 0.6f;
145     ballFixture.shape = &ballShape;
146 
147     ballBody->CreateFixture(&ballFixture);
148     ballBody->SetGravityScale(10);
149     /**
150     float vx = touch->getLocation().x > panda->getPositionX() ? 100.0f : -100.0f;
151     panda->updateState();
152     int cur_state = panda->getCurrentState();
153     if( cur_state == Panda::RUN )
154     {
155         panda_body->ApplyForce(b2Vec2(vx,1000),panda_body->GetPosition(),true);
156         panda->play(Panda::JUMP);
157     }else if(cur_state == Panda::JUMP)
158     {
159         panda_body->ApplyForce(b2Vec2(vx,800),panda_body->GetPosition(),true);
160         panda->play(Panda::JUMP2);
161     }*/
162     return true;
163 }
164 
165 void GameMain::update(float dt)
166 {
167     world->Step(dt,10,10);
168     b2Body* b = world->GetBodyList();
169     while (b)
170     {
171         b2Body* bNext = b->GetNext();
172         Sprite * sp = (Sprite *)b->GetUserData();
173         if( sp != nullptr )
174             sp->setPosition(b->GetPosition().x*DRAW_SCALE,b->GetPosition().y*DRAW_SCALE);
175 
176         b = bNext;
177     }
178 }
179 
180 //generate floors
181 void GameMain::gen_step(const std::string& res, float posX, float posY)
182 {
183     Sprite * sp = Sprite::create(res);
184     sp->setPosition(posX, posY);
185     addChild(sp);
186 
187     Size contentSize = sp->getContentSize();
188 
189     b2BodyDef bodyDef;
190     bodyDef.position.Set(posX/DRAW_SCALE, posY/DRAW_SCALE);
191     b2Body * body = world->CreateBody(&bodyDef);
192 
193     b2PolygonShape shape;
194     shape.SetAsBox(contentSize.width/DRAW_SCALE, contentSize.height/DRAW_SCALE);
195 
196     b2FixtureDef fixtureDef;
197     fixtureDef.shape = &shape;
198     fixtureDef.density = 1.0f;
199     fixtureDef.friction = 0.3f;
200     body->CreateFixture(&fixtureDef);
201     sp->setVisible(SHOW_DEBUG);
202 }
203 
204 bool GameMain::onContactBegin(const PhysicsContact& contact)
205 {
206     log("Contacted...");
207     return true;
208 }
209 
210 void GameMain::onTouchEnded(Touch * touch, Event * event)
211 {
212 
213 }
214 
215 void GameMain::onTouchMoved(Touch * touch, Event * event)
216 {
217 
218 }
219 
220 void GameMain::onEnter()
221 {
222     Layer::onEnter();
223     this->schedule(schedule_selector(GameMain::update),0.03f);
224 }
225 
226 void GameMain::onExit()
227 {
228     delete world;
229     delete debugDraw;
230     Layer::onExit();
231     this->unschedule(schedule_selector(GameMain::update));
232 }
GameMain.cpp

需要注意:

1 所有的熊猫动作打包成一个plist,所有的场景素材打包到另一个plist

这就是我们在场景类的init方法里面预加载的两个文件:

1 SpriteFrameCache::getInstance()->addSpriteFramesWithFile("panda.plist");//add panda animate
2     SpriteFrameCache::getInstance()->addSpriteFramesWithFile("scene.plist");//add scene resources

资源目录应该是这样的:

2 去cocos2d-x-3.2 estscpp-testsClassesBox2DTestBed下面将GLES-Render.hGLES-Render.cpp拷到项目里面来,因为Box2d没有b2Debug的实现,这个是我们手头上需要的实现。

3 使用Box2d的时候极有可能会出现编译连接错误,找不到Box2d相关的类,这个时候需要将cocos2d-x-3.2externalBox2D编译一下,然后在项目的连接器中加入引用:

4 通过b2World::SetDebugDraw(b2Draw * draw)GLESDebugDraw实例设置为worlddebugDraw之后,每帧调用world->DrawDebugData()是不会生效的,只有复写Layer::draw()方法并在其中调用此方法才会显示debugDraw

由于debugDraw是调用显卡去渲染的,所以debugDraw是位于场景最底层的,当你把所有场景内的显示对象的通过setVisible设置为false的时候,你就可以看到了。

可以设置SHOW_DEBUG的值来设置显示对象的visible

如下:

 

 可以看到下面的debugDraw有点测漏了。

5 cocos2dx 3.2内置了chipmunk物理引擎,用起来比较简单,但是我之前学习ActionScript的时候有用过Box2d,并且Box2d的功能比较强大一些,所以选择了Box2dActionScript还有一个效率比Box2d稍强的无力引擎:Nape

以下是一开始用chipmunk实现的一些功能的代码:

  1 #include "GameMain.h"
  2 #include "cocos2d.h"
  3 
  4 USING_NS_CC;
  5 
  6 Scene* GameMain::createScene()
  7 {
  8     auto scene = Scene::createWithPhysics();
  9     scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
 10     scene->getPhysicsWorld()->setUpdateRate(0.5);
 11     auto layer = GameMain::create();
 12     scene->addChild(layer);
 13     return scene;
 14 }
 15 
 16 
 17 bool GameMain::init()
 18 {
 19     if ( !Layer::init() )
 20     {
 21         return false;
 22     }
 23     
 24     speed = 5.0f;
 25     
 26     auto listener = EventListenerTouchOneByOne::create();
 27     listener->onTouchBegan = CC_CALLBACK_2(GameMain::onTouchBegan,this);
 28     listener->onTouchEnded = CC_CALLBACK_2(GameMain::onTouchEnded,this);
 29     listener->onTouchMoved = CC_CALLBACK_2(GameMain::onTouchMoved,this);
 30 
 31     auto contact_listener = EventListenerPhysicsContact::create();
 32     contact_listener->onContactBegin = CC_CALLBACK_1(GameMain::onContactBegin,this);
 33 
 34     Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
 35     Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(contact_listener,1);
 36 
 37     visibleSize = Director::getInstance()->getVisibleSize();
 38     Vec2 origin = Director::getInstance()->getVisibleOrigin();
 39     SpriteFrameCache::getInstance()->addSpriteFramesWithFile("panda.plist");//add panda animate
 40     SpriteFrameCache::getInstance()->addSpriteFramesWithFile("scene.plist");//add scene resources
 41 
 42     middle_bg_0 = Sprite::create("bbg_snow_bone.jpg");
 43     cSize = middle_bg_0->getContentSize();
 44     middle_bg_0->setPosition(visibleSize.width*0.5, visibleSize.height*0.5);
 45     middle_bg_1 = Sprite::create("bbg_snow_bone.jpg");
 46     middle_bg_1->setPosition(visibleSize.width*1.5, visibleSize.height*0.5);
 47     addChild(middle_bg_0);
 48     addChild(middle_bg_1);
 49 
 50     gen_floor();
 51 
 52     panda = Panda::create();
 53     panda->setPosition(visibleSize.width/2, visibleSize.height/2);
 54     Size panda_size = Size(50.0f,100.0f);
 55     panda->play(Panda::RUN);
 56     auto panda_body = PhysicsBody::createBox(panda_size);
 57     panda_body->retain();
 58     panda->setPhysicsBody(panda_body);
 59     this->addChild(panda);
 60     
 61     auto edge_sp = Sprite::create();
 62     auto edge_body = PhysicsBody::createEdgeBox(visibleSize,PHYSICSBODY_MATERIAL_DEFAULT,3);
 63     edge_sp->setPosition(visibleSize.width/2, visibleSize.height/2);
 64     edge_sp->setPhysicsBody(edge_body);
 65     edge_sp->setTag(0);
 66     addChild(edge_sp);
 67     return true;
 68 }
 69 
 70 bool GameMain::onContactBegin(const PhysicsContact& contact)
 71 {
 72     log("Contacted...");
 73     return true;
 74 }
 75 
 76 bool GameMain::onTouchBegan(Touch * touch, Event * event)
 77 {
 78     log("Touched.....");
 79     int cur_state = panda->getCurrentState();
 80     panda->getPhysicsBody()->applyForce(Vect(500.0f,500.0f));
 81     if( cur_state == Panda::RUN )
 82     {
 83         panda->play(Panda::JUMP);
 84     }else if(cur_state == Panda::JUMP)
 85     {
 86         panda->play(Panda::JUMP2);
 87     }
 88     return true;
 89 }
 90 
 91 void GameMain::onTouchEnded(Touch * touch, Event * event)
 92 {
 93 
 94 }
 95 
 96 void GameMain::onTouchMoved(Touch * touch, Event * event)
 97 {
 98 
 99 }
100 
101 void GameMain::update(float dt)
102 {
103     /**
104     middle_bg_0->setPositionX(middle_bg_0->getPositionX()-speed);
105 
106     if(middle_bg_0->getPositionX() < -cSize.width*0.5)
107     {
108         middle_bg_0->setPositionX(cSize.width*1.5);
109     }
110 
111     middle_bg_1->setPositionX(middle_bg_1->getPositionX()-speed);
112     if(middle_bg_1->getPositionX() < -cSize.width*0.5)
113     {
114         middle_bg_1->setPositionX(cSize.width*1.5);
115     }*/
116 }
117 
118 void GameMain::onEnter()
119 {
120     Layer::onEnter();
121     this->schedule(schedule_selector(GameMain::update),0.05f);
122 }
123 
124 void GameMain::onExit()
125 {
126     Layer::onExit();
127     this->unschedule(schedule_selector(GameMain::update));
128 }
129 
130 void GameMain::createFloor(int posx,int posy,int w,int h)
131 {
132     
133 }
134 //generate floors
135 void GameMain::gen_floor()
136 {
137     Sprite * sp_l = Sprite::create("platform_l.png");
138     auto body_l = PhysicsBody::createBox(sp_l->getContentSize());
139     body_l->setDynamic(false);
140     sp_l->setPhysicsBody(body_l);
141     sp_l->setPosition(50.0f,150);
142     addChild(sp_l);
143     
144     Sprite * sp_m = Sprite::create("platform_m.png");
145     auto body_m = PhysicsBody::createBox(sp_m->getContentSize());
146     body_m->setDynamic(false);
147     sp_m->setPhysicsBody(body_m);
148     sp_m->setPosition(sp_l->getPositionX() + (sp_l->getContentSize().width+sp_m->getContentSize().width)/2,150);
149     addChild(sp_m);
150 
151     Sprite * sp_r = Sprite::create("platform_r.png");
152     auto body_r = PhysicsBody::createBox(sp_r->getContentSize());
153     body_r->setDynamic(false);
154     sp_r->setPhysicsBody(body_r);
155     sp_r->setPosition(sp_m->getPositionX() + (sp_m->getContentSize().width+sp_r->getContentSize().width)/2,150);
156     addChild(sp_r);
157 }
GameMain.cpp

建议:

不想吐槽搜索引擎,建议大家遇到问题先尝试自己解决,解决不了的然后可以用国外的搜索引擎搜索一下,或者可以直接去StackFlow去搜索

参考文章:

(翻译)介绍Box2D的Cocos2D 2.X教程:弹球
[Cocos2D-x For WP8]Box2D物理引擎
How to enable Box2d debug draw with Coco2d-x 3.0 beta 2
原文地址:https://www.cnblogs.com/adoontheway/p/3953773.html