SpriteKit 保衛(wèi)蘿卜1項(xiàng)目實(shí)戰(zhàn)(一)

本次項(xiàng)目實(shí)戰(zhàn)所用的資源均來自保衛(wèi)蘿卜官方App 保衛(wèi)蘿卜官網(wǎng)
保護(hù)知識(shí)產(chǎn)權(quán),人人有責(zé)结澄!

前言:從事iOS應(yīng)用開發(fā)好幾年了拄查,跟著Swift語言的發(fā)展過來的,這些年來沒有接觸過游戲開發(fā)煤墙,感覺挺可惜的麻惶,所以決定開始學(xué)習(xí)用SpriteKit來開發(fā)游戲馍刮。寫文章把自己的開發(fā)過程記錄下來,希望能夠和其他開發(fā)者更多進(jìn)行交流學(xué)習(xí)窃蹋。

創(chuàng)建項(xiàng)目

開發(fā)環(huán)境:Xcode12卡啰、Swift 5

我們在Xcode上選擇File → New → Project或者使用快捷鍵Shift + Command + N來打開創(chuàng)建項(xiàng)目面板静稻,填入項(xiàng)目名稱和組織名稱,游戲語言Swift匈辱,游戲框架選擇SpriteKit振湾,點(diǎn)擊Next開始自己的新項(xiàng)目。

項(xiàng)目配置

新項(xiàng)目中有些文件我們暫時(shí)用不到亡脸,先把GameScene.sksActions.sks這兩個(gè)文件刪除了吧押搪,這兩個(gè)文件是為了方便管理SKNode(節(jié)點(diǎn))SKAction(動(dòng)作)的。我們先從代碼開始學(xué)習(xí)暫時(shí)就不需要這種方式來構(gòu)建場景浅碾。

然后我們創(chuàng)建三個(gè)新的目錄Utils大州、NodesScenes,分別用來管理通用垂谢、節(jié)點(diǎn)和場景類的文件摧茴。我們在Utils目錄下創(chuàng)建Functions.swiftConstants.swiftExtensions.swift三個(gè)文件埂陆,接著在Nodes目錄下創(chuàng)建BaseNode.swift文件,然后把GameScene.swift文件移動(dòng)到Scenes目錄下娃豹,最后項(xiàng)目的文件結(jié)構(gòu)如下:

AppDelegate.swift          // 應(yīng)用入口
GameViewController.swift   // 視圖控制器
Main.storyboard            // 故事板
|-- Utils                  // 通用目錄
    |-- Constants.swift    // 通用常量
    |-- Extensions.swift   // 通用拓展
    |-- Functions.swift    // 通用方法
|-- Nodes                  // 節(jié)點(diǎn)目錄
    |-- BaseNode.swift     // 自定義的 SKSpriteNode 節(jié)點(diǎn)
|-- Scenes                 // 場景目錄
    |-- GameScene.swift    // 應(yīng)用主場景
文件結(jié)構(gòu)

添加資源

正所謂兵馬未動(dòng)糧草先行焚虱,項(xiàng)目要開發(fā)了當(dāng)然要準(zhǔn)備圖片和音頻等資源啦,把資源文件添加進(jìn)項(xiàng)目里面吧懂版,注意勾選Copy items if needed鹃栽,選擇Create groups,然后點(diǎn)擊Add躯畴,這些資源包括了應(yīng)用圖標(biāo)民鼓、啟動(dòng)圖、散圖蓬抄、紋理集丰嘉、音頻、數(shù)值設(shè)定等文件嚷缭。

添加資源文件

設(shè)置應(yīng)用圖標(biāo)和啟動(dòng)圖

使用快捷鍵 Command + R開始編譯項(xiàng)目

Hello World

開始的項(xiàng)目沒有應(yīng)用圖標(biāo)饮亏、啟動(dòng)圖,我們需要自己設(shè)置阅爽。把資源文件里的應(yīng)用圖標(biāo)對應(yīng)地拖進(jìn)項(xiàng)目吧路幸,然后給應(yīng)用起一個(gè)新的名稱

應(yīng)用圖標(biāo)

