Sprite Kit 基礎(chǔ)

Sprite Kit 是iOS 7開始添加的一個(gè)新內(nèi)置框架。主要用于開發(fā)2D游戲咙边。支持內(nèi)容包括 精靈猜煮、各種特效(視頻次员、濾鏡遮罩),繼承了物理引擎等許多內(nèi)容王带。

timg-2.jpeg
SpriteKit常用的類:

SKSpriteNode ----- 用于繪制精靈的紋理
SKVideoNod ----- 用于播放視頻
SKLabelNode ----- 用于渲染文本
SKShapeNode ----- 用于渲染基于Core Graphics 路徑的形狀
SKEmitterNode ----- 用于創(chuàng)建和渲染粒子系統(tǒng)
SKCropNode ----- 用于使用遮罩來裁剪子節(jié)點(diǎn)
SKEffectNode ----- 用于使用遮罩來裁剪子節(jié)點(diǎn)

簡(jiǎn)單介紹一下SpriteKit淑蔚,下面介紹開始spriteKit 中基礎(chǔ)類的使用。

SKScene 場(chǎng)景

使用SKScene之前先說一下SKView愕撰,SKView 類是專門用來呈現(xiàn)Sprite Kit 的View刹衫,在這個(gè)類中可以渲染和管理一個(gè)SKScene,每個(gè)Scene中可以加載多個(gè)精靈搞挣,Scene可以管理精靈的行為带迟。

導(dǎo)入SpriteKit 創(chuàng)建SKScene:

func createScene() {
        let skView = SKView.init(frame: self.view.bounds)
        if(skView.scene == nil){
            skView.showsFPS = true
            skView.showsNodeCount = true
            let scene = GameScene(size: skView.bounds.size)
            skView.presentScene(scene)
        }
        self.view.addSubview(skView)
    }

在使用時(shí),一般會(huì)將Scene子類化囱桨,在子類中設(shè)置它的屬性仓犬。在游戲中都會(huì)有多個(gè)場(chǎng)景,就會(huì)有場(chǎng)景切換蝇摸,單純的場(chǎng)景切換會(huì)顯得非常生硬婶肩,所以SpriteKit中提供了過度動(dòng)畫。

crossFadeWithDuration 交叉淡入淡出過渡動(dòng)畫
doorsCloseHorizontalWithDuration 從左右兩邊水平關(guān)閉
doorsCloseVerticalWithDuration 從上下兩邊垂直關(guān)閉
doorsOpenHorizontalWithDuration 從中間向左右兩邊水平打開
doorsOpenVerticalWithDuration 從中間向左右兩邊垂直打開
doorwayWithDuration 從中間向兩邊打開貌夕,新場(chǎng)景從后方向屏幕靠近
fadeWithColor 淡入淡出的過渡動(dòng)畫律歼,先變成指定顏色,再變成目標(biāo)場(chǎng)景
fadeWithDuration 淡入淡出的過渡動(dòng)畫啡专,先變成黑色险毁,再變成指定顏色
flipHorizontalWithDuration 以水平中軸線垂直翻轉(zhuǎn)
flipVerticalWithDuration 以垂直中中軸線水平翻轉(zhuǎn)
movenInWithDirection 新場(chǎng)景從指定方向移入
pushWithDirection 新場(chǎng)景從指定方向推入
revealWithDirection 舊場(chǎng)景向指定方向移除,新場(chǎng)景在舊場(chǎng)景下面
使用:skView.presentScene(scene, transition:SKTransition)

SKSpriteNode 精靈

精靈分為有紋理精靈和無紋理精靈们童,紋理精靈是常用的畔况,是我們把插圖放到場(chǎng)景中的方法,像游戲中的任務(wù)角色和背景等慧库。

使用方法跷跪,創(chuàng)建精靈:
let KScreenWidth = UIScreen.main.bounds.width
let KScreenHeight = UIScreen.main.bounds.height
func addNode() {
        let texture = SKTexture.init(imageNamed: "ao.jpg")  // 紋理
        let splash = SKSpriteNode.init(texture: texture)
//        let splash = SKSpriteNode.init(imageNamed: "ao.jpg")
        splash.size = CGSize.init(width: KScreenWidth, height: KScreenHeight)
        splash.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        // 設(shè)置錨點(diǎn)
//        splash.anchorPoint = CGPoint.init(x: 0.0, y: 0.0)
        // 精靈著色
        splash.color = SKColor.green
        splash.colorBlendFactor = 0.3   // 顏色混合因子0~1
        splash.setScale(2)  // 縮放 放大兩倍
//        splash.xScale = 2   // 單獨(dú)縮放x
        splash.zRotation = CGFloat(Double.pi)/2  // 旋轉(zhuǎn)
        splash.alpha = 0.5
        splash.isHidden = false
        self.addChild(splash)
        
//        splash.removeFromParent()
//        removeAllChildren()
    }

