使用SpriteKit做一個Frvr游戲

一,游戲怎么玩奔脐?

好吧俄周,我又回來了,之前利用SpriteKit游戲引擎做過一個十字消除的游戲髓迎。對于不會其它引擎的人來說峦朗,SpriteKit的優(yōu)點就是比較簡單迅速,快速開發(fā)些有趣的小游戲排龄。前些天甚垦,玩了一個很好玩的在線游戲Hex Frvr,是使用Html5做的涣雕,在AppStore上有可以下載玩到艰亮,在線游戲的地址點這里

frvr游戲

從這里下載完整的Demo工程挣郭,在Xcode里面直接打開運行吧迄埃。玩起來的效果是這樣的:

frvr2

Ok,東西就是這么個東東兑障,本文就詳細描述下demo里面的內(nèi)容侄非,用SpriteKit來實現(xiàn)吧。

二流译,開始制作游戲之旅逞怨。

1,素材的準備福澡。

好吧叠赦,之前做十字消游戲的時候,使用程序生成方塊的素材革砸。這次素材是六邊形除秀,程序這塊本想研究下怎么生成的,不過學習使人進步算利,我最近研究了下Mac OS下的一個設計神器“Sketch”册踩,然我由此走上了設計師的路(尼瑪,老板你怎么不請美工靶谩)暂吉。

ok胖秒,簡單使用下Sketch,畫個六邊形慕的。如果不想畫的哥們扒怖,請直接拿Demo工程里面的素材,不謝不謝业稼!

Sketch繪制六邊形的方法:
(1)繪制六邊形盗痒。
a,打開Sketch低散,新建一個畫布(A)

新建畫布

b俯邓,插入多邊形,默認是5邊形熔号,先畫一個稽鞭。在右邊檢查器里選6,增加一個點引镊,就生成了6變形朦蕴。
注意:按著Shift鍵拉動,調(diào)整成正六邊形弟头。

選擇多邊形

編輯多變形點個數(shù)

編輯多邊形點數(shù)

(2)上顏色加增加立體效果吩抓。
a,上顏色赴恨。
在右側檢查器的Fill欄疹娶,選擇喜歡顏色,然后Blending模式選擇Normal伦连。就有基本的底色了雨饺。

b,增加圖像的立體感惑淳。
增加增加線性漸變:Fill欄里额港,添加線性漸變,Blending模式選擇Overlay歧焦。
圓形漸變:Fill欄里移斩,添加圓形漸變,Blending模式選擇Overlay倚舀。
效果特效自己可以隨便設置叹哭,我都是以最上面那個點為漸變起點忍宋,最底下的點為漸變終點痕貌,強調(diào)一下立體的感覺。
最終效果如圖所示:

六邊形素材最終效果

線性漸變和圓形漸變

c糠排,導出素材
點擊export舵稠,按照提示到處png格式圖片。

2,游戲玩法和規(guī)則哺徊。

游戲規(guī)則(百度詞條)

“游戲的主界面是一個大六邊形棋盤[2] 室琢,六邊形的每一邊又由5個小六邊形組成,構成共有61格的棋盤空間落追。玩家拖動系統(tǒng)自動輸出的各種六邊形組合置于大六邊形的空白處盈滴,使之排列成完整的一行或多行并且消除得分,而連續(xù)消除會有額外Combo加分轿钠。直到棋盤上再也無法擺下任意一個六邊形組合的時候巢钓,游戲就會失敗×贫猓”

OK症汹,歸納成編寫程序的輸入,我們要實現(xiàn)下面的東東:
(1)61個小六邊形組成的蜂巢狀棋盤贷腕。
如圖的游戲主界面所示背镇,主界面是如游戲名Hex所代表的蜂窩狀六邊形組合成的棋盤,共有61格泽裳,為了顯示方便瞒斩,我都邊上了號碼。

游戲界面

(2)24種有4個小六邊形組成的不同形狀+1個單六邊形涮总。
如圖2.6所示济瓢,4個小六邊形所排列組合成的不同形狀,就是我們要填入到棋盤格子里面的圖形和形狀妹卿。

