子龙山人

http://www.cnblogs.com/andyque/archive/2011/07/02/2095527.html

Learning,Sharing,Improving!

(译)如何制作一个类似tiny wings的游戏:第二部分(完)

免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作!

原文链接地址:http://www.raywenderlich.com/3913/how-to-create-a-game-like-tiny-wings-part-2

教程截图:

  这是本系列教程的最后一部分,主要是教大家如何制作一个类似Tiny Wings的游戏。

  在预备教程中,我们学会了如何创建动态山丘纹理和背景纹理。

  在第一部分教程中,我们学会了如何动态创建游戏里所需要的山丘。

  在这篇教程中,也是本系列教程的最后一篇,我们将会学习到更加有意思的部分---如何往游戏里面添加主角,同时使用BOX2D来仿真主角的移动!

  再说明一下,这个教程系列是基于Sergey Tikhonov所写的一个非常好的demo project制作的---所以我要特别感谢Sergey!

  这个教程假设你对cocos2d和box2d已经很熟悉了。如果你对这两者还很陌生的话,建议你先阅读本博客上翻译的cocos2d教程和box2d教程。

Getting Started

  如果你还没有准备好,可以先下载上一篇教程中完成的样例工程。

  接下来,我们将添加一些基本的box2d代码。我们将创建一个box2d world和一些代码来激活debug drawing,同时还会添加一些测试用shape,以此确保BOX2D环境被正确搭建起来!

  首先,打开HelloWorldLayer.h,然后作如下修改:

// Add to top of file
#import"Box2D.h"
#define PTM_RATIO 32.0

// Add inside @interface
b2World * _world;

  这里包含了box2d的头文件和debug draw的头文件,同时定义一个_world变量来追踪box2d的world与debug draw类。

  同时,我们也声明了一个像素/米的转换率(PTM_RATIO)为32.回顾一下,这个变量主要作用是在box2d的单位(米)和cocos2d的单位(点)之间做转换。

  然后,我们在HelloWorldLayer.mm中添加一下新的方法,添加位置在init方法上面:

- (void)setupWorld { 
b2Vec2 gravity = b2Vec2(0.0f, -7.0f);
bool doSleep =true;
_world =new b2World(gravity, doSleep); 
}

- (void)createTestBodyAtPostition:(CGPoint)position {

b2BodyDef testBodyDef;
testBodyDef.type = b2_dynamicBody;
testBodyDef.position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
b2Body * testBody = _world->CreateBody(&testBodyDef);

b2CircleShape testBodyShape;
b2FixtureDef testFixtureDef;
testBodyShape.m_radius =25.0/PTM_RATIO;
testFixtureDef.shape =&testBodyShape;
testFixtureDef.density =1.0;
testFixtureDef.friction =0.2;
testFixtureDef.restitution =0.5;
testBody->CreateFixture(&testFixtureDef);

}

  

  如果你对box2d很熟悉的话,上面这个方法只是一个回顾。

  setupWorld方法创建一个有重力的world--但是比标准的重力-9.8m/s^2要小一点点。

  createTestBodyAtPostition创建一个测试对象---一个25个点大小的圆。我们将使用这个方法来创建一个测试对象,每一次你点击屏幕就会在那个地方产生一个圆,不过这只是测试用,之后会被删除掉。

  你现在还没有完成HelloWorldLayer.mm--现在再作一些修改,如下所示:

// Add to the TOP of init
[self setupWorld];

// Replace line to create Terrain in init with the following
_terrain = [[[Terrain alloc] initWithWorld:_world] autorelease];

// Add to the TOP of update
staticdouble UPDATE_INTERVAL =1.0f/60.0f;
staticdouble MAX_CYCLES_PER_FRAME =5;
staticdouble timeAccumulator =0;

timeAccumulator += dt; 
if (timeAccumulator > (MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL)) {
timeAccumulator = UPDATE_INTERVAL;
}

