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

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

f:id:tukumosanzou:20180702205113p:plain

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アプリコース

動画配信サービスのおすすめを比較する【個性で選ぶべし!】。

f:id:tukumosanzou:20180708224820j:plain

皆さん動画配信サービスは、どこを利用してますか?。

ゆっくりとくつろげる時間が有るときは、動画配信ですきな映画やドラマ・アニメ等を見ましょう!


動画配信のお勧めを比較する

動画配信の四天王といえば

U-NEXT
Netflix
Hulu
Amazonプライム・ビデオ

でしょうか?

他にもありますが個人的には今の所この4つがオススメです。 どれも国内外の映画やドラマ等を配信していますが、それぞれ個性を打ち出しています。

自分にあったものがわかれば楽しさ倍増します。

比較

サービス名 月額料金(税抜) コンテンツ数 画質 無料お試し期間 ダウンロード機能
U-NEXT 1990円 12万以上 フルHD/4K 31日間
Netflix 800/1200/1800円 非公開 SD/HD/4K 1ヶ月間
Hulu 933円 4万以上 HD 14日間
amazon 370円(年会費だと300円) 3万5000以上 SD/HD/4K 30日間




U-NEXT

・料金は1990円(税抜)と群を抜いて高いですが継続ボーナスが毎月1200円分付きます。


・31日間無料トライアルの特典として、見放題作品が31日間無料で視聴可能! 600円分のポイントプレゼント!


 一部最新作を含む、すべてのジャンルの見放題作品を無料で視聴可能です、
 ただし、最新作はレンタル配信(個別課金)となってますね。


・映画、ドラマ、アニメなどが、12万本以上配信されてます。
  ※見放題作品8万本、レンタル作品4万本(2018年4月末時点)

・なんと追加料金なく、70誌以上の雑誌も読み放題できちゃいます!

・それ以外にもU-NEXTには「SMART USEN」月額490円(税抜)という音楽配信サービスがありまして、利用したら毎月71ポイント、嬉しいことに利用しない場合でも追加で521ポイントで合計600ポイントもらえます。

これは動画の視聴にもつかえるので両方あわせて1800ポイントが毎月もらえます。
 ※これは正規会員の場合ですね。


・新作の映画で話題性の有るものなどはDVDレンタル前に400ポイントぐらい〜1000ポイントぐらいで先行配信さたりもするので、レンタルしたいけど借りれないなんてことがなくなります。


料金はちょっと割高ですがその辺は捉え方次第でしょう、個人的には新作をいち早く見れるのでよく利用しています。


・新作・準新作で有料またはポイント利用や、見放題(料金は別に発生しない)作品が定期的に追加されるので何が追加されたか楽しめる部分もあります。


・見放題に関してメジャーどころの作品は有料のままが多い感じがしますが、たまにシリーズの新作や関連作なんかが出た時に等、キャンペーンで見放題になったり低料金(またはポイント)で利用できたりしますよ。


・ジャンルも幅広く網羅しています、韓国ものはトップカテゴリーに単独であるくらい韓流推しなようです、K-POP等も人気ですもんね。


・国内外平均的にジャンルが充実してる感じがします。


・レンタル期間は作品や全話パック等レンタル方法によって違ったりします、新作や先行配信は2日程度でこのあたりは実店舗のレンタルと近いですね。


スマホタブレット用にアプリがあり動画もダウンロードできるので外出先等で楽しむことも可能です。


U-NEXTは、かなりの映画好きの方には楽しめるサービスだと思いますよ。

【 U-NEXT 】- 日本最大級のビデオオンデマンド 今なら無料トライアル実施中!
本ページの情報は2018年7月時点のものです。最新の配信状況は U-NEXT サイトにてご確認ください。


Netflix

・料金は800/1200/1800円の3パターンで画質と同時接続数によって違いがあります。


・コンテンツは全て定額で視聴できます。


・他の動画配信サービスと決定的に違うところはオリジナルコンテンツに力を入れており海外の有名な賞にノミネートされたりするくらいクオリティが高いです。


有名な俳優たちの出演が多くなってきています、一時期はNetflix製の作品が有名な賞のノミネートのを巡って大騒ぎになっていましたが個人的には面白い作品であればそれで良いと思っています。


