SpriteKit(4) - 动作

动作

  • 以点的方式移动
let actionMoveToPoint = SKAction.move(to: CGPoint(x: 100, y: 100), duration: 5)
let actionMoveToX = SKAction.moveTo(x: 700, duration: 2)
let actionMoveToY = SKAction.moveTo(y: 500, duration: 2)
  • 以偏移量的方式移动
let actionMoveByPoint = SKAction.moveBy(x: 100, y: 100, duration: 5)
let actionMoveByV = SKAction.move(by: CGVector(dx: 100, dy: 100), duration: 5)

动作序列 (以let scene = GameAction()方式创建)

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        let sprite : SKSpriteNode = SKSpriteNode(imageNamed: "1.png")
        sprite.position = CGPoint(x: size.width * 0.5,
                                  y: size.height * 0.5)
        sprite.setScale(1)
        self.addChild(sprite)
        
        //创建并设置节点移动的动作,即斜向下移动(100,-100)
        let actionMidMove = SKAction.move(to: CGPoint(x: size.width * 0.5 + 100,y: size.height * 0.5 - 100),  duration: 2.5)
        //创建并设置节点移动的动作,即斜向上移动(200,0)
        let actionMove = SKAction.move(to: CGPoint(x: size.width * 0.5 + 200,y: size.height * 0.5),duration: 2.5)
        
        //创建序列动作
        let squence = SKAction.sequence([actionMidMove,actionMove])
        sprite.run(squence)
    }
}

重复动作

        //创建序列动作
        let squence = SKAction.sequence([actionMidMove,actionMove])
//        sprite.run(squence)

        //重复动作
        let repeatAction = SKAction.repeat(squence, count: 5)
        sprite.run(repeatAction)

重复动作的注意点 : 注意设计具体需要重复的路线就好

延迟动作


import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node1 = SKSpriteNode()
        node1.position = CGPoint(x: 0, y: size.height * 0.5)
        node1.anchorPoint = CGPoint(x: 0, y: 0)
        node1.color = UIColor.red
        node1.size = CGSize(width: 100, height: 100)
        self.addChild(node1)
        
        let node2 = SKSpriteNode()
        node2.position = CGPoint(x: 0, y: size.height * 0.5)
        node2.anchorPoint = CGPoint(x: 0, y: 1)
        node2.color = UIColor.blue
        node2.size = CGSize(width: 100, height: 100)
        self.addChild(node2)
        
        //创建并设置节点移动的动作,向前300
        let actionMoveForward = SKAction.move(to: CGPoint(x:300,y: size.height * 0.5),  duration: 1.0)
        //创建并设置节点移动的动作,回到原点
        let actionMoveBackward = SKAction.move(to: CGPoint(x: 0,y: size.height * 0.5),duration: 1.0)
        
        let waitAction1 = SKAction.wait(forDuration: 1)
        let squence1 = SKAction.sequence([actionMoveForward,waitAction1,actionMoveBackward])
        let repeatAction1 = SKAction.repeat(squence1, count: 5)
        node1.run(repeatAction1)
        
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
            let waitAction2 = SKAction.wait(forDuration: 1.0)
            let squence2 = SKAction.sequence([actionMoveForward,waitAction2,actionMoveBackward])
            let repeatAction2 = SKAction.repeat(squence2, count: 5)
            node2.run(repeatAction2)
        }
    }
}
延时动作

缩放动作

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node = SKSpriteNode()
        node.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
        node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        node.color = UIColor.red
        node.size = CGSize(width: 100, height: 100)
        self.addChild(node)
        
        let zoom = SKAction.scale(by: 2, duration: 0.5)
        let skrink = SKAction.scale(by: 0.5, duration: 0.5)
        let squence = SKAction.sequence([zoom,skrink])
        let repeatAction = SKAction.repeat(squence, count: 5)
        
        node.run(repeatAction)
    }
}
缩放

PS : 这里要注意的是缩放的比例的控制

旋转动作

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node = SKSpriteNode()
        node.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
        node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        node.color = UIColor.red
        node.size = CGSize(width: 100, height: 100)
        self.addChild(node)
        
        let rotate = SKAction.rotate(byAngle: CGFloat.pi/4.0, duration: 0.25)
        let repeatAction = SKAction.repeat(rotate, count: 10)
        
        node.run(repeatAction)
    }
}
旋转

调整尺寸

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node = SKSpriteNode()
        node.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
        node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        node.color = UIColor.red
        node.size = CGSize(width: 100, height: 100)
        self.addChild(node)
        
        let resizeWidth = SKAction.resize(toWidth: 300, duration: 1)
        let wait = SKAction.wait(forDuration: 1)
        let resizeHeight = SKAction.resize(toHeight: 300, duration: 1)
        let squence = SKAction.sequence([resizeWidth,wait,resizeHeight])
        
        node.run(squence)
    }
}
调整尺寸

调整尺寸和缩放有点类似,但是更精确

组合动作