其中的錨點(diǎn)可以根據(jù)下面的圖理解

B2588466-9F89-4209-9EB8-BC732A1F1935.png

可以理解為將圖片訂在墻上,錨點(diǎn)相當(dāng)于釘子釘?shù)奈恢闷氚澹J(rèn)是(0.5, 0.5)吵瞻。

刪除精靈
splash.removeFromParent()
removeAllChildren()
SKLightNode

為了讓精靈更具有真實(shí)感,SpriteKit提供了SKLightNode作為光源節(jié)點(diǎn)甘磨。

SKLightNode 可以定義光源的顏色橡羞、陰影和衰減程度。繼承于SKNode济舆。為了在SKSpriteNode的效果更加逼真卿泽,SKSpriteNode 提供了normalTexture 屬性,用來儲(chǔ)存原貼圖的發(fā)現(xiàn)貼圖NormalMap滋觉。

SKLightNode常用屬性:

enabled 光源的開關(guān)
ambientColor 環(huán)境顏色签夭,默認(rèn)黑色(無)
lightColor 光的顏色齐邦,默認(rèn)白色
shadowColor 被精靈物體遮擋產(chǎn)生的陰影顏色
falloff 光源強(qiáng)度的衰減比率
categoryBitMask 光的種類,32位整數(shù)第租。SKSpriteNode的 lightingBItMask(被何種光照亮)侄旬、shadowedBitMask(被何種光產(chǎn)生陰影)、shadowCastBitMask(遮擋何種光線并產(chǎn)生陰影) 存儲(chǔ)著光的種類煌妈。

SKLightNode使用:
func addLightNode() {
        backgroundColor = SKColor.black
        // 創(chuàng)建精靈
        let spriNode = SKSpriteNode.init(color: UIColor.white, size: CGSize.init(width: 300, height: 300))
        spriNode.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        self.addChild(spriNode)
        // 添加光源
        let nodeNormMap = spriNode.texture?.generatingNormalMap()
        spriNode.normalTexture = nodeNormMap
        spriNode.lightingBitMask = 1    // 被何種光照
        spriNode.name = "SprNOde"
        let lightSprite = SKLightNode() //實(shí)例化光源
        lightSprite.position = CGPoint.init(x: KScreenWidth/2 + 60, y: KScreenHeight/2) // 關(guān)照位置
        lightSprite.name = "LightSptite"
        lightSprite.categoryBitMask = 1 // 光的種類
        self.addChild(lightSprite)
    }

運(yùn)行結(jié)果截圖:

C9C46872B5421D98C7940C17C21B4D3C.png

SKAction 動(dòng)作

SKAction是游戲中很重要的一部分儡羔,內(nèi)容很多啊,會(huì)寫的比較長(zhǎng)璧诵。首先預(yù)覽下內(nèi)容汰蜘,動(dòng)作的分類:動(dòng)作屬性、移動(dòng)動(dòng)作之宿、序列動(dòng)作族操、重復(fù)動(dòng)作、延遲動(dòng)作比被、縮放動(dòng)作色难、旋轉(zhuǎn)動(dòng)作、調(diào)整尺寸的動(dòng)作等缀、組合動(dòng)作枷莉、改變透明度的動(dòng)作、改變顏色的動(dòng)作尺迂、以動(dòng)畫的形式改變紋理的動(dòng)作笤妙、路徑動(dòng)作、反向運(yùn)動(dòng)噪裕、速度動(dòng)作蹲盘、顯示或隱藏動(dòng)作、塊動(dòng)作膳音、自定義動(dòng)作召衔、刪除動(dòng)作。

創(chuàng)建動(dòng)作方法
let spriteMoveUp = SKAction.moveBy(x: 300, y: 0, duration: 1.0) // X方向向右移100
1祭陷、移動(dòng)動(dòng)作

包括以點(diǎn)的方式移動(dòng)和 以偏移量的方式移動(dòng)

