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

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

f:id:tukumosanzou:20180702205113p:plain

前回までで、完成してますが今回はおまけを、すこし追加したいと思います。

せっかくですから、LaunchScreen.storyboard を調整してゲームのオープニング画面を作ります。


LaunchScreen.storyboard は既にあるので開いてください。

以下のような、感じに変更していきます。
f:id:tukumosanzou:20180728001821p:plain


右下の Object Library から Labelview に追加して以下の図の様に変更します。
f:id:tukumosanzou:20180728002028p:plain


"SPACE" "SHOOTER" の各テキストをクリックして図の部分の白い四角形内の赤い線が太くなっていたら線自体をクリックして図の状態にして Autoresizing の設定をオフにします。

各テキストごとに行ってください。
f:id:tukumosanzou:20180728002333p:plain


ちょっとわかりづらいので、拡大しますね。
f:id:tukumosanzou:20180728002507p:plain

赤い太線をクリックすると、以下のようになります。 そうすると、右側の赤い四角が中央に来ると思います。
f:id:tukumosanzou:20180728002522p:plain
これで、テキストがデバイスのサイズに合わせて自動で中央に表示できるようになります。



以上で終了です、全てはうまく説明仕切れてないかもですがなんとなく感じが掴めてもらえれば幸いです。

ありがとうございました。

完成した各ファイルの全コードを載せておきます。

GameScene.swift

import SpriteKit
import GameplayKit

var gameScore = 0

class GameScene: SKScene, SKPhysicsContactDelegate {
    
    var logoLabel: SKLabelNode!
    var gameState = GameState.startGame
    
    var livesImages = [SKSpriteNode]()
    var lives = 3
    
    var player: SKSpriteNode!
    
    var enemy: SKSpriteNode!
    var enemyArray = ["ufoBlue", "ufoRed", "ufoGreen", "ufoYellow"]
    
    var getTimer: Timer!
    
    var scoreLabel: SKLabelNode!
    var score = gameScore {
        didSet {
            scoreLabel.text = "SCORE: \(score)"
        }
    }
    
