SpriteKit之第一个项目

1 名词概念

SpriteKit:提供一个图形渲染和动画的基础,可以有效的利用图形硬件来渲染动画的帧,而无须开发人员编写绘图指令,可以专注的解决更高层次的设计问题。

Sprite:精灵,在游戏里的背景,人物,物品等都是精灵。

SKView:动画和渲染由SKView执行,需要在一个窗口中放置该视图,然后渲染内容。

Scenes:场景,游戏中的内容会被组织成场景,由SKScene对象表示。包含了精灵和其它需要渲染的内容。一个游戏,可能需要创建一个或多个SKScene类或其子类。

SKNode:节点,实际上SKScene是SKNode的子类,场景对象是一个节点对象的根节点,决定子类哪个内容被绘制以及渲染。所有节点对象都是响应者,可以继承任何节点来创建接收用户输入的新类。

纹理:用来渲染精灵的共享图像,比如需要多个相同图像时,使用纹理来直接创建,而无需再次重新读取图形文件。

actions:动作,能够让场景内容动起来,每一个动作都是一个对象,由SKAction类表示。

2 开始

知道上方概念和大概作用后,我们开始写第一个项目,使用的是Xcode8.0和Swift3.0。

1.创建一个空项目

如下图,创建一个Single View Application,然后创建一个名词为Game的项目:
可能有人会问,为什么不选Game?我的回答是,没有写过游戏的朋友最好别创建Game模板,因为会自动给你添加很多东西很多方法,第一次看会觉得莫名其妙的。

SpriteKit之第一个项目_第1张图片
屏幕快照 2017-01-24 上午11.40.42.png

2.项目修改

创建好后,项目需要做一些修改:
1.在ViewController.swift里,添加:

import SpriteKit

2.在Main.storyboard里,修改当前VC的View为SKView。如下:

SpriteKit之第一个项目_第2张图片
屏幕快照 2017-01-24 上午11.46.07.png

3.修改ViewController.swift如下:

import UIKit
import SpriteKit

class ViewController: UIViewController {
    
    var spriteView: SKView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        spriteView = view as! SKView
        
        spriteView.showsDrawCount = true//使用多少绘画,越少越好
        spriteView.showsNodeCount = true//节点个数
        spriteView.showsFPS = true//FPS开启
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

此时,运行程序,就可以看到初步的效果了。如下:

SpriteKit之第一个项目_第3张图片
屏幕快照 2017-01-24 上午11.52.46.png

3.编写场景代码

1.创建一个场景类,HelloScene继承自SKScene
2.HelloScene内导入SpriteKit
3.添加如下代码:

import UIKit
import SpriteKit

class HelloScene: SKScene {

    var contentCreated = false//标记场景是否已经创建
    
    override func didMove(to view: SKView) {//每当场景要被呈现时,会调用该方法,并且只在第一次调用
        if !contentCreated {
            createSceneContents()
            contentCreated = true
        }
    }
    
    func createSceneContents() {//自定义的创建场景内容的方法
        backgroundColor = SKColor.blue//背景,SKColor不是一个类,是一个宏,iOS上是UIColor,OS X上是NSColor。
        scaleMode = .aspectFit//缩放模式
        addChild(newHelloNode())
    }
    
    func newHelloNode() -> SKLabelNode {//创建一个label
        let helloNode = SKLabelNode(fontNamed: "Chalkduster")
        helloNode.text = "你好!"
        helloNode.fontSize = 42
        helloNode.position = CGPoint(x: frame.width/2, y: frame.height/2)
        return helloNode
    }
}

4.回到ViewController.swift中,添加present代码,呈现场景视图:

 override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let hello = HelloScene(size: CGSize(width: view.frame.width, height: view.frame.height))
        spriteView.presentScene(hello)
    }

运行,就可以看到结果了。

SpriteKit之第一个项目_第4张图片
屏幕快照 2017-01-24 下午2.11.45.png

3 使用Action动作

上面做出了一个静态的界面,我们可以通过Action动作将场景内的东西具有动作。我们创建一个action对象来描述想要的改变,然后告诉一个节点运行,当场景渲染时,动作会被执行。

给项目添加一个功能,当点击场景时,文字淡出,背景颜色变化。

在HelloScene场景类的newHelloNode()方法中,给节点添加名称,方便使用时查找:

helloNode.name = "LabelNode"

然后重写touchesBegan方法:

override func touchesBegan(_ touches: Set, with event: UIEvent?) {
        let helloNode = childNode(withName: "LabelNode")
        if let node = helloNode {
            node.name = ""//防止按压事件重复触发,HelloNode被重复动作
            let moveUp = SKAction.moveBy(x: 0, y: 100, duration: 0.5)//上移
            let zoom = SKAction.scale(to: 2.0, duration: 0.25)//放大
            let pause = SKAction.wait(forDuration: 0.5)//暂停
            let fade = SKAction.fadeIn(withDuration: 0.25)//消失
            let remove = SKAction.removeFromParent()//移除
            let colorChange = SKAction.colorize(with: .orange, colorBlendFactor: 1, duration: 0.5)//改变背景色
            let moveSequence = SKAction.sequence([moveUp, zoom, pause, fade, remove])
            //动作执行
            node.run(moveSequence)
            self.run(colorChange)
        }
    }

