注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

风的驿站

一徐清风,半指烛光,觥筹已净,只余茶香。残卷一章,妙趣非常,忽闻帘响,愿闻其详?

 
 
 

日志

 
 
关于我

喜欢写生 编程 音乐 设计 喜欢把自己的想法变成实实在在的东西 喜欢安静的做一些事情 CSDN博客:http://blog.csdn.net/qwertyupoiuytr

网易考拉推荐

【原创】手把手教你制作一款Box2D小游戏(一)  

2014-06-23 11:30:51|  分类: Box2D |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

这次我们利用Box2D物理引擎来制作一款类似于下楼梯的小游戏,关于Box2D物理引擎的介绍,可以参考我博客中的Box2D v2.3.0 用户指南进行学习。

我们先来看一下最终效果:

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

游戏的组成元素有:

滚动背景(左右两个宽度为15,与屏幕等高的部分),上升的台阶(或者说是楼梯),滚动的球,分数。

滚动背景的制作我们不做介绍了,制作方法可以参考FlaggyBird的滚动背景的制作方法(手把手教你制作那个风靡的flappy bird小游戏),背景大部分面积填充的是深蓝色(静止),用平铺的方法平铺两个小的纹理:

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站 

我们先来介绍使用Box2D来创建台阶:

首先创建StepBlock类,注意我们在创建类之后默认会创建出.h.m文件,因为Box2D是基于C++的框架,所以需要我们手动将.m文件的扩展名更改为.mmStepBlock类声明如下:

#import "CCNode.h"

#import "CCPhysicsSprite.h"

#import "Box2D.h"

#import "TagDefinitions.h"

 

@interface StepBlock : CCNode{

    float screenWidth;

    float screenHeight;

    CCPhysicsSprite* shape;

    b2Body* body;

    int tagSave;

}

 

- (id)initWithY:(float) y;

- (id)initWithPos:(CGPoint) pos andType:(StepBlockTypes)type;

- (void)resetWithY:(float) yPos;

- (BOOL)moveUp:(float) length lowestStepY:(float) lowestStepY;

- (void)resetWithPos:(CGPoint) pos andType:(StepBlockTypes) type;

 

@end

类中我们定义了screenHeightscreenWidth用来存放屏幕长宽,避免反复获取影响效率。同时我们定义了shape,来存储StepBlock(后面简称Block)的图形(CCPhysicsSpriteCCSprite用法相同,只不过可以指定b2Body作为其成员,这里我们也可以使用CCSprite,不影响效果)。另外又定义了一个body对象,用来存储StepBlock的刚体对象。tagSave我们后面会用到,这里先忽略这个成员。

另外我们定义了一系列的方法,initWithY用来初始化StepBlock,所以这个初始化方法只需要指定y值即可。initWithPos:andType:方法用一个确定的初始位置和Block类型来初始化,这里Block类型我们接下来会介绍,resetWithY方法重置Block的类型和位置,moveUp用来将Block上移,resetWithPos:andType:用确定的位置和Block类型来重置Block。我们看到头文件中的“TagDefinitions.h”,这个头文件中包含了下面的枚举定义和预编译指令:

#ifndef Steps_TagDefinitions_h

#define Steps_TagDefinitions_h

 

#define PTM_RATIO 100

 

typedef enum{

    StepBlockNormal = 0,

    StepBlockConcave,

    StepBlockConvex,

    StepBlockHighLow,

    StepBlockLowHigh,

    StepBlockRough,

    StepBlockSlideLeft,

    StepBlockSlideRight

} StepBlockTypes;

 

typedef enum {

    ForceNone,

    ForceLeft,

    ForceRight

} ForceType;

 

#endif

这里PTM_RATIO定义了Box2D中“米”和“像素”的转化比例,StepBlockTypes定义了Block类型的枚举,ForceType定义了对小球的施力方向枚举,我们后面会用到。

下面是用到的不同类型Block的贴图:

step_high_low.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_low_high.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_concave.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_normal.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_rough.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_slide_left.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_slide_right.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

step_convex.png

【原创】手把手教你制作一款Box2D小游戏(一) - 远行的风 - 风的驿站

将这些图片导入到工程资源中。接着我们来看StepBlock.mm中的类定义。首先定义一个静态数组,用来存放Block的类型名:

static NSArray* stepBlockTypes = [NSArray arrayWithObjects:@"step_normal", @"step_concave", @"step_convex", @"step_high_low", @"step_low_high", @"step_rough", @"step_slide_left", @"step_slide_right", nil];

接着定义下面的方法,用来设置Block的精灵对象:

- (void)initShape:(NSString*) shapeName{

    shape = [CCSprite spriteWithFile:shapeName];

 

    [self addChild:shape];

}

下面的方法用来初始化screenHeightscreenWidth属性:

- (void)initProps{

    //screen dimensions

    CGSize screenSize = [[CCDirector sharedDirector] winSize];

    screenHeight = screenSize.height;

    screenWidth = screenSize.width;

}

接着我们定义resetWithPos:andType:方法:

- (void)resetWithPos:(CGPoint) pos andType:(StepBlockTypes) type{

    float xPos = pos.x;

    xPos = max(65, xPos);                  // 15(wall width) + 50(half the step block width)

    xPos = min(xPos, screenWidth - 65);    // 65 = 100(step block width) + 15(wall width) - 50(half the step block width)

   

    if (body) {

        [[GameLayer gameLayer] sharedWorld]->DestroyBody(body);

    }

    b2BodyDef bodyDef;

    bodyDef.type = b2_staticBody;

    bodyDef.userData = [NSNumber numberWithInteger:tagSave];

    body = [[GameLayer gameLayer] sharedWorld]->CreateBody(&bodyDef);

   

    [self generateShapeAndFixture:ccp(xPos, pos.y) withType:type];

}

在计算xPos的时候我们进行了一些判断,防止Block的位置超出左右的墙壁。并且由于我们在reset的时候会随机更换Block的类型,所以会先将body清除掉(destroy),但是第一次初始化的时候body并没有定义,所以添加了if语句进行了判断。这里用到的GameLayer类是游戏的主场景(CCScene)的层(CCLayer),我们下面会介绍,sharedWorld是我们这个游戏里的世界对象。在清除了body对象后,我们用b2BodyDef来定义body,定义的类型是静态物体(staticBody),因为我们不需要Block像小球一样受力运动,他们只需要匀速上升即可。接着我们定义了bodyuserData,将tagSave存储进去,这个值在我们后面记分(score)的时候会用到。接着使用CreateBody来创建刚体,然后调用generateShapeAndFixture:withType:方法。方法定义如下:

- (void)generateShapeAndFixture:(CGPoint) pos withType:(int) type{

    NSString *shapeName = [stepBlockTypes objectAtIndex:type];

    shape.texture = [[CCTextureCache sharedTextureCache] addImage:[NSString stringWithFormat:@"%@.png", shapeName]];

    shape.position = pos;

    [[GB2ShapeCache sharedShapeCache] addFixturesToBody:body forShapeName:shapeName];

    shape.anchorPoint = ccp(0.5f, 0.5f);

    b2Vec2 newPos;

    newPos.Set(pos.x/PTM_RATIO, pos.y/PTM_RATIO);

    body->SetTransform(newPos, 0);

}

这个方法刷新了形状的纹理(texture),然后使用GB2ShapeCache类的addFixturesToBody:forShapeName:来初始化物体的fixtureGB2ShapeCache类可以在PhysicsEditor(简称PE)的dmg文件中的“\Loaders\ generic-box2d-plist”路径下找到,关于PE的用法,请参考手把手教你使用PhysicsEditor来辅助制作Box2D刚体。将PE中创建导出的plist文件导入到Box2D工程中,使用下面的语句导入:

[[GB2ShapeCache sharedShapeCache] addShapesWithFile:@"steps-elements.plist"];

其中“steps-elements.plist”为PE生成的文件。

SetTransform方法用来重置物体的位置和角度,第一个参数是位置,第二个是角度,这里Block为水平放置,所以角度为0

定义好之后,我们继续添加下面两个reset方法,只是参数上有所不同,复用上面的方法:

- (void)resetWithY:(float) yPos{

    float xPos = CCRANDOM_0_1() * (screenWidth - 100);  // 100 is the width of the step block

    [self resetWithPos:ccp(xPos, yPos)];

}

 

- (void)resetWithPos:(CGPoint) pos{

    int type = rand() % 8;

    [self resetWithPos:pos andType:(StepBlockTypes)type];

}

最后,我们定义好Block的初始化方法:

- (id)initWithY:(float) y{

    if (self = [super init]) {

        [self initProps];

        [self initShape:@"step_normal.png"];

        [self resetWithY:y];

    }

   

    return self;

}

 

- (id)initWithPos:(CGPoint)pos andType:(StepBlockTypes)type{

    if (self = [super init]) {

        [self initProps];

        NSString *shapeName = [NSString stringWithFormat:@"%@.png", [stepBlockTypes objectAtIndex:(int)type]];

        [self initShape:shapeName];

        [self resetWithPos:pos andType:type];

    }

   

    return self;

}

这里我们还差一个moveUp的方法,定义如下:

- (BOOL)moveUp:(float) length lowestStepY:(float) lowestStepY{

    float y = shape.position.y + length;

    float x = shape.position.x;

    BOOL isReallyMovedUp = true;

    if (y > screenHeight + 15) {

        y = lowestStepY;

        isReallyMovedUp = false;

        [self resetWithY:y];

    }

    shape.position = ccp(x, y);

    b2Vec2 newPos;

    newPos.Set(x/PTM_RATIO, y/PTM_RATIO);

    body->SetTransform(newPos, 0);

   

    return isReallyMovedUp;

}

使用SetTransform方法来移动刚体的位置,注意的一点是,当Block移动到屏幕外时,并不清理掉这个Block,而是重置Block并将其移动到最下方的Block的下面去,lowestStepY即是最下方的Blocky坐标。返回值isReallyMovedUp用来标记Block是否被重置到了最下方。

到这里StepBlock类就完成了定义。


下一篇我们继续来制作这个Box2D小游戏。

手把手教你制作一款Box2D小游戏(二) 

  评论这张
 
阅读(163)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017