1.初始化地图并且绘制地图。
这是我的图片素材,大家可以找更漂亮的。
SKTexture类里面的textureWithRect方法,作用是利用一个纹理的部分区域生成一个新的纹理。第一个参数是一个矩形,值得注意的是,矩形的四个参数都是一个不大于1的小数,表示的是新纹理在原纹理中的比例。
连连看的行和列的乘积必须为偶数,这样才能保证连到最后不会剩下一个。我的做法是,地图数组前一半在图片数组范围内随机赋值,后一半复制前一半的值,然后通过洗牌的方法打乱整个地图。
2.捕捉点击事件并且计算两次所选的位置。
左下角是坐标(0,0)点。
刚开始获得的坐标是在场景上的坐标,要减去相应的边距才能得到在地图上的坐标,然后计算出相应的行和列。记录两次点击的位置,并且确保两次位置不相同。
3.判断两次选择的图片是否可以相连。
判断两个图片是否可以相连,分为以下几种。水平相连,垂直相连,通过一个转角相连,通过两个转角相连,通过边界相连。
4.添加选中和连线的动画。
动画的方法放在update方法里面。其中,实现连线动画,需要记录各个转角点的坐标。
详细代码如下:
GameScene.h
#import <SpriteKit/SpriteKit.h>
//图片个数
#define IMAGE_NUMBER 7
//map的行和列的乘积必须为偶数,这样才可以保证游戏有解。
#define MAP_ROW 8
#define MAP_COLUMN 8
//屏幕尺寸
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 480
//图片尺寸
#define BLOCK_WIDTH 32
#define BLOCK_HEIGHT 32
//地图尺寸
#define MAP_WIDTH BLOCK_WIDTH * MAP_COLUMN
#define MAP_HEIGHT BLOCK_HEIGHT * MAP_ROW
//左边距和下边距
#define LEFT (SCREEN_WIDTH - BLOCK_WIDTH * IMAGE_NUMBER - 1) / 2
#define BOTTOM (SCREEN_HEIGHT - BLOCK_HEIGHT * IMAGE_NUMBER - 1) / 2
typedefstruct Select{
int row;
int column;
}Select;
typedefstruct LinePath{
Select point1;
Select point2;
}LinePath;
typedefenum SELECT_TYPE{
SELECT_NONE =0,
SELECT_ONE =1,
SELECT_TWO =1<<1,
}SELECT_TYPE;
@interface GameScene :SKScene
{
SKTexture * imgArray[IMAGE_NUMBER];
int map[MAP_ROW][MAP_COLUMN];
Select firstSelect;
Select secondSelect;
SELECT_TYPE selectType;
LinePath linePath;
}
@end
GameScene.m
#import "GameScene.h"
@implementation GameScene
- (id)initWithSize:(CGSize)size{
if(self = [super initWithSize:size]){
memset(map, -1,sizeof(map));
memset(&firstSelect, -1,sizeof(Select));
memset(&secondSelect, -1,sizeof(Select));
memset(&linePath, -1,sizeof(LinePath));
SKTexture * img = [SKTexture textureWithImageNamed:@"img.png"];
//init imgArray
for(int i =0; i <IMAGE_NUMBER; i++){
imgArray[i] = [SKTexture textureWithRect:CGRectMake((float)i /IMAGE_NUMBER, 0.0,1.0 /IMAGE_NUMBER,1.0)
inTexture:img];
}
//init and draw map
/**
这里要注意一个问题,任意一个元素出现的个数必须为偶数,这样本游戏才可能有解。
解决方法如下,
一.数组前一半用随机赋值,后一半复制前一半的值。
二.利用洗牌算法使整个数组乱序。
*/
int * point = &map[0][0];
int count =MAP_ROW *MAP_COLUMN /2;
for(int i =0; i < count; i++){
*(point + i) =arc4random()%IMAGE_NUMBER;
*(point + count + i) = *(point + i);
}
[self shuffle];
[self drawMap];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for(UITouch * touch in touches){
CGPoint location = [touch locationInNode:self];
//获取两次选择的图片的行和列,并确保两次位置不同。
location.x -= (LEFT -BLOCK_WIDTH /2);
location.y -= (BOTTOM -BLOCK_HEIGHT /2);
if((location.x >0) && (location.x <MAP_WIDTH) && (location.y >0) && (location.y <MAP_HEIGHT)){
int row = location.y /BLOCK_WIDTH;
int column = location.x /BLOCK_HEIGHT;
if(map[row][column] != -1){
if((firstSelect.row == -1) && (firstSelect.column == -1)){
firstSelect.row = row;
firstSelect.column = column;
selectType =SELECT_ONE;
}else{
if((firstSelect.row != row) || (firstSelect.column != column)){
secondSelect.row = row;
secondSelect.column = column;
selectType =SELECT_TWO;
}
else{
memset(&firstSelect, -1,sizeof(Select));
selectType =SELECT_NONE;
}
}
}
}
}
}
- (void)update:(NSTimeInterval)currentTime{
[self playMatchAction];
}
#pragma mark 洗牌
- (void)shuffle{
int *point = &map[0][0];
int size =MAP_ROW *MAP_COLUMN;
while(size >1){
size--;
int index =arc4random()%size +1;
int swap = *(point + index);
*(point + index) = *(point + size);
*(point + size) = swap;
}
}
#pragma mark 绘制
- (void)drawMap{
for(int i =0; i <MAP_ROW; i++){
for(int j =0; j <MAP_COLUMN; j++){
SKSpriteNode * spriteNode = [SKSpriteNode spriteNodeWithTexture:imgArray[map[i][j]]];
spriteNode.name = [NSString stringWithFormat:@"%d行%d列",i,j];
spriteNode.position =CGPointMake(j *BLOCK_WIDTH +LEFT,i *BLOCK_HEIGHT +BOTTOM);
[self addChild:spriteNode];
}
}
}
#pragma mark - 判断两个图片是否可以消去
- (BOOL)match:(Select)startSelect andOtherSeclet:(Select)endSelect{
//判断是否是一样的图片
if(map[startSelect.row][startSelect.column] !=map[endSelect.row][endSelect.column]){
return NO;
}
//水平直连
if([self horizon:startSelect andOtherSeclet:endSelect] ==YES){
return YES;
}
//垂直直连
if([self vertical:startSelect andOtherSeclet:endSelect] ==YES){
return YES;
}
//一个转角
if([self oneCorner:startSelect andOtherSeclet:endSelect] ==YES){
return YES;
}
//两个转角
if([self twoCorner:startSelect andOtherSeclet:endSelect] ==YES){
return YES;
}
//是否可以通过边界相连
if([self border:startSelect andOtherSeclet:endSelect] ==YES){
return YES;
}
return NO;
}
- (BOOL)horizon:(Select)startSelect andOtherSeclet:(Select)endSelect{
if(startSelect.row == endSelect.row){
int start = startSelect.column < endSelect.column ? startSelect.column : endSelect.column;
int end = startSelect.column < endSelect.column ? endSelect.column : startSelect.column;
for(start = start +1; start < end; start++){
if(map[startSelect.row][start] != -1){
return NO;
}
}
return YES;
}
return NO;
}
- (BOOL)vertical:(Select)startSelect andOtherSeclet:(Select)endSelect{
if(startSelect.column == endSelect.column){
int start = startSelect.row < endSelect.row ? startSelect.row : endSelect.row;
int end = startSelect.row < endSelect.row ? endSelect.row : startSelect.row;
for(start = start +1; start < end; start++){
if(map[start][startSelect.column] != -1){
return NO;
}
}
return YES;
}
return NO;
}
- (BOOL)oneCorner:(Select)startSelect andOtherSeclet:(Select)endSelect{
Select point;
memset(&point, -1,sizeof(Select));
point.row = startSelect.row;
point.column = endSelect.column;
if(map[point.row][point.column] == -1){
if(([self horizon:startSelect andOtherSeclet:point] && [self vertical:point andOtherSeclet:endSelect]) ==YES){
linePath.point1 = point;
return YES;
}
}
point.row = endSelect.row;
point.column = startSelect.column;
if(map[point.row][point.column] == -1){
if(([self vertical:startSelect andOtherSeclet:point] && [self horizon:point andOtherSeclet:endSelect]) ==YES){
linePath.point1 = point;
return YES;
}
}
return NO;
}
- (BOOL)twoCorner:(Select)startSelect andOtherSeclet:(Select)endSelect{
Select point1;
Select point2;
memset(&point1, -1,sizeof(Select));
memset(&point1, -1,sizeof(Select));
point1 = startSelect;
for(point1.column = point1.column -1; point1.column >0; point1.column--){
if(map[point1.row][point1.column] != -1){
break;
}else{
point2.row = endSelect.row;
point2.column = point1.column;
if(map[point2.row][point2.column] != -1){
break;
}
if([self vertical:point1 andOtherSeclet:point2] && [self horizon:point2 andOtherSeclet:endSelect]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
}
}
point1 = startSelect;
for(point1.column = point1.column +1; point1.column <MAP_COLUMN; point1.column++){
if(map[point1.row][point1.column] != -1){
break;
}else{
point2.row = endSelect.row;
point2.column = point1.column;
if(map[point2.row][point2.column] != -1){
break;
}
if([self vertical:point1 andOtherSeclet:point2] && [self horizon:point2 andOtherSeclet:endSelect]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
}
}
point1 = startSelect;
for(point1.row = point1.row -1; point1.row >0; point1.row--){
if(map[point1.row][point1.column] != -1){
break;
}else{
point2.row = point1.row;
point2.column = endSelect.column;
if(map[point2.row][point2.column] != -1){
break;
}
if([self horizon:point1 andOtherSeclet:point2] && [self vertical:point2 andOtherSeclet:endSelect]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
}
}
point1 = startSelect;
for(point1.row = point1.row +1; point1.row <MAP_ROW; point1.row++){
if(map[point1.row][point1.column] != -1){
break;
}else{
point2.row = point1.row;
point2.column = endSelect.column;
if(map[point2.row][point2.column] != -1){
break;
}
if([self horizon:point1 andOtherSeclet:point2] && [self vertical:point2 andOtherSeclet:endSelect]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
}
}
return NO;
}
- (BOOL)border:(Select)startSelect andOtherSeclet:(Select)endSelect{
Select point1;
Select point2;
memset(&point1, -1,sizeof(Select));
memset(&point2, -1,sizeof(Select));
point1.row = firstSelect.row;
point2.row = secondSelect.row;
if([self horizon:point1 andOtherSeclet:firstSelect] && [self horizon:point2 andOtherSeclet:secondSelect]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
point1.column =MAP_COLUMN;
point2.column =MAP_COLUMN;
if([self horizon:firstSelect andOtherSeclet:point1] && [self horizon:secondSelect andOtherSeclet:point2]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
point1.row = -1;
point1.column =firstSelect.column;
point2.row = -1;
point2.column =secondSelect.column;
if([self vertical:point1 andOtherSeclet:firstSelect] && [self vertical:point2 andOtherSeclet:secondSelect]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
point1.row =MAP_ROW;
point2.row =MAP_ROW;
if([self vertical:firstSelect andOtherSeclet:point1] && [self vertical:secondSelect andOtherSeclet:point2]){
linePath.point1 = point1;
linePath.point2 = point2;
return YES;
}
return NO;
}
#pragma mark -
#pragma mark 播放消去动画
- (void)playMatchAction{
switch(selectType){
caseSELECT_NONE:
if([self childNodeWithName:@"selected1"] !=nil){
[[self childNodeWithName:@"selected1"] removeFromParent];
}
if([self childNodeWithName:@"selected2"] !=nil){
[[self childNodeWithName:@"selected2"] removeFromParent];
}
if([self childNodeWithName:@"line"] !=nil){
[[self childNodeWithName:@"line"] removeFromParent];
}
break;
caseSELECT_ONE:
if([self childNodeWithName:@"selected1"] ==nil){
SKSpriteNode * selected = [SKSpriteNode spriteNodeWithImageNamed:@"selected.png"];
selected.position =CGPointMake(firstSelect.column *BLOCK_WIDTH + LEFT,firstSelect.row *BLOCK_HEIGHT +BOTTOM);
selected.name =@"selected1";
[self addChild:selected];
}
break;
caseSELECT_TWO:
if([self childNodeWithName:@"selected2"] ==nil){
SKSpriteNode * selected = [SKSpriteNode spriteNodeWithImageNamed:@"selected.png"];
selected.position =CGPointMake(secondSelect.column *BLOCK_WIDTH + LEFT,secondSelect.row *BLOCK_HEIGHT +BOTTOM);
selected.name =@"selected2";
[self addChild:selected];
if([self match:firstSelect andOtherSeclet:secondSelect] ==YES){
[self matchAction];
}
memset(&firstSelect, -1,sizeof(Select));
memset(&secondSelect, -1,sizeof(Select));
selectType =SELECT_NONE;
}
break;
}
}
- (void)matchAction{
[self lineAction];
[[self childNodeWithName:[NSString stringWithFormat:@"%d行%d列",firstSelect.row,
firstSelect.column]] removeFromParent];
[[self childNodeWithName:[NSString stringWithFormat:@"%d行%d列",secondSelect.row,
secondSelect.column]] removeFromParent];
map[firstSelect.row][firstSelect.column] = -1;
map[secondSelect.row][secondSelect.column] = -1;
}
- (void)lineAction{
SKShapeNode * line = [[SKShapeNode alloc] init];
CGMutablePathRef myPath =CGPathCreateMutable();
if((linePath.point1.row == -1) && (linePath.point2.row == -1)){
CGPoint point[2];
point[0].x =firstSelect.column *BLOCK_WIDTH + LEFT;
point[0].y =firstSelect.row *BLOCK_HEIGHT + BOTTOM;
point[1].x =secondSelect.column *BLOCK_WIDTH + LEFT;
point[1].y =secondSelect.row *BLOCK_HEIGHT + BOTTOM;
CGPathAddLines(myPath,NULL, point,2);
}elseif(linePath.point2.row == -1){
CGPoint point[3];
point[0].x =firstSelect.column *BLOCK_WIDTH + LEFT;
point[0].y =firstSelect.row *BLOCK_HEIGHT + BOTTOM;
point[1].x =linePath.point1.column *BLOCK_WIDTH + LEFT;
point[1].y =linePath.point1.row *BLOCK_HEIGHT + BOTTOM;
point[2].x =secondSelect.column *BLOCK_WIDTH + LEFT;
point[2].y =secondSelect.row *BLOCK_HEIGHT + BOTTOM;
CGPathAddLines(myPath,NULL, point,3);
}else{
CGPoint point[3];
point[0].x =firstSelect.column *BLOCK_WIDTH + LEFT;
point[0].y =firstSelect.row *BLOCK_HEIGHT + BOTTOM;
point[1].x =linePath.point1.column *BLOCK_WIDTH + LEFT;
point[1].y =linePath.point1.row *BLOCK_HEIGHT + BOTTOM;
point[2].x =linePath.point2.column *BLOCK_WIDTH + LEFT;
point[2].y =linePath.point2.row *BLOCK_HEIGHT + BOTTOM;
point[3].x =secondSelect.column *BLOCK_WIDTH + LEFT;
point[3].y =secondSelect.row *BLOCK_HEIGHT + BOTTOM;
CGPathAddLines(myPath,NULL, point,4);
}
line.path = myPath;
line.name =@"line";
[selfaddChild:line];
memset(&linePath, -1,sizeof(LinePath));
}
#pragma mark -
@end