Swiftでゲームを作る
Swiftでゲーム作る場合、2Dゲームであれば、
Spritekitを使うのが一般的だと思います。
プロジェクト作成から作っていきます。
Xcode Version 14.3
上のメニューバーからFile→New→Projectを選び
iosタブのAppを選択しNextボタンを押す。
Project Nameでプロジェクト名を入力し(今回はblock breakerと入力しました。)
Nextボタンを押して保存先を決めます。
下準備、
いらない物を消す。
左のファイル一覧にある
SceneDelegate.swift
を削除。
右クリック→delete→Move To trash(ゴミ箱に移動)
同じファイル一覧にある
info(Info.plist)
Application Scene Manifest
を選択しバックスペースで削除。
ファイルを編集していきます。
ViewController.swiftのファイル名をGameViewController.swiftに変更します。
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = GameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsPhysics = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .resizeFill
skView.presentScene(scene)
}
}
AppDelegate.swift
AppDelegateも編集します。
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window:UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
window?.makeKeyAndVisible()
return true
}
}
ストーリーボードの編集
左のファイル一覧にあるMain(Main.storyboard)を選択し
画像で丸した所をクリックしてclass欄のViewControllerからGameViewControllerへ変更する。
続いてViewの所画像の順番にクリックしSKViewに変更する。
ここまで下準備。
ゲームシーンを作成。
わかりやすくするためにシーンファイルを置くフォルダを作る。
半角でgameと入力し右クリックしてNew Fileを選択
Swift Fileを選択しNext
Save As:にGameScene.swiftと入力しCreateボタンを押す。
動作テストしてみる。ブロック崩しサンプル
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
private var ball: SKShapeNode!
private var paddle: SKSpriteNode!
private var blocks = [SKSpriteNode]()
private let ballCategory: UInt32 = 0x1 << 0
private let paddleCategory: UInt32 = 0x1 << 1
private let blockCategory: UInt32 = 0x1 << 2
private let edgeCategory: UInt32 = 0x1 << 3
override func didMove(to view: SKView) {
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
physicsWorld.contactDelegate = self
createBall()
createPaddle()
createBlocks()
createPhysicsBoundaries()
// ボールに初速を与える
let dx: CGFloat = 200.0 // x方向の初速度
let dy: CGFloat = 400.0 // y方向の初速度
ball.physicsBody?.velocity = CGVector(dx: dx, dy: dy)
}
func createBall() {
ball = SKShapeNode(circleOfRadius: 10)
ball.fillColor = UIColor.red
ball.position = CGPoint(x: frame.midX, y: frame.midY)
ball.physicsBody = SKPhysicsBody(circleOfRadius: 10)
ball.physicsBody?.categoryBitMask = ballCategory
ball.physicsBody?.contactTestBitMask = blockCategory
ball.physicsBody?.collisionBitMask = blockCategory | paddleCategory | edgeCategory
ball.physicsBody?.isDynamic = true
addChild(ball)
}
func createPaddle() {
paddle = SKSpriteNode(color: UIColor.blue, size: CGSize(width: 100, height: 20))
paddle.position = CGPoint(x: frame.midX, y: frame.minY + 100)
paddle.physicsBody = SKPhysicsBody(rectangleOf: paddle.size)
paddle.physicsBody?.categoryBitMask = paddleCategory
paddle.physicsBody?.restitution = 1.0
paddle.physicsBody?.collisionBitMask = ballCategory
paddle.physicsBody?.isDynamic = false
addChild(paddle)
}
func createBlocks() {
let numRows = 3
let numCols = 5
let blockWidth = frame.width / CGFloat(numCols)
let blockHeight: CGFloat = 20
for row in 0..<numRows {
for col in 0..<numCols {
let block = SKSpriteNode(color: UIColor.green, size: CGSize(width: blockWidth, height: blockHeight))
block.position = CGPoint(x: blockWidth * CGFloat(col) + blockWidth / 2, y: frame.height - CGFloat(row) * blockHeight - blockHeight / 2)
block.physicsBody = SKPhysicsBody(rectangleOf: block.size)
block.physicsBody?.categoryBitMask = blockCategory
block.physicsBody?.collisionBitMask = ballCategory
block.physicsBody?.isDynamic = false
blocks.append(block)
addChild(block)
}
}
}
override func update(_ currentTime: TimeInterval) {
// ボールの速度を一定に保つことで停止させない
let minSpeed: CGFloat = 300.0
let speed = sqrt(ball.physicsBody!.velocity.dx * ball.physicsBody!.velocity.dx + ball.physicsBody!.velocity.dy * ball.physicsBody!.velocity.dy)
if speed < minSpeed {
let scale = minSpeed / speed
ball.physicsBody?.velocity.dx *= scale
ball.physicsBody?.velocity.dy *= scale
}
}
func createPhysicsBoundaries() {
let edge = SKNode()
edge.physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
edge.physicsBody?.friction = 0.0
edge.physicsBody?.restitution = 1.0
edge.physicsBody?.categoryBitMask = edgeCategory
addChild(edge)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
paddle.position.x = location.x
}
}
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == blockCategory || contact.bodyB.categoryBitMask == blockCategory {
let blockNode = contact.bodyA.categoryBitMask == blockCategory ? contact.bodyA.node : contact.bodyB.node
blockNode?.removeFromParent()
if let index = blocks.firstIndex(of: blockNode as! SKSpriteNode) {
blocks.remove(at: index)
}
}
}
}