组合动作就是在同时对两个或两个以上的动作进行执行.

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node = SKSpriteNode()
        node.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
        node.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        node.color = UIColor.red
        node.size = CGSize(width: 100, height: 100)
        self.addChild(node)
        
        let resizeWidth = SKAction.resize(toWidth: 300, duration: 1)
        let wait = SKAction.wait(forDuration: 1)
        let resizeHeight = SKAction.resize(toHeight: 300, duration: 1)
        let squence = SKAction.sequence([resizeWidth,wait,resizeHeight])
        
        let rotate = SKAction.rotate(byAngle: CGFloat.pi/2, duration: 2)
        let group = SKAction.group([squence,rotate])
        
        node.run(group)
    }
}
两个动作同步一起做

改变透明度

  • 不需要指定alpha值
let fadeOut = SKAction.fadeOut(withDuration: 1)
let fadeIn = SKAction.fadeIn(withDuration: 1)
  • 指定alpha值
let fadeAlphaTo1 = SKAction.fadeAlpha(to: 1, duration: 1)
let fadeAlphaTo2 = SKAction.fadeAlpha(by: 0.5, duration: 1)

可以通过这种做一些,加载时候的效果.

改变颜色

  • 改变混合因子
let color1 = SKAction.colorize(withColorBlendFactor: 0.3, duration: 1)
let color2 = SKAction.colorize(withColorBlendFactor: 0.8, duration: 1)
  • 改变颜色和混合因子
let color = SKAction.colorize(with: UIColor.blue, colorBlendFactor: 1.0, duration: 1)
原图
变换过程

最终过程

以动画的形式改变纹理的动作

        let f1 = SKTexture(imageNamed: "texture1.png")
        let f2 = SKTexture(imageNamed: "texture2.png")
        let f3 = SKTexture(imageNamed: "texture3.png")
        let f4 = SKTexture(imageNamed: "texture4.png")
        let textureArray = [f1,f2,f3,f4]
        let playerSprite = SKSpriteNode(texture: f1)
        playerSprite.position=CGPoint(x : 50,y :  170)
        self.addChild(playerSprite)
        let runRightAction = SKAction.animate(with: textureArray, timePerFrame: 0.1)
        let runForever = SKAction.repeatForever(runRightAction)
        let actionMove = SKAction.move(to: CGPoint(x: 100, y: playerSprite.position.y),duration: 5)
        let group = SKAction.group([runForever, actionMove])
        
        playerSprite.run(group)
移动1
移动2

以不断切换纹理图片的形式,做出节点在活动的假象.
不过感觉这里有个bug,有些时候切换纹理的时候会一闪一闪的,也就是切换第一张,正常,第二张就显示不出来,第三张又好了的样子.交错显示.但是呢,多运行几次又正常了.应该是一个bug.不知道是什么鬼情况.(先不要在意,跳过这里,知道有这个细节,看看后续能否悟出原因,我用的是Xcode9,和iOS11.0的版本,也有可能是新版本里面的bug)

动作路径

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node1 = SKSpriteNode()
        node1.position = CGPoint(x: 150, y: size.height * 0.5 - 50)
        node1.color = UIColor.red
        node1.size = CGSize(width: 50, height: 50)
        self.addChild(node1)
        
        let node2 = SKSpriteNode()
        node2.position = CGPoint(x: 200, y: size.height * 0.5)
        node2.color = UIColor.blue
        node2.size = CGSize(width: 50, height: 50)
        self.addChild(node2)
        
        //让node1以矩形路径运动
        let playRect = CGRect(x: 0, y: 0, width: 100, height: 100)
        let screenBorders = CGPath(rect: playRect, transform: nil)
        let followAction1 = SKAction.follow(screenBorders, duration: 3)
        let repeatAction1 = SKAction.repeatForever(followAction1)
        node1.run(repeatAction1)
        
        
        let node3 = SKSpriteNode()
        node3.position = CGPoint(x: 400, y: size.height * 0.5 - 50)
        node3.color = UIColor.red
        node3.size = CGSize(width: 50, height: 50)
        self.addChild(node3)
        
        let node4 = SKSpriteNode()
        node4.position = CGPoint(x: 450, y: size.height * 0.5)
        node4.color = UIColor.blue
        node4.size = CGSize(width: 50, height: 50)
        self.addChild(node4)
        
        //让node1以圆形路径运动
        let playRect2 = CGRect(x: 400, y: size.height * 0.5 - 50, width: 100, height: 100)
        let circle = CGPath(roundedRect: playRect2, cornerWidth: 50, cornerHeight: 50, transform: nil)
        let followAction2 = SKAction.follow(circle, asOffset: false, orientToPath: true, duration: 5)
        let repeatAction2 = SKAction.repeatForever(followAction2)
        node3.run(repeatAction2)
    }
}
运动轨迹

路径考虑 : 这里面的路径考虑从锚点出发,锚点根据设置的路径来执行.
这里有些比较有意思的考虑点

  • 矩形路径 : 考虑的角度是红色节点的锚点,也就是矩形参考红色节点的锚点位置.x和y值为0,0,也就是初始点.每次路径结束都会重新计算一次路径.
  • 圆形路径 : 考虑的角度是圆本身的路径,也就是圆形参考场景坐标系.每次路径计算都是固定的值.