因?yàn)橛螒蝽?xiàng)目基本是橫屏的,所以需要修改項(xiàng)目支持的屏幕方向付翁,在項(xiàng)目設(shè)置中的Device OrientationPortrait勾選項(xiàng)給取消掉简肴。
應(yīng)用啟動(dòng)頁推薦使用 LaunchScreen.storyboard, 創(chuàng)建一個(gè) LaunchScreen文件,然后在該文件上添加自己想要的啟動(dòng)頁視圖就好了百侧,這里我直接放了一張圖片砰识,只需要一張橫屏圖就可以適配絕大部分機(jī)型了能扒。

啟動(dòng)圖

配置場景

創(chuàng)建場景

新項(xiàng)目的的文件入口是 Main.storyboard → GameViewController.swift → GameScene.swift

因?yàn)槲覀儎h除了默認(rèn)生成的場景文件GameScene.sks,里面的場景也無法獲取了仍翰,我們需要通過代碼來創(chuàng)建新的場景赫粥,我們需要在GameViewController.swift文件的viewDidLoad()方法中修改成以下代碼:

override func viewDidLoad() {
    super.viewDidLoad()
    if let view = self.view as! SKView? {
        let scene = GameScene(size: CGSize(width: 1334, height: 750))
        // 設(shè)置錨點(diǎn)位置在中心
        scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        // 設(shè)置場景的縮放模式
        scene.scaleMode = .aspectFill
        // 展示場景
        view.presentScene(scene)
        // 設(shè)置忽略同一z軸上的節(jié)點(diǎn)添加順序
        view.ignoresSiblingOrder = true
        // 顯示fps
        view.showsFPS = true
        // 顯示節(jié)點(diǎn)數(shù)量
        view.showsNodeCount = true
    }
}

關(guān)于anchorPoint的部分我們下面會(huì)進(jìn)行補(bǔ)充,我們接著進(jìn)入 GameScene.swift文件中予借,刪除系統(tǒng)自動(dòng)生成的代碼越平,剩下的代碼如下:

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    override func sceneDidLoad() {

    }
}

接下來我們要添加首頁背景圖片,開始之前需要解釋一下紋理集 SKTextureAtlas灵迫,這個(gè)和其他開發(fā)框架中的圖集概念差不多秦叛,比如 cocoa2d-x中經(jīng)常使用的 .pvr.ccz文件(支持加密),紋理集或圖集可以把多張圖片集合到一張圖片中瀑粥,用 plist文件描述每張圖片的尺寸等信息挣跋,可以更方便地管理圖片資源。
項(xiàng)目中的圖片資源我根據(jù) plist文件編譯生成了對應(yīng)的獲取紋理集圖片的 struct狞换。
紋理集的目錄結(jié)構(gòu)如下:

|-- Mainscene1-hd.atlasc
    |-- Mainscene1-hd.plist
    |-- Mainscene1-hd.png
    |-- Mainscene1-hd.swift
  • Mainscene1-hd.plist → 圖片描述文件
  • Mainscene1-hd.png → 合成的大圖片
  • Mainscene1-hd.swift → 根據(jù) plist文件編譯的 struct

其中 Mainscene1-hd.swift的代碼示例如下:

import SpriteKit

struct Mainscene1_hd {
    private static let textureAtlas = SKTextureAtlas(named: "Mainscene1-hd")
    
    static let mainbg = textureAtlas.textureNamed("mainbg") 
}

添加首頁背景圖片

我們先創(chuàng)建一個(gè)自定義的精靈節(jié)點(diǎn)避咆,方便管理后面添加的所有節(jié)點(diǎn),在?BaseNode.swift文件中添加下面的代碼:

import SpriteKit

class BaseNode: SKSpriteNode {
    