func nodeAction() {
        let texture = SKTexture.init(imageNamed: "field")  // 紋理
        let background = SKSpriteNode.init(texture: texture)
        background.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        background.size = CGSize.init(width: KScreenWidth, height: KScreenHeight)
        self.addChild(background)

        let ball = SKSpriteNode.init(imageNamed: "soccer")
        ball.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        ball.setScale(1.05) // 縮放
        ball.size = CGSize.init(width: 50, height: 50)
        self.addChild(ball)

        // 動(dòng)作   以點(diǎn)的方式移動(dòng)
        let spriteMoveUp = SKAction.moveBy(x: 300, y: 0, duration: 1.0) // X方向向右移100
        // ball.run(spriteMoveUp)
        // 動(dòng)作  以偏移量的方式移動(dòng)
        let negDelta = CGVector.init(dx: -300, dy: -100)
        let actionMove = SKAction.move(by: negDelta, duration: 2)
        ball.run(actionMove)
    }
2苍凛、動(dòng)作屬性

speed 速度
duration 時(shí)間
timingMode 曲線方式

曲線方式包括四種:

SKActionTimingLinear 平均分布
SKActionTimingEaseIn 開始較慢,再加快
SKActionTimingEaseOut 開始快颗胡,再變慢
SKActionTimingEaseInEaseOut 開始慢毫深,再加快至中間吩坝,再變慢
let spriteMoveUp = SKAction.moveBy(x: 300, y: 0, duration: 1.0)

spriteMoveUp.speed = 1.3  // 速度
spriteMoveUp.timingMode = SKActionTimingMode.easeInEaseOut  // 曲線方式
print(ball.speed)  // 獲取并輸出動(dòng)作所需時(shí)間
3毒姨、 序列動(dòng)作

使用sequence() 方法實(shí)現(xiàn)。以上面移動(dòng)動(dòng)作為例钉寝,將spriteMoveUp弧呐、actionMove作為一個(gè)序列動(dòng)作然后執(zhí)行闸迷。

let sequence = SKAction.sequence([spriteMoveUp, actionMove])
ball.run(sequence)
4、重復(fù)動(dòng)作

重復(fù)動(dòng)作分為無限重復(fù)和有次數(shù)的重復(fù)俘枫,使用方法:

let sequence = SKAction.sequence([spriteMoveUp, actionMove])
//        let runForever = SKAction.repeatForever(sequence)  // 無限重復(fù)
let runRepeat = SKAction.repeat(sequence, count: 2)  // 重復(fù)兩次(執(zhí)行兩次)
ball.run(runRepeat)
5腥沽、延遲動(dòng)作

使用waitForDuration()方法實(shí)現(xiàn)。以序列動(dòng)作為例鸠蚪,在序列中插入一個(gè)延遲動(dòng)作今阳。

let wait = SKAction.wait(forDuration: 1.0)   // 延遲動(dòng)作(延遲1s)
let sequence = SKAction.sequence([spriteMoveUp, wait, actionMove])
ball.run(sequence)
6、縮放動(dòng)作

縮放動(dòng)作分為:以縮放倍數(shù)縮放(scaleTo()茅信、scaleXTo())盾舌、以增量值縮放(scaleBy()、scaleXBy())

func scaleAction() {
        let ball = SKSpriteNode.init(imageNamed: "soccer")
        ball.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        ball.size = CGSize.init(width: 50, height: 50)  // 設(shè)置初始大)
        self.addChild(ball)
        
        // 以縮放倍數(shù)縮放
        let shrink = SKAction.scale(to: 0.1, duration: 0.5) // 縮小
        let zoom = SKAction.scale(to: 10, duration: 2) // 放大
        // 對(duì)寬高進(jìn)行縮放
//        let shrink = SKAction.scaleX(to: 0.1, duration: 3) // 縮小
//        let zoom = SKAction.scale(to: 1, duration: 3) // 放大
        let sequence = SKAction.sequence([shrink, zoom])
        let runForever = SKAction.repeatForever(sequence)
//        ball.run(runForever)
        
        // 以增量值縮放
        let scaleZoom = SKAction.scale(by: 1, duration: 0.2)    // 放大
        let scaleShrink = SKAction.scale(by: -1, duration: 0.2) // 縮小
//        let scaleZoom = SKAction.scaleX(by: 1, duration: 0.2)    // 放大
//        let scaleShrink = SKAction.scaleX(by: -1, duration: 0.2) // 縮小
        let scaleSequence = SKAction.sequence([scaleZoom, scaleShrink])
        let scaleForever = SKAction.repeatForever(scaleSequence)
        ball.run(scaleForever)
    }
