如何制作一个类似tiny framework 类似wings的游戏

(译)如何制作一个类似tiny wings的游戏:第二部分(完)
时间: 22:46:26
&&&& 阅读:274
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
免责申明(必读!):本博客提供的所有教程的翻译原稿均来自于互联网,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作!
原文链接地址:
教程截图:
  这是本系列教程的最后一部分,主要是教大家如何制作一个类似的游戏。
  在中,我们学会了如何创建动态山丘纹理和背景纹理。
  在教程中,我们学会了如何动态创建游戏里所需要的山丘。
  在这篇教程中,也是本系列教程的最后一篇,我们将会学习到更加有意思的部分---如何往游戏里面添加主角,同时使用BOX2D来仿真主角的移动!
  再说明一下,这个教程系列是基于所写的一个非常好的制作的---所以我要特别感谢Sergey!
  这个教程假设你对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 @interfaceb2World&*&_
  这里包含了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 testBodyD testBodyDef.type&=&b2_dynamicB
testBodyDef.position.Set(position.x/PTM_RATIO,
position.y/PTM_RATIO);
b2Body&*&testBody&=&_world-&CreateBody(&testBodyDef);b2CircleShape
testBodyS b2FixtureDef testFixtureD testBodyShape.m_radius&=25.0/PTM_RATIO;
testFixtureDef.shape&=&testBodyS
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 updatestaticdouble&UPDATE_INTERVAL&=1.0f/60.0f;
staticdouble&MAX_CYCLES_PER_FRAME&=5;
staticdouble&timeAccumulator&=0;timeAccumulator&+=&&
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
ccTouchesBeganUITouch&*anyTouch&=&[touches anyObject]; CGPoint
touchLocation&=&[_terrain
convertTouchToNodeSpace:anyTouch]; [self
createTestBodyAtPostition:touchLocation];
  第一段代码,我们调用setupWorld方法来创建一个box2d世界。然后使用box2d的world来初始化Terrain类。这样,我们就可以使用这个world来创建山丘的body了。为此,我们将会写一些桩代码(placeholder)。
  第二段代码,我们调用_world-&Step方法来运行物理仿真。注意,这里使用的是固定时间步长的实现方式,它比变长时间步长的方式物理仿真效果要更好。对于具体这个是怎么工作的,可以去看看我们的书籍中关于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 @interfaceb2World&*_
GLESDebugDraw&*&_debugD//&Add after @interface-&(id)initWithWorld:(b2World&*)
  这里只是包含box2d头文件,然后创建一些实例变量来追踪box2d的world,以及山丘的body,还有支持debug
drawing的对象。同时,我们还定义了初始化方法,它接收box2d的world作为参数。
  然后在Terrain.m中添加一个新的方法,位置在generateHills上面:
resetBox2DBody {if(_body)&return;CGPoint
p0&=&_hillKeyPoints[0];
CGPoint p1&=&_hillKeyPoints[kMaxHillKeyPoints-1];b2BodyDef
bd.position.Set(0,&0);
_body&=&_world-&CreateBody(&bd);b2PolygonShape
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
//&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&=& [self setupDebugDraw]; [self
generateHills]; [self resetHillVertices]; } return& }//&Add at bottom of drawglDisable(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组织中的每一个实体创建一条边,具体方法如下:
resetBox2DBody {if(_body)
{ _world-&DestroyBody(_body);
}b2BodyD bd.position.Set(0,&0);_body&=&_world-&CreateBody(&bd);b2PolygonShape
b2Vec2 p1, p2; for&(int&i=0;
i&_nBorderVertices-1;
{ 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&*_
BOOL _ }-&(id)initWithWorld:(b2World&*)
-&(void)@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.CGPoint
startPosition&=&ccp(0,
screenH/2+radius);b2BodyDef
bd.type&=&b2_dynamicB bd.linearDamping&=0.1f;
bd.fixedRotation&=true;
bd.position.Set(startPosition.x/PTM_RATIO,
startPosition.y/PTM_RATIO);
_body&=&_world-&CreateBody(&bd);b2CircleShape
shape.m_radius&=&radius/PTM_RATIO;b2FixtureDef
fd.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&=& [self createBody]; }
return&}-&(void)update
{self.position&=&ccp(_body-&GetPosition().x*PTM_RATIO,
_body-&GetPosition().y*PTM_RATIO);
b2Vec2 vel&=&_body-&GetLinearVelocity();
b2Vec2 weightedVel&=& float&angle&=&ccpToAngle(ccp(vel.x, vel.y));& if&(_awake) {&
self.rotation&=-1*&CC_RADIANS_TO_DEGREES(angle); }
  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 @interfaceCCSpriteBatchNode&*&_batchN//&After @implementation@property
(retain) CCSpriteBatchNode&*&batchN
  然后,打开Terrain.mm,并作如下修改:
//&Add to top of file@synthesize&batchNode&=&_batchN//&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 @interfaceHero&*&_
  同时修改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改成下面的样子:
setOffsetX:(float)newOffsetX
{ CGSize winSize&=&[CCDirector
sharedDirector].winS_offsetX&=&newOffsetX; self.position&=&CGPointMake(winSize.width/8-_offsetX*self.scale,&0);
[self resetHillVertices]; }
  这里把海豹的位置旋转在屏幕的1/8处,这样子海豹看起来就会往右边一点点了。编译并运行,现在可以看到海豹的全貌啦!
使海豹移动
  我们离一个完整的游戏越来越近了---我们有一只海豹,我们只需要让它飞起来就可以啦!
  我们采取的策略如下:
第一次点击屏幕的时候,我们让海豹稍微往右边跳起来一点点,代表开始了!
不管什么时候点击屏幕,我们应用一个冲力使海豹往下落。当海豹下山时,会使它的速度变得更快,这样到下一个山头的时候就可以飞起来了。
添加一些代码让海豹移动的距离稍微远一点,我们可不想让我们的海豹卡住!
  让我们来实现这些策略吧!打开Hero.h,作如下修改:
//&Add after @implementation@property
(readonly)
BOOL -&(void)
-&(void)limitV
  然后对Hero.mm作如下修改:
//&Add to top of file@synthesize&awake&=&_//&Add new methods-&(void)
wake { _awake&=&YES; _body-&SetActive(true);
_body-&ApplyLinearImpulse(b2Vec2(1,2),
_body-&GetPosition());
dive { _body-&ApplyForce(b2Vec2(5,-50),_body-&GetPosition());
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/s2,Y轴方向-40m/s2。
  基本上要完成了---只需要再修改一下HelloWorldLayer类。首先打开HelloWorldLayer.h,然后添加一个新的实例变量:
  同时修改HelloWorldLayer.mm:
//&Add at the top of the update
methodif&(_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 @interfaceb2Vec2
_prevVels[NUM_PREV_VELS]; int&_nextV
  然后修改Hero.mm的update方法:
-&(void)update
{self.position&=&ccp(_body-&GetPosition().x*PTM_RATIO,
_body-&GetPosition().y*PTM_RATIO);
b2Vec2 vel&=&_body-&GetLinearVelocity();
b2Vec2 weightedVel&=&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++]&=& 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个线性速度作加权平均,然后使用平均值来修正海豹的旋转。编译并运行,现在你可以看到更加平滑的海豹啦!
Wings有一个很酷的特性就是,你飞得越高,那么屏幕就会越小。这使得视觉感观更加逼真!
  为了实现这个,我们只需要在HelloWorldLayer.mm的update方法里面的[_hero
update]调用之后,再添加下面代码就行了:
winSize&=&[CCDirector sharedDirector].winS
float&scale&=&(winSize.height*3/4)&/&_hero.position.y; if&(scale&&1)
_terrain.scale&=&
  如果hero在winSize.height*3/4以下,那么scale就为1.如果它大于winSize.height*3/4,那么scale就会小于1,就会有缩小的感觉了。
  编译并运行,现在看看你能飞多高吧!
免费的动画和音乐
  你懂的,我不能让你们这些粉丝没有一些免费的动画和音乐可玩。:)
  只需要花上几秒钟的时间就可以使游戏变得更有趣!首先,打开Hero.h,并作如下修改:
//&Add inside @interfaceCCAnimation&*_normalA
CCAnimate&*_normalA//&Add after @interface-&(void)
-&(void)runForceA
-&(void)runNormalA
  这里声明我们即将创建的动画,还有一个新方法将在海豹没有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&=& [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。
  编译并运行代码,大功造成了!
  这里有本系列教程的。
  到目前为止,你有一个基本的游戏框架可以玩了。为什么不尝试着完善这个游戏呢?把海豹移动的行为修改得更加逼真、更加平滑一些?或者,你可以添加一些物品和道具,充分发挥你的想象力吧!
  如果你扩展了本项目,不妨拿出来分享一下,大家一起学习一下吧!
PS:译者水平有限,翻译不准的地方望不吝指出,谢谢!
著作权声明:本文由翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:/cooka/p/3559206.html
教程昨日排行
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!<!-- super cache发布时间: 11:53:31
来源:ptbus
  本篇Bouncetro游戏评测为玩家们介绍的是一款风格类似于Tiny Wings 的休闲游戏。游戏的主角是一只看起来有点像鱼的小生物,它拥有圆圆的脑袋,大眼睛和一个三角形的尾巴。游戏的玩法非常简单,玩家只需要点击屏幕控制角色向下俯冲滑行即可。
不一样的Tiny Wings 休闲类Bouncetro游戏评测
  游戏画面非常简洁,整个内容也很简单,只有无尽的关卡模式等待着玩家,而关卡则比较有趣,全部是由五颜六色的反弹面以及黑色的鼓面组成,上下不同的曲折坡度构成一条不断变化的通道,我们的主角&&姑且称它为大眼睛就要在这条通道上跳跃滑行前进。延绵不断的通道划分为不同的关卡,每一个关卡都有限定时间,当时间快要结束,画面就会慢慢变暗,全部黑下来的时候表示时间已经所剩无几,这时候还不能通过本关,游戏就要从头开始。
不一样的Tiny Wings 休闲类Bouncetro游戏评测
  游戏基本原理很清晰,就是按住屏幕控制好大眼睛的上升高度和俯冲,让它借助通道的斜坡获得速度,随后松开屏幕获得前行的力量。因为上下方都有屏障,所以也可以利用适当的反弹来加快前进速度。当然《Bouncetro》只有玩法和《Tiny Wings》相近,其他很多元素甚至关卡的细节都与后者有着很大不同,玩家在这里需要解决的是另外一种技巧,收获的也是不同的乐趣。
不一样的Tiny Wings 休闲类Bouncetro游戏评测
  在这里玩家获得的视听感受非常新鲜,当大眼睛撞击不同的&地面&以及&天花板&,都会发出不同的声音,撞击力度合适的话,就是一串清脆的音符倾泻而出,配合着游戏的节奏显得异常灵动欢快。游戏中不仅要抓紧时间过关,还要尽量收集到分散在不同地方的音符,或者依靠撞击使音符出现,音符的数量越多,你就可以在商店里交换到更多奖励。
不一样的Tiny Wings 休闲类Bouncetro游戏评测
  《Bouncetro》比《Tiny Wings》难玩的地方在于,如果你的操作不适当,不仅会让大眼睛的速度变得很缓慢,使本来愉快的滑行变成艰难的爬坡,甚至很多时候还会因为过多的反弹变得寸步难行。一些连续的拱坡往往会把你弹回去,如果这时候玩家过于急躁的按住屏幕想要摆脱困境,反而会加剧这种无用的反弹,白白浪费时间。
  这时候该肿么破呢?大家可以看到画面左侧的几个能力按钮,一开始你可能不知道它们到底有什么用处,事实上在顺利前行时你看不到它的作用。如果你碰到某些相对比较&危险&的情况,左侧几个能力会有所帮助,第一个是加速冲刺,让大眼睛短时间内获得迅猛的前进动力;第二个是瞬间向前位移一小段距离并且让大眼睛的身体恢复平衡;第三个是让大眼睛回到通道的较中间位置;第四个是获得轻微的前进动力。所以当你不慎在关卡中难以前进,可以快速的利用这几个不同按键让大眼睛继续前进。
不一样的Tiny Wings 休闲类Bouncetro游戏评测
   关卡中除了散布在各处的音符以外,也有冲刺道具和小鱼变身道具可以拿到。在商店里用音符来升级大眼睛的各项能力,可以帮助玩家到达更远的距离。另外还有各种不同的大眼睛小鱼供解锁,不同的小鱼具有不同的音色,所以玩起来又是另外一种美妙的声音。
不一样的Tiny Wings 休闲类Bouncetro游戏评测
  游戏刚开始可能会让人有点莫名其妙,因为没有过关指示也没有关于使用能力的说明,但是多玩几遍你就能体会到和《Tiny Wings》一样的休闲乐趣但是又能从中体会不同的游戏元素,画面和声音都极具治愈效果,推荐尝试。
巴士手游(了解更多游戏资讯)

我要回帖

更多关于 tinypng 类似 的文章

 

随机推荐