    init(texture: SKTexture?) {
        let size: CGSize = texture != nil ? CGSize(width: texture!.size().width, height: texture!.size().height) : .zero
        super.init(texture: texture, color: .clear, size: size)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

來添加首頁的背景圖片吧修噪,在sceneDidLoad()方法中添加下面的代碼就可以了:

let background = BaseNode(texture: Mainscene1_hd.mainbg)
background.zPosition = -1
addChild(background)
  • sceneDidLoad() → 場景加載完成查库,場景初始化后僅會(huì)調(diào)用一次
  • didMove(to view: SKView) → 場景入口,每次進(jìn)入場景都會(huì)調(diào)用
  • addChild(_ node: SKNode) → 尾部添加子節(jié)點(diǎn)SKNode黄琼,常見的節(jié)點(diǎn)有:
    SKSpriteNode → 精靈節(jié)點(diǎn)樊销,最常用的節(jié)點(diǎn),管理紋理實(shí)例(即圖片)
    SKVideoNode → 視頻節(jié)點(diǎn)
    SKAudioNode → 音頻節(jié)點(diǎn)
    SKLabelNode → 文本節(jié)點(diǎn)
    SKShapeNode → 形狀節(jié)點(diǎn)
    SKEmitterNode → 粒子節(jié)點(diǎn)
    SKCropNode → 裁剪節(jié)點(diǎn)
    SKEffectNode → 核心圖像過濾節(jié)點(diǎn)脏款,SKScene繼承自該類
    SKTileMapNode → 瓦片地圖節(jié)點(diǎn)围苫,常用于構(gòu)建地圖
    SK3DNode → 3D節(jié)點(diǎn)
  • texture:SKTexture → 紋理實(shí)例,每個(gè)紋理實(shí)例代表一張可復(fù)用的圖片
  • zPosition = -1 → 設(shè)置背景圖的圖層在最底層撤师,避免出現(xiàn)同層的圖片被背景遮蓋的情況

運(yùn)行項(xiàng)目剂府,效果如下:

首頁背景圖片

圖片正常顯示出來了,可喜可賀丈氓,鼓掌啪啪啪周循!但是,其實(shí)這里隱藏著一個(gè)問題万俗!因?yàn)榭s放顯示的原因湾笛,場景左右都出現(xiàn)了空白區(qū)域,如果場景中添加的其他節(jié)點(diǎn)超出了背景圖的左右邊界闰歪,就會(huì)顯示成這樣:

大蘿卜你是怎么回事嚎研?

這可不符合我們的效果預(yù)期,我都可以想到后面的炮塔子彈超出背景的時(shí)候出現(xiàn)能打穿屏幕的滑稽場面了,我們需要想想辦法了临扮。

裁剪顯示區(qū)域

考慮到項(xiàng)目資源中的背景圖片比例是(960,640)论矾,再參考如下設(shè)備橫屏寬高比例:

  • (4/3 - 1.33) ,設(shè)備:iPad 所有型號(hào)
  • (16/9 - 1.77) 杆勇,設(shè)備:iPhone 6/7/8/SE s系列贪壳、Plus系列
  • (448/207 - 2.16),設(shè)備:iPhone X/XR/XS/11/12 Max系列蚜退、Pro系列闰靴、mini系列

如果我們使用默認(rèn)的圖片比例1.5的話,在大部分設(shè)備上都會(huì)出現(xiàn)空白區(qū)域钻注,我用了一個(gè)笨方法蚂且,動(dòng)態(tài)修正場景的尺寸,使其和顯示區(qū)域一致幅恋。

我們在Constants.swift文件添加以下常量和變量:

public let kImageWidth: CGFloat = 960
public let kImageHeight: CGFloat = 640
public let kImageRatio: CGFloat = kImageWidth/kImageHeight
public var kImageScale: CGFloat = 1.0

然后在Functions.swift文件添加以下方法:

public func sceneSize() -> CGSize {
    var deviceWidth: CGFloat = 0, deviceHeight: CGFloat = 0
    // 獲取當(dāng)前設(shè)備的長邊和短邊
    let maxBound: CGFloat = max(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
    let minBound: CGFloat = min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
    // 判斷當(dāng)前設(shè)備是不是iPhone杏死,如果是,默認(rèn)橫屏顯示
    if UIDevice.current.userInterfaceIdiom == .phone {
        deviceWidth = maxBound
        deviceHeight = minBound
    } else {
        // 用switch語句判斷當(dāng)前設(shè)備的方向
        switch UIDevice.current.orientation {
        case .unknown:
            // 未知即初次啟動(dòng)未改變屏幕方向捆交,之間設(shè)置當(dāng)前設(shè)備的寬高
            deviceWidth = UIScreen.main.bounds.width
            deviceHeight = UIScreen.main.bounds.height
        case .portrait, .portraitUpsideDown:
            // 豎屏
            deviceWidth = minBound
            deviceHeight = maxBound
        default:
            // 默認(rèn)橫屏
            deviceWidth = maxBound
            deviceHeight = minBound
        }
    }
    // 計(jì)算設(shè)備寬高比
    let ratio = deviceWidth / deviceHeight
    var width: CGFloat = 0, height: CGFloat = 0
    // 通過對比設(shè)備的寬高比和圖片的寬高比來確定場景的寬高
    if ratio < kImageRatio {
        kImageScale = deviceWidth/kImageWidth
        width = deviceWidth
        height = width / kImageRatio
    } else {
        kImageScale = deviceHeight/kImageHeight
        height = deviceHeight
        width = height * kImageRatio
    }
    
    return CGSize(width: width, height: height)
}

讓我們回到GameViewController.swift文件淑翼,修改viewDidLoad()中的代碼:

override func viewDidLoad() {
    super.viewDidLoad()

    if let skView = view as? SKView {
        let scene = GameScene(size: sceneSize())
        scene.backgroundColor = .black
        scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        scene.scaleMode = .aspectFit

        skView.presentScene(scene)

        skView.ignoresSiblingOrder = true
        skView.showsFPS = true
        skView.showsNodeCount = true
    }
}

接著還需要在BaseNode.swift中修改初始化方法:

init(texture: SKTexture?) {
    let size: CGSize = texture != nil ? CGSize(width: texture!.size().width * kImageScale, height: texture!.size().height * kImageScale) : .zero
    super.init(texture: texture, color: .clear, size: size)
}

運(yùn)行項(xiàng)目,效果如下:

舒服了

場景的縮放模式

場景有一個(gè)屬性是scaleMode品追,是一個(gè)枚舉值窒舟,其值如下:

  • aspectFit 此模式可以保持場景比例不變,而且全部顯示在視圖中
  • aspectFill 此模式可以保持場景比例不變诵盼,會(huì)填充整個(gè)視圖,但是可能只有部分場景顯示出來
  • fill 此模式可以讓場景全部顯示出來银还,但是會(huì)導(dǎo)致場景變形
  • resizeFill 此模式可以保證場景與視圖的尺寸相匹配

我們使用的場景拉伸模式是aspectFit风宁,在iPad等大型顯示設(shè)備上也有不俗的效果,如下所示:

iPad 橫屏
Pad 豎屏

添加節(jié)點(diǎn)和動(dòng)畫

前面我們添加了首頁的背景圖片蛹疯,那么就接著在GameScene中添加其他節(jié)點(diǎn)吧戒财。

let carrot = SKSpriteNode(texture: Mainscene1_hd.carrot)
addChild(carrot)

效果如下:

添加精靈節(jié)點(diǎn)

場景坐標(biāo)系

仔細(xì)一看,小蘿卜的位置需要調(diào)整稗嘞摇饮寞!此時(shí)我們需要先了解 SKScene場景中的坐標(biāo)系。
SKScene場景的坐標(biāo)系默認(rèn)以屏幕的中心點(diǎn)為原點(diǎn)(實(shí)際是SKScene的錨點(diǎn)列吼,可以通過修改值來改變原點(diǎn)位置)幽崩,分別有x軸、y軸寞钥、z軸慌申。我們添加的子節(jié)點(diǎn)如果沒有進(jìn)行設(shè)置,默認(rèn)都在原點(diǎn)的位置理郑。

那么我們怎么修改節(jié)點(diǎn)的位置呢蹄溉,首先要了解節(jié)點(diǎn)的兩個(gè)屬性 anchorPoint(錨點(diǎn))position(位置)咨油。

  • anchorPoint(錨點(diǎn))→ 錨點(diǎn)是一個(gè)節(jié)點(diǎn)的真正核心位置,其概念和現(xiàn)實(shí)中物體的重心差不多柒爵,網(wǎng)上有很多詳盡的資料役电,我這里就簡單介紹好了。錨點(diǎn)的值在 0~1的范圍內(nèi)棉胀,賦予其他值會(huì)被修正法瑟,默認(rèn)是在中心點(diǎn) (0.5,0.5) ,其位置如下所示:
(0,1)—————————(1,1)
  |             |
  |  (0.5,0.5)  |
  |             |
(0,0)—————————(1,0)
  • position(位置)→ 自身錨點(diǎn)相對于父節(jié)點(diǎn)錨點(diǎn)的位置

請務(wù)必注意膏蚓,如果先設(shè)置 position調(diào)整好節(jié)點(diǎn)的位置瓢谢,之后又修改了 anchorPoint會(huì)導(dǎo)致節(jié)點(diǎn)的坐標(biāo)出現(xiàn)偏移,當(dāng)然也可以通過拓展節(jié)點(diǎn)來優(yōu)化坐標(biāo)計(jì)算驮瞧。

Constants.swift文件中添加新的常量:

// 默認(rèn)錨點(diǎn)氓扛,通過這個(gè)值統(tǒng)一子節(jié)點(diǎn)的位置計(jì)算
public let kAnchorPoint = CGPoint(x: 0.5, y: 0.5)

Extensions.swift文件中添加新的拓展:

public extension SKSpriteNode {
    var autoPosition: CGPoint {
        set {
            let realWidth = frame.width / kImageScale
            let realHeight = frame.height / kImageScale
            position = CGPoint(x: (newValue.x + (realWidth * (anchorPoint.x - kAnchorPoint.x))) * kImageScale, y: (newValue.y + (realHeight * (anchorPoint.y - kAnchorPoint.y))) * kImageScale)
        } get {
            return position
        }
    }
    
    var autoAnchorPoint: CGPoint {
        set {
            anchorPoint = CGPoint(x: limit(newValue.x), y: limit(newValue.y))
            position = CGPoint(x: (position.x + (frame.width * (anchorPoint.x - kAnchorPoint.x))), y: (position.y + (frame.width * (anchorPoint.y - kAnchorPoint.y))))
        } get {
            return anchorPoint
        }
    }
    // 限制值的范圍在0~1之間
    private func limit(_ num: CGFloat) -> CGFloat {
        return max(0, min(num, 1))
    }
}

之后對節(jié)點(diǎn)的 autoPositionautoAnchorPoint進(jìn)行設(shè)置,無論怎么怎么改變錨點(diǎn)的位置论笔,統(tǒng)一以錨點(diǎn)在(0.5,0.5)來計(jì)算位置采郎。

給節(jié)點(diǎn)添加動(dòng)畫

上面我們介紹了 anchorPoint,如果我們給節(jié)點(diǎn)添加動(dòng)作 SKAction的話狂魔,需要注意動(dòng)作是基于anchorPoint來進(jìn)行的蒜埋,如果默認(rèn)的錨點(diǎn)位置不能達(dá)成想要的動(dòng)畫效果,就需要通過修改錨點(diǎn)來調(diào)整動(dòng)畫效果了最楷。
我們在Functions.swift文件中添加通用角度轉(zhuǎn)換的方法:

public func angle(_ angle: CGFloat) -> CGFloat {
    return angle * CGFloat.pi / 180
}

接著在GameScene.swift文件中添加setupCarrot()方法并進(jìn)行調(diào)用

func setupCarrot() {
    // 加載紋理
    let carrot = SKSpriteNode(texture: Mainscene1_hd.carrot)
    carrot.autoPosition = CGPoint(x: 0, y: 45)

    let leaf1 = SKSpriteNode(texture: Mainscene1_hd.leaf_1)
    leaf1.autoPosition = CGPoint(x: -65, y: 130)
        
    let leaf2 = SKSpriteNode(texture: Mainscene1_hd.leaf_2)
    leaf2.autoPosition = CGPoint(x: 5, y: 160)
        
    let left3 = SKSpriteNode(texture: Mainscene1_hd.leaf_3)
    left3.autoPosition = CGPoint(x: 60, y: 140)
    // 修改錨點(diǎn)整份,添加動(dòng)畫
    leaf2.autoAnchorPoint = CGPoint(x: 0.4, y: 0)
    leaf2.run(.sequence([
        .rotate(toAngle: angle(-10), duration: 0),
        .wait(forDuration: 2),
        .repeatForever(rotateAction())
    ]))
    // 修改錨點(diǎn),添加動(dòng)畫
    left3.autoAnchorPoint = CGPoint(x: 0.2, y: 0)
    left3.run(.sequence([
        .wait(forDuration: 6),
        .repeatForever(rotateAction())
    ]))
    // 添加節(jié)點(diǎn)
    addChild(leaf1)
    addChild(left3)
    addChild(leaf2)
    addChild(carrot)
    // 添加上層標(biāo)題節(jié)點(diǎn)
    let codebg = SKSpriteNode(texture: Mainscene1_hd.mainbg_cn)
    codebg.position = CGPoint(x: -14, y: -54)
    addChild(codebg)
}
/// 根據(jù)已有角度生成搖晃SKAction
func rotateAction() -> SKAction {
    return .sequence([
        .rotate(byAngle: angle(10), duration: 0.1),
        .rotate(byAngle: angle(10), duration: 0.1),
        .rotate(byAngle: angle(10), duration: 0.1),
        .rotate(byAngle: angle(-10), duration: 0.1),
        .wait(forDuration: 8)
    ])
}

因?yàn)樘}卜的圖層在上方籽孙,所以需要修改添加順序烈评,也可以通過修改節(jié)點(diǎn)的zPosition屬性改變精靈的層級(jí)來達(dá)到效果,zPosition默認(rèn)是0犯建,數(shù)值越大讲冠,節(jié)點(diǎn)層級(jí)越高