int32 velocityIterations =3;
int32 positionIterations =2;
while (timeAccumulator >= UPDATE_INTERVAL) { 
timeAccumulator -= UPDATE_INTERVAL; 
_world->Step(UPDATE_INTERVAL, 
velocityIterations, positionIterations); 
_world->ClearForces();

}

// Add to bottom of ccTouchesBegan
UITouch *anyTouch = [touches anyObject];
CGPoint touchLocation = [_terrain convertTouchToNodeSpace:anyTouch];
[self createTestBodyAtPostition:touchLocation];

  第一段代码,我们调用setupWorld方法来创建一个box2d世界。然后使用box2d的world来初始化Terrain类。这样,我们就可以使用这个world来创建山丘的body了。为此,我们将会写一些桩代码(placeholder)。

  第二段代码,我们调用_world->Step方法来运行物理仿真。注意,这里使用的是固定时间步长的实现方式,它比变长时间步长的方式物理仿真效果要更好。对于具体这个是怎么工作的,可以去看看我们的cocos2d书籍中关于box2d的那一章节内容。

  最后一段代码是添加到ccTouchesBegan里面,不管什么时候你点击屏幕,就会创建一个box2d的body。再说一下,这样做只是为了测试box2d环境可以run起来了。

  注意,我们这里得到的touch坐标是在地形的坐标之内。这是因为,地形将会滚动,而我们想知道地形的位置,而不是屏幕的位置。

  接下来,让我们修改一下Terrain.h/m。首先,修改Terrain.h,如下所示:

// Add to top of file
#import"Box2D.h"
#import"GLES-Render.h"

// Add inside @interface
b2World *_world;
b2Body *_body;
GLESDebugDraw * _debugDraw;

// Add after @interface
- (id)initWithWorld:(b2World *)world;

  这里只是包含box2d头文件,然后创建一些实例变量来追踪box2d的world,以及山丘的body,还有支持debug drawing的对象。同时,我们还定义了初始化方法,它接收box2d的world作为参数。

  然后在Terrain.m中添加一个新的方法,位置在generateHills上面:

- (void) resetBox2DBody {

if(_body) return;

CGPoint p0 = _hillKeyPoints[0];
CGPoint p1 = _hillKeyPoints[kMaxHillKeyPoints-1];

b2BodyDef bd;
bd.position.Set(0, 0);
_body = _world->CreateBody(&bd);

b2PolygonShape shape;
b2Vec2 ep1 = b2Vec2(p0.x/PTM_RATIO, 0);
b2Vec2 ep2 = b2Vec2(p1.x/PTM_RATIO, 0); 
shape.SetAsEdge(ep1, ep2);
_body->CreateFixture(&shape, 0);
}

  这里仅仅是一个辅助方法,用来创建山丘的的底部body,代表“地面”。这里只是暂时用这个方法,用来防止随机生成的圆会掉到屏幕之外去。之后,在我们建模好山丘后,我们会再次修改。

  目前,我们只是把第一个关键点和最后一个关键点用一条边连接起来。

  接下来,在Terrain.m中添加一些代码来调用上面的代码,同时建立起debug drawing:

// Add inside resetHillVertices, right after "prevToKeyPointI = _toKeyPointI" line:
[self resetBox2DBody];

// Add new method above init
- (void)setupDebugDraw { 
_debugDraw =new GLESDebugDraw(PTM_RATIO*[[CCDirector sharedDirector] contentScaleFactor]);
_world->SetDebugDraw(_debugDraw);
_debugDraw->SetFlags(b2DebugDraw::e_shapeBit | b2DebugDraw::e_jointBit);
}

// Replace init with the following
- (id)initWithWorld:(b2World *)world {
if ((self = [super init])) {
_world = world;
[self setupDebugDraw];
[self generateHills];
[self resetHillVertices];
}
return self;
}

// Add at bottom of draw
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

_world->DrawDebugData();

glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

  每一次山丘顶点被重置的时候,我们调用resetBox2DBody来创建可见部分山丘的body。目前,这个body是不变的(它只是添加了一条线,当作地面)。但是,接下来,我们将修改这个来建模可见部分的山丘。

  setupDebugDraw方法设置了激活box2d 对象debug drawing所需要的一些配置。如果你熟悉box2d的话,那么这个就是回顾啦。

  然后,你可能会奇怪,为什么debug draw的代码要放在Terrain.m文件中呢?而不是放在HelloWorldLayer.mm中呢?这是因为,这个游戏中的滚动效果是在Terrain.m中实现的。因此,为了使box2d的坐标系统和屏幕范围内可见部分的坐标系统匹配起来,我们就把debug drawing代码放在Terrain.m中了。

  最后一步,如果你现在想要编译的话,可能会出现几百个错误。这是因为Terrain.m导入了Terrain.h文件,而Terrain.h文件又包含了HelloWorldLayer.h文件,而它又导入了Box2D.h头文件。而不管什么时候,只要你在.m文件中使用c++的话,那么就会产生一大堆的错误。

  不过还好,解决办法非常简单---只要把Terrain.m改成Terrain.mm就可以了。

  编译并运行,现在,你点击一下屏幕,你会看到许多圆形对象掉在屏幕里面拉!

在box2d里面为山丘定义body边界

  现在,我们只拥有一个box2d的shape代表屏幕的底部边界,但是,我们真正想要的是代表山丘边界的shape。

  幸运的是,因为我们拥有所有的线段了,所以添加边界会非常简单!

  • 我们有一个山丘顶部所有顶点的数组(borderVertices). 在上一个教程的resetHillVertices方法中,我们生成了这样一个数组。
  • 我们有一个方法,不管什么时候顶点为被改变了,它都会被调用,那就是resetBox2DBody.

  因此,我们需要修改resetBox2DBody方法,我们要为borderVertices组织中的每一个实体创建一条边,具体方法如下:

- (void) resetBox2DBody {

if(_body) {
_world->DestroyBody(_body);
}

b2BodyDef bd;
bd.position.Set(0, 0);

_body = _world->CreateBody(&bd);

b2PolygonShape shape;

b2Vec2 p1, p2;
for (int i=0; i<_nBorderVertices-1; i++) {
p1 = b2Vec2(_borderVertices[i].x/PTM_RATIO,_borderVertices[i].y/PTM_RATIO);
p2 = b2Vec2(_borderVertices[i+1].x/PTM_RATIO,_borderVertices[i+1].y/PTM_RATIO);
shape.SetAsEdge(p1, p2);
_body->CreateFixture(&shape, 0);
}
}

  这个新的实现首先看看是不是存在一个已有的box2d body,如果是的话,就销毁原来的body。

  然后,它创建一个新的body,循环遍历border vertices数组里面的所有顶点,这些顶点代表山丘顶部。对于每2个顶点,都将创建一条边来连接它们。

  很简单,对不对?编译并运行,现在,你可以看到一个带有斜坡的box2d body了,而且它沿着山丘的纹理边界。

添加海豹

  我们之前把工程命名为Tiny Seal,可是并没有seal 啊!

  接下来,让我们把海豹添加进去!

  首先,下载并解压这个工程的资源文件,然后把"Sprite sheets“和"Sounds“直接拖到工程里去,对于每一个文件夹,都要确保“Copy items into destination group’s folder”被复选中,然后点击"Finish”。

  然后,点击File\New\New File,选择iOS\Cocoa Touch\Objective-C class,再点Next。选择CCSprite作为基类,再点Next,然后把文件命名为Hero.mm(注意,.mm是因为我们将使用到box2d的东西),最后点击Finish.

  接着,把Hero.h替换成下面的内容:

#import"cocos2d.h"
#import"Box2D.h"

#define PTM_RATIO 32.0

@interface Hero : CCSprite {
b2World *_world;
b2Body *_body;
BOOL _awake;
}

- (id)initWithWorld:(b2World *)world;
- (void)update;

