SpriteKitでゲーム その1- SPACE SHOOTER⑨
前回までで、完成してますが今回はおまけを、すこし追加したいと思います。
せっかくですから、LaunchScreen.storyboard を調整してゲームのオープニング画面を作ります。
LaunchScreen.storyboard は既にあるので開いてください。
以下のような、感じに変更していきます。
右下の Object Library から Label を view に追加して以下の図の様に変更します。
"SPACE" "SHOOTER" の各テキストをクリックして図の部分の白い四角形内の赤い線が太くなっていたら線自体をクリックして図の状態にして Autoresizing の設定をオフにします。
各テキストごとに行ってください。
ちょっとわかりづらいので、拡大しますね。
赤い太線をクリックすると、以下のようになります。
そうすると、右側の赤い四角が中央に来ると思います。
これで、テキストがデバイスのサイズに合わせて自動で中央に表示できるようになります。
以上で終了です、全てはうまく説明仕切れてないかもですがなんとなく感じが掴めてもらえれば幸いです。
ありがとうございました。 完成した各ファイルの全コードを載せておきます。
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) } } } }