動(dòng)作效果如下:

搖晃動(dòng)畫(20幀)

關(guān)于動(dòng)作SKAction

在前面我們給節(jié)點(diǎn)添加了動(dòng)作, SKAction 是我們生成動(dòng)畫的核心類适瓦,下面簡單介紹一下它的幾個(gè)重要屬性和方法:

  • duration → 動(dòng)作時(shí)長竿开,通常在初始化動(dòng)作的時(shí)候設(shè)置,動(dòng)作組會(huì)自動(dòng)計(jì)算時(shí)長

  • speed → 動(dòng)作速度玻熙,默認(rèn)值是1.0否彩,像游戲中的二倍速、三倍速可以通過調(diào)節(jié)這個(gè)屬性了達(dá)成效果

  • move(to location: CGPoint, duration: TimeInterval) -> SKAction → 節(jié)點(diǎn)位置移動(dòng)方法嗦随,創(chuàng)建一個(gè)移動(dòng)到坐標(biāo)點(diǎn) location的動(dòng)作胳搞,動(dòng)作時(shí)間為 duration。該動(dòng)作不可逆,動(dòng)作結(jié)束后保持移動(dòng)的位置肌毅。還有其他單獨(dú)移動(dòng)x軸 moveTo(x: CGFloat, duration: TimeInterval)和單獨(dú)移動(dòng)y軸 moveTo(y: CGFloat, duration: TimeInterval)的方法筷转。在本次項(xiàng)目中經(jīng)常應(yīng)用的就是怪物和炮塔子彈的移動(dòng)了。

  • move(by delta: CGVector, duration: TimeInterval) -> SKAction → 節(jié)點(diǎn)位置移動(dòng)方法悬而,動(dòng)作可逆呜舒,創(chuàng)建一個(gè)x軸和y軸偏移的動(dòng)作,delta包含了x軸和y軸的偏移量笨奠。

  • rotate(byAngle radians: CGFloat, duration: TimeInterval) -> SKAction → 節(jié)點(diǎn)旋轉(zhuǎn)方法袭蝗,基于原有角度進(jìn)行相對角度旋轉(zhuǎn),每次旋轉(zhuǎn)不改變節(jié)點(diǎn)的原有角度般婆,動(dòng)作結(jié)束后回到原有角度到腥。

  • rotate(toAngle radians: CGFloat, duration: TimeInterval) -> SKAction → 節(jié)點(diǎn)旋轉(zhuǎn)方法,基于傳入角度進(jìn)行絕對角度旋轉(zhuǎn)蔚袍,每次旋轉(zhuǎn)都改變節(jié)點(diǎn)的原有角度乡范,動(dòng)作結(jié)束后保持旋轉(zhuǎn)角度。

