SpriteKitでのスクロール処理

マニュアルを縦長の画面で表示したいと思って
SpriteKitでのスクロール処理をどうしようかと調べていたところ
こちらのページを発見。

記事内ではサンプルとして
テキスト2つ(上部と下部)を配置しているので
上部を縦長のマニュアル画像を1枚に差し替えれば終わりかなと安易に考え
SKSpriteNodeに縦4画面分相当の画像を当ててみたところ
真っ黒な画像(参照なしの×印でもない)な画像になってしまった、、

大きすぎる画像は描画できないのかと思い、小さくしてみたら表示されたので、
仕方なく画像を分割して順番に配置する事に。

少し冗長的になってしまいそうだったのと
今後も使用する可能性がありそうだったので画像を並べる前提でクラス化。
ついでに各端末に合わせられるように
横幅を画面幅に合わせ、縦幅を比率維持で変動するようにしています。

以下ソースです。需要はなさそうですが・・・
「ScrollUtil.swift」

import SpriteKit

class ScrollUtil {
var moveableArea = SKNode()

var startY: CGFloat = 0.0
var lastY: CGFloat = 0.0
var scrollSpeed: CGFloat = 1.0

//先頭をスクロールで下げる事が可能な位置
var topLimit: CGFloat = 0.0

//スクロール可能な範囲の下限
var bottomLimit: CGFloat = 1.0

//画像名のリスト
var imgNameList: [String] = []

//画像配置開始位置
var startHight: CGFloat = 0.0

//呼び出し元のシーン
var scene: SKScene


init(_self: SKScene) {
self.scene = _self

moveableArea.position = CGPoint(x: 0, y: 0)
moveableArea.zPosition = 1
self.scene.addChild(self.moveableArea)
}

func setTopLimit(top: CGFloat) {
self.topLimit = top
}
func setScrollSpeed(speed: CGFloat) {
self.scrollSpeed = speed
}
func setStartHight(start: CGFloat) {
self.startHight = start
}
func setImage(imageNames: [String]) {
self.imgNameList = imageNames
self.setImage()
}


//タッチ時の位置記憶、呼び出し元の touchesBegan で実行
func touchBegan(touch: UITouch) {
let location = touch.locationInNode(scene)
self.startY = location.y
self.lastY = location.y
}

//描画位置をずらす処理、呼び出し元の touchesMoved で実行
func touchMove(touch: UITouch) {
let location = touch.locationInNode(scene)
let currentY = location.y

let newY = moveableArea.position.y + ((currentY-lastY)*scrollSpeed)

if newY < scene.size.height * (-topLimit) {
moveableArea.position =
CGPointMake(moveableArea.position.x, scene.size.height * (-topLimit))

} else if newY > scene.size.height * bottomLimit {
moveableArea.position =
CGPointMake(moveableArea.position.x, scene.size.height * bottomLimit)

} else {
moveableArea.position =
CGPointMake(moveableArea.position.x, newY)
}

lastY = currentY
}


//画像を配置
private func setImage() {
var nextStartHeight: CGFloat = scene.size.height - (scene.size.height * startHight)

//画像の配置
for imgName in self.imgNameList {
nextStartHeight =
self.setImg(imgName, heightStart: nextStartHeight)
}

//下限位置の調整
self.bottomLimit = nextStartHeight / scene.size.height * -1
}

//画像を配置、横幅を端末サイズに合わせてリサイズ
private func setImg(imgName: String, heightStart: CGFloat) -> CGFloat {
let helpImg = SKSpriteNode(imageNamed: imgName)

//横幅を合わせた際の縦横サイズを計算
let (help_fix_w, help_fix_h) =
clacSize(helpImg.size.width, orgH: helpImg.size.height, fixW: scene.size.width, fixH: nil)

let height = heightStart - (help_fix_h / 2)
helpImg.position = CGPoint(x: help_fix_w*0.5, y: height)
helpImg.size.width = help_fix_w
helpImg.size.height = help_fix_h
helpImg.zPosition = 0
self.moveableArea.addChild(helpImg)

return heightStart - help_fix_h
}

//比率を維持した縦横サイズを計算
private func clacSize(orgW: CGFloat, orgH: CGFloat, fixW: CGFloat?, fixH: CGFloat?) -> (CGFloat, CGFloat) {
let width_org = orgW
let height_org = orgH

var width_fix = CGFloat(0)
var height_fix = CGFloat(0)
if fixW != nil {
width_fix = fixW!
height_fix = height_org * (width_fix / width_org)
} else if fixH != nil {
height_fix = fixH!
width_fix = width_org * (height_fix / height_org)
}

return (width_fix, height_fix)
}
}



使用例)
「HogeScene.swift」※スクロールさせたいsceneクラス

import SpriteKit

class HogeScene: SKScene {
var scroll: ScrollUtil?

~省略

override func didMoveToView(view: SKView) {

//背景(一番奥に配置)
let background = SKSpriteNode(imageNamed: "bg")
background.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5)
background.size = self.size
background.zPosition = 0
self.addChild(background)

//スクロールさせるノード
//Util内でzPosition:1固定にしているので背景の1個手前
self.scroll = ScrollUtil(_self: self)
self.scroll!.setStartHight(0.2)
self.scroll!.setImage(["img1", "img2", "img3", "img4"])


//上部を部分的に隠す為に、被せる画像
let backgroundTop = SKSpriteNode(imageNamed: "bg_top")
backgroundTop.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.925)
backgroundTop.size.width = self.size.width
backgroundTop.size.height = self.size.height*0.15
backgroundTop.zPosition = 2
self.addChild(backgroundTop)

~省略
}

override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
if let touch = touches.first as UITouch? {
~省略

//スクロール開始処理
self.scroll!.touchBegan(touch)
}
}

override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
if let touch = touches.first as UITouch? {
~省略

//スクロール描画処理
self.scroll!.touchMove(touch)
}
}

~省略
}


UIScrollViewをなんとかして埋め込もうかと思っていたところだったので
上記サイトのおかげでかなり簡単に実装出来て助かりました。


※以下、私が参考にしている本の紹介になります。







スポンサーリンク

この記事へのコメント


この記事へのトラックバック