怎样在UIKit中使用cocos2d-x

怎样在UIKit中使用cocos2d-x,第1张

cocos2d-x 是一款基于 c++/Opengl 的强劲跨平台引擎,通过一次编码,你可以同时用于 android , iOS 等大多数主流平台。这使得多平台的开发更加方便。

虽然比起带团 cocos2d-x 的有名的兄弟 -cocos2d-iphone , -x 还很年轻并缺少教程,但是由于团队的不懈努力,使得 -x 逐渐完善并不断被市场认可。

如果你想把 UIKit 折腾进 Cocos2d-x , Github 有一个开源工程,推荐给大家学习没袜一下: open source project on GitHub .

相反,如果你想把 coocs2d-x 折腾进 UIKit (UIVIewController),以下是详细步骤:

0. 废话少说,这里是本文的示例代码: Sample project Cocos2dxOnUikit.zip .

1.我们有一个 UIKit 工程,同时希望在某一个 view controller中显示Cocos2d-x (OpenGL view)。

2. 下载 Cocos2d-x 代码(哥说了句废话,你知道该去哪下载的)

3. 解压(废话 again )

4. 创建工程,如果你不会,推荐看看泰然以往的教程。

5. 移除cocos2dx/platform/目录下的CCImage.cpp 和 CCThread.cpp

6. 打开 xcode 的项目配置,点击 build Settings ,在 “ Library Search Paths ” 参数添加$(SRCROOT)/cocos2dx/platform/third_party/ios/libraries/(为了在cocos2dx中使用curl库)

7. 接着,在“ Headers Search Paths ” 参数添加

$(SRCROOT)/cocos2dx and $(SDKROOT)/usr/include/libxml2 (为了蠢察橘使用libxml 库)

8. 在 “ Other C++ Flags ” 参数添加-DCC_UNDER_IOS

9.从HelloWorld示例工程中拷贝AppDelegate.cpp 和 AppDelegate.h并添加到我们现在这个工程中。

#import <UIKit/UIKit.h>是objective-c文件才能使用的,你不会从c++文件调用了吧。

如果是这个原因,你可以换用cocos2d-iPhone。

或者写wrapper class(与native Objective-C class 交流)需要写wrapper class可以继续问。