由于所有节点都是UIResponder的子类,所以可以直接使用touchBegan来添加交互内容。

添加好后,运行,如图:

SpriteKit之第一个项目_第5张图片
2017-01-24 15_05_19.gif

4 场景切换

场景之间的切换使用SpriteKit会非常容易。

1.创建新的ship场景继承于SKScene类,添加如下代码:

import UIKit
import SpriteKit

class ShipScene: SKScene {
    
    var contentCreated = false
    
    override func didMove(to view: SKView) {
        if !contentCreated {
            createScreated()
            contentCreated = true
        }
    }
    
    func createScreated() {
        backgroundColor = .black
        scaleMode = .aspectFit
    }

}

2.在HelloScene类中,修改touchesBegan方法中,node.run方法,如下:

node.run(moveSequence) {
                let ship = ShipScene(size: self.size)
                let transition = SKTransition.doorsOpenVertical(withDuration: 2)//动画类型
                self.view?.presentScene(ship, transition: transition)//呈现ship场景后,hello场景会被丢弃
            }

上面代码的作用是,当action执行完成后,切换场景。

运行,最终效果如图:

SpriteKit之第一个项目_第6张图片
2017-01-24 15_28_50.gif

5 构造复杂的内容

新的场景没有任何内容,我可以使用很多个SKSpriteNode对象,创建出很复杂的内容。

我们创建出一个模拟的飞船,有两道亮光。
在ShipScene类的createScreated方法中添加飞船,代码如下:

func createScreated() {
        backgroundColor = .black
        scaleMode = .aspectFit
        
        let ship = newShip()
        ship.position = CGPoint(x: frame.width/2, y: frame.height/2)
        addChild(ship)
    }
    
    func newShip() -> SKSpriteNode {
        //添加飞船
        let node = SKSpriteNode(color: .green, size: CGSize(width: 100, height: 50))
        let hover = SKAction.sequence([SKAction.wait(forDuration: 1),
                                       SKAction.moveBy(x: 100, y: 50, duration: 1),
                                       SKAction.wait(forDuration: 1),
                                       SKAction.moveBy(x: -100, y: 150, duration: 1)])
        node.run(hover)
        
        //飞船添加亮光,亮光添加到飞船上后,飞船移动后,亮光也会一起移动,旋转等也是。
        let lingt1 = newLight()
        lingt1.position = CGPoint(x: 0, y: 30)
        node.addChild(lingt1)
        
        let lingt2 = newLight()
        lingt2.position = CGPoint(x: 0, y: -30)
        node.addChild(lingt2)
        
        return node
    }
    
    func newLight() -> SKSpriteNode {
        let lingt = SKSpriteNode(color: .white, size: CGSize(width: 50, height: 2))
        let blink = SKAction.sequence([SKAction.fadeOut(withDuration: 0.25),
                                       SKAction.fadeIn(withDuration: 0.25)])
        let blinkForever = SKAction.repeatForever(blink)//一直重复动作
        lingt.run(blinkForever)
        return lingt
    }

添加好后,运行,如图:

SpriteKit之第一个项目_第7张图片
2017-01-24 16_01_42.gif

6 添加节点之间的交互

通常,游戏开始后,节点互相之间是可以进行交互的,SpriteKit提供了一个完整的物理模拟,可以添加行为到节点,我们在飞船上方添加掉落的石块来演示。

1.给飞船添加物理体

//给飞船添加物理体
        node.physicsBody = SKPhysicsBody(rectangleOf: node.size)
        node.physicsBody?.isDynamic = false//防止非常受物理交互影响,开启后,飞船的速度不会受物理碰撞影响

2.当前场景添加产生岩石的action

 //产生岩石
        let makeRocks = SKAction.sequence([SKAction.perform(#selector(addRock), onTarget: self),
                                           SKAction.wait(forDuration: 0.1, withRange: 0.15)])
        run(SKAction.repeatForever(makeRocks))

3.实现addRock方法:

//添加岩石
    func addRock() {
        let rock = SKSpriteNode(color: .white, size: CGSize(width: 10, height: 10))
        rock.position = CGPoint(x: frame.width*2/3, y: frame.height)
        rock.name = "rock"
        rock.physicsBody = SKPhysicsBody(rectangleOf: rock.size)
        rock.physicsBody?.usesPreciseCollisionDetection = true
        addChild(rock)
    }
    
    //岩石离开屏幕后,移除
    override func didSimulatePhysics() {
        enumerateChildNodes(withName: "rock") { (node, _) in
            if node.position.y < 0 {
                node.removeFromParent()
            }
        }
    }

添加完毕后,运行如图:

SpriteKit之第一个项目_第8张图片
2017-01-24 16_48_44.gif

结语

这是使用SpriteKit的第一步,知道了很多基础的东西,比如画面是如何呈现,界面的层级关系,如何跳转等等。这只是一个开始,后面还有很多需要学的。

本文代码可以在我的github上面找到(Game01):https://github.com/flywo/SwiftGame

你可能感兴趣的:(SpriteKit之第一个项目)