PS : 关于其他路劲,多尝试一下吧.

反向运动

let actionMove = SKAction.moveTo(x: 100, duration: 1)
let reversed = actionMove.reversed()

速度

可以通过一个给定的速度值来改变场景中精灵或者其他节点执行动作的速度.

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node1 = SKSpriteNode()
        node1.position = CGPoint(x: 50, y: size.height * 0.5 - 50)
        node1.color = UIColor.red
        node1.size = CGSize(width: 50, height: 50)
        self.addChild(node1)

        let moveAction = SKAction.moveTo(x: 550, duration: 20)
        let scaleAction = SKAction.scale(to: 2.5, duration: 20)
        let speedAction = SKAction.speed(to: 5, duration: 1)
        let group = SKAction.group([speedAction,moveAction,scaleAction])
        node1.run(group)
    }
}
速度动作
  • 动作的 speed 属性改变动画播放的速率。你可以在动画默认计时上加速或减速。
  • speed 值为 1.0 是正常的速度。如果动作的 speed 属性设置为 2.0,当节点执行动作时,
  • 它速度快了一倍。要暂停动作,将值设置为 0。 如果你调整那些包含其他动作(例如组、序列或重复动作)的动作的速率,速率会应用到所
    包含的动作。附加的动作也会受到它们自己的 speed 属性的作用。
  • 节点的 speed 属性与动作的 speed 属性具有相同的效果,但该速率适用于该节点或景树中的任意后代所处理的所有动作。

简单粗暴的理解 :
let speedAction = SKAction.speed(to: 0, duration: 4)
在4秒钟之后,动作执行的速度变为0

显示或隐藏

let hide = SKAction.hide()
let unhide = SKAction.unhide()

动作块

有时候,开发者需要将一系列的动作放入到一个块中,此时就是需要使用动作块.

简单粗暴的理解 :
就是将某些固定的动作封装在一个动作块中,到时候直接调用就好了.

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node1 = SKSpriteNode()
        node1.position = CGPoint(x: 50, y: size.height * 0.5 - 50)
        node1.color = UIColor.red
        node1.size = CGSize(width: 50, height: 50)
        self.addChild(node1)
        
        
        let block = SKAction.run {
            let rotate = SKAction.rotate(byAngle: CGFloat.pi, duration: 2)
            let runForever = SKAction.repeatForever(rotate)
            node1.run(runForever)
        }
        node1.run(block)
    }
}

自定义动作

import SpriteKit
import GameplayKit

class GameAction: SKScene {
    override func didMove(to view: SKView) {
        self.size = UIScreen.main.bounds.size
        
        let node1 = SKSpriteNode()
        node1.name = "node1"
        node1.position = CGPoint(x: 250, y: size.height * 0.5 - 50)
        node1.color = UIColor.red
        node1.size = CGSize(width: 50, height: 50)
        self.addChild(node1)
        
        let duration : TimeInterval = 2
        let blinkTimes = 2.0
        
        //node : 节点运行操作的节点。
        //elapsedTime : 在动画中传递的时间量。根据withDuration给定的参数
        let customAction1 = SKAction.customAction(withDuration: duration) { (node, elapsedTime) in
            let slice = duration / blinkTimes
            let remainder = elapsedTime.truncatingRemainder(dividingBy: 2)
            node.isHidden = remainder > CGFloat(slice) / 2.0
            print(elapsedTime)
        }
        let repeatAction = SKAction.repeatForever(customAction1)
        node1.run(repeatAction)

        //移动
        let customAction2 = SKAction.customAction(withDuration: duration) { (node, elapsedTime) in
            let moveAction = SKAction.moveTo(x: 500, duration: duration)
            node.run(moveAction)
        }
        node1.run(customAction2)
    }
}

理解 : 其实有点像动作块,也还是一样将自定义的动作打包.

动作属性

  • 速度 speed
  • 时间 duration
  • 曲线方式 timingMode
    • SKActionTimingLinear 线性执行
    • SKActionTimingEaseIn 淡入
    • SKActionTimingEaseOut 淡出
    • SKActionTimingEaseInEaseOut 淡入淡出

删除动作

let remove = SKAction.removeFromParent()

这个比较好理解,也就是删除节点的动作.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 斩断自己的退路,才能更好地赢得出路。在很多时候,我们都需要一种斩断自己退路的勇气。 SKAction简介 在先前的...
    神经骚栋阅读 6,300评论 24 60
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,863评论 6 13
  • Dear 三大只: 当时光荏苒了岁月,岁月褪去了铅华,我想我还是会一如既往地喜欢着你们、关注着你们,这是一种说...
    澄Ruan阅读 322评论 0 3
  • 传送门http://www.cnblogs.com/lucyjiayou/archive/2012/01/04/2...
    Fattyu阅读 842评论 0 0