設(shè)計(jì)一個(gè)對(duì)角棋(二)

這個(gè)對(duì)角棋我將使用swift+SpriteKit實(shí)現(xiàn)岂津。本篇介紹基本的邏輯處理誊爹。
初步考慮贞远,有以下過程是我必須實(shí)現(xiàn)的:
1.繪制棋盤,加載棋子;
2.移動(dòng)棋子的邏輯笨忌;
3.判定勝負(fù)的邏輯蓝仲。
在實(shí)際做的過程中,還有更多零碎的邏輯等著我實(shí)現(xiàn)官疲。

1.定義各種記錄數(shù)據(jù)的變量袱结。

    //棋盤的變量
    var chessMap:ChessMap?
    //記錄你此時(shí)是否已經(jīng)點(diǎn)擊了某個(gè)棋子
    var clickedPiece:Bool = false
    //所有棋子
    var allPieceArray:NSMutableArray = []
    //記錄已點(diǎn)擊的棋子位置:從0到8
    var clickedPointIndex = -1
    //記錄白棋和黑棋的位置
    var allPosition:[Int] = [0,3,6,2,5,8]
    //分別記錄黑棋和白棋的位置
    var whitePieces:[Int] = []
    var blackPieces:[Int] = []

2.創(chuàng)建棋盤和棋子,棋子在游戲過程中是不必消除的途凫。

    override func didMove(to view: SKView) {
        if !contentCreated
        {
            createSceneContens()
            contentCreated = true
        }
    }
    //創(chuàng)建內(nèi)容
    private func createSceneContens()
    {
        self.backgroundColor = SKColor.yellow
        self.scaleMode = .aspectFit
        
        //增加背景棋盤:如何移到線條下方
        let chessBackImage = SKSpriteNode.init(imageNamed: "chessBack")
        chessBackImage.position = CGPoint(x:SCREEN_WIDTH/2,y:200)
        self.addChild(chessBackImage)
        
        chessMap = ChessMap.init(origin: CGPoint(x:SCREEN_WIDTH/2-80 ,y:120))
        self.addChild(chessMap!)
        
        createAllPieces()
    }
    //創(chuàng)建6枚棋子
    private func createAllPieces()
    {
        //寫到這里
        for chessIndex in 0...8
        {
            if chessIndex%3 == 0
            {
                let singlePiece = SKSpriteNode.init(imageNamed: "blackChess")
                singlePiece.position = (chessMap?.positions[chessIndex])!
                singlePiece.name = "blackChess"
                self.addChild(singlePiece)
                allPieceArray.add(singlePiece)
            }
            else if chessIndex%3 == 2
            {
                let singlePiece = SKSpriteNode.init(imageNamed: "whiteChess")
                singlePiece.position = (chessMap?.positions[chessIndex])!
                singlePiece.name = "whiteChess"
                self.addChild(singlePiece)
                allPieceArray.add(singlePiece)
            }
        }
    }

3.移動(dòng)棋子的邏輯
這一步驟考慮的比較多垢夹,比如兩個(gè)玩家怎么輪流出手,棋子從一個(gè)位置是否能夠移動(dòng)到那里维费,移動(dòng)之后是否分出勝負(fù)了果元,所以自然會(huì)調(diào)用別的邏輯。

    //移動(dòng)棋子的邏輯犀盟,并更新數(shù)據(jù),單個(gè)函數(shù)絕不超過50行
    private func moveSinglePiece(positionIndex:Int)
    {
        let _position:CGPoint = (chessMap?.positions[positionIndex])!
        for i in 0...allPieceArray.count-1
        {
            let whitePiece0:SKSpriteNode = allPieceArray[i] as! SKSpriteNode
            
            if whitePiece0.position == chessMap?.positions[clickedPointIndex]
            {
                whitePiece0.position = _position
                //同時(shí)更新所有棋子位置的數(shù)組
                for k in 0...allPosition.count-1 {
                    if allPosition[k] == clickedPointIndex
                    {
                        allPosition.remove(at: k)
                        break
                    }
                }
                allPosition.append(positionIndex)
            }
            if whitePiece0.name == "whiteChess"
            {
                for index in 0...(chessMap?.positions.count)!-1
                {
                    if whitePiece0.position == chessMap?.positions[index]
                    {
                        whitePieces.append(index)
                        break
                    }
                }
            }
            else if whitePiece0.name == "blackChess"
            {
                for index in 0...(chessMap?.positions.count)!-1
                {
                    if whitePiece0.position == chessMap?.positions[index]
                    {
                        blackPieces.append(index)
                        break
                    }
                }
            }
        }
        //判定是否一方勝利:必須統(tǒng)計(jì)移動(dòng)過后的棋子,并給出場(chǎng)景的提示
        if hasWinTheGame(positions: whitePieces){
            print("勝負(fù)已分")
            showWinTips(blackWin: false)
        }
        else if hasWinTheGame(positions: blackPieces)
        {
            showWinTips(blackWin: true)
        }
        whitePieces = []
        blackPieces = []
    }

4.單個(gè)小邏輯的實(shí)現(xiàn)