根據(jù)上面的介紹啤咽,大家應(yīng)該能夠觀察到 SKAction各種動(dòng)作的規(guī)律了晋辆,使用 by都是基于現(xiàn)有狀態(tài)的相對變化,使用 to是一種絕對變化宇整,根據(jù)自己的需求使用對應(yīng)的方法吧瓶佳。

關(guān)于 SKAction的其他動(dòng)作還有很多,這里就最終介紹已經(jīng)使用了的剩余相關(guān)動(dòng)作:

  • sequence(_ actions: [SKAction]) -> SKAction → 根據(jù)動(dòng)作組創(chuàng)建一個(gè)串行隊(duì)列動(dòng)作鳞青,如果了解過線程概念的應(yīng)該都比較懂霸饲,串行隊(duì)列中的動(dòng)作會(huì)按順序來運(yùn)行,如果使用動(dòng)作的 reversed()方法會(huì)會(huì)使串行隊(duì)列的動(dòng)作變成逆向運(yùn)行臂拓,例如:[1,2,3] -> [3R,2R,1R]贴彼。

  • group(_ actions: [SKAction]) -> SKAction → 根據(jù)動(dòng)作組創(chuàng)建一個(gè)并行隊(duì)列動(dòng)作,并行隊(duì)列中的動(dòng)作會(huì)同時(shí)進(jìn)行埃儿,總動(dòng)作時(shí)長是由隊(duì)列中動(dòng)作的最長時(shí)間決定的。

  • wait(forDuration duration: TimeInterval) -> SKAction → 等待一定時(shí)間融涣。

  • repeatForever(_ action: SKAction) -> SKAction → 動(dòng)作一直循環(huán)童番。

  • repeat(_ action: SKAction, count: Int) -> SKAction → 動(dòng)作循環(huán)一定次數(shù)。