・最近ではますますオリジナルコンテンツの配信が活発になっているようで、個人的には「アナイアレーション」「スペクトル」「オクジャ」「ブライト」なんかが面白かったですね(他のもおもしろいですよ)。

・映画は旧作が多く最新作の入荷はかなり遅めですので新作を見たい場合はあまりおすすめではないですね、「ワンダーウーマン」なんかは早かったですけどね。


・アニメもオリジナルで、しかも日本のアニメーション製作会社と手を組んでクオリティの高いものを作っています。

シーズン単位で配信するパターンが多いようです、アニメーションの製作手法を変えるのではないかと一時期話題になってました。


・オリジナルコンテンツに力を入れているのと外資系のサービスだからか国内映画・ドラマは少し物足りない気がします。

有名どころから、いわゆるB級・C級と言われるレベルを平均的に扱っている感じがします。


スマホタブレット用にアプリがあり動画もダウンロードできるので外出先等で楽しむことも可能です。


Netfilixのオリジナルドラマや・映画が面白いと思った人は楽しめると思います。


Netflix - 大好きな映画やドラマを楽しもう!





Hulu

・月額933円(税抜)で視聴できます、少し前は配信会社の変更にともないいろいろと賛否両論ありましたが、元気に配信していますね。

・海外発のサービスなだけに海外ドラマは他のサービスと比べ充実してます。

「ゲームオブスローンズ」「ウォーキングデッド」などはここが最初に独占配信を行っていました。

・国内事業が国内のテレビ局に買収された経緯もあり系列の国内ドラマ・バラエティ・アニメ・韓流ドラマのコンテンツが多いです、過去の配信のドラマをまとめて見れるのはうれしいと思います。

・オリジナルのコンテンツにも、Netflix程ではないですが力を入れています、少し前にはHBOと共同で女性版シャーロックホームズの「ミス・シャーロック」を製作していましたね。

・ここも映画の新作はすこし遅めですが海外ドラマ・国内ドラマ・国内バラエティなどが好きな方はおすすめです。


・アプリもスマホタブレット用がありますしアプリへのダウロードも可能でオフラインでも視聴可能になってます。




【 Hulu 】今なら2週間無料トライアル実施中





amazon プライムビデオ

Amazonプライム会員で受けられるサービスのひとつなんですが、プライムビデオだけの利用もできます。

Amazonプライム会員だと単体で月額370円(税抜)(年会費だと月割りで300円(税抜))で動画見放題サービスが視聴できます。

ただ見放題のコンテンツは他のサービスに比べ少なくレンタル購入の作品が多いようです、まあこの価格でならば納得だとは思いますけどね。


・作品よっては新作も先行配信があるのもうれしいポイントです。

・ここも比較的オリジナルコンテンツに力を入れている感じです「アマゾンズ」「DOCUMENTAL」などが有名ですね。

・海外ドラマは他のサービスと比べラインナップが多い印象です、他のサービスでは配信していない海外ドラマも多く、それを目当てに利用している方も多いようですので海外ドラマには力を入れているようですね。




Amazonプライム・ビデオ: プライム特典の映画・テレビ番組が見放題!






各サービス共無料お試し期間があるので順番に試して見て自分にあったものを選ぶのが良いと思います。



そしてこんな生活に欠かせないのが!

Amazon fire TV stick

・自宅のHDMI端子対応のテレビに挿すだけでAmazon プライムビデオはもちろんU-NEXT Netflix Huluの動画配信サービスが楽しめます。


・以前はパソコンで利用していたんですが流石に24時間稼働しっぱなしで、CPUがPentiumなので熱暴走地獄におちいり電源落ちまくり(わかる人にはわかるはず)、あえなく撃沈したのをキッカケに以前から注目していたAmazon Fire TV Stickを購入しました。


・パソコン買い換えるより遥かに安上がりで、性能も文句無しです。


Amazon Fire TV Stickは定期的に割引セールも行なっているのでその時に迷わず買いました!。


・正直パソコンよりも快適ですし主な動画配信サービスがこれ一つで利用できてしまうからたまりません、YouTubeも見れますからもはやパソコン要らず?!。







動画配信サービスを楽しみましょう!。

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