@end

  这个也非常简单---只是导入box2d.h头文件,然后定义一些变量来追踪world和海豹的body.

  然后,打开Hero.mm,然后作如下修改:

#import"Hero.h"

@implementation Hero

- (void)createBody {

float radius =16.0f;
CGSize size = [[CCDirector sharedDirector] winSize];
int screenH = size.height;

CGPoint startPosition = ccp(0, screenH/2+radius);

b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.linearDamping =0.1f;
bd.fixedRotation =true;
bd.position.Set(startPosition.x/PTM_RATIO, startPosition.y/PTM_RATIO);
_body = _world->CreateBody(&bd);

b2CircleShape shape;
shape.m_radius = radius/PTM_RATIO;

b2FixtureDef fd;
fd.shape =&shape;
fd.density =1.0f;
fd.restitution =0.0f;
fd.friction =0.2;

_body->CreateFixture(&fd);

}

- (id)initWithWorld:(b2World *)world {

if ((self = [super initWithSpriteFrameName:@"seal1.png"])) {
_world = world;
[self createBody];
}
return self;

}

- (void)update {

self.position = ccp(_body->GetPosition().x*PTM_RATIO, _body->GetPosition().y*PTM_RATIO);
b2Vec2 vel = _body->GetLinearVelocity();
b2Vec2 weightedVel = vel;
float angle = ccpToAngle(ccp(vel.x, vel.y)); 
if (_awake) { 
self.rotation =-1* CC_RADIANS_TO_DEGREES(angle);
}
}

@end

  createBody方法为海豹创建了一个圆形的shape。这个方法和之前写过的createTestBodyAtPosition方法几乎没有什么区别,除了圆的大小和海豹图片的大小要匹配(不过实际上要比图片大小小一些,这样子碰撞检测效果会更好)

  同时,这里的摩擦系数(friction)设置为0.2(因为海豹是很滑的),同时反弹系数(restitution)设置为0(这样子,当海豹碰撞到山丘的时候就不会反弹起来了)。

  同时,我们也设置body的线性阻尼( linear damping),这样子海豹就会随着时间慢慢减速。同时,设置body的固定旋转为真,这样子,海豹在游戏里面就不会旋转body了。

  在initWithWorld方法里面,我们把精灵初始化为一个特定的精灵帧(seal1.png),同时保存一份world的指针,然后调用上面的createBody方法。

  这里的update方法基于box2d body的位置来更新海豹精灵的位置,同时基于海豹的body的速度来更新海豹精灵的旋转。

  接下来,你需要修改一下Terrain.h和Terrain.mm,因为,我们将要在Terrain.mm中添加一个sprite batch node。

  首先,打开Terrain.h,并作以下修改:

// Inside @interface
CCSpriteBatchNode * _batchNode;

// After @implementation
@property (retain) CCSpriteBatchNode * batchNode;

  然后,打开Terrain.mm,并作如下修改:

// Add to top of file
@synthesize batchNode = _batchNode;