7蘸鲸、旋轉(zhuǎn)動(dòng)作

使用rotateByAngle()方法實(shí)現(xiàn)妖谴。

   let rotate = SKAction.rotate(byAngle: CGFloat(Double.pi)*2, duration: 3)
   ball.run(rotate)
8、調(diào)整尺寸的動(dòng)作

調(diào)整尺寸的動(dòng)作包括:以目標(biāo)值調(diào)整尺寸酌摇、以增量調(diào)整尺寸

let resizeWidth = SKAction.resize(toWidth: 100, height: 100, duration: 2)  // 以目標(biāo)值調(diào)整尺寸
ball.run(resizeWidth)
let resize = SKAction.resize(byWidth: 200, height: 200, duration: 2)  // 以增量調(diào)整尺寸
ball.run(resize)
9膝舅、組合動(dòng)作

就是同時(shí)對(duì)兩個(gè)及以上的動(dòng)作進(jìn)行執(zhí)行。使用group()方法實(shí)現(xiàn)窑多。

func groupAction() {
        backgroundColor = SKColor.black
        
        let star = SKSpriteNode.init(imageNamed: "star.jpg")
        star.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        star.size = CGSize.init(width: 300, height: 300)
        self.addChild(star)
        
        let zoom = SKAction.scale(to: 1, duration: 0.2)
        let shrink = SKAction.scale(to: 0.1, duration: 0.2)
        let sequence = SKAction.sequence([zoom, shrink])
        let rotate = SKAction.rotate(byAngle: CGFloat(Double.pi)*2, duration: 1.5)
        
        let group = SKAction.group([sequence, rotate])  // 組合動(dòng)畫
        let runForever = SKAction.repeatForever(group)
        star.run(runForever)
    }
10仍稀、改變透明度的動(dòng)作

有兩種,分別是不需要指定alpha值和指定alpha值(以目標(biāo)值指定埂息、以增量值指定)琳轿。

// 不需要指定alpha值
let fadeOut = SKAction.fadeOut(withDuration: 0.25)
let fadeIn = SKAction.fadeIn(withDuration: 0.25)
// 指定alpha值
let fadeOutAlpha = SKAction.fadeAlpha(to: 0, duration: 0.2) // 以目標(biāo)值指定
let fadeInAlpha = SKAction.fadeAlpha(to: 1, duration: 0.2)
let hide = SKAction.fadeAlpha(by: -1, duration: 0.2)    // 以增量值指定
let show = SKAction.fadeAlpha(by: 1, duration: 0.2)
11、改變顏色的動(dòng)作

分為兩種:改變混合因子耿芹、改變顏色和混合因子崭篡。

// 改變混合因子
let color1 = SKAction.colorize(withColorBlendFactor: 0.8, duration: 0.5)
let color2 = SKAction.colorize(withColorBlendFactor: 0.0, duration: 0.5)
// 改變顏色和混合因子
let color = SKAction.colorize(with: SKColor.green, colorBlendFactor: 0.7, duration: 2)
12、以動(dòng)畫的形式改變紋理的動(dòng)作

使用animateWithTextures()方法實(shí)現(xiàn)

func animateTexturesAction() {
        // 加載動(dòng)畫紋理
        let textures = NSMutableArray.init()
        for index in 4...13 {
            let texture = SKTexture.init(imageNamed: "frame-\(index)")
            textures.add(texture)
        }
        
        let playerSprite = SKSpriteNode.init(texture: textures.firstObject as? SKTexture)
        playerSprite.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        self.addChild(playerSprite)
        
        let runRightAction = SKAction.animate(with: textures as! [SKTexture], timePerFrame: 0.1)
        let runForever = SKAction.repeatForever(runRightAction)
        playerSprite.run(runForever)
    }
13吧秕、路徑動(dòng)作

使用followPath()方法實(shí)現(xiàn)琉闪。方法中的屬性:

path 用來指定一個(gè)CGPathRef路徑
offset 用來指定路徑中的點(diǎn)是否為相對(duì)坐標(biāo),true(相對(duì)坐標(biāo))砸彬,false(絕對(duì)坐標(biāo))
orient 指定Z軸在旋轉(zhuǎn)時(shí)屬性是否改變
sec 動(dòng)作時(shí)間

func pathAction() {
        let background = SKSpriteNode.init(imageNamed: "field")
        background.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        background.size = CGSize.init(width: KScreenWidth, height: KScreenHeight)
        self.addChild(background)
        
        let ball = SKSpriteNode.init(imageNamed: "soccer")
        ball.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        ball.size = CGSize.init(width: 50, height: 50)
        self.addChild(ball)
        
        let circle = CGPath.init(roundedRect: CGRect.init(x: 200, y:100 , width: 200, height: 200), cornerWidth: 100, cornerHeight: 100, transform: nil)
        let follow = SKAction.follow(circle, asOffset: false, orientToPath: false, duration: 5)
        let runRepeat = SKAction.repeatForever(follow)
        // 反向運(yùn)動(dòng)
        let reverse = runRepeat.reversed()
        // 速度動(dòng)作
        let speedaction = SKAction.speed(to: 15, duration: 1.0)
        let group = SKAction.group([speedaction, reverse])
        ball.run(group)
        
    }
14颠毙、反向運(yùn)動(dòng)
let spriteMoveUp = SKAction.moveBy(x: 300, y: 0, duration: 1.0)
let reverse = spriteMoveUp.reversed()  // 反向運(yùn)動(dòng)
15、速度動(dòng)作

使用 speedTo() 或者 speedBy() 實(shí)現(xiàn)砂碉。

let speedaction = SKAction.speed(to: 5, duration: 1.0)
16蛀蜜、顯示或隱藏動(dòng)作

使用 hide() 和unhide()方法實(shí)現(xiàn)

let hide = SKAction.hide()      // 顯示動(dòng)作
let show = SKAction.unhide()    // 隱藏動(dòng)作
17、塊動(dòng)作

使用runBlock()方法實(shí)現(xiàn),異步調(diào)用動(dòng)作的方法闹究,可指定執(zhí)行的線程剪个。

func blockAction() {
        let ball = SKSpriteNode.init(imageNamed: "soccer")
        ball.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        ball.size = CGSize.init(width: 80, height: 80)
        self.addChild(ball)

        // 創(chuàng)建塊動(dòng)作
        let blockAction = SKAction.run { 
            let rotate = SKAction.rotate(byAngle: CGFloat(Double.pi*2), duration: 3)
            let runRepeat = SKAction.repeatForever(rotate)
            ball.run(runRepeat)
        }
        ball.run(blockAction)
    }

設(shè)置動(dòng)作執(zhí)行的線程:

SKAction.run({
}, queue: DispatchQueue)
18闸准、自定義動(dòng)作

使用customActionWithDuration()實(shí)現(xiàn)

func customAction() {
        let background = SKSpriteNode.init(imageNamed: "field")
        background.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        background.size = CGSize.init(width: KScreenWidth, height: KScreenHeight)
        self.addChild(background)
        
        let ball = SKSpriteNode.init(imageNamed: "soccer")
        ball.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        ball.size = CGSize.init(width: 50, height: 50)
        self.addChild(ball)
        
        let customAction = SKAction.customAction(withDuration: 2) { (node: SKNode, elapsedTime: CGFloat) in
            let fraction = CGFloat(elapsedTime) / 2.0
            let yOff = 100 * 4 * fraction * (1 - fraction)
            node.position = CGPoint.init(x: node.position.x, y: KScreenHeight/2 + CGFloat(yOff))
        }
        let runRepeat = SKAction.repeatForever(customAction)
        ball.run(runRepeat)
        
        // MARK: 刪除動(dòng)作
//        let remove = SKAction.removeFromParent()
    }
19霎奢、刪除動(dòng)作

使用removeFromParent()方法實(shí)現(xiàn)户誓。

let remove = SKAction.removeFromParent()


用戶交互

1、觸摸

觸摸是最常見的用戶交互之一幕侠。分為單拍帝美、多拍觸摸(touchesBegan),移動(dòng)觸摸(touchesMoved)晤硕,結(jié)束和取消觸摸(touchesEnded)悼潭。