f:id:tukumosanzou:20180702205113p:plain

今回は、playerをつくるfunc createPlayer()を追加したいと思います。
前回作成した、func createBackground()の直前にfunc createPlayer()を追加します、必要なパラメーターもついでに追加します。

import SpriteKit

//SKPhysicsContactDelegateを追加する。
class GameScene: SKScene, SKPhysicsContactDelegate {

    //ゲーム中にplayerを参照する必要があるのでplayerのパラメーターを作成します
    var player: SKSpriteNode!

    //衝突判定で使うビットを構造体で作る。
    struct PhysicsCategories {
        static let none: UInt32 = 0
        static let player: UInt32 = 0x1 << 1 //1
        static let laser: UInt32 = 0x1 << 2 //2
        static let enemy: UInt32 = 0x1 << 3 //3
    }

    override func didMove(to view: SKView) {

       //ゲームに重力シミュレートを追加する
      physicsWorld.gravity = CGVector(dx: 0, dy: 0)

      //物理衝突があったことを通知する。
      physicsWorld.contactDelegate = self

      createBackground()
       
       //関数呼び出し。
      createPlayer()

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

    //playerを作成する
    func createPlayer() {

        //SpriteNodeで使うテクスチャにplayer.pngを指定する。
        let playerTexture = SKTexture(imageNamed: "player")

        //SpriteNodeを作成する
        player = SKSpriteNode(texture: playerTexture)
        
        //衝突判定のために物理ボディを設定する。
        player.physicsBody = SKPhysicsBody(circleOfRadius: max(player.size.width / 2, player.size.height / 2))

        //物理ボディにカテゴリマスクを設定する。
        player.physicsBody!.categoryBitMask = PhysicsCategories.player

        //物理ボディに衝突マスクを設定する。
        player.physicsBody!.collisionBitMask = PhysicsCategories.none

        //物理ボディにコンタクトテストマスクを設定する。
        player.physicsBody!.contactTestBitMask = PhysicsCategories.enemy
        
        //SpriteNodeの大きさを実寸の半分にする。
        player.setScale(0.5)

        //重なり順番を10に設定する。
        player.zPosition = 10

        //名前をつける。
        player.name = "player"

        //最初の出現位置を決める。
        player.position = CGPoint(x: frame.midX, y: UIScreen.main.bounds.height * 0.05)

        //GameSceneに追加する。
        addChild(player)
    }

    func createBackground() {
        //省略
    }
}

func createBackground()と同じ部分は説明を省きます。
大きな違いはphysicsBody(物理エンジン)を追加する部分です。
これを追加することでオブジェクトの衝突判定が可能になり、いろいろと便利になります。
SKPhysicsBody - SpriteKit | Apple Developer Documentation を参照

physicsBody(物理エンジン)を使用しかつ衝突判定がをするためには必ず必要なものがあります、以下の部分です。

//SKPhysicsContactDelegateを追加する。
class GameScene: SKScene, SKPhysicsContactDelegate {
    
    //省略

    override func didMove(to view: SKView) {

        //ゲームに重力シミュレートを追加する
        physicsWorld.gravity = CGVector(dx: 0, dy: 0)

        //物理衝突があったことを通知する。
       physicsWorld.contactDelegate = self

    }