// Add at bottom of init
_batchNode = [CCSpriteBatchNode batchNodeWithFile:@"TinySeal.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"TinySeal.plist"];

  这里只是为TinySeal.png精灵表单创建了一个batch node,然后从TinySeal.plist文件中加载了精灵帧的定义信息到sprite frame cache中。

  差不多完成了!接下来,让我们修改HelloWorldLayer.h:

// Add to top of file
#import"Hero.h"

// Add inside @interface
Hero * _hero;

  同时修改HelloWorldLayer.mm:

// Add to bottom of init
_hero = [[[Hero alloc] initWithWorld:_world] autorelease];
[_terrain.batchNode addChild:_hero];

// In update, comment out the three lines starting with PIXELS_PER_SECOND and add the following
[_hero update];
float offset = _hero.position.x;

  编译并运行,你现在可以看到一只happy的海豹在屏幕左边了!

  但是,看起来有起奇怪,它在屏幕之外!如果我们把它往右边挪一下,那样子看起来会更好。

  当然,这个改起来很简单!打开Terrain.mm,然后把setOffsetX改成下面的样子:

- (void) setOffsetX:(float)newOffsetX {
CGSize winSize = [CCDirector sharedDirector].winSize;

_offsetX = newOffsetX;
self.position = CGPointMake(winSize.width/8-_offsetX*self.scale, 0);
[self resetHillVertices];
}

  这里把海豹的位置旋转在屏幕的1/8处,这样子海豹看起来就会往右边一点点了。编译并运行,现在可以看到海豹的全貌啦!

使海豹移动

  我们离一个完整的游戏越来越近了---我们有一只海豹,我们只需要让它飞起来就可以啦!

  我们采取的策略如下:

  • 第一次点击屏幕的时候,我们让海豹稍微往右边跳起来一点点,代表开始了!
  • 不管什么时候点击屏幕,我们应用一个冲力使海豹往下落。当海豹下山时,会使它的速度变得更快,这样到下一个山头的时候就可以飞起来了。
  • 添加一些代码让海豹移动的距离稍微远一点,我们可不想让我们的海豹卡住!

  让我们来实现这些策略吧!打开Hero.h,作如下修改:

// Add after @implementation
@property (readonly) BOOL awake;
- (void)wake;
- (void)dive;
- (void)limitVelocity;

  然后对Hero.mm作如下修改:

// Add to top of file
@synthesize awake = _awake;

// Add new methods
- (void) wake {
_awake = YES;
_body->SetActive(true);
_body->ApplyLinearImpulse(b2Vec2(1,2), _body->GetPosition());
}

- (void) dive {
_body->ApplyForce(b2Vec2(5,-50),_body->GetPosition());
}

- (void) limitVelocity { 
if (!_awake) return;

constfloat minVelocityX =5;
constfloat minVelocityY =-40;
b2Vec2 vel = _body->GetLinearVelocity();
if (vel.x < minVelocityX) {
vel.x = minVelocityX;
}
if (vel.y < minVelocityY) {
vel.y = minVelocityY;
}
_body->SetLinearVelocity(vel);
}

  这个wake方法应用一个冲力(impulse)使得海豹刚开始往右上方飞。

  dive方法应用一个比较大的向下的冲力,和一个比较小的向右的力。这个向下的冲力会使得海豹往山丘上撞,这时,山丘的斜坡越大,那么小鸟就飞得越高。(应该是上山的时候,下山相反)

  limitVelocity方法确保海豹速度至少在 x轴方向5m/s²,Y轴方向-40m/s²。

  基本上要完成了---只需要再修改一下HelloWorldLayer类。首先打开HelloWorldLayer.h,然后添加一个新的实例变量:

BOOL _tapDown;

  同时修改HelloWorldLayer.mm:

// Add at the top of the update method
if (_tapDown) {
if (!_hero.awake) {
[_hero wake];
_tapDown = NO;
} else {
[_hero dive];
}
}
[_hero limitVelocity];

// Replace ccTouchesBegan with the following
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self genBackground];
_tapDown = YES; 
}

// Add new methods
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
_tapDown = NO; 
}

- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
_tapDown = NO;
}

  编译并运行,现在你有一只可以飞的海豹啦!

修正海豹身体的摇晃

  你可能注意到了,当海豹往下飞的时候,身体摇摇晃晃的。

  一种方式就是,使用之前的线性速度和现在得到的速度作加权平均。

  让我们来实现一下。先打开Hero.h:

// Add to top of file
#define NUM_PREV_VELS 5

// Add inside @interface
b2Vec2 _prevVels[NUM_PREV_VELS];
int _nextVel;

  然后修改Hero.mm的update方法:

- (void)update {

self.position = ccp(_body->GetPosition().x*PTM_RATIO, _body->GetPosition().y*PTM_RATIO);
b2Vec2 vel = _body->GetLinearVelocity();
b2Vec2 weightedVel = vel;

for(int i =0; i < NUM_PREV_VELS; ++i) {
weightedVel += _prevVels[i];
}
weightedVel = b2Vec2(weightedVel.x/NUM_PREV_VELS, weightedVel.y/NUM_PREV_VELS); 
_prevVels[_nextVel++] = vel;
if (_nextVel >= NUM_PREV_VELS) _nextVel =0;

float angle = ccpToAngle(ccp(weightedVel.x, weightedVel.y)); 
if (_awake) { 
self.rotation =-1* CC_RADIANS_TO_DEGREES(angle);
}
}

  这里使用之前的5个线性速度作加权平均,然后使用平均值来修正海豹的旋转。编译并运行,现在你可以看到更加平滑的海豹啦!

缩小

  Tiny Wings有一个很酷的特性就是,你飞得越高,那么屏幕就会越小。这使得视觉感观更加逼真!

  为了实现这个,我们只需要在HelloWorldLayer.mm的update方法里面的[_hero update]调用之后,再添加下面代码就行了:

CGSize winSize = [CCDirector sharedDirector].winSize;
float scale = (winSize.height*3/4) / _hero.position.y;
if (scale >1) scale =1;
_terrain.scale = scale;

  如果hero在winSize.height*3/4以下,那么scale就为1.如果它大于winSize.height*3/4,那么scale就会小于1,就会有缩小的感觉了。

  编译并运行,现在看看你能飞多高吧!

免费的动画和音乐

  你懂的,我不能让你们这些粉丝没有一些免费的动画和音乐可玩。:)

  只需要花上几秒钟的时间就可以使游戏变得更有趣!首先,打开Hero.h,并作如下修改:

// Add inside @interface
CCAnimation *_normalAnim;
CCAnimate *_normalAnimate;

// Add after @interface
- (void)nodive;
- (void)runForceAnimation;
- (void)runNormalAnimation;

  这里声明我们即将创建的动画,还有一个新方法将在海豹没有diving的时候被调用。

  接下来,修改Hero.mm:

// Add new methods
- (void)runNormalAnimation {
if (_normalAnimate ||!_awake) return;
_normalAnimate = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:_normalAnim]];
[self runAction:_normalAnimate];
}

- (void)runForceAnimation {
[_normalAnimate stop];
_normalAnimate = nil;
[self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"seal_downhill.png"]];
}

- (void)nodive {
[self runNormalAnimation];
}

// Add at bottom of initWithWorld:
_normalAnim = [[CCAnimation alloc] init];
[_normalAnim addFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"seal1.png"]];
[_normalAnim addFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"seal2.png"]];
_normalAnim.delay =0.1;

  

  这里为海豹的正常飞行创建了动画效果,同时添加一个方法来播放这个动画。diving动画实际上只是一个精灵帧,因此我们添加了一个辅助方法来完成divng动画的播放。

  最后,我们修改一下HelloWorldLayer.mm:

// At top of file
#import"SimpleAudioEngine.h"

// At end of init
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"TinySeal.caf" loop:YES];

// At start of update, add an else case for the if (_tapDown):
else {
[_hero nodive];
}

// Inside ccTouchesBegan
[_hero runForceAnimation];

// Inside ccTouchesEnded AND ccTouchesCancelled
[_hero runNormalAnimation];

  最后,打开Terrian.mm,注释掉draw方法里面的_world->DrawDebugData。

  编译并运行代码,大功造成了!

何去何从?

  这里有本系列教程的全部源代码。

  到目前为止,你有一个基本的游戏框架可以玩了。为什么不尝试着完善这个游戏呢?把海豹移动的行为修改得更加逼真、更加平滑一些?或者,你可以添加一些物品和道具,充分发挥你的想象力吧!

  如果你扩展了本项目,不妨拿出来分享一下,大家一起学习一下吧!

(译)如何制作一个类似tiny wings的游戏:第二部分(完) - 子龙山人 ...相关推荐

  1. 如何制作一个类似Tiny Wings的游戏 Cocos2d-x 2.1.4

    在第一篇<如何使用CCRenderTexture创建动态纹理>基础上,增加创建动态山丘,原文<How To Create A Game Like Tiny Wings with Co ...

  2. 如何制作一个类似Tiny Wings的游戏 Cocos2d-x 2 1 4

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在第一篇 ...

  3. 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4内含iOS版源代码

    在第二篇<如何制作一个类似Tiny Wings的游戏>基础上,增加添加主角,并且使用Box2D来模拟主角移动,原文<How To Create A Game Like Tiny Wi ...

  4. 如何制作一个类似Tiny Wings的游戏(2) Cocos2d-x 2.1.4

    在第二篇<如何制作一个类似Tiny Wings的游戏>基础上,增加添加主角,并且使用Box2D来模拟主角移动,原文<How To Create A Game Like Tiny Wi ...

  5. (译)如何制作一个类似tiny wings的游戏:第一部分

    免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作 ...

  6. 制作一个类似苹果VFL的格式化语言来描述UIStackView

    在项目中总是希望页面上各处的文字,颜色,字体大小甚至各个视图控件布局都能够在发版之后能够修改以弥补一些前期考虑不周,或者根据统计数据能够随时进行调整,当然是各个版本都能够统一变化.看到这样的要求后,第 ...

  7. 如何制作一个横版格斗过关游戏 2 Cocos2d x 2 0 4

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在第一篇 ...

  8. 如何制作一个横版格斗过关游戏(2) Cocos2d-x 2.0.4 .

    本文原创版权归 csdn 无幻 所有,转载请详细标明原创作者及出处,以示尊重! 作者:无幻 原文:http://blog.csdn.net/akof1314/article/details/85725 ...

  9. 如何制作一个横版格斗过关游戏(2) Cocos2d-x 2.0.4

    在第一篇<如何制作一个横版格斗过关游戏>基础上,增加角色运动.碰撞.敌人.AI和音乐音效,原文<How To Make A Side-Scrolling Beat 'Em Up Ga ...

  10. Unity 4 3 制作一个2D横版射击游戏 2

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在上一篇 ...

最新文章

  1. leetcode 1: 找出两个数相加等于给定数 two sum
  2. SAP:2019年会有多么不一样?
  3. day36 Pyhton 网络编程03
  4. [蓝桥杯2017决赛]数位和-模拟(水题)
  5. oracle的空闲等待事件,Oracle 常见的33个等待事件详解
  6. 看完就会明白windows RT推出的原因、它和window 8到底有些什么区别、微软有什么战略企图--有关于微软Windows RT 你不知道的那些事
  7. 485串口测试工具软件_(案例)电脑和仪表之间485通讯的奇怪现象及解决方案
  8. Flex布局使用总结
  9. Dxg——C# 开发笔记整理分类合集【所有的相关记录,都整理在此】
  10. app逆向 安卓开发环境搭建
  11. 几个不错的网站(转)
  12. 奔图 Pantum M6550 打印机驱动
  13. 斐波那契数列(Fibonacci)
  14. 移动硬盘读取速度突然变慢?教你7个方法解决
  15. LWN:替换 congestion_wait()!
  16. CCF201809-1 卖菜(JAVA)
  17. 机械臂编程_建立自己的机械臂-编程
  18. Unity生成随机数
  19. 九龙证券|又3个涨停,退市风险急升!
  20. matlab命令中什么时候加分号

热门文章

  1. 收藏 :数据资源下载网址大全
  2. 常用EXCEL函数公式入门
  3. NodeJs安装教程:看教程一步步学会安装NodeJs
  4. 对外汉语语料库有哪些_国内外有哪些比较好的语料库?(corpora)
  5. Linux下破解UE
  6. STM32 学习周记
  7. UNI-APP 小程序生成海报
  8. s3c2440linux2.6mmc/sd驱动程序
  9. ioccc代码分析(1)
  10. Messagebox用法