    var backgroundMusic = SKAudioNode()
    let musicURL = Bundle.main.url(forResource: "music", withExtension: "m4a")
    let laserSound = SKAction.playSoundFileNamed("LaserSoundEffect.mp3", waitForCompletion: false)
    let explosionSound = SKAction.playSoundFileNamed("explosion.wav", waitForCompletion: false)
    
    
    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
    }
    
    enum GameState {
        case startGame
        case endGame
    }
    
    
    override func didMove(to view: SKView) {
        
        physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        physicsWorld.contactDelegate = self
        
        createBackground()
        createPlayer()
        createScore()
        createLives()
        
        if getTimer == nil {
            getTimer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
        }

        
        backgroundMusic = SKAudioNode(url: musicURL!)
        addChild(backgroundMusic)
    }
    
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        guard let touch = touches.first else { return }
        
        switch gameState {
        case .startGame:
            let location = touch.location(in: self)
            
            
            if location.x < player.position.x {
                player.position.x -= 50
            } else if location.x > player.position.x {
                player.position.x += 50
            }
            
            if player.position.x > frame.maxX - player.size.width {
                player.position.x = frame.maxX - player.size.width / 2
                
            }
            
            if player.position.x < frame.minX + player.size.width {
                player.position.x = frame.minX + player.size.width / 2
            }
            
            createLaser()
            
        case .endGame:
            break
        }
    }
    
    
    override func update(_ currentTime: TimeInterval) {
       
    }
    
    
    func didBegin(_ contact: SKPhysicsContact) {
        
        if contact.bodyA.node?.name == "laser" || contact.bodyB.node?.name == "laser" {
            if contact.bodyA.node?.name == "enemy" {
                contact.bodyA.node?.removeFromParent()
                contact.bodyB.node?.removeFromParent()
                
                if let explosion = SKEmitterNode(fileNamed: "ExplosionEffect") {
                    explosion.position = (contact.bodyA.node?.position)!
                    addChild(explosion)
                }
                
            } else {
                contact.bodyA.node?.removeFromParent()
                contact.bodyB.node?.removeFromParent()
                
                if let explosion = SKEmitterNode(fileNamed: "ExplosionEffect") {
                    explosion.position = (contact.bodyB.node?.position)!
                    addChild(explosion)
                }
            }
            
            run(explosionSound)
            
            gameScore += 1
            score = gameScore
            
            return
        }
        
        guard contact.bodyA.node != nil && contact.bodyB.node != nil else { return }
        
        if contact.bodyA.node?.name == "player" || contact.bodyB.node?.name == "player" {
            if let explosion = SKEmitterNode(fileNamed: "ExplosionEffect") {
                explosion.position = player.position
                addChild(explosion)
            }
            
            run(explosionSound)
            
            contact.bodyA.node?.removeFromParent()
            contact.bodyB.node?.removeFromParent()
            
            subtractLife()
            createPlayer()
            
        }
    }
    
    
    func changeScene() {
        
        let scene = GameOverScene(size: frame.size)
        scene.scaleMode = self.scaleMode
        let transition = SKTransition.crossFade(withDuration: 1.5)
        view?.presentScene(scene, transition: transition)
    }
    
    
    func runGameOver() {
        if getTimer != nil {
            getTimer.invalidate()
            getTimer = nil
            
        }
        
        let changeSceneAction = SKAction.run(changeScene)
        let waitToChangeScene = SKAction.wait(forDuration: 2.5)
        let changeSceneSequence = SKAction.sequence([waitToChangeScene, changeSceneAction])
        run(changeSceneSequence)
    }
    
    
    func subtractLife() {
        lives -= 1
        
        var life: SKSpriteNode
        
        if lives == 2 {
            life = livesImages[0]
        } else if lives == 1 {
            life = livesImages[1]
        } else {
            life = livesImages[2]
        }
        
        life.removeFromParent()
        
        if lives == 0 {
            gameState = .endGame
            runGameOver()
        }
    }
    
    
    func createLives() {
        for i in 0 ..< lives {
            let spriteNode = SKSpriteNode(imageNamed: "player")
            spriteNode.position = CGPoint(x: frame.minX + 40 + CGFloat(i * 99) * 0.25, y: UIScreen.main.bounds.height * 0.90)
            spriteNode.setScale(0.25)
            addChild(spriteNode)
            
            livesImages.append(spriteNode)
        }
    }
    
    
    func createScore() {
        scoreLabel = SKLabelNode(fontNamed: "Optima-ExtraBlack")
        scoreLabel.fontSize = 24

        scoreLabel.position = CGPoint(x: frame.minX + 80, y: UIScreen.main.bounds.height * 0.92)
        scoreLabel.text = "SCORE:0"
        scoreLabel.fontColor = UIColor.white
        
        addChild(scoreLabel)
    }
    
    
    @objc func createEnemy() {
        
        enemyArray = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: enemyArray) as! [String]
        print(enemyArray)
        let enemyTexture = SKTexture(imageNamed: enemyArray[0])
        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
        
        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)
        addChild(enemy)
        
        let moveEnemy = SKAction.moveTo(y: -self.size.height + enemy.size.height, duration: 5)
        let moveReset = SKAction.removeFromParent()
        let moveSequence = SKAction.sequence([moveEnemy, moveReset])
        let moveForever = SKAction.repeatForever(moveSequence)
        
        enemy.run(moveForever)
    }
    

    func createLaser() {
        let laser = SKSpriteNode(imageNamed: "laser")
        
        laser.physicsBody = SKPhysicsBody(circleOfRadius: max(laser.size.width / 2, laser.size.height / 2))
        laser.physicsBody!.categoryBitMask = PhysicsCategories.laser
        laser.physicsBody!.collisionBitMask = PhysicsCategories.none
        laser.physicsBody!.contactTestBitMask = PhysicsCategories.enemy
        
        laser.zPosition = 5
        laser.name = "laser"
        laser.position = CGPoint(x: player.position.x, y: player.position.y + player.size.height * 0.8)
        addChild(laser)
        
        let moveLaser = SKAction.moveTo(y: self.size.height + laser.size.height, duration: 1)
        let moveReset = SKAction.removeFromParent()
        let moveSequence = SKAction.sequence([laserSound, moveLaser, moveReset])
        
        laser.run(moveSequence)
    }
    
    
    func createPlayer() {
        let playerTexture = SKTexture(imageNamed: "player")
        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
        
        player.setScale(0.5)
        player.zPosition = 10
        player.name = "player"
        player.position = CGPoint(x: frame.midX, y: UIScreen.main.bounds.height * 0.05)
        addChild(player)
    }

    
    func createBackground() {
        let backgroundTexture = SKTexture(imageNamed: "background")
        
        for i in 0 ... 1 {
            let background = SKSpriteNode(texture: backgroundTexture)
            background.zPosition = -30
            background.anchorPoint = CGPoint.zero
            background.position = CGPoint(x: 0, y: (backgroundTexture.size().height * CGFloat(i)) - CGFloat(1 * i))
            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)
            let moveLoop = SKAction.sequence([moveDown, moveReset])
            let moveForever = SKAction.repeatForever(moveLoop)
            
            background.run(moveForever)
        }
    }
}