    //省略

}

SKPhysicsContactDelegate--- 物理衝突があったことを知らせるプロトコルです。

physicsWorld.contactDelegate = self --- 知らせる先はどこなのかを指定します、selfなので GameScene になります。

physicsWorld.gravity = CGVector(dx: 0, dy: 0 ) --- 重力のかかる方向を指定します、dx(X軸) dy(Y軸)ですが値が0なのは重力シミュレート自体は必要なのですが影響は受けたくないためです、物理エンジンで衝突判定をするためにはこの指定は必要なのでこのようにしています。

この3つはセットで使用すると思えば良いと思います。

Protocol - The Swift Programming Language (Swift 4.2)
SKPhysicsContactDelegate - SpriteKit | Apple Developer Documentation
SKPhysicsWorld - SpriteKit | Apple Developer Documentation
contactDelegate - Spritekit | Apple Developer Documentation
gravity - SpriteKit | Apple Developer Documentation

衝突判定について少し説明します。

f:id:tukumosanzou:20180705180127p:plain

衝突処理についてですが仮に図のようにplayerとenemyの2つの物体があり衝突するとします、必要なパラメーターは3つです。

categoryBitMask --- 物体を識別する一意の数字です基本的に同じものはありません。

collisionBitMask --- 自分自身に衝突を許可する物体のcategoryBitMaskを指定します複数ある場合は" | "で区切って表記します。

contactTestBitMask --- 設定してある物体にたいして衝突する相手のcategoryBitMaskを指定することで衝突したことにより発生する処理を行いたいときに使います、複数ある場合は" | "で区切って表記します。
ゲームの場合は爆発や得点が入る処理などが主だと思います。

ですが数字で表記すると結局わけがわからなくなりやすいので最初から2進数表現してなおかつ定数・変数に代入してしまうのがわかりやすいようです。

実際のコードをみた方がわかりやすいと思うので、今までの説明を踏まえて。
ここでは先ず、それぞれの物体のcategoryBitMaskを定数に入れて構造体(structures)を作成します。
Structures and Classes - The Swift Programming Language (Swift 4.2)

struct PhysicsCategories {
    static let none: UInt32 = 0
    static let player: UInt32 = 0x1 << 1 //1
    static let laser: UInt32 = 0x1 << 2 //2
    static let enemy: UInt32 = 0x1 << 3 //3
}

図のような部分になります。
struct(構造体)で2進数を各定数に入れます、0x1 << 1 は1のビットシフトです。ビットシフトを使わずplayer = 0b001とういう書き方もありますがその辺りは好みが分かれるところです。
Advanced Operators - The Swift Programming Language (Swift 4.2)

これを使用する場合はPhysicsCategories.playerと表記します。
続いてplayer に物理ボディ(物理エンジン)を追加する部分をです。

func createPlayer() {

    //省略

    //衝突判定のために物理ボディを設定する。
    player.physicsBody = SKPhysicsBody(circleOfRadius: max(player.size.width / 2, player.size.height / 2))

    //物理ボディにカテゴリマスクを設定する。
    player.physicsBody!.categoryBitMask = PhysicsCategories.player

    //物理ボディに衝突マスクを設定する。
    player.physicsBody!.collisionBitMask = PhysicsCategories.none

    //物理ボディにコンタクトテストマスクを設定する。
    player.physicsBody!.contactTestBitMask = PhysicsCategories.enemy

    //省略

}

SKPhysicsBody(circleOfRdius:) --- playerを包み込むように円形の物理ボディを作成します。他にもいくつかパターンがあります。 シミュレータで確認すると player の周りに青い円できてるはずです。

PhysicsCategories.none = 0 なのですがcollisionBitMaskに0を指定すると全ての衝突を受け入れることになります、厳密に指定するのもありなのですがこのゲームの場合playerにはenemyしか衝突しないので1対1の衝突の場合等はそれでも良いと思います。

ちなみにcategoryBitmaskが0は全てに属し、contactTestBitMaskが0は何が衝突しても衝突検出しません。

今回はcontactTestBitMask = PhysicsCategories.enemyとなってますので衝突検出はplayerから見てenemyとだけです。 もし複数の場合は PhysicsCategories.enemy | PhysicsCategories.laser みたいに" | "で区切ります。

SKPhysicsBody - SpriteKit | Apple Developer Documentation
categoryBitMask - SKPhysicsBody | Apple Developer Documentation
collisionBitMask - SKPhysicsBody | Apple Developer Documentation
contactTestBitMask - SKPhysicsBody | Apple Developer Documentation

以上でplayerの作成は終わりましたが、衝突検出をするのに相手側がないとはじまりません。
次回は相手側となるfunc createEnemy()を作成したいと思います。

ではまた次回。



swiftの詳細なら。

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

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

f:id:tukumosanzou:20180702205113p:plain

完成のコードを必要な場合は以下に記載してます。 tukumosanzou.hatenablog.com



では今回から実際に作業に入りましょう。  

GameScene.sksを開きます。 

f:id:tukumosanzou:20180704011653p:plain 

ここではGameScene(Scene: 要するにゲーム画面)の設定を行います。

右上の枠の中です。 

変更点だけ説明します、ColorをブラックSizeをW(width)375H(height)667とします。  

これはIPhone8のディスプレイサイズです(このゲームはiPad第5世代〜とiPhone5s〜に最適化する様に設定するためです。)  

Anchor PointをX(x軸)0 Y(Y軸)0 これはGameSceneの中心座標(つまり原点)がどこかを決めます

 

Gravity(重力)はXを0Yを-9.8(現実世界と同じ重力をシミュレートします。)から0にします。
SKPhysicsWorld - SpriteKit | Apple Developer Documentation を参照

PreviewのShow Camera Boundaries / Show Physics Boundaries / Use Camera Nodeのチェックはとりあえず入れておきます。

ここで一つ説明を。
f:id:tukumosanzou:20180704015708p:plain
Anchor Pointが出てきましたがSpriteKitを使うときは必ず出てきます。 

 

図のように数字は意味をもちます。

赤い四角形がGameSceneだとした場合は(0.0, 0.0)は左下、(0.5, 0.5)で中心ということになります。
これは  

ポジションを指定するときはこのAnchor Pointが重要になります。

SKScene - SpriteKit | Apple Developer Documentation を参照

 

GameScene.swiftを開きます。  

import SpriteKit

class GameScene:  SKScene {

