[iOS 10] SpriteKit の SKWarpGeometryGrid をさわってみた #2

2016.11.08

今回は、前回のを少しだけ応用してタップした方向に歪みながら移動するサンプルを作ってみます。

上下左右に移動するので少し小さめにキャラを配置します。

warp_02_01

で、ソースはこちら

GameScene.swift

import SpriteKit
import GameplayKit

class GameScene: SKScene {
    
    private var penguin: SKSpriteNode!
    
    let sourcePositions = [
        float2(0, 0), float2(0.5, 0), float2(1, 0),
        float2(0, 0.5), float2(0.5, 0.5), float2(1, 0.5),
        float2(0, 1), float2(0.5, 1), float2(1, 1)
    ]
    
    let horizontalDestinationPositions = [
        float2(-0.5, 0), float2(0.5, 0), float2(1.5, 0),
        float2(-0.5, 0.5), float2(0.5, 0.5), float2(1.5, 0.5),
        float2(-0.5, 1), float2(0.5, 0.8), float2(1.5, 1)
    ]
    
    let verticalDestinationPositions = [
        float2(0, -0.5), float2(0.5, -0.5), float2(1, -0.5),
        float2(0.2, 0.5), float2(0.5, 0.5), float2(0.8, 0.5),
        float2(0, 1.5), float2(0.5, 1.5), float2(1, 1.5)
    ]
    
    override func didMove(to view: SKView) {
        penguin = self.childNode(withName: "penguin") as! SKSpriteNode
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let location = touches.first?.location(in: self)
        let angle = self.angle(a: penguin.position, b: location!)
        var destinationPositions: [float2]!
        var toPoint: CGPoint!
        
        if 45 < angle && angle <= 135 {
            // 上へ
            toPoint = CGPoint(x: penguin.position.x, y: penguin.position.y + 100)
            destinationPositions = verticalDestinationPositions
            
        } else if 135 < angle && angle <= 225 {
            // 左へ
            toPoint = CGPoint(x: penguin.position.x - 100, y: penguin.position.y)
            destinationPositions = horizontalDestinationPositions
            
        } else if 225 < angle && angle <= 315 {
            // 下へ
            toPoint = CGPoint(x: penguin.position.x, y: penguin.position.y - 100)
            destinationPositions = verticalDestinationPositions
            
        } else {
            // 右へ
            toPoint = CGPoint(x: penguin.position.x + 100, y: penguin.position.y)
            destinationPositions = horizontalDestinationPositions
        }
        
        let warpGeometryGrid = SKWarpGeometryGrid(columns: 2, rows: 2,
                                                  sourcePositions: sourcePositions,
                                                  destinationPositions: destinationPositions)
        let warpGeometryGridNoWarp = SKWarpGeometryGrid(columns: 2, rows: 2)
        penguin.warpGeometry = warpGeometryGridNoWarp
        let warp = SKAction.animate(withWarps:[warpGeometryGrid, warpGeometryGridNoWarp], times: [0.25, 0.5])
        let move = SKAction.move(to: toPoint, duration: 0.5)
        
        penguin.run(SKAction.group([move, warp!]))
    }
    
    func angle(a:CGPoint, b:CGPoint) -> CGFloat {
        var r = atan2(b.y - a.y, b.x - a.x)
        if r < 0 {
            r += 2 * CGFloat.pi
        }
        // 度 = ラジアン × 180 ÷ 円周率
        return r * 180 / CGFloat.pi
    }
    
}

angleメソッドでキャラとタップした座標の角度を取得していて、その角度を元に上下左右どの方向に移動するかを判別しています。
縦方向に移動する場合と、横方向に移動する場合で、ひしゃげ方を変えています。

起動するとタップした方向に、こんな感じにねっとり動きます。(スクショはわかりやすいようにわざと残像を残してます。)

warp_02_02

ではでは。