待填入圖形

(3)將(2)中的不同形狀填入(1)中的棋盤旺矾,在橫向,左斜方向和右斜方向有占滿的六邊形格子就消除夺克。
(4)每回合有三個(2)中的形狀箕宙,填入一個補充一個。如果三個形狀都無法再填入61格子的棋盤中铺纽,游戲結束柬帕。
其游戲過程可以參見文章開頭的動圖顯示。

3狡门,游戲實現(xiàn)數(shù)據(jù)結構及算法說明陷寝。

(1)要有方向。

一個六邊形有六個方向其馏,因此如果要在棋盤中進行比較和消除凤跑,必須比較每一個小六邊形單元六個方向的情況。很顯然叛复,我們將六邊形的六個方向做一個編號:

//LeftTop:0
//RightTop:1
//Right:2
//RightBottom:3
//LeftBottom:4
//Left:5

typedef enum : NSInteger {
    SUDNone = -1,
    SUDTopLeft = 0,
    SUDTopRight,
    SUDRight,
    SUDBottomRight,
    SUDBottomLeft,
    SUDLeft,
} ShapeUnitDirector;

其方向示意如圖所示:

六邊形比較方向示意圖

(2)要有順序仔引。

如何檢查2.(2)中的25種形狀是否可以放入2.(1)中的棋盤呢扔仓?嗯,好了咖耘,計算機要一個一個的比較翘簇,沒有你聰明。不過好在它的速度飛快儿倒!
但是你要告訴電腦怎么弄版保。首先比較是有順序的,對比較的不同的形狀夫否,必須規(guī)定一個比較順序找筝。為其中每一個單元的六邊形編一個序號,表示比較的順序慷吊。這個順序要是一個連續(xù)的袖裕,可達的路徑,計算機比較的時候能有來有回溉瓶。路徑可以用上面規(guī)定的方向來表示急鳄。如圖選了兩個形狀,來說明他們的比較順序堰酿。

比較順序

“一”和“二”的兩個圖形里每個小六邊形都有編號疾宏,其編號就是其比較順序,1非常重要触创,是比較的起始點坎藐。
“一”圖形里,1是起始比較點哼绑,比較1后岩馍,就要比較2,2位于1的LeftBottom方位抖韩,所以要將LeftBottom記住蛀恩。3位于2的RightBottom位置,4位于3的RightTop方位茂浮。所以按照1到4的順序双谆,比較路徑就是[LeftBottom,RightBottom席揽,RightTop]顽馋,紅色箭頭所示。
同理幌羞,“二”的圖形里寸谜,比較路徑就是[Right,RightBottom新翎,LeftBottom]程帕。
注意:這個形狀比較順序非常重要住练,要理解清楚地啰。

(3)要會比較愁拭。

a,第一種比較是亏吝,將圖形放置到棋盤上后岭埠,看圖形里的每一個六邊形是否能放置到棋盤上去。在程序里面其實算法很簡單蔚鸥,就是遍歷圖形里每一個小六邊形惜论,看其所在位置下的棋盤格子是否是空的,如果全都是空的就可以放上去了止喷。
b馆类,每一次成功放置了形狀后,都會補充一個新的形狀弹谁。此時乾巧,要判定游戲失敗條件,即游戲是否可以進行下去预愤。將現(xiàn)有的沒有放進棋盤的三個形狀沟于,迭代的對棋盤里的每一個位置進行一下比較,看是否能放得進去植康。如果三個形狀都放不進棋盤旷太,那么游戲結束了。

注意销睁,這里的比較供璧,就要使用到剛才定義的比較順序了,如“一”里面的[LeftBottom冻记,RightBottom嗜傅,RightTop],因為你知道棋盤格每一個的位置檩赢,棋盤六個方向的位置也可以通過數(shù)據(jù)結構來記錄吕嘀,但是你需要知道放置的圖形,它的比較路徑和位置信息贞瞒,才能夠很好的便利偶房,所以才會定義比較路徑和比較起始點,有了這兩個元素军浆,比較才能進行棕洋。