    //ゲーム開始時に呼び出される部分。
    override func didMove(to view: SKView) {

    }

    //画面にタッチした時に呼び出される部分。
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

}

コードがいろいろ書いてありますが上の図になる様に他の部分は消してください。

ゲーム画面の背景になるfunc createBackground()を作成します。

import SpriteKit

class GameScene: SKScene {

    override func didMove(to view: SKView) {

    //関数の呼び出し。
    createBackground()

    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    }

    func createBackground() {

        //SpriteNodeで使うテクスチャにbackground.pngを設定(拡張子は省ける),定数に入れる。
        let backgroundTexture = SKTexture(imageNamed: "background")

        //0~1の間で{}で囲まれた処理を繰り返す
        for i in 0 ... 1 {
            
            //SpriteNodeを作る、テクスチャにばbackgroundを格納した定数backgroundTextureを使う。
            let background = SKSpriteNode(texture: backgroundTexture)

            //描画順を-30にする
            background.zPosition = -30

            //Nodeの中心点をzero=左下隅(0.0, 0.0)にする
            background.anchorPoint = CGPoint.zero

            //backgroundノードの位置を決める、変数iに0〜1の数字が入る事で位置が変化するようにする。
            background.position = CGPoint(x: 0, y: (backgroundTexture.size().height * CGFloat(i)) - CGFloat(1 * i))

            //scene(GameScene)に追加する。
            addChild(background)
            
            //スクリーンの上から下に移動するアクションを作る
            let moveDown = SKAction.moveBy(x: 0, y: -backgroundTexture.size().height, duration: 20)

            //位置を元に戻すアクションを作る。
            let moveReset = SKAction.moveBy(x: 0, y: backgroundTexture.size().height, duration: 0)

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

            //sequenceアクションをループさせる。
            let moveForever = SKAction.repeatForever(moveLoop)
            
            //アクショッンを実行する。
            background.run(moveForever)
        }
    }
}

override func touchesBegan()の直後に図のようにfunc background() {}を作成します。

ここではSKSpriteNode(imageNamed: "background")とせずにlet backgroundTexture = SKTexture(imageNamed: "background")としてますが、何故こうしているか理由ですがpositionを決めるときにbackgroundの高さを利用するためです、そうでなければ直接background.pngをSpriteNodeとして指定することもできます。
SKSpriteNode - SpriteKit | Apple Developer Documentation を参照

次にzPosition = -30とありますがこれは何か?。
webサイトを作成するときの技術にCSSがありますがその中のz-indexと同じようなものです。
以下ように図にしてみました。

f:id:tukumosanzou:20180705025718p:plain

SpriteKitはX軸Y軸Z軸で考えます、zPositionは0番目を基点にしてますがあくまでも基準ですので300 20 1 -2などでも構いませんが指定しなければデフォルトで0番になるだけです、2桁の時は2桁または負数は負数で統一するなどある程度のパターン化する方がコード上可読性は良いと思います。

SpriteNodeはaddChild(background)としないとGameSceneに追加されず画面上に表示されないのでこれはお約束だと思ってください。

SKActionでこの背景画像に動きをつけています。
SKAction - SpriteKit | Apple Developer Documentation を参照

つまりfunc createBackground()で何をしているかと言うと背景を上から下にアニメーションさせて昔懐かしい縦スクロールゲームを再現します。
図にすると以下の様になります。

f:id:tukumosanzou:20180705032528p:plain

for i in 0 ... 1なので0〜1の間(計11回)でループさせます。
例としてi=0 i=0.5 i= 1の3パターンで図にしました。

positionのCGPoint(x:, y:)のY軸での位置が変数iによりその都度変動します(変数 i は小数点も含むのでCGFloat()を使う)、その度にmoveBy()で逆Y軸方向に -backgroundTexture.size.height(backgroundの高さ)を20秒(duration: 20)かけて移動(let moveDown)して(0, 0)の元の位置(let moveReset)に戻す、sequenceで連続したアクションとしrepeatForeverで繰り返します。iの値ごとにこのアクションが連続してるので、これで背景が動いてゲームに臨場感が出てきます。
SKAction - SpriteKit |Apple Developer Documentation を参照

ここでシミュレータをiPhone Xで起動してください。

f:id:tukumosanzou:20180705035136p:plain

背景が上から下へ動いていれば成功です。

ではまた次回。



swiftの詳細なら。

TechAcademy [テックアカデミー]

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

プログラミング無料体験やってます!。

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

f:id:tukumosanzou:20180702205113p:plain

(画像はイメージです。)

SwiftのフレームワークのSpriteKitで遊ぼう。

 

swiftの基礎をなんとなくでも理解できたらSpriteKitで2Dゲームを作って楽しみながら学習しようというのが目的です。

SpriteKitについてはSpriteKit | Apple Developer Document に詳細があります。

swiftの詳細なら。

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

 

完成したゲームは以下の様になります。

画像はiPadですが、iPhoneにも対応しています。