在觸摸中常用的事件處理:?jiǎn)闻暮投嗯挠|摸在一個(gè)方法中監(jiān)聽,所以需要進(jìn)行區(qū)分

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let mytouches = touches as NSSet
        let touch: AnyObject? = mytouches.anyObject() as AnyObject
        if(touch?.tapCount == 1){
            // 單拍
        }
        if(touch?.tapCount == 2) {
            // 多拍
        }
    }

在移動(dòng)觸摸中獲取當(dāng)前點(diǎn)擊的坐標(biāo)位置

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let mytouchs = touches as NSSet
        let touch = mytouchs.anyObject() as! UITouch
        let touchLocation = touch.location(in: self)
        print(touchLocation)
    }
2舞箍、手勢(shì)

常見的手勢(shì)識(shí)別器:

名稱 功能
UITapGestureRecognizer 輕拍
UIPinchGestureRecognizer
UISwipeGestureRecognizer 滑動(dòng)
UIRotationGestureRecognizer 旋轉(zhuǎn)
UIPanGestureRecognizer 移動(dòng)
UILongPressGestureRecognizer 長(zhǎng)按
  • 輕拍
    分兩步女责,添加手勢(shì)、實(shí)現(xiàn)手勢(shì)方法创译。
    func addGestureRecognizer() {
        let tapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(self.handleTap))
        self.view?.addGestureRecognizer(tapGestureRecognizer)
    }

    func handleTap() {
        backgroundColor = UIColor.yellow
    }

  • 捏 其實(shí)就是通過兩個(gè)手指的張合抵知,實(shí)現(xiàn)圖片的放大和縮小。
    func addGestureRecognizer() {
        let pinchGestureRecognizer = UIPinchGestureRecognizer.init(target: self, action: #selector(handlepin(recognizer:)))
        self.view?.addGestureRecognizer(pinchGestureRecognizer)
    }

    var lastScale: CGFloat = 0.0
    func handlepin(recognizer: UIPinchGestureRecognizer) {
        self.view?.bringSubview(toFront: view!)
        // 復(fù)原
        if(recognizer.state == UIGestureRecognizerState.ended){
            lastScale = 1.0
            return
        }
        
        let scale: CGFloat = 1.0 - (lastScale - recognizer.scale)
        let current: CGAffineTransform = recognizer.view!.transform
        let newaa = current.scaledBy(x: scale, y: scale)
        recognizer.view?.transform = newaa
        lastScale = recognizer.scale
    }
  • 旋轉(zhuǎn)
    通過旋轉(zhuǎn)手勢(shì)软族,兩個(gè)手指旋轉(zhuǎn)控制圖片旋轉(zhuǎn)刷喜。
    func addGestureRecognizer() {
        let rotationGestureRecognizer = UIRotationGestureRecognizer.init(target: self, action: #selector(handRotation(recognizer:)))
        self.view?.addGestureRecognizer(rotationGestureRecognizer)
    }
    // 旋轉(zhuǎn)
    func handRotation(recognizer: UIRotationGestureRecognizer) {
        let rataion:CGFloat = recognizer.rotation
        sprite.zRotation = -rataion
    }
  • 移動(dòng)
    和觸摸中的touchesMoved類似效果,通過移動(dòng)手勢(shì)立砸,可以使圖片跟著手指的移動(dòng)手勢(shì)移動(dòng)掖疮。
    func addGestureRecognizer() {
        let panGestureRecognizer = UIPanGestureRecognizer.init(target: self, action: #selector(handPan(recognizer:)))
        self.view?.addGestureRecognizer(panGestureRecognizer)
    }
    // 移動(dòng)
    func handPan(recognizer: UIPanGestureRecognizer) {
        let point = recognizer.location(in: self.view)
        let pointY = (self.view?.frame.size.height)! - point.y
        sprite.position = CGPoint.init(x: point.x, y: pointY)
    }
  • 滑動(dòng)
    滑動(dòng)手勢(shì):UISwipeGestureRecognizer。在使用時(shí)可以使用direction屬性設(shè)置滑動(dòng)手勢(shì)滑動(dòng)的方向颗祝。
    func addGestureRecognizer() {
        let swipeLeftGestureRecognizer = UISwipeGestureRecognizer.init(target: self, action: #selector(handSwipeLeft))     // 向左滑動(dòng)
        swipeLeftGestureRecognizer.direction = UISwipeGestureRecognizerDirection.left;
        self.view?.addGestureRecognizer(swipeLeftGestureRecognizer)
        
        let swipeRightGestureRecognizer = UISwipeGestureRecognizer.init(target: self, action: #selector(handSwipeRight))     // 向右滑動(dòng)
        swipeRightGestureRecognizer.direction = UISwipeGestureRecognizerDirection.right;
        self.view?.addGestureRecognizer(swipeRightGestureRecognizer)
    }
    // 滑動(dòng)
    func handSwipeLeft() {
        let actionMove = SKAction.move(to: CGPoint.init(x: sprite.size.width/2, y: KScreenHeight/2), duration: 1)
        sprite.run(actionMove)
    }
    func handSwipeRight() {
        let actionMove = SKAction.move(to: CGPoint.init(x: KScreenWidth - sprite.size.width/2, y: KScreenHeight/2), duration: 1)
        sprite.run(actionMove)
    }
  • 長(zhǎng)按
    func addGestureRecognizer() {
        let longPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(handLongPress))
        self.view?.addGestureRecognizer(longPressGestureRecognizer)
    }
    // 長(zhǎng)按
    func handLongPress() {
        backgroundColor = UIColor.gray
    }
3浊闪、重力感應(yīng)

重力感應(yīng)事件又被稱為加速計(jì)事件,屬于運(yùn)動(dòng)事件的一種螺戳。運(yùn)動(dòng)時(shí)間產(chǎn)生可以通過:傾斜搁宾、搖動(dòng)設(shè)備等。這些運(yùn)動(dòng)事件的檢測(cè)基于設(shè)設(shè)備的加速計(jì)或陀螺儀倔幼。需要訪問這些數(shù)據(jù)盖腿,需要通過coreMotion這個(gè)框架,coreMotion有提供訪問加速計(jì)和陀螺儀數(shù)據(jù)的接口损同。

導(dǎo)入coerMotion框架翩腐,實(shí)例化CMMotionManager()對(duì)象。
在使用重力感應(yīng)前膏燃,需要判斷設(shè)備是否支持重力感應(yīng):

import CoreMotion
var mManger:CMMotionManager = CMMotionManager()
override func didMove(to view: SKView) {
    if(!mManger.isAccelerometerAvailable){
        // 重力感應(yīng)不可用
    }
}

在判斷設(shè)備支持重力感應(yīng)后茂卦。我們來做一個(gè)小功能,使用重力感應(yīng)來控制精靈對(duì)象的移動(dòng)组哩。

步驟:

  • 1等龙、創(chuàng)建場(chǎng)景处渣。
  • 2、判斷重力感應(yīng)是否可用而咆。
  • 3、添加物理引擎幕袱,添加物理體暴备。
  • 4、獲取重力感應(yīng)accelerometer的數(shù)據(jù)们豌。
  • 5涯捻、根據(jù)數(shù)據(jù)移動(dòng)精靈。

代碼:

import Foundation
import UIKit
import SpriteKit
import CoreMotion

var mManger:CMMotionManager = CMMotionManager()
class GravityScene: SKScene {
    
    var gravityBall = SKSpriteNode.init(imageNamed: "soccer")
    
    override func didMove(to view: SKView) {
        // 創(chuàng)建兩個(gè)精靈對(duì)象望迎,場(chǎng)景和移動(dòng)體
        let background = SKSpriteNode.init(imageNamed: "field")
        background.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        background.size = CGSize.init(width: KScreenHeight, height: KScreenWidth)
        self.addChild(background)
        
        gravityBall.position = CGPoint.init(x: KScreenWidth/2, y: KScreenHeight/2)
        gravityBall.size = CGSize.init(width: 50, height: 50)
        self.addChild(gravityBall)
        
        // 判斷重力感應(yīng)是否可用
        if(!mManger.isAccelerometerAvailable){
            // 重力感應(yīng)不可用
            let alert:UIAlertController = UIAlertController.init(title: "提示", message: "重力感應(yīng)不可用", preferredStyle: UIAlertControllerStyle.alert)
            let cancel:UIAlertAction = UIAlertAction.init(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)
            alert.addAction(cancel)
            
            self.getCurrentVC()?.present(alert, animated: true, completion: {
            })
            
        }else {
            mManger.startAccelerometerUpdates()
        }
        
        
        // 添加物理引擎障癌,添加物理體
        self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
        //創(chuàng)建矩形物理體
        self.gravityBall.physicsBody = SKPhysicsBody.init(rectangleOf: self.gravityBall.frame.size)
        self.gravityBall.physicsBody?.isDynamic = true  // 能承受碰撞和其他外力作用
        self.gravityBall.physicsBody?.affectedByGravity = false // 不承受重力影響
        self.gravityBall.physicsBody?.mass = 0.2    // 給物體任意質(zhì)量,使移動(dòng)就會(huì)顯得自然
        
    }
    
    // 飛創(chuàng)移動(dòng)的方法
    func ballUpdate() {
        let data:CMAccelerometerData? = mManger.accelerometerData
        // 獲取accelerometer數(shù)據(jù)
        var value:Double? = data?.acceleration.x
        if(value == nil){
            value = 0
        }
        
        // 判斷設(shè)備傾斜方向
        if(fabs(value!) > 0.2){
            let fvector = CGVector.init(dx: 40*CGFloat(value!), dy: 0)
            self.gravityBall.physicsBody?.applyForce(fvector)
        }
    }
    
    override func update(_ currentTime: TimeInterval) {
        ballUpdate()
    }
    
    // 當(dāng)前控制器響應(yīng)者
    func getCurrentVC()->UIViewController?{
        var result:UIViewController?
        var window = UIApplication.shared.keyWindow
        if window?.windowLevel != UIWindowLevelNormal{
            let windows = UIApplication.shared.windows
            for tmpWin in windows{
                if tmpWin.windowLevel == UIWindowLevelNormal{
                    window = tmpWin
                    break
                }
            }
        }
        
        let fromView = window?.subviews[0]
        if let nextRespnder = fromView?.next{
            if nextRespnder.isKind(of: UIViewController.classForCoder()){
                result = nextRespnder as? UIViewController
            }else{
                result = window?.rootViewController
            }
        }
        return result
    }
}

將此場(chǎng)景添加到控制器的視圖上顯示即可辩尊。

    // 創(chuàng)建重力感應(yīng)場(chǎng)景
    func createGravityScene() {
        let skView = SKView.init(frame: self.view.bounds)
        if(skView.scene == nil){
            skView.showsFPS = true
            skView.showsNodeCount = true
            let scene = GravityScene(size: skView.bounds.size)
            skView.presentScene(scene)
        }
        self.view.addSubview(skView)
    }

最后完成的效果是涛浙,場(chǎng)景中的ball精靈會(huì)根據(jù)手機(jī)的左右傾斜方向來移動(dòng)。

最后奉上前面所有內(nèi)容的demo Sprite Kit 基礎(chǔ)

參考:《iOS游戲框架 Sprite Kit技術(shù)詳解》

基礎(chǔ)篇就這些了摄欲。接下來就是進(jìn)階部分了:Sprite Kit 進(jìn)階(音頻轿亮、視頻、粒子系統(tǒng))胸墙。 還有最后的高級(jí):Sprite Kit 高級(jí)(物理引擎我注、瓦片地圖)。會(huì)不定期更新迟隅,有興趣的可以關(guān)注下哦但骨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市智袭,隨后出現(xiàn)的幾起案子奔缠,更是在濱河造成了極大的恐慌,老刑警劉巖吼野,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件添坊,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡箫锤,警方通過查閱死者的電腦和手機(jī)贬蛙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谚攒,“玉大人阳准,你說我怎么就攤上這事×蟪簦” “怎么了野蝇?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵讼稚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我绕沈,道長(zhǎng)锐想,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任乍狐,我火速辦了婚禮赠摇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浅蚪。我一直安慰自己藕帜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布惜傲。 她就那樣靜靜地躺著洽故,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盗誊。 梳的紋絲不亂的頭發(fā)上时甚,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音哈踱,去河邊找鬼撞秋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嚣鄙,可吹牛的內(nèi)容都是我干的吻贿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼哑子,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼舅列!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起卧蜓,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤帐要,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后弥奸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榨惠,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年盛霎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赠橙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愤炸,死狀恐怖期揪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情规个,我是刑警寧澤凤薛,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布姓建,位于F島的核電站,受9級(jí)特大地震影響缤苫,放射性物質(zhì)發(fā)生泄漏速兔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一活玲、第九天 我趴在偏房一處隱蔽的房頂上張望涣狗。 院中可真熱鬧,春花似錦翼虫、人聲如沸屑柔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至死陆,卻和暖如春招拙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背措译。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工别凤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人领虹。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓规哪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親塌衰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子诉稍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

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