獣は月夜に何を見る...

SpriteKitでゲーム その1- SPACE SHOOTER④

func createEnemy()をさくせいします。
func createPlayer()の直前に追加してください。
必要なパラメーター等も追加していきます。
全体図を示します。

import SpriteKit

//GKRandomSourceを使うため必要。
import GameplayKit

class GameScene: SKScene, SKPhysicsContactDelegate {
    
    
    var player: SKSpriteNode!
    
    //ゲーム中にenemyを参照する必要があるのでenemyのプロパティを作成します
    var enemy: SKSpriteNode!

    //変数に配列で4種類の名前を入れる。
    var enemyArray = ["ufoBlue", "ufoRed", "ufoGreen", "ufoYellow"]
    
    //Timerクラスを使うためのプロパティを作成。
    var getTimer: Timer!
    
    //サウンド再生用のプロパティを作成。
    let explosionSound = SKAction.playSoundFileNamed("explosion.wav", waitForCompletion: false)
    
    
    struct PhysicsCategories {
       //省略
    }
    
    enum GameState {
       //省略
    }
    
    
    override func didMove(to view: SKView) {
        
        physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        physicsWorld.contactDelegate = self
        
        createBackground()
        createPlayer()
        
        //0.5秒間隔でcreateEnemy()を呼び出す。
        if getTimer == nil {
            getTimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
        }
    }
            
    @objc func createEnemy() {
        
        //配列の中身をランダムに並び替える。
        enemyArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: enemyArray) as! [String]
        
        //テクスチャの名前を配列の0番目に指定する。
        let enemyTexture = SKTexture(imageNamed: enemyArray[0])

        //SpriteNodeを作成する。
        enemy = SKSpriteNode(texture: enemyTexture)
        
        //物理ボディを作成する。
        enemy.physicsBody = SKPhysicsBody(circleOfRadius: max(enemyTexture.size().width / 2, enemyTexture.size().height / 2))

        //カテゴリマスクを設定する。
        enemy.physicsBody!.categoryBitMask = PhysicsCategories.enemy

        //衝突マスクを設定する。
        enemy.physicsBody!.collisionBitMask = PhysicsCategories.none

        //衝突検出マスクを設定する。
        enemy.physicsBody!.contactTestBitMask = PhysicsCategories.player | PhysicsCategories.laser
        
        //重なり順を-10にする。
        enemy.zPosition = -10

        //名前を設定する。
        enemy.name = "enemy"

        //大きさを半分に設定する。
        enemy.setScale(0.5)
        
        //指定して範囲内で乱数を生成する。
        let randomDistribute = GKRandomDistribution(lowestValue: Int(enemy.size.width), highestValue: Int((frame.size.width) - enemy.size.width))

        //出現位置を設定する。
        enemy.position = CGPoint(x: CGFloat(randomDistribute.nextInt()), y: frame.size.height)

        //GameSceneに追加する。
        addChild(enemy)
        
        //出現位置から画面の外まで5秒かけて移動する。
        let moveEnemy = SKAction.moveTo(y: -self.size.height + enemy.size.height, duration: 5)

        //GameSceneから削除する。
        let moveReset = SKAction.removeFromParent()

        //順番にアクションを実行するsequenceを作る。
        let moveSequence = SKAction.sequence([moveEnemy, moveReset])

        //sequenceアクションをループさせる。
        let moveForever = SKAction.repeatForever(moveSequence)
        

        //アクションを実行する。
        enemy.run(moveForever)
    } 
    
    func createPlayer() {
    }

    
    func createBackground() {
    }
}




ではポイントごとに解説します。 func CreateEnemy()に関しては今までのようにただ呼び出すだけではなくランダムに位置を変えて出現するようにしたいので以下の部分のようにします。

//省略

//Timerクラスを使うためのプロパティを作成。
    var getTimer: Timer!

//省略

