概要
SpriteKit の CGVector は指定方向に力を与えることができます
今回はノードに対して力を加え動かし壁に衝突したら永遠に反射しつづけるものを作成してみました
環境
- macOS X 10.13.1
- Xcode 9.1 (9B55)
コード
import SpriteKit
class GameScene: SKScene {
var ball = SKSpriteNode()
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
self.physicsBody?.affectedByGravity = false
self.physicsBody?.isDynamic = false
self.physicsBody?.linearDamping = 0
self.physicsBody?.friction = 0
self.physicsBody?.restitution = 1
ball = self.childNode(withName: "ball") as! SKSpriteNode
ball.physicsBody = SKPhysicsBody(texture: ball.texture!, size: ball.size)
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.restitution = 1
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos : CGPoint) {
print(abs(pos.x - ball.position.x))
if (abs(pos.x - ball.position.x) <= 200 && abs(pos.y - ball.position.y) <= 200) {
let vector = CGVector(dx: (pos.x - ball.position.x) / 10, dy: (pos.y - ball.position.y) / 10)
ball.physicsBody?.applyImpulse(vector)
}
}
}
説明
.sks
ファイルでは中央に 30x30 の円上のノードを 1 つ用意しています
それを childNode(withName:)
で読み込んでいます
物理エンジンはコード上で設定します
今回壁に反射してもスピードが減衰しない角度が変わらないようにする必要があります
それを実現するための必須プロパティは以下の通りです
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.restitution = 1
重力の影響を受けないようにして直線移動時の減衰率を 0 にして反発率を 1 にすることで反射時にも減衰しないようにします
加えて衝突する壁にも以下の設定が必須となります
self.physicsBody?.affectedByGravity = false
self.physicsBody?.isDynamic = false
self.physicsBody?.linearDamping = 0
self.physicsBody?.friction = 0
self.physicsBody?.restitution = 1
重力の影響と衝突の影響を受けないようにします
そして直線の減衰と反発時の減衰が発生しないようにします
ボールの設定と違って friction = 0
も設定します
これは摩擦係数の値で 1 に近いほど摩擦が多くなります
なので 0 にすることで壁に衝突したときの減衰をなくしています
今回はタップした方向に対してボールに力を与えます
ボールとタップした距離が 200 以下の場合にタップした座標への距離の 1/10 の力をボールに加え移動させています
なぜ 1/10 にしているかというと距離分力を加えるとものすごいスピードでボールが動き出してしまいます
ある程度の速度なら問題ないですが速度が早すぎると物理エンジンの当たり判定がうまく動作しないケースがあったので速度を抑えるために 1/10 にしています
本当は速度を一定にするためにタップした座標との方向はそのままで距離を一手にするような計算処理を入れればいいのですがとりあえず今回はさっくり動かしたかったので 1/10 にしました
CGVector の情報はノードに対して applyImpulse を設定することで割り当てることができます
動作確認
実行すると以下のように動作すると思います
最後に
SpriteKit で CGVector を使って外部から力を加えてみました
SpriteKit では重力以外の力も加えることができます
今回の手法は主にビーム光線やブロック崩しなどに使われます
結構使える技なので覚えておいて損はないかなと思います
0 件のコメント:
コメントを投稿