スクリーンセーバーに設定できるものの中に、ラインアートがあります。
今回はSwiftとSpriteKitでラインアートのようなアプリを
日々大量のバグを生み出し続けるWebプログラマー「エイチ」と
バグが大好物なエイチのペット「バグバグ」とともに実装してみます。
バグバグ 「zzz zzz zzz」
エイチ 「バグバグ ねぇ バグバグ 起きなよ
Swiftで簡単なラインアートみたいなアプリを作ってみるよ」
バグバグ 「!!」
エイチ 「XCodeからプロジェクトを作ろっと
テンプレートはGameでー
ゲームエンジンはSpriteKitでー」
カチャカチャッ タンッ!
エイチ 「プロジェクト出来たから実装するよ」
カチャカチャッ タンッ!
GameScene.swift
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
private var pointNode: SKShapeNode?
private var shapeNode: SKShapeNode?
private var gravityUpdateTime: TimeInterval?
private var colorValue: CGFloat?
private var colorSign: CGFloat = 1.0
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
self.physicsBody?.restitution = 0.75
self.physicsBody?.contactTestBitMask = 1
self.physicsWorld.contactDelegate = self
self.pointNode = SKShapeNode(circleOfRadius: 10.0)
if let point = self.pointNode {
point.fillColor = SKColor.white
point.alpha = 0.75
point.physicsBody = SKPhysicsBody(circleOfRadius: 10.0)
point.physicsBody?.contactTestBitMask = 1
self.addChild(point)
}
let w = (self.size.width + self.size.height) * 0.05
self.shapeNode = SKShapeNode.init(rectOf: CGSize.init(width: w, height: w), cornerRadius: w * 0.3)
if let shapeNode = self.shapeNode {
shapeNode.lineWidth = 5.0
shapeNode.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI), duration: 1.0)))
shapeNode.run(SKAction.sequence([
SKAction.group([
SKAction.fadeOut(withDuration: 1.0),
SKAction.scale(to: 0.1, duration: 1.0),
]),
SKAction.removeFromParent(),
]))
}
}
override func update(_ currentTime: TimeInterval) {
if self.gravityUpdateTime == nil {
self.gravityUpdateTime = currentTime
}
if self.gravityUpdateTime! + 0.05 <= currentTime { self.physicsWorld.gravity = CGVector(dx: getRandomDoubleNumber(min: -10.0, max: 10.0), dy: getRandomDoubleNumber(min: -10.0, max: 10.0)) self.gravityUpdateTime = currentTime } if self.colorValue == nil { self.colorValue = CGFloat(getRandomDoubleNumber(min: 0.0, max: 1.0)) } let color = SKColor.init(hue: self.colorValue!, saturation: 1.0, brightness: 1.0, alpha: 0.5) self.makeShapeNode(atPoint: (self.pointNode?.position)!, atColor: color) self.updateColorValue() } func makeShapeNode(atPoint pos: CGPoint, atColor color: SKColor) { if let n = self.shapeNode?.copy() as! SKShapeNode? { n.position = pos n.strokeColor = color self.addChild(n) self.shapeNode?.position = pos } } func updateColorValue() { self.colorValue = self.colorValue! + (self.colorSign * 0.01) if self.colorValue! > 1.0 {
self.colorValue = 1.0
self.colorSign = -1.0
}
else if self.colorValue! < 0.0 { self.colorValue = 0.0 self.colorSign = 1.0 } } func getRandomDoubleNumber(min: Double, max: Double) -> Double {
return ( Double(arc4random_uniform(UINT32_MAX)) / Double(UINT32_MAX) ) * (max - min) + min
}
}
エイチ 「よしっ 実行してみよっと」
ポチッ!
バグバグはラインを目で追って ヨダレを垂らしているようだ
エイチ 「バグバグ 待てだよ! 待て!!」
バグバグ 「・・・」
エイチ 「基本的にはこうだよ」
- 円pointNodeは重力にしたがって移動する
- 円pointNodeは画面の上下左右にあたると跳ね返る
- ゲームループの中で毎回、四角のラインshapeNodeを円pointNodeがそのときいる場所に表示する
- ラインshapeNodeは一定時間内に、回転、フェードアウト、縮小して画面から消える
エイチ 「あとやってることと言えば」
- ゲームループの中で定期的に、円pointNodeの動きに変化をつけるために重力を変更する
- ゲームループの中で毎回表示する四角のラインshapeNodeの線の色を調整する
エイチ 「お待たせ バグバグ ソースコード 全部お食べ」
バグバグ 「バグバグ バグバグ バグバグ」
エイチ 「美味しかったろう バグバグ」