大家也可以到Ray的网站查看本教程的中文版本。Simple Breakout Game ScreenshotBbox2d是一个非常强大的物理引擎库,同时它与cocos2d结合非常适合在iphone上面做游戏开发。著名的angry birds,tiny wings都是用box2d写的。你可以用它做好多事情,当然,最好的学习方法就是使用它来创建一个简单的游戏。在这个教程中,我们将一步一步创建一个简单的breakout游戏,完成碰撞检测,篮球反d物理效果,通过touch拖动paddle(就是上图的白色矩形),以及胜利/失败的场景。 (Jump to part two of the series.)如果你还不了解cocos2d和box2d,你可能先要读一读 《如何使用cocos2d制作一个简单的iphone游戏》 以及《在cocos2d里面如何使用box2d物理引擎:d球》.好了,是时候制作breakout了!一个永远反d的球S首先,打开Xcode,选择 cocos2d-0.99.1 Box2d Application template创建一个工程,命名为“ Box2DBreakout”. 删除掉模板代码,因此你会有一个空的工程来重新开始—具体步骤可以参照 《在cocos2d里面如何物游使用box2d物理引擎:d球》 这个教程。一旦你有了一个很好的干净的工罩毕销程后,接下来,在HelloWorldScene.h中导入下面的头文件: #import "Box2D.h" 同时在HelloWorld类中添加以下成员变量: b2World *_worldb2Body *_groundBodyb2Fixture *_bottomFixtureb2Fixture *_ballFixture然后在HelloWorldScene.mm文件顶部定义比率: #define PTM_RATIO 32 这个比率我们在上一个教程中已经讨论过了,这里就不再啰嗦了。然后,在init方法中加入下列代码: CGSize winSize = [CCDirector sharedDirector].winSize// Create a world b2Vec2 gravity = b2Vec2(0.0f, 0.0f)bool doSleep = true_world = new b2World(gravity, doSleep)// Create edges around the entire screen b2BodyDef groundBodyDefgroundBodyDef.position.Set(0,0)_groundBody = _world->CreateBody(&groundBodyDef)b2PolygonShape groundBoxb2FixtureDef groundBoxDefgroundBoxDef.shape = &groundBoxgroundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0))_bottomFixture = _groundBody->CreateFixture(&groundBoxDef)groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO))_groundBody->CreateFixture(&groundBoxDef)groundBox.SetAsEdge(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO))_groundBody->CreateFixture(&groundBoxDef)groundBox.SetAsEdge(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/数行PTM_RATIO, 0))_groundBody->CreateFixture(&groundBoxDef)好,这个代码和我们上一个教程中,为整个屏幕创建一个盒子边界差不多。然后,这一次,我们把重力设置为0,因为,在我们的breakout游戏中,我们并不需要重力!注意,我们存储了底部的fixture的一个指针,以方便后面使用(在后面的教程中,我们将用来追踪什么时候篮球与顶部相碰撞了)。现在,下载我制作的 篮球图片 并且拖到Resources文件夹中,确保 “Copy items into destination group’s folder (if needed)” 被复选中。让我们往场景里面添加一个精灵吧。紧接着上面的代码,加入下面的代码片段: // Create sprite and add it to the layer CCSprite *ball = [CCSprite spriteWithFile:@"Ball.jpg" rect:CGRectMake(0, 0, 52, 52)]ball.position = ccp(100, 100)ball.tag = 1[self addChild:ball]这里没什么疑问,我们已经做过好多次类似的事情了。注意,我们为篮球设置了一个tag标识,后面你会看到,这个tag标记有什么用。接下来,为shape创建一个body: // Create ball body b2BodyDef ballBodyDefballBodyDef.type = b2_dynamicBodyballBodyDef.position.Set(100/PTM_RATIO, 100/PTM_RATIO)ballBodyDef.userData = ballb2Body * ballBody = _world->CreateBody(&ballBodyDef)// Create circle shape b2CircleShape circlecircle.m_radius = 26.0/PTM_RATIO// Create shape definition and add to body b2FixtureDef ballShapeDefballShapeDef.shape = &circleballShapeDef.density = 1.0fballShapeDef.friction = 0.fballShapeDef.restitution = 1.0f_ballFixture = ballBody->CreateFixture(&ballShapeDef)这个看起来和上一篇教程中的也很像。再巩固一下吧,为了创建一个body对象,我们先要创建一个body定义结构,然后再创建body,接着是shape,再指定fixture结构,最后是创建fixture对象。更新:注意,我们也把球的摩擦力设置为0.这样可以防止球在碰撞的时候,由于摩擦损失能量,导致来回碰撞的过程中会有一点点偏差。好了,是时候做一些完全不同的事了!紧接上面的代码: b2Vec2 force = b2Vec2(10, 10)ballBody->ApplyLinearImpulse(force, ballBodyDef.position)这里往球上面施加了一个冲力(impulse),这样可以让它初始化的时候朝一个特定的方向运动。最后一件事情,就是在init方法中,增加一个tick调度方法: [self schedule:@selector(tick:)]下面是tick方法的实现: - (void)tick:(ccTime) dt { _world->Step(dt, 10, 10)for(b2Body *b = _world->GetBodyList()bb=b->GetNext()) { if (b->GetUserData() != NULL) { CCSprite *sprite = (CCSprite *)b->GetUserData()sprite.position = ccp(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO)sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle())} } } 当然,这里也和上一个教程中的一样,没有什么特别的。最后一件事我们永远不忘记!那就是清理: - (void)dealloc { delete _world_groundBody = NULL[super dealloc]} 好了,让我们试一下吧。编译并运行工程,你将会看到一个球无限地在屏幕里面来回d!—-很酷吧!增加Paddle如果没有一个paddle的话,那么就不可能称其为一个breakout游戏。下载我制作的paddle图片 然后把它拖到Resources文件夹中,同时确保 “Copy items into destination group’s folder (if needed)” 被复选上。然后在HelloWorldScene.h文件中往HelloWorld类中添加下列成员变量: b2Body *_paddleBodyb2Fixture *_paddleFixture然后,在init方法中构建paddle body: // Create paddle and add it to the layer CCSprite *paddle = [CCSprite spriteWithFile:@"Paddle.jpg"]paddle.position = ccp(winSize.width/2, 50)[self addChild:paddle]// Create paddle body b2BodyDef paddleBodyDefpaddleBodyDef.type = b2_dynamicBodypaddleBodyDef.position.Set(winSize.width/2/PTM_RATIO, 50/PTM_RATIO)paddleBodyDef.userData = paddle_paddleBody = _world->CreateBody(&paddleBodyDef)// Create paddle shape b2PolygonShape paddleShapepaddleShape.SetAsBox(paddle.contentSize.width/PTM_RATIO/2, paddle.contentSize.height/PTM_RATIO/2)// Create shape definition and add to body b2FixtureDef paddleShapeDefpaddleShapeDef.shape = &paddleShapepaddleShapeDef.density = 10.0fpaddleShapeDef.friction = 0.4fpaddleShapeDef.restitution = 0.1f_paddleFixture = _paddleBody->CreateFixture(&paddleShapeDef)我不想花太多的时间解释上面的内容了。因为,和之前的创建篮球的body的过程差不太多。这里只给出不同的地方:当你创建CCSprite的时候,你并不需要指定精灵的大小。如果你传递一个文件名给它,它会自动计算出大小。注意,这里不是使用circle shape了。这一次,我们使用polygon shape。我们使用一个辅助方法来创建shape,当然,其形状是个盒子。我们使用了SetAsBox方法来指定shape相对于body的位置,这个方法在构建复杂的对象的时候比较有用。这里,我们只是让shape在body中间。我把paddle的密度设置得比球要大得多,同时调节了一下其它的参数。(这些参数要靠试,按照真实的高中物理知识去计算,可能得不到)同时,我们存储paddleBody和paddleFixture的引用,为了方便后面使用。如果你编译并运行的话,你将会看到屏幕中间有一个paddle,而且球碰到它将会反d。 然后,这还不是很有趣,因为我们还不能移动paddle!移动Paddle移动paddle需要touch事件,所以先在init方法中允许touch事件: self.isTouchEnabled = YES然后,在HelloWorldScene.h的HelloWorld类中添加下面的成员变量: b2MouseJoint *_mouseJoint现在,让我们实现touch方法!首先是ccTouchesBegan: - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if (_mouseJoint != NULL) returnUITouch *myTouch = [touches anyObject]CGPoint location = [myTouch locationInView:[myTouch view]]location = [[CCDirector sharedDirector] convertToGL:location]b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO)if (_paddleFixture->TestPoint(locationWorld)) { b2MouseJointDef mdmd.bodyA = _groundBodymd.bodyB = _paddleBodymd.target = locationWorldmd.collideConnected = truemd.maxForce = 1000.0f * _paddleBody->GetMass()_mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md)_paddleBody->SetAwake(true)} } 呃,好多新知识!让我们一点一点来讨论。首先,我们把touch坐标转换成coocs2d坐标(convertToGL)然后,再转换成Box2d坐标(locationWorld)。然后,我们使用paddle fixture的一个方法来测试这个touch点是否在fixture内部。如果是的话,我们就创建一个所谓的”鼠标关节“。在Box2d里面,一个鼠标关节用来让一个body朝着一个指定的点移动—在这里个例子中,就是用户点的方向。当你创建一个mouse joint后,你赋值给它两个body。第一个没有被使用,通常都是设置成ground body。第二个,就是你想让它移动的body,在这个例子中就是paddle。接下来,你指定移动的终点—这个例子中就是用户点击的位置。然后,你告诉box2d,但bodyA和bodyB碰撞的时候,把它当成是碰撞,而不是忽略它。这个很重要!因为,我之前没有设置它为ture,结果不行!因此,当我们用鼠标拖动这个paddle的时候,它并不会与屏幕的边界相碰撞,而且有时候,我的paddle直接就飞出屏幕之外了。这个非常非常奇怪,不过我现在知道是为什么了。因为没有设置bodyA和bodyB是可碰撞的。你然后指定移动body的最大的力是多少。如果你减少这个数值的话,paddle body响应鼠标移动时就会慢一些。但是,我们想让paddle快速地响应鼠标的变化。最后,我们把这个关节加入到world中,同时,保存这个指针,因为后面有用。同时,我们还要把body设置成苏醒的(awake)。之所以要这么做,是因为如果body在睡觉的话,那么它就不会响应鼠标的移动!好了,接下来,让我们添加ccTouchesMoved方法: -(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { if (_mouseJoint == NULL) returnUITouch *myTouch = [touches anyObject]CGPoint location = [myTouch locationInView:[myTouch view]]location = [[CCDirector sharedDirector] convertToGL:location]b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO)_mouseJoint->SetTarget(locationWorld)} 这个方法的开头部分和ccTouchesBegan差不多—我们把touch坐标转换成Box2d坐标。唯一的区别就是,我们更新了鼠标关节的目标位置(也就是我们想让paddle移动的位置的)。接下来,我们添加ccTouchesCacelled和ccTouchesEnded方法: -(void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { if (_mouseJoint) { _world->DestroyJoint(_mouseJoint)_mouseJoint = NULL} } - (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if (_mouseJoint) { _world->DestroyJoint(_mouseJoint)_mouseJoint = NULL} } 我们在这些方法中做的只有一件事,就是在我们移动完paddle或者取消移动之后销毁mouse joint。编译并运行,你现在可以用鼠标移动paddle了,同时可以让它与篮球相互碰撞了! 很好。。。不过,等一下,这还不是一个breakout!我们不可以把paddle移动到任何位置,我们只能在屏幕底部左右来回移动它!限制Paddle的移动我们可以很容易地限制paddle的移动,只需要添加另外一个关节,叫做prismatic joint。这个关节会限制一个body的移动沿着一根指定的轴。因此,我们可以使用这种方法来限制paddle相对于地面移动,也就是说只能沿着x轴移动。让我们看看相关代码。往init方法中加入下列代码: // Restrict paddle along the x axis b2PrismaticJointDef jointDefb2Vec2 worldAxis(1.0f, 0.0f)jointDef.collideConnected = truejointDef.Initialize(_paddleBody, _groundBody, _paddleBody->GetWorldCenter(), worldAxis)_world->CreateJoint(&jointDef)第一件事情就是指定一个沿着x轴的向量。然后,我们需要指定collideConnected为true,因此,我们的球才能够正确的反d,而不是飞到屏幕之外去。然后,初始化关节,指定paddle和ground两个body,再使用world对象来创建关节!更新:我第一次尝试去修正这个bug的时候,我通过直接调整球的速度,使用SetLinearVelocity方法。然后,Steve Oldmeadow也指出,这非常不好!它会破坏物理仿真,最好的方法是通过调用SetLinearDamping方法,间接影响速度。因此,现在这个教程就是这个做的。(damping就是阻尼的意思)接下来,在tick方法中添加下列代码,具体位置是在获得user data之后: if (sprite.tag == 1) { static int maxSpeed = 10b2Vec2 velocity = b->GetLinearVelocity()float32 speed = velocity.Length()if (speed >maxSpeed) { b->SetLinearDamping(0.5)} else if (speed <maxSpeed) { b->SetLinearDamping(0.0)} } 这里,我们判断sprite的tag,看是否是球的tag。如果是的话,我们就检查它的速度,如果太大的话,就设置它的阻尼为0.5,这样可以让它慢下来。如果你编译并运行的话,你将会看到一个球以非常适中的速度在屏幕四周来回反d。给我源代码!这里是本教程的 完整源代码 。这只是一部分,第二部分的教程会包含一个完整的breakout的源码。接下来呢?目前为止,我们已经有一个篮球在屏幕四周来回反d了,同时还有一个paddle可以用鼠标来控制其移动。在下个教程中,我们将创建一些方块,当球碰到它们的时候,方块就会消失。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12194807.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存