//通過數(shù)組判斷勝利邏輯
    private func hasWinTheGame(positions:[Int])->Bool
    {
        if (positions.contains(0)&&positions.contains(4)&&positions.contains(8)) || (positions.contains(2)&&positions.contains(4)&&positions.contains(6)){
            return true
        }
        else
        {
            return false
        }
    }
    //游戲結(jié)束而晒,加載勝利的動(dòng)畫
    private func showWinTips(blackWin:Bool){
        let winNode = addWinNode(blackWin: blackWin)
        self.addChild(winNode)
        
        let moveUp = SKAction.moveBy(x: 0, y: 100, duration: 0.5)
        let zoom = SKAction.scale(to: 2, duration: 0.25)
        let pause = SKAction.wait(forDuration: 1)
        let fadeaway = SKAction.fadeOut(withDuration: 0.25)
        let remove = SKAction.removeFromParent()
        //設(shè)置多個(gè)action的集合
        let moveSequence = SKAction.sequence([moveUp,zoom,pause,fadeaway,remove])
        winNode.run(moveSequence, completion: {
            //移除原有的SKNode
            winNode.removeAllActions()
            winNode.removeFromParent()
        })
    }
    //加載勝利的場(chǎng)景:最好能有音樂
    private func addWinNode(blackWin:Bool)->SKLabelNode
    {
        let winLabel = SKLabelNode.init(fontNamed: "Chalkduster")
        if blackWin {
            winLabel.text = "黑棋獲得勝利"
        }
        else
        {
            winLabel.text = "白棋獲得勝利"
        }
        winLabel.fontSize = 24
        winLabel.position = CGPoint(x:self.size.width/2,y:self.size.height/2)
        winLabel.fontColor = SKColor.red
        winLabel.name = "winChessNode"
        
        return winLabel
    }
    
    //判斷是否能夠從一個(gè)點(diǎn)移動(dòng)到另一個(gè)點(diǎn)
    private func canMovePiece(position1:Int,position2:Int)->Bool
    {
        let canMoveHorizotal = abs(position1-position2)==3 //橫向移動(dòng)
        let canMoveVertical = abs(position1-position2)==1 && (position1/3)==(position2/3)//縱向移動(dòng)
        let canMoveSlant = (abs(position1-position2)==4 && position1%4==0) || (abs(position1-position2)==2 && (position1*position2==8 || position1*position2==24))//斜向移動(dòng)
        return canMoveHorizotal || canMoveVertical || canMoveSlant
    }

5.重載touches:方法,將所有邏輯集合阅畴。這里需要判斷是否點(diǎn)擊在棋子的位置倡怎。

    //主要還是依賴于觸摸方法:必須簡(jiǎn)化該方法
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        let touchPosition = touch?.location(in: self)
        
        var isTouchPositionForPiece = false
        //判斷是否在9個(gè)點(diǎn)上->判斷是否在當(dāng)前位置上
        for positionIndex in 0...8
        {
            let _position:CGPoint = (chessMap?.positions[positionIndex])!
            if distanceFrom(point1: _position, point2: touchPosition!) <= 20
            {
                isTouchPositionForPiece = true
        
                if allPosition.contains(positionIndex)//必須點(diǎn)擊了已有棋子的位置
                {
                    clickedPiece = true
                    clickedPointIndex = positionIndex
                }
                else//否則將上次點(diǎn)擊的棋子移動(dòng)該處
                {
                    if clickedPiece && clickedPointIndex>=0
                    {
                        //先判斷是否能夠移動(dòng),如果不能后面不在操作,同時(shí)取消選中狀態(tài)
                        if !canMovePiece(position1: clickedPointIndex, position2: positionIndex)
                        {
                            clickedPiece = false
                            //點(diǎn)擊完畢之后恢復(fù)
                            clickedPointIndex = -1
                            return
                        }
                        
                        moveSinglePiece(positionIndex: positionIndex)
                    }
                    clickedPiece = false
                    //點(diǎn)擊完畢之后恢復(fù)
                    clickedPointIndex = -1
                }

                break
            }
        }
        
    }

以上就是實(shí)現(xiàn)基本功能的過程了监署。當(dāng)然還有開場(chǎng)動(dòng)畫颤专,音樂等效果都屏蔽了,不是核心邏輯钠乏。
因?yàn)橛螒虮容^簡(jiǎn)單栖秕,沒有實(shí)現(xiàn)業(yè)務(wù)實(shí)現(xiàn)和業(yè)務(wù)邏輯的分離。另一個(gè)重要的問題是雖然節(jié)點(diǎn)是可以移除和釋放的缓熟,但是一旦在iOS應(yīng)用中加載了SpriteKit頁(yè)面內(nèi)存總會(huì)增加幾十M累魔,現(xiàn)在還沒找到辦法能回收這部分內(nèi)存。
寫完又發(fā)現(xiàn)自己寫的有點(diǎn)弱够滑,繼續(xù)努力吧垦写!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市彰触,隨后出現(xiàn)的幾起案子梯投,更是在濱河造成了極大的恐慌,老刑警劉巖况毅,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件分蓖,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡尔许,警方通過查閱死者的電腦和手機(jī)么鹤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來味廊,“玉大人蒸甜,你說我怎么就攤上這事∮喾穑” “怎么了柠新?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)辉巡。 經(jīng)常有香客問我恨憎,道長(zhǎng),這世上最難降的妖魔是什么郊楣? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任憔恳,我火速辦了婚禮,結(jié)果婚禮上痢甘,老公的妹妹穿的比我還像新娘喇嘱。我一直安慰自己,他們只是感情好塞栅,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布者铜。 她就那樣靜靜地躺著腔丧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪作烟。 梳的紋絲不亂的頭發(fā)上愉粤,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音拿撩,去河邊找鬼衣厘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛压恒,可吹牛的內(nèi)容都是我干的影暴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼探赫,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼型宙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伦吠,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤妆兑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后毛仪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搁嗓,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年箱靴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腺逛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衡怀,死狀恐怖屉来,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狈癞,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布茂契,位于F島的核電站蝶桶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏掉冶。R本人自食惡果不足惜真竖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厌小。 院中可真熱鬧恢共,春花似錦、人聲如沸璧亚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至透硝,卻和暖如春狰闪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背濒生。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工埋泵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人罪治。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓丽声,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親觉义。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雁社,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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