總結(jié)

在這次開發(fā)過程中威鹿,我們創(chuàng)建了新項(xiàng)目剃斧,也學(xué)習(xí)了紋理集和簡單動(dòng)畫的使用,對于簡單的頁面布置應(yīng)該沒什么問題了忽你,接下來就是時(shí)間的活啦幼东,讓我們來把首頁鋪滿吧!

在下次的學(xué)習(xí)中,我們將學(xué)習(xí)節(jié)點(diǎn)的點(diǎn)擊事件和場景切換根蟹,也會(huì)開始制作選關(guān)界面脓杉!

在學(xué)習(xí)過程中,我學(xué)習(xí)了很多文章简逮,也搬運(yùn)了一個(gè)流程比較清晰的游戲項(xiàng)目開發(fā)教程球散,大家可以先參考下面的文章,加深對SpriteKit的了解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末散庶,一起剝皮案震驚了整個(gè)濱河市蕉堰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悲龟,老刑警劉巖屋讶,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異须教,居然都是意外死亡皿渗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門没卸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羹奉,“玉大人,你說我怎么就攤上這事约计【魇茫” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵煤蚌,是天一觀的道長耕挨。 經(jīng)常有香客問我,道長尉桩,這世上最難降的妖魔是什么筒占? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮蜘犁,結(jié)果婚禮上翰苫,老公的妹妹穿的比我還像新娘。我一直安慰自己这橙,他們只是感情好奏窑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屈扎,像睡著了一般埃唯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鹰晨,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天墨叛,我揣著相機(jī)與錄音止毕,去河邊找鬼。 笑死漠趁,一個(gè)胖子當(dāng)著我的面吹牛扁凛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棚潦,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼令漂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了丸边?” 一聲冷哼從身側(cè)響起叠必,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎妹窖,沒想到半個(gè)月后纬朝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡骄呼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年共苛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜓萄。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隅茎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嫉沽,到底是詐尸還是另有隱情辟犀,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布绸硕,位于F島的核電站堂竟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏玻佩。R本人自食惡果不足惜出嘹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一舅列、第九天 我趴在偏房一處隱蔽的房頂上張望惜浅。 院中可真熱鬧,春花似錦狞贱、人聲如沸垮斯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甚脉。三九已至,卻和暖如春铆农,著一層夾襖步出監(jiān)牢的瞬間牺氨,已是汗流浹背狡耻。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猴凹,地道東北人夷狰。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像郊霎,于是被迫代替她去往敵國和親沼头。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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