PS:其實還有別的方法,僅需要圖形的起始點乒融,把起始點移到棋盤的每一格掰盘,按照比較a里的位置判斷方法比較摄悯。好了,其實比較簡單啦愧捕!理解下就好奢驯。

4,編程實現(xiàn)次绘。

SpriteKit的用法和Cocos2dx比較像瘪阁,也是將實體精靈Sprite以樹形結構組織,你來規(guī)定Sprite節(jié)點的交互和動畫邮偎,達到游戲的結果管跺。在iOS9系統(tǒng)中加入了很多的新功能,實在值得好好研究禾进,不過這里我們用的比較簡單豁跑。大家也可以看看我之前寫的《使用SpriteKit游戲引擎,做一個十字消游戲》泻云。里面有SpriteKit的普及和基礎知識艇拍,我們在這里就不對SpriteKit引擎進行過多的講解。

游戲界面:
(1)設計游戲界面布局壶愤。
第一淑倾,由于是蜂巢狀的六邊形,每一行的個數(shù)先是增加征椒,后來又遞減娇哆,而且位置又不太相同。所以需要記錄棋盤每行的單元格個數(shù)勃救。計算出橫向和縱向的距離碍讨,再進行添加。
第二蒙秒,需要記錄蜂巢狀六邊形的六個方向的單元格編號勃黍,方便比較的時候搜索。我在這里使用了一個JSON文件晕讲,將每一個單元格的信息寫入里面覆获,初始化的時候讀入,生成相關的信息數(shù)據(jù)結構瓢省。其結構如下弄息,serialNum號就是單元格編號,如圖2.5所示勤婚。adjacent就是鄰接的單元點編號摹量,-1代表該方向沒有單元格。