                                       f:id:tukumosanzou:20180702210820p:plain

では、さっそく作業にかかりましょう。
開発環境
macOS High Sierra
Xcode 9.4.1
swift 4.1.2

 

Xcodeを立ち上げて新規プロジェクトを作成、ios/Gameを選び名前をspace-shooterとして保存します。

 

f:id:tukumosanzou:20180702211658p:plain

こんな感じですね。

f:id:tukumosanzou:20180702213357p:plain

図の青枠部分のDeployment Infoの設定だけ変更してます。

 

使用する画像等のアセットをAssets.xcassetsフォルダにコピーします。

f:id:tukumosanzou:20180702214222p:plain

枠の部分にドラッグ&ドロップしてコピーします。

player laser enemy 用の画像はkenny.nlで入手できます(ライセンスはCC0です、詳しくはサイトをみてください。)。

laser 爆発の効果音はOpenGameArtORG、 BGM は OpenGameArtORG で入手可能(ライセンスはCC0)他にもたくさんあるので気に入ったものをどうぞ。

 

ファイル名はリネームするなりして使用してください。
laser の効果音は LaserSoundEffect.mp3
爆発音は Explosion.wav

 

BGMは music.m4a の名前を使ってますファイルの形式は違っても構いません、大概のファイル形式は使えます。

音源は space shooter フォルダに入れてください。

 

background用の画像はunsplash.comより入手(星空で明るさが平均的な物が良いです、サイズが大きすぎるので適切な大きさにトリミングしてください)。

今回は iPad のサイズ幅1536 x 高さ2048ぐらいで良いと思います。

こんな感じの画像が良いです。

 

background.png

f:id:tukumosanzou:20180702215300j:plain

player.png         ufoBlue.png         ufoGreen.png   ufoRed.png    ufoYellow.png

f:id:tukumosanzou:20180702215612p:plain        f:id:tukumosanzou:20180702215713p:plain        f:id:tukumosanzou:20180702215841p:plain        f:id:tukumosanzou:20180702215858p:plain        f:id:tukumosanzou:20180702215909p:plain

 

これで作業に必要な材料が揃いました。

ではまた次回。