GameViewController.swift

import UIKit
import SpriteKit

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let view = self.view as! SKView? {
            if let scene = SKScene(fileNamed: "GameScene") {
                if (UIDevice.current.model.range(of: "iPad") != nil) {
                    scene.scaleMode = .resizeFill
                } else if UIScreen.main.nativeBounds.height == 2436.0 {
                    scene.scaleMode = .resizeFill
                } else {
                    scene.scaleMode = .aspectFill
                }
                view.presentScene(scene)
            }
            
            
            view.ignoresSiblingOrder = true
            
            view.showsFPS = true
            view.showsNodeCount = true
            view.showsPhysics = true
        }
    }

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }
}



GameOverScene.swift

import Foundation
import SpriteKit

class GameOverScene: SKScene {
    
    let restartLabel = SKLabelNode(fontNamed: "AppleSDGothicNeo-Bold")
    
    override func didMove(to view: SKView) {
        
        let background = SKSpriteNode(imageNamed: "background")
        background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
        background.zPosition = 0
        addChild(background)
        
        
        let gameeOverLabel = SKLabelNode(fontNamed: "Helvetica-Bold")
        gameeOverLabel.text = "GAME OVER"
        gameeOverLabel.fontSize = 60
        gameeOverLabel.fontColor = SKColor.white
        gameeOverLabel.position = CGPoint(x: frame.size.width * 0.5, y: frame.size.height * 0.7)
        gameeOverLabel.zPosition = 1
        addChild(gameeOverLabel)
        
        
        let scoreLabel = SKLabelNode(fontNamed: "AppleSDGothicNeo-Bold")
        scoreLabel.text = "SCORE: \(gameScore)"
        scoreLabel.fontSize = 30
        scoreLabel.fontColor = SKColor.white
        scoreLabel.position = CGPoint(x: frame.size.width / 2, y: frame.size.height * 0.55)
        scoreLabel.zPosition = 1
        addChild(scoreLabel)
        
        
        let defaults = UserDefaults()
        var highScoreNumber = defaults.integer(forKey: "highScoreSaved")
        
        if gameScore > highScoreNumber {
            highScoreNumber = gameScore
            defaults.set(highScoreNumber, forKey: "highScoreSaved")
        }
        
        
        let highScoreLabel = SKLabelNode(fontNamed: "AppleSDGothicNeo-Bold")
        highScoreLabel.text = "HIGH SCORE: \(highScoreNumber)"
        highScoreLabel.fontSize = 30
        highScoreLabel.fontColor = SKColor.white
        highScoreLabel.zPosition = 1
        highScoreLabel.position = CGPoint(x: frame.size.width / 2, y: frame.size.height * 0.45)
        addChild(highScoreLabel)
        
        
        restartLabel.text = "Restart"
        restartLabel.fontSize = 30
        restartLabel.fontColor = SKColor.white
        restartLabel.zPosition = 1
        restartLabel.position = CGPoint(x: frame.size.width / 2, y: frame.size.height * 0.3)
        addChild(restartLabel)

    }
    
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch: AnyObject in touches {
            let pointOfTouch = touch.location(in :self)
            
            if restartLabel.contains(pointOfTouch) {
                let scene = GameScene(size: self.size)
                scene.scaleMode = self.scaleMode
                let transition = SKTransition.crossFade(withDuration: 0.5)
                view?.presentScene(scene, transition: transition)
            }
        }
    }
}