読者です 読者をやめる 読者になる 読者になる

Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 894 - 話はとびまくりGameplayKitチュートリアルに戻ります

人様が作ったチュートリアルに取り組んでいると、最近不満に思うことが増えています。「もう少しツッコんだ説明が欲しいな」とか「もう少し実践的なコーディングの説明ないかな」なんて思います。

GameplayKitのチュートリアルも少々古く、iOS10で加わった新しい機能を追加して改訂してくれたらいいのにな、なんて不満があって途中で止めてしまいそうになりましたが。何が何でも続けるという信条でPathfindingの説明を続けます。

MovementComponentを作ったので、これをEntityに加えます。新しい敵キャラ(赤いスクエアですが)をEntityとして登録します。

GameScene.swiftの冒頭に次のプロパティを登録します。

var enemies = [GKEntity]()

GKEntityタイプの空のアレーを用意します。

次に「createGrid()」メソッドの下に次のコードを加えます。

func createEnemies() {

}

ここで敵entityを作って、画面の左端から右端のゴールに向かって動いてもらいます。

let enemy = GKEntity()
let gridPosition = int2(0, Int32(height) / 2)
let destination = int2(Int32(width) - 1, Int32(height) / 2)

gridPositionはenemyの現在位置と言っていいでしょう。画面左端の真ん中からスタートします。destinationは目的地となります。どちらの値もint2型で、GKGridGraphの座標系です。

実際に画面に表示をするためにSKSpriteNodeが必要になります。

let sprite = SKSpriteNode(color: UIColor.red, 
                           size: CGSize(width: boxSize * 0.6, 
                                       height: boxSize * 0.6))
sprite.position = pointFor(coordinate: gridPosition)

spriteはただの赤い箱です。位置情報は、int2型からCGPoint型に変換するメソッド「pointFor(coordinate:)」を使います。

SKViewに表示することと、GKGridGraphに表示することが異なることを理解しておく必要があります。<-このやり方が違うような気がするんですがどうなんでしょう?

どちらにしろ次のコーディングは、GKGridGraphに表示させるためにMovementComponentインスタンスを作ります(VisualCompanentを継承してるからです)。そして移動先も登録します。

let movementComponent = MovementComponent(scene: self, 
                                         sprite: sprite, 
                                     coordinate: gridPosition, 
                                    destination: destination)

このコンポーネントを敵entityに登録します。

enemy.addComponent(movementComponent)

そして、このenemyをenemiesに登録します。

enemies.append(enemy)

これでエンティティは用意されたけど、実際SKViewでは何も生じません。次はSKSpriteKitを使って、画面上で動きを表示させるステップです。

var sequence = [SKAction]()

アクションの入れ籠を用意します。複数の敵キャラに動きを対応するためです。今のところenemyは1つだけですが、次のようにループを実行させます。

for enemy in enemies {
    let action = SKAction.run { [unowned self] in
        let movementComponent = 
            enemy.component(ofType: MovementComponent.self)!
        self.addChild(movementComponent.sprite)
                
        // updateは後で追加
                
        // 一時的に以下のコードを加えて動作チェック
        let path = movementComponent.pathToDestination()
        movementComponent.followPath(path: path)
    }
            
    let delay = SKAction.wait(forDuration: 2)
            
    sequence += [action, delay]
}

タワーが設置されることで、パスファインディングの再計算をさせてupdateさせないといけませんが、今は、ちゃんと敵が動くかどうか確認するためにMovementComponentの「followPath()メソッドを使ってActionシークエンスを実行させてみます。

このコードを「didMove(to view: SKView)」に組み込みます。

override func didMove(to view: SKView) {
        
    createGrid()
    graph = 
        GKGridGraph(fromGridStartingAt: int2(0, 0), 
                                 width: Int32(width), 
                                height: Int32(height), 
                      diagonalsAllowed: false)
    createEnemies()
}

これでランすると、赤い箱が画面の左端から右端に動いていきます。

f:id:yataiblue:20161226170543j:plain

まだupdateが実装されていないので、進行方向にタワーを設置してもすり抜けていきます。

今日はここまで。