(译)如何使用cocos2d制作一个Slide Image Game
2013-04-12 14:37
411 查看
转自:/article/4834761.html
原文链接地址:http://www.iphonegametutorials.com/2010/09/23/cocos2d-game-tutorial-building-a-slide-image-game/
教程截图:
这是一张完整的图片:
这是一张打乱了的图片:
PS:为了方便大家更好地交流学习cocos2d,一位热心的网友组建了一个ios游戏开发交流群,群号见博客右边。以后大家有问题可以去群里面讨论。想加入翻译工作的朋友也可以加群,以后有教程更新和翻译相关内容,都会在群里面讨论。另外,我翻译这些教程的目的,是希望和大家更好地交流学习心得,帮助新手更好地入门。其实游戏开发,我还是推荐大家看E文,因为大部分资料都是E文的,不可能全部有人替你翻译。
已经有一周时间没有出教程了,在这篇新的教程中,我们将征服一个新的游戏---滑动图片游戏。你肯定知道这是一个什么样的游戏,玩家的任务就是先把一张图片打乱,然后再把打乱的图片拼好。(当然,教程结束后,诸位可以改进,用程序把图片打乱,然后再让玩家直接还原图片,最好弄个完整的图片作参考啊!^^)制作这种类型的游戏,最大的好处就是可以为我们接下来学习和理解Tiled Map游戏做铺垫。(不过事实正好相反,我先翻译了Tiled Map的游戏教程,不过也没关系)
那么,为了制作一个这样的游戏,我们需要做哪些事情呢?下面就是制作这个滑动图片游戏的步骤列表:
创建一个“Tile”类,它包含sprite,position(x,y)和value这些实例变量。
创建一个管理类,它负责创建所有的Tile,同时可以追踪所有的Tile的状态。
添加touch组件,这样玩家可以交换两个tile的位置。
添加一些代码来随机加载图片,这样游戏可以有更多的花样。
就这么多,当我把步骤写出来的时候,是不是觉得很简单?(译者:补充一点,看我教程的朋友,不要仅仅局限于具体的技术细节,要多想想游戏创作的步骤,这个游戏有4步,你的游戏需要几步呢?多思考,这样就不会看着教程能做,没教程就无从下手了)接下来,我会一步步实现所有的功能,你会发现其实真的也很简单。
这里有第二部分,也就是本教程完整源代码,你们可以先下下来,看看什么效果。
这里是这篇教程的源代码。
讲了那么多,可能你还不知道我们要做一个什么样的游戏,下载完整源代码,可以帮助大家都本系列教程将要完成的产品有一个完整的认识,这很重要。。。
说真的,这个简单的游戏例子,能给你很多启发。。。今后,我将会基于这个系列的教程,给你们介绍更多的这种类型的游戏(译者:比如拼图啦,华容道啦,推箱子啦,连连看啦)
不管怎么说,先让我们实现这个游戏再说!为了完成了这个艰巨的任务,我们需要一些辅助类。这些类是Tile.h, Tile.m, Box.h, Box.m。
如果你看了我博客上其它教程的话,你肯定已经知道“SceneManager”和"PlayLayer“类了,这里就不再啰嗦了。如果还没有的话,请参考《cocos2d菜单教程》和《cocos2d精灵教程》。
首先,先让我们看看Tile类的实现。
Tile.h:
tile类主要就是代表从一张大图里面提取出来的一小块内容,有X,Y位置(注意,这里的x,y坐标不等于精灵的位置坐标,精灵的位置坐标是sprite.position),有精灵,有value。这里的value可以是任何值 ,比如可以代表每个tile在原图中的位置(这样的话,我们就可以用这些位置来判断玩家是否正确拼成完整的图了),在这个版本中,我们暂时不会使用这个value;
现在,让我们看看其具体实现:
Tile.m:
大部分内容一看就能明白--我们实现了四个方法 “initWithX”, “nearTile”, “trade” and “pixPosition”.
“initWithX”方法,从名字就可以看出来它是做什么的---它是Tile类的初始化代码,它Tile类被初始化的时候被调用。它接收一个x,y值,这两个值和世界坐标无关,而是与包含它们的Box类有关。举个例子,我们使用 initWithX:3 Y:4,假如我们的box是7*7的话,那么,这个Tile被放置在3,4号位置)我们可以用pixPosition函数来计算每个Tile的精灵在屏幕上的位置。
“nearTile”接收一个Tile类型的参数,判断两个Tile是否是邻居,如果是,就返回YES,否则返回NO。
“trade”就是把两个Tile的精灵交换一下。交换两个变量,相信学过C语言的都会,定义一个临时变量temp,然后temp = a; a=b; b=temp;
最后,“pixPosition”计算得到每个Tile的精灵在屏幕上的正确的坐标位置---你将会在后面看到这个函数的特殊用途。
Box类的主要功能就是处理所有单个Tile类的创建,加载相应精灵,以及把它们放置在屏幕上的正确位置。
Box.h:
单看头文件,有些内容你也可以猜到它的作用了。。。size就是我们将要创建的网格的大小(3*3, 4*5, 5*3,7*7等等)
Box类最主要的两个变量就是“content”和“readyToRemove”。
content变量实际上是一个多维数组,至少也是一维(如果SIZE为1*1的话)。我们将创建一个NSMutableArray代码列,然后会在每一列中再加入一个NSMutableArray作为一行。我们可以使用 “return [[content objectAtIndex: y] objectAtIndex: x];”来得到正确的Tile。
readyToRemove变量,在这个教程中,只是初始化了,但是,今后,我会介绍另一个游戏,在那里面我会大量使用这个变量----在这个教程中,我将使用它加载所有新创建的精灵。
接下来,让我们看看Box类的具体实现:
Box.m:
那么,这个类到底做了些什么事呢---我认为"initWithSize" 和 "getObjectAt" 这两个方法已经很清楚了。。这里就不再啰嗦了。
因此,最重要的方法---check。首先,我们判断readyToRemoveTiles数组中是否包含任何Tiles。。在我们这个例子中,所有的Tile都在里面。。。非常好!然后我们遍历这个数组里面所有的元素,把其中的精灵一个个全部清除掉,最后,我们把整个数组里的元素全部清空。现在,你可能知道了,当制作一个游戏的多个关卡的时候,如何做好清理化工作了。
接下来,我们从资源文件中加载纹理(比如1.png, 2.png, 3.png等等),然后把它们存储在一个CCTexture2D对象中,之后我们会从CCTexture2D对象来构建所有的精灵帧。我们将创建49个精灵帧。因为我们的图片大小是280*280,所以每个CCSpriteFrame大小就是40*40。这里面用了一个双重for循环。
上面这部分代码,对于本教程来说,其实并不是必须的,但是,它可以用来判断有多少Tile需要替换图片。这种机制非常好,尤其是当你制作一个Tile drop游戏(比如宝石迷阵)的时候,因为你不想一次替换掉所有的Tile。。。在本例中,我们将检测Tile的value属性是否为0,然后用extension变量来追踪有多少个value为0的Tile。在本例中,由于所有的Tile都存在了readyToRemoveTiles中,所以extension变量永远都是7。
下面,我们得到第一个Y坐标为(kBoxHeight-extension+i)的Tile。。因为,在我们的例子中, kBoxHeight = 7,而extension总是为7,所以,我们实际上只需要关心变量i就可以了。i会从0一直递增到6.好了,你可能会问,为什么我要这样?因为,我会在其实游戏中使用到,如果现在我们就熟悉了的话,以后的工作会很轻松:)。接下来,看看精灵是如何工作的吧。。。
然后,我们创建了新的CCSprite,通过给定的CCSpriteFrame,并且把精灵放置在box的合适的位置。我们把所有的Tile的imgValue都设置成一样的。
最后,看看PlayLayer类,我们应该很熟悉了。。。它将会处理touches,以及box类的初始化工作。我们需要追踪前面两次touch--“selectedTile”变量指代玩家当前选择的Tile,这时候,如果玩家选择另外一个Tile的时候,就会和前面的Tile进行交换。接下来,看看具体实现吧。
PlayLayer.h:
接下来是其实现:
PlayLayer.m:
这个类中主要有3个方法---init方法用来初始化box类,ccTouchesBegan方法,决定哪个Tile被用户选择,如果新选择的Tile等于原Tile的话就直接返回;如果是邻近的Tile的话,就交换;否则,就不做任何事情。交换Tile的时候,调用CCSequence 和 CCMoveTo来展示交换的动画。实际上,我们真正交换的代码只有[a trade b]。
首先,在tile.h中,我们需要添加一个新的变量“originalValue”,用来保存Tile的初始位置。这样的话,当你把Tile打乱的时候,我们就可以使用这个位置与新的位置作比较,以此来判断玩家是否完成拼图。
接下来,我们打开box.m,然后在check函数的底部,作下面的修改:
如果你是直接从第一个工程的源代码进行修改的话,那么,原来的代码如下所示:
在你完成这些修改以后,我们还有最后一件事件需要做,就是在box.m里面添加一个新的函数,用来判断游戏状态。
这里就是遍历所有的Tiles,然后比较value和originalValue的值,如果全部相等,则表明成功解谜,否则,就表明失败。
最后,在PlayLayer.m中,我们在ChangeTileWithA方法里面添加下面的代码:
这样,每一次你交换两个小图片的时候,都会判断一下游戏的状态,同时用CCLabel显示在屏幕上面。
如果大家有什么问题,请留言。
下篇教程见!
著作权声明:本文由http://www.cnblogs.com/andyque翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!
原文链接地址:http://www.iphonegametutorials.com/2010/09/23/cocos2d-game-tutorial-building-a-slide-image-game/
教程截图:
这是一张完整的图片:
这是一张打乱了的图片:
PS:为了方便大家更好地交流学习cocos2d,一位热心的网友组建了一个ios游戏开发交流群,群号见博客右边。以后大家有问题可以去群里面讨论。想加入翻译工作的朋友也可以加群,以后有教程更新和翻译相关内容,都会在群里面讨论。另外,我翻译这些教程的目的,是希望和大家更好地交流学习心得,帮助新手更好地入门。其实游戏开发,我还是推荐大家看E文,因为大部分资料都是E文的,不可能全部有人替你翻译。
已经有一周时间没有出教程了,在这篇新的教程中,我们将征服一个新的游戏---滑动图片游戏。你肯定知道这是一个什么样的游戏,玩家的任务就是先把一张图片打乱,然后再把打乱的图片拼好。(当然,教程结束后,诸位可以改进,用程序把图片打乱,然后再让玩家直接还原图片,最好弄个完整的图片作参考啊!^^)制作这种类型的游戏,最大的好处就是可以为我们接下来学习和理解Tiled Map游戏做铺垫。(不过事实正好相反,我先翻译了Tiled Map的游戏教程,不过也没关系)
那么,为了制作一个这样的游戏,我们需要做哪些事情呢?下面就是制作这个滑动图片游戏的步骤列表:
创建一个“Tile”类,它包含sprite,position(x,y)和value这些实例变量。
创建一个管理类,它负责创建所有的Tile,同时可以追踪所有的Tile的状态。
添加touch组件,这样玩家可以交换两个tile的位置。
添加一些代码来随机加载图片,这样游戏可以有更多的花样。
就这么多,当我把步骤写出来的时候,是不是觉得很简单?(译者:补充一点,看我教程的朋友,不要仅仅局限于具体的技术细节,要多想想游戏创作的步骤,这个游戏有4步,你的游戏需要几步呢?多思考,这样就不会看着教程能做,没教程就无从下手了)接下来,我会一步步实现所有的功能,你会发现其实真的也很简单。
这里有第二部分,也就是本教程完整源代码,你们可以先下下来,看看什么效果。
这里是这篇教程的源代码。
讲了那么多,可能你还不知道我们要做一个什么样的游戏,下载完整源代码,可以帮助大家都本系列教程将要完成的产品有一个完整的认识,这很重要。。。
说真的,这个简单的游戏例子,能给你很多启发。。。今后,我将会基于这个系列的教程,给你们介绍更多的这种类型的游戏(译者:比如拼图啦,华容道啦,推箱子啦,连连看啦)
不管怎么说,先让我们实现这个游戏再说!为了完成了这个艰巨的任务,我们需要一些辅助类。这些类是Tile.h, Tile.m, Box.h, Box.m。
如果你看了我博客上其它教程的话,你肯定已经知道“SceneManager”和"PlayLayer“类了,这里就不再啰嗦了。如果还没有的话,请参考《cocos2d菜单教程》和《cocos2d精灵教程》。
首先,先让我们看看Tile类的实现。
Tile.h:
#import "cocos2d.h" #import "Constants.h"; @interface Tile : NSObject { int x, y, value; CCSprite *sprite; } -(id) initWithX: (int) posX Y: (int) posY; @property (nonatomic, readonly) int x, y; @property (nonatomic) int value; @property (nonatomic, retain) CCSprite *sprite; -(BOOL) nearTile: (Tile *)othertile; -(void) trade:(Tile *)otherTile; -(CGPoint) pixPosition; @end
tile类主要就是代表从一张大图里面提取出来的一小块内容,有X,Y位置(注意,这里的x,y坐标不等于精灵的位置坐标,精灵的位置坐标是sprite.position),有精灵,有value。这里的value可以是任何值 ,比如可以代表每个tile在原图中的位置(这样的话,我们就可以用这些位置来判断玩家是否正确拼成完整的图了),在这个版本中,我们暂时不会使用这个value;
现在,让我们看看其具体实现:
Tile.m:
#import "Tile.h" @implementation Tile @synthesize x, y, value, sprite; -(id) initWithX: (int) posX Y: (int) posY{ self = [super init]; x = posX; y = posY; return self; } -(BOOL) nearTile: (Tile *)othertile{ return (x == othertile.x && abs(y - othertile.y)==1) || (y == othertile.y && abs(x - othertile.x)==1); } -(void) trade: (Tile *)otherTile{ CCSprite *tempSprite = [sprite retain]; int tempValue = value; self.sprite = otherTile.sprite; self.value = otherTile.value; otherTile.sprite = tempSprite; otherTile.value = tempValue; [tempSprite release]; } -(CGPoint) pixPosition{ return ccp(kStartX + x * kTileSize +kTileSize/2.0f,kStartY + y * kTileSize +kTileSize/2.0f); } @end
大部分内容一看就能明白--我们实现了四个方法 “initWithX”, “nearTile”, “trade” and “pixPosition”.
“initWithX”方法,从名字就可以看出来它是做什么的---它是Tile类的初始化代码,它Tile类被初始化的时候被调用。它接收一个x,y值,这两个值和世界坐标无关,而是与包含它们的Box类有关。举个例子,我们使用 initWithX:3 Y:4,假如我们的box是7*7的话,那么,这个Tile被放置在3,4号位置)我们可以用pixPosition函数来计算每个Tile的精灵在屏幕上的位置。
“nearTile”接收一个Tile类型的参数,判断两个Tile是否是邻居,如果是,就返回YES,否则返回NO。
“trade”就是把两个Tile的精灵交换一下。交换两个变量,相信学过C语言的都会,定义一个临时变量temp,然后temp = a; a=b; b=temp;
最后,“pixPosition”计算得到每个Tile的精灵在屏幕上的正确的坐标位置---你将会在后面看到这个函数的特殊用途。
Box类的主要功能就是处理所有单个Tile类的创建,加载相应精灵,以及把它们放置在屏幕上的正确位置。
Box.h:
#import "cocos2d.h" #import "Constants.h" #import "Tile.h" @interface Box : NSObject { CGSize size; NSMutableArray *content; NSMutableSet *readyToRemoveTiles; CCLayer *layer; Tile *OutBorderTile; NSInteger imgValue; } @property(nonatomic, retain) CCLayer *layer; @property(nonatomic, readonly) CGSize size; -(id) initWithSize: (CGSize) size factor: (int) facotr; -(Tile *) objectAtX: (int) posX Y: (int) posY; -(BOOL) check; @end
单看头文件,有些内容你也可以猜到它的作用了。。。size就是我们将要创建的网格的大小(3*3, 4*5, 5*3,7*7等等)
Box类最主要的两个变量就是“content”和“readyToRemove”。
content变量实际上是一个多维数组,至少也是一维(如果SIZE为1*1的话)。我们将创建一个NSMutableArray代码列,然后会在每一列中再加入一个NSMutableArray作为一行。我们可以使用 “return [[content objectAtIndex: y] objectAtIndex: x];”来得到正确的Tile。
readyToRemove变量,在这个教程中,只是初始化了,但是,今后,我会介绍另一个游戏,在那里面我会大量使用这个变量----在这个教程中,我将使用它加载所有新创建的精灵。
接下来,让我们看看Box类的具体实现:
Box.m:
#import "Box.h" #import "Box.h" @implementation Box @synthesize layer; @synthesize size; @synthesize lock; -(id) initWithSize: (CGSize) aSize imgValue: (int) aImgValue{ self = [super init]; imgValue = aImgValue; size = aSize; OutBorderTile = [[Tile alloc] initWithX:-1 Y:-1]; content = [NSMutableArray arrayWithCapacity: size.height]; readyToRemoveTiles = [NSMutableSet setWithCapacity:50]; for (int y=0; y < size.height; y++) { NSMutableArray *rowContent = [NSMutableArray arrayWithCapacity:size.width]; for (int x=0; x < size.width; x++) { Tile *tile = [[Tile alloc] initWithX:x Y:y]; [rowContent addObject:tile]; [readyToRemoveTiles addObject:tile]; [tile release]; } [content addObject:rowContent]; [content retain]; } [readyToRemoveTiles retain]; return self; } -(Tile *) objectAtX: (int) x Y: (int) y{ if (x <0|| x >= kBoxWidth || y <0|| y >= kBoxHeight) { return OutBorderTile; } return [[content objectAtIndex: y] objectAtIndex: x]; } -(BOOL) check{ NSArray *objects = [[readyToRemoveTiles objectEnumerator] allObjects]; if ([objects count] ==0) { return NO; } int countTile = [objects count]; for (int i=0; i < countTile; i++) { Tile *tile = [objects objectAtIndex:i]; tile.value =0; if (tile.sprite) { [layer removeChild: tile.sprite cleanup:YES]; } } [readyToRemoveTiles removeAllObjects]; NSString *name = [NSString stringWithFormat:@"%d.png",imgValue]; CCTexture2D * texture = [[CCTextureCache sharedTextureCache] addImage:name]; NSMutableArray *imgFrames = [NSMutableArray array]; [imgFrames removeAllObjects]; for (int i =0; i <7; i++) { for (int j =6; j >=0; j--) { CCSpriteFrame *imgFrame = [CCSpriteFrame frameWithTexture:texture rect:CGRectMake(i*40, j*40, 40, 40) offset:CGPointZero]; [imgFrames addObject:imgFrame]; } } for (int x=0; x< size.width; x++) { int extension =0; for (int y=0; y < size.height; y++) { Tile *tile = [self objectAtX:x Y:y]; if(tile.value ==0){ extension++; }elseif (extension ==0) { } } for (int i=0; i < extension; i++) { Tile *destTile = [self objectAtX:x Y:kBoxHeight-extension+i]; CCSpriteFrame * img = [imgFrames objectAtIndex:0]; CCSprite *sprite = [CCSprite spriteWithSpriteFrame:img]; [imgFrames removeObjectIdenticalTo:img]; sprite.position = ccp(kStartX + x * kTileSize + kTileSize/2, kStartY + (kBoxHeight + i) * kTileSize + kTileSize/2- kTileSize * extension); [layer addChild: sprite]; destTile.value = imgValue; destTile.sprite = sprite; } } return YES; } @end
那么,这个类到底做了些什么事呢---我认为"initWithSize" 和 "getObjectAt" 这两个方法已经很清楚了。。这里就不再啰嗦了。
因此,最重要的方法---check。首先,我们判断readyToRemoveTiles数组中是否包含任何Tiles。。在我们这个例子中,所有的Tile都在里面。。。非常好!然后我们遍历这个数组里面所有的元素,把其中的精灵一个个全部清除掉,最后,我们把整个数组里的元素全部清空。现在,你可能知道了,当制作一个游戏的多个关卡的时候,如何做好清理化工作了。
接下来,我们从资源文件中加载纹理(比如1.png, 2.png, 3.png等等),然后把它们存储在一个CCTexture2D对象中,之后我们会从CCTexture2D对象来构建所有的精灵帧。我们将创建49个精灵帧。因为我们的图片大小是280*280,所以每个CCSpriteFrame大小就是40*40。这里面用了一个双重for循环。
for (int x=0; x< size.width; x++) { int extension =0; for (int y=0; y < size.height; y++) { Tile *tile = [self objectAtX:x Y:y]; if(tile.value ==0){ extension++; }elseif (extension ==0) { } }
上面这部分代码,对于本教程来说,其实并不是必须的,但是,它可以用来判断有多少Tile需要替换图片。这种机制非常好,尤其是当你制作一个Tile drop游戏(比如宝石迷阵)的时候,因为你不想一次替换掉所有的Tile。。。在本例中,我们将检测Tile的value属性是否为0,然后用extension变量来追踪有多少个value为0的Tile。在本例中,由于所有的Tile都存在了readyToRemoveTiles中,所以extension变量永远都是7。
下面,我们得到第一个Y坐标为(kBoxHeight-extension+i)的Tile。。因为,在我们的例子中, kBoxHeight = 7,而extension总是为7,所以,我们实际上只需要关心变量i就可以了。i会从0一直递增到6.好了,你可能会问,为什么我要这样?因为,我会在其实游戏中使用到,如果现在我们就熟悉了的话,以后的工作会很轻松:)。接下来,看看精灵是如何工作的吧。。。
for (int i=0; i < extension; i++) { Tile *destTile = [self objectAtX:x Y:kBoxHeight-extension+i]; CCSpriteFrame * img = [imgFrames objectAtIndex:0]; CCSprite *sprite = [CCSprite spriteWithSpriteFrame:img]; [imgFrames removeObjectIdenticalTo:img]; sprite.position = ccp(kStartX + x * kTileSize + kTileSize/2, kStartY + (kBoxHeight + i) * kTileSize + kTileSize/2- kTileSize * extension); [layer addChild: sprite]; destTile.value = imgValue; destTile.sprite = sprite; }
然后,我们创建了新的CCSprite,通过给定的CCSpriteFrame,并且把精灵放置在box的合适的位置。我们把所有的Tile的imgValue都设置成一样的。
最后,看看PlayLayer类,我们应该很熟悉了。。。它将会处理touches,以及box类的初始化工作。我们需要追踪前面两次touch--“selectedTile”变量指代玩家当前选择的Tile,这时候,如果玩家选择另外一个Tile的时候,就会和前面的Tile进行交换。接下来,看看具体实现吧。
PlayLayer.h:
#import "cocos2d.h" #import "Box.h" @interface PlayLayer : CCLayer { Box *box; Tile *selectedTile; NSInteger value; } -(void) changeWithTileA: (Tile *) a TileB: (Tile *) b sel : (SEL) sel; -(void) check: (id) sender data: (id) data; @end
接下来是其实现:
PlayLayer.m:
#import "PlayLayer.h" @implementation PlayLayer -(id) init{ self = [super init]; value = (arc4random() % kKindCount+1); box = [[Box alloc] initWithSize:CGSizeMake(kBoxWidth,kBoxHeight) imgValue:value]; box.layer = self; box.lock= YES; [box check]; self.isTouchEnabled = YES; return self; } - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; CGPoint location = [touch locationInView: touch.view]; location = [[CCDirector sharedDirector] convertToGL: location]; if (location.y < (kStartY) || location.y > (kStartY + (kTileSize * kBoxHeight))) { return; } int x = (location.x - kStartX) / (kTileSize); int y = (location.y - kStartY) / (kTileSize); if (selectedTile && selectedTile.x == x && selectedTile.y == y) { selectedTile = nil; return; } Tile *tile = [box objectAtX:x Y:y]; if (tile.x >=0&& tile.y >=0) { if (selectedTile && [selectedTile nearTile:tile]) { [box setLock:YES]; [self changeWithTileA: selectedTile TileB: tile sel: @selector(check:data:)]; selectedTile = nil; } else { if (selectedTile) { if (selectedTile.x == x && selectedTile.y == y) { selectedTile = nil; } } selectedTile = tile; } } } -(void) changeWithTileA: (Tile *) a TileB: (Tile *) b sel : (SEL) sel{ CCAction *actionA = [CCSequence actions: [CCMoveTo actionWithDuration:kMoveTileTime position:[b pixPosition]], [CCCallFuncND actionWithTarget:self selector:sel data: a], nil ]; CCAction *actionB = [CCSequence actions: [CCMoveTo actionWithDuration:kMoveTileTime position:[a pixPosition]], [CCCallFuncND actionWithTarget:self selector:sel data: b], nil ]; [a.sprite runAction:actionA]; [b.sprite runAction:actionB]; [a trade:b]; } -(void) check: (id) sender data: (id) data{ } @end
这个类中主要有3个方法---init方法用来初始化box类,ccTouchesBegan方法,决定哪个Tile被用户选择,如果新选择的Tile等于原Tile的话就直接返回;如果是邻近的Tile的话,就交换;否则,就不做任何事情。交换Tile的时候,调用CCSequence 和 CCMoveTo来展示交换的动画。实际上,我们真正交换的代码只有[a trade b]。
首先,在tile.h中,我们需要添加一个新的变量“originalValue”,用来保存Tile的初始位置。这样的话,当你把Tile打乱的时候,我们就可以使用这个位置与新的位置作比较,以此来判断玩家是否完成拼图。
@interface Tile : NSObject { int x, y, value, originalValue; CCSprite *sprite; } -(id) initWithX: (int) posX Y: (int) posY; @property (nonatomic, readonly) int x, y; @property (nonatomic) int value; @property (nonatomic) int originalValue; @property (nonatomic, retain) CCSprite *sprite; -(BOOL) nearTile: (Tile *)othertile; -(void) trade:(Tile *)otherTile; -(CGPoint) pixPosition; @end
接下来,我们打开box.m,然后在check函数的底部,作下面的修改:
destTile.value = (7* destTile.x) + destTile.y; destTile.originalValue = destTile.value; destTile.sprite = sprite;
如果你是直接从第一个工程的源代码进行修改的话,那么,原来的代码如下所示:
destTile.value = imgValue; destTile.sprite = sprite;
在你完成这些修改以后,我们还有最后一件事件需要做,就是在box.m里面添加一个新的函数,用来判断游戏状态。
-(BOOL) checkSolution { BOOL isSolved =true; for (int x=0; x < size.width; x++) { for (int y=0; y < size.height; y++) { Tile *tile = [self objectAtX:x Y:y]; if (tile.originalValue != tile.value) { isSolved =false; } } } if (isSolved) { NSLog(@"The Sliding Image is Solved"); returntrue; } else { NSLog(@"The Sliding Image is NOT Solved"); returnfalse; } returntrue; }
这里就是遍历所有的Tiles,然后比较value和originalValue的值,如果全部相等,则表明成功解谜,否则,就表明失败。
最后,在PlayLayer.m中,我们在ChangeTileWithA方法里面添加下面的代码:
NSLog(@"Check Solution"); BOOL isSolved = [box checkSolution]; CCLabel *solvedLabel = (CCLabel*)[self getChildByTag:kSolvedText]; if (isSolved) { [solvedLabel setString:@"The Puzzle is Solved"]; } else { [solvedLabel setString:@"The Puzzle is NOT Solved"]; }
这样,每一次你交换两个小图片的时候,都会判断一下游戏的状态,同时用CCLabel显示在屏幕上面。
如果大家有什么问题,请留言。
下篇教程见!
著作权声明:本文由http://www.cnblogs.com/andyque翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!
相关文章推荐
- (译)如何使用cocos2d制作一个Slide Image Game:第一部分
- (译)如何使用cocos2d制作一个滑动图片游戏(Slide Image Game):第一部分
- (译)如何使用cocos2d制作一个太空射击游戏
- (译)如何使用cocos2d制作一个塔防游戏:第三部分
- 如何使用cocos2d-x制作一个塔防游戏:引子
- 如何使用cocos2d制作一个多向滚屏射击游戏-第一部分
- 如何使用cocos2d-x来制作一个塔防游戏:第一部分
- (译)如何使用cocos2d制作一个太空射击游戏
- (译)如何使用cocos2d来制作一个打地鼠的游戏:第一部分
- 如何使用cocos2d制作一个太空射击游戏
- 如何使用cocos2d-x来制作一个塔防游戏:第二部分
- 如何使用cocos2d和box2d来制作一个Breakout游戏:第一部分
- 如何使用cocos2d制作一个多向滚屏射击游戏-第二部分
- (译)如何使用cocos2d来制作一个打地鼠的游戏:第一部分
- (译)如何使用cocos2d制作一个塔防游戏:第四部分(完)
- (译)如何使用cocos2d来制作一个塔防游戏:第一部分
- 14. 如何使用cocos2d来制作一个打地鼠的游戏:第一部分
- 如何使用cocos2d和box2d来制作一个Breakout游戏
- 如何使用cocos2d制作一个太空射击游戏(转载)
- 如何使用cocos2d-x来制作一个塔防游戏:第三部分