//0.5秒間隔でcreateEnemy()を呼び出す。
if getTimer == nil {
    getTimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
}

//省略

@objc func createEnemy() {
    //省略
}

getTimer == nil で変数が存在するかの判定をします。 Timer.scheduledTimer( ) で0.5秒間隔でcreateEnemy を呼び出します。

target: selfでGameSceneに対してなのでself。

selector: #selector(createEnemy)の部分の#selecotr()で呼び出す元を指定できます、ここではcreateEnemyでfunc createEnemy()を呼び出します。

@objc と言うのがfunc createEnemy()の頭に付いてますがこれはTimerクラスがObjective-Cで出来ているからです、swiftで書いたメソッド・プロパティをObjective-Cで使えるようにするお約束と思ってください。

Timer - Foundation | Apple Developer Documentation
scheduledTimer(timeInterval:target:selector:userInfo:repeats:) - Apple Developer Documentation

func createEnemy()の内部を説明します。

//省略

class GameScene: SKScene, SKPhysicsContactDelegate {
    
    //省略

    //変数に配列で4種類の名前を入れる。
    var enemyArray = ["ufoBlue", "ufoRed", "ufoGreen", "ufoYellow"]
    
    //省略

//配列の中身をランダムに並び替える。
enemyArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: enemyArray) as! [String]

//指定して範囲内で乱数を生成する。
let randomDistribute = GKRandomDistribution(lowestValue: Int(enemy.size.width), highestValue: Int((frame.size.width) - enemy.size.width))

//テクスチャの名前を配列の0番目に指定する。
let enemyTexture = SKTexture(imageNamed: enemyArray[0])

    //省略

//出現位置を設定する。
enemy.position = CGPoint(x: CGFloat(randomDistribute.nextInt()), y: frame.size.height)

GKRandomSourceとGKRandomDistributionは import GameplayKit で使うことができるランダムな処理を行うクラスです。

変数enemyArrayに4種類のテクスチャに使うイメージの名前を入れて配列を作ります。

二つ目は配列enemyArrayの中身をランダムに並び替えています、そして並び変えるたびにその0番目 enemyArray[0] を SpriteNode のテクスチャにすることでランダムにenemyの外見を変更します。

三つ目は乱数を生成してるだけですが、整数である必要があるのでInt(enemy.size.width)です。 enemy.size.widthはenemy.png自体の幅のことです、出現位置を画面の幅以内にしたいのでこうしていますenemyのアンカーポイントは中心のままなのでその幅以下にすると画面からはみ出すか見えなくなる場合があります。

GKRandomSource - GameplayKit | Apple Developer Documentation
GKRandomDistribution - GameplayKit | Apple Developer Documentation

四つ目で位置をしていします、x座標には先ほどの乱数を使います。 CGFloat(randomDistribute.nextInt())のCGFloat()は浮動小数点数型です、nextInt()は乱数の生成を実行する意味です、SKActionのrun()みたいなものです。


残りの部分です。

//出現位置から画面の外まで5秒かけて移動する。
let moveEnemy = SKAction.moveTo(y: -self.size.height + enemy.size.height, duration: 5)

//GameSceneから削除する。
let moveReset = SKAction.removeFromParent()

//順番にアクションを実行するsequenceを作る。
let moveSequence = SKAction.sequence([moveEnemy, moveReset])

//sequenceアクションをループさせる。
let moveForever = SKAction.repeatForever(moveSequence)
        

//アクションを実行する。
enemy.run(moveForever)

行なっている内容はcreateBackground()でも出てきた部分です。
-self.size.height + enemy.heightのselfはGameSceneを指しますのでこれは画面の高さのことですマイナス符号があるので下向きに移動することになります。

ここでシミュレーターで確認するとenemyがランダムな位置に出現しながら下方向に移動してると思います。

今回はここまでです。 ではまた次回。



swiftの詳細なら!。

オンラインブートキャンプ iPhoneアプリコース