"unitInfos" : [
   {
      "x" : 0,
      "y" : 0,
      "serialNum" : 0,
      "adjacent" : "-1 -1 1 6 5 -1"
   },

添加棋盤的代碼參見Demo代碼里的GameScene.m的如下代碼:

- (void)addPlayground
{
    // 1  初始化相關數(shù)據(jù)結構
    SKSpriteNode *node;
    self.unitNodeArray = [[NSMutableArray alloc] init];
    
    self.unitTexture = [SKTexture textureWithImageNamed:@"6kuai_gray.png"];
    self.unitWidth = self.unitTexture.size.width;
    self.unitHight= self.unitTexture.size.height;
    
    //2 生成每行的單元格個數(shù),并設置起始點缨称。
    NSArray *arrayNumber = @[@5,@6,@7,@8,@9,@8,@7,@6,@5];
    CGPoint startPoint = CGPointMake(CGRectGetMidX(self.frame) -2*self.unitWidth, CGRectGetHeight(self.frame)-150 );
    
  // 3 兩層循環(huán)凝果,擺放棋盤單元格,并填入從JSON中讀取的信息睦尽,放入userdata字段器净。
    int index = 0;
    int nodeCount = 0;
    for (NSNumber *lineNumber in arrayNumber) {
        int count = lineNumber.intValue;
        for (int i = 0; i < count; i++) {
            //3.1 生成單元格節(jié)點
            node = [SKSpriteNode spriteNodeWithTexture:self.unitTexture];

            //3.2 擺放位置
            if (index <= 4) {
                [node setPosition:CGPointMake(startPoint.x-XDISTANCE*index +i*self.unitWidth, startPoint.y-YDISTANCE*index)];
            }
            else
            {
                [node setPosition:CGPointMake(startPoint.x - XDISTANCE*((PLAYGROUNDLINE-1)-index) + i*self.unitWidth, startPoint.y - YDISTANCE*index)];
            }
            
            // 3.3 讀取單元格信息,并填入userData
            ShapeUnitInfo *unitInfo = [_unitInfoArray objectAtIndex:nodeCount];
            unitInfo.unitPosition = node.position;
            node.userData = [[NSMutableDictionary alloc] init];
            [node.userData setValue:unitInfo forKey:@"unitInfo"];
            [node setName:@"unitShape"];
            
            // 3.4 加入數(shù)字標簽
            SKLabelNode *label = [SKLabelNode labelNodeWithText:[NSString stringWithFormat:@"%d",nodeCount]];
            label.position = CGPointMake(0, 0);
            label.fontColor = [UIColor blackColor];
            label.fontSize = 18;
            label.zPosition = 2;
            [node addChild:label];
            
            //3.5 添加節(jié)點入GameScene
            [self addChild:node];
            [self.unitNodeArray addObject:node];
            nodeCount++;
        }
        index++;
    }
}

- (void)addPlayground
{
    // 1  初始化相關數(shù)據(jù)結構
    SKSpriteNode *node;
    self.unitNodeArray = [[NSMutableArray alloc] init];
    
    self.unitTexture = [SKTexture textureWithImageNamed:@"6kuai_gray.png"];
    self.unitWidth = self.unitTexture.size.width;
    self.unitHight= self.unitTexture.size.height;
    
    //2 生成每行的單元格個數(shù)骂删,并設置起始點掌动。
    NSArray *arrayNumber = @[@5,@6,@7,@8,@9,@8,@7,@6,@5];
    CGPoint startPoint = CGPointMake(CGRectGetMidX(self.frame) -2*self.unitWidth, CGRectGetHeight(self.frame)-150 );
    
  // 3 兩層循環(huán)四啰,擺放棋盤單元格宁玫,并填入從JSON中讀取的信息,放入userdata字段柑晒。
    int index = 0;
    int nodeCount = 0;
    for (NSNumber *lineNumber in arrayNumber) {
        int count = lineNumber.intValue;
        for (int i = 0; i < count; i++) {
            //3.1 生成單元格節(jié)點
            node = [SKSpriteNode spriteNodeWithTexture:self.unitTexture];
 
            //3.2 擺放位置
            if (index <= 4) {
                [node setPosition:CGPointMake(startPoint.x-XDISTANCE*index +i*self.unitWidth, startPoint.y-YDISTANCE*index)];
            }
            else
            {
                [node setPosition:CGPointMake(startPoint.x - XDISTANCE*((PLAYGROUNDLINE-1)-index) + i*self.unitWidth, startPoint.y - YDISTANCE*index)];
            }
            
            // 3.3 讀取單元格信息欧瘪,并填入userData
            ShapeUnitInfo *unitInfo = [_unitInfoArray objectAtIndex:nodeCount];
            unitInfo.unitPosition = node.position;
            node.userData = [[NSMutableDictionary alloc] init];
            [node.userData setValue:unitInfo forKey:@"unitInfo"];
            [node setName:@"unitShape"];
            
            // 3.4 加入數(shù)字標簽
            SKLabelNode *label = [SKLabelNode labelNodeWithText:[NSString stringWithFormat:@"%d",nodeCount]];
            label.position = CGPointMake(0, 0);
            label.fontColor = [UIColor blackColor];
            label.fontSize = 18;
            label.zPosition = 2;
            [node addChild:label];
            
            //3.5 添加節(jié)點入GameScene
            [self addChild:node];
            [self.unitNodeArray addObject:node];
            nodeCount++;
        }
        index++;
    }
}

(2)設置游戲相關初始化數(shù)據(jù)。
這里就是讀入JSON文件匙赞,并將分數(shù)置0佛掖。

- (void)unitInfoInit
{
    // 1 初始化信息存入的數(shù)據(jù)容器,一個NSArray
    if (_unitNodeArray != nil) {
        return;
    }
    
    _unitInfoArray = [[NSMutableArray alloc] init];
    
    // 2  讀入JSON文件
    NSString *bundleDir = [[NSBundle mainBundle] bundlePath];
    NSString *path = [bundleDir stringByAppendingPathComponent:@"unitInfo.json"];
    
    NSURL *url = [NSURL fileURLWithPath:path];
    NSData *data = [NSData dataWithContentsOfURL:url];
    
    NSError *error = nil;
    
    // 3 解析JSON文件涌庭,并存入Arrary容器
    NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
    
    NSArray *unitInfos = [jsonDic objectForKey:@"unitInfos"];
    
    if (unitInfos != nil) {
        for (NSDictionary *unitInfoDic in unitInfos) {
            ShapeUnitInfo *unitInfo = [[ShapeUnitInfo alloc] init];
            int x = ((NSNumber *)[unitInfoDic objectForKey:@"x"]).intValue;
            int y = ((NSNumber *)[unitInfoDic objectForKey:@"y"]).intValue;
            int sn = ((NSNumber *)[unitInfoDic objectForKey:@"serialNum"]).intValue;
            NSString *adjacentString = (NSString *)[unitInfoDic objectForKey:@"adjacent"];
            NSArray *adjacents = [adjacentString componentsSeparatedByString:@" "];
            unitInfo.unitLocation = CGPointMake(x, y);
            unitInfo.serialNumber = sn;
            
            [unitInfo.adjacentArray addObjectsFromArray:adjacents];
            
            [_unitInfoArray addObject:unitInfo];
        }
    }
}

(3)三個備選容器添加.
在棋盤下面的位置添加三個備選容器芥被,如圖2.5種的2所標示的位置。

 - (void)addShapeFrame
{
   //1 初始化存儲容器
    SKSpriteNode *node;
    _shapePosArray = [[NSMutableArray alloc] initWithCapacity:3];
    _shapeArray = [[NSMutableArray alloc] initWithCapacity:3];
 
   // 2 生成被選位置節(jié)點坐榆,并加入到Scene中去
    for (int i = 0; i < 3; i++) {
        node = [[SKSpriteNode alloc] init];
        node.size = CGSizeMake(100, 100);
        node.position= CGPointMake(CGRectGetMidX(self.frame) + (i - 1)*120, 220);
        node.name = [NSString stringWithFormat:@"shapeFrame_%d",i];
        [self addChild:node];
        
        [_shapePosArray addObject:[NSValue valueWithCGPoint:node.position]];
    }
    
    // 3 調(diào)用生成被選圖形的接口拴魄,填充入這些位置節(jié)點。
    [self shapeFill];
}

(4)隨機生成填充形狀席镀。

上面(3)中代碼的最后一步匹中,在GameScene里面調(diào)用shapeFill方法來,填充三個備選容器豪诲。實際上是調(diào)用RandomShapeMgr.h中的RandomShapeMgr的單例對象顶捷,生成如圖2.6所示的25種不同的待填入形狀。重要的是將其編號屎篱,和比較隊列寫好服赎,放入一個隊列對象。RandomShapeMgr里的代碼里面的posInfoInit方法可以研究下交播,節(jié)點的位置隊列和比較隊列如何生成好保存重虑。

游戲交互
實際上SpriteKit里面的交互和iOS應用里的交互一脈相承。由于有點擊堪侯,拖動圖形嚎尤,放下圖形等操作,所以使用如下幾個方法:

a伍宦,-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event芽死;
b乏梁,- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
c关贵,- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event遇骑;

分別在點擊開始,中途和結束時進行程序處理完成主要核心交互揖曾,如下三個功能:
(1)點擊形狀落萎,識別形狀,并移動炭剪。
點擊形狀练链,調(diào)用方法a。在方法a中,根據(jù)節(jié)點Name值,判斷是否時需要保存處理的形狀節(jié)點霸妹。如是的話,使用 _handleNode來持有绿鸣。因為屏幕大小限制暂氯,平時待選的圖形僅僅只有單元格大小的1/2,因此點擊持有形狀后痴施,會執(zhí)行動畫,將待選形狀擴大一倍晾剖。處理邏輯:

if ([node.name isEqual:@"shape"]) {
//            NSLog(@"shape");
            _handleNode = node;
            [_handleNode runAction:[SKAction scaleTo:2 duration:0.4] completion:^{
            }];
            
            break;
        }

移動持有圖形,調(diào)用方法b齿尽,如果_handleNode有值的話,實時更新_handleNode的位置Position值循头。

(2)放置形狀,并判斷是否能夠放置入棋盤卡骂。
在方法c中,判定是否能夠放入棋盤全跨。就是判斷圖形里的節(jié)點是否能否放在它下面的那個單元格中。處理邏輯:

if (_handleNode != nil) {
        
        // 1 獲取放入形狀的所有小六邊形,并獲取其顏色紋理texuture
        NSArray *handleShapeNodes = [_handleNode children];
        SKTexture *texture = [(SKSpriteNode *)[[_handleNode children] firstObject] texture];;
        
       // 2 遍歷所有的小六邊形渺杉,獲取其位置,并察看該位置下是否存在Unit單元格是越,如果存在單元格,察看是否是被占狀態(tài)倚评。如果所有的小六邊形下,都有未被占用的單元格天梧,那么就可以放置在棋盤上了盔性;反之,返回形狀待選區(qū)域腿倚。
        NSUInteger index = 0;
        NSUInteger ocuppiedCount = 0;
        NSMutableArray *tempArray = [[NSMutableArray alloc] init];
        // 2.1 遍歷小六邊形
        for (SKSpriteNode *child in handleShapeNodes) {
            index++;
            // 2.2 獲取小六邊形位置
            CGPoint childLocation = CGPointMake(child.position.x*2 +_handleNode.position.x, child.position.y*2+_handleNode.position.y);
 
            // 2.3 獲取該位置下的所有節(jié)點
            NSArray *shapeNodes = [self nodesAtPoint:childLocation];
 
           // 2.4 看該節(jié)點下纯出,是否存在違背占用的單元格
            for (SKNode *shapeNode in shapeNodes) {
                if ([self isShapeUnit:(SKSpriteNode *)shapeNode] && ![self isUnitOcuppied:(SKSpriteNode *)shapeNode]) {
                    ocuppiedCount++;
                    [tempArray addObject:shapeNode];
                }
            }
        }
       
        // 2.5 如果所有六邊形都用空白的Unit可以占蚯妇,那么就可以放入敷燎。
        if ( index == ocuppiedCount ) {
            // 2.6 執(zhí)行占用,并調(diào)用shapeFill補充shape
            for (SKSpriteNode *unitNode in tempArray) {
                [unitNode setTexture:texture];
                ShapeUnitInfo *unitInfo = [unitNode.userData objectForKey:@"unitInfo"];
                unitInfo.occupy = YES;
//                NSLog(@"set occupy");
            }
            [_shapeArray removeObject:_handleNode];
            
            [_handleNode removeFromParent];
            [self shapeFill];
        }
        else {
            // 2.7  否則就將shape移動回待選區(qū)域箩言。
            NSUInteger index = [_shapeArray indexOfObject:_handleNode];
            CGPoint location = [(NSValue *)[_shapePosArray objectAtIndex:index] CGPointValue];
            SKAction *scale = [SKAction scaleTo:1 duration:0.3];
            SKAction *move = [SKAction moveTo:location duration:0.3];
            SKAction *group = [SKAction group:@[scale,move]];
            group.timingMode = SKActionTimingEaseOut;
            [_handleNode runAction:group];
        }
 
        
        _handleNode = nil;

(3)消除判斷硬贯,消除積分增加。
在方法c中陨收,還需要進行消除判斷饭豹,填入形狀后,是否會在橫务漩,左斜和右斜方向存在填滿一行的情況拄衰,如果有就需要進行消除,并積分饵骨。

// 檢查消除并積分
 [self resultDealElimination];

使用數(shù)組記錄下Top和Bottom行的單元格編號翘悉,并記錄每一行開頭的單元格編號:

// 1 每一行開頭的單元格編號
    NSArray *compareIndexRow = @[@0,@5,@11,@18,@26,@35,@43,@50,@56];
 
   // 2 Top行所有元素的編號
    NSArray *compareIndexTopSlash = @[@0,@1,@2,@3,@4];
 
    // 3 Bottom行所有元素的編號
    NSArray *compareIndexBottomSlash = @[@56,@57,@58,@59,@60];

涉及單元格如圖:

比較單元格.png

比較方向如下圖所示,1是橫向居触,2是Top斜妖混,3是Bottom斜:

比較方向.png

比較方向按六邊形方向定義比較,具體見代碼轮洋。

(4)游戲結束判斷
將三個待填入的圖形分別比較放在棋盤里進行

// 調(diào)用檢查是否能Continue
 [self checkContinue];

比較方案如上述所描述制市,按照填入圖形的比較序列,逐個對每個單元格進行比對弊予,如果還存在可以填入的位置祥楣,游戲就可以繼續(xù),如果不存在,游戲就結束误褪。核心比較代碼:

- (BOOL)isOccupByShape:(SKSpriteNode *)shapeNode atUnit:(SKSpriteNode *)unitNode
{
   // 1 獲取該形狀Shape的比較序列
    NSArray *comSeqArray = (NSArray *)[shapeNode.userData objectForKey:@"shapeCompOrder"];
    
   // 2 以讀入的單元格為起始比較單元格床未,按照比較序列進行比較。
    SKSpriteNode *tempNode = unitNode;
    ShapeUnitInfo *nodeInfo = (ShapeUnitInfo *)[tempNode.userData objectForKey:@"unitInfo"];
    if ([nodeInfo isOccupied]) {
        return YES;
    }
    
    for (NSNumber *index in comSeqArray) {
        
        NSInteger nodeIndex = [(NSNumber *)[nodeInfo.adjacentArray objectAtIndex:[index unsignedIntegerValue]] integerValue];
        if(-1 == nodeIndex) {
            return YES;
        }
        
        tempNode = (SKSpriteNode *)[_unitNodeArray objectAtIndex:nodeIndex];
        nodeInfo = (ShapeUnitInfo *)[tempNode.userData objectForKey:@"unitInfo"];
        if ([nodeInfo isOccupied]) {
            return YES;
        }
    }
    
    return NO;
}

三薇搁,游戲效果渡八,何去何從。

好了屎鳍,從這里下載完整的Demo工程逮壁,在Xcode里面運行打開吧。執(zhí)行效果文章開始所示卖宠。
好了忧饭,其實還有很多的功能可以添加和細化词裤。比如添加很多的動畫效果,增加積分機制和加入社交化分享逆航,廣告條因俐。很多功能可以添加赖瞒,有興趣的哥們,就在GitHub的Frvr項目吧兔,這個工程里面境蔼,好好加油,我頂你哦箍土!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吴藻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子侧但,更是在濱河造成了極大的恐慌禀横,老刑警劉巖粥血,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件复亏,死亡現(xiàn)場離奇詭異,居然都是意外死亡茫舶,警方通過查閱死者的電腦和手機刹淌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門有勾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔼卡,“玉大人雇逞,你說我怎么就攤上這事茁裙。” “怎么了掉蔬?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箭启。 經(jīng)常有香客問我蛉迹,道長,這世上最難降的妖魔是什么赏僧? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任淀零,我火速辦了婚禮驾中,結果婚禮上模聋,老公的妹妹穿的比我還像新娘。我一直安慰自己持痰,他們只是感情好工窍,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布患雏。 她就那樣靜靜地躺著罢维,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匀借。 梳的紋絲不亂的頭發(fā)上平窘,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天初婆,我揣著相機與錄音猿棉,去河邊找鬼萨赁。 笑死杖爽,一個胖子當著我的面吹牛紫皇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播化焕,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼撒桨,長吁一口氣:“原來是場噩夢啊……” “哼键兜!你這毒婦竟也來了普气?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤夷磕,失蹤者是張志新(化名)和其女友劉穎赶盔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡烘浦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年闷叉,在試婚紗的時候發(fā)現(xiàn)自己被綠了握侧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡埋合,死狀恐怖萄传,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情振诬,我是刑警寧澤赶么,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布脊串,位于F島的核電站,受9級特大地震影響印屁,放射性物質(zhì)發(fā)生泄漏斩例。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一础钠、第九天 我趴在偏房一處隱蔽的房頂上張望叉谜。 院中可真熱鬧,春花似錦很钓、人聲如沸码倦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽补疑。三九已至莲组,卻和暖如春栈妆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嬉橙。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工市框, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枫振。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓粪滤,卻偏偏與公主長得像雀扶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子予权,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容