SpriteKitの使い方を解説します。
SpriteKit 入門 ③ で自機(画像)から弾を発射することができるようになりました。今回は敵を表示して衝突判定を実装していきます。
(環境:Xcode12.1 Swift5.3)
##敵の表示
前回学んだSKShapeNode
を使用して敵を表示します。今回は簡易的に、画面上部から出現するようにしてみました。出現するx座標はCGFloat.random()
を使用してランダムにしています。
var enemy: SKShapeNode?
var lastUpdateTime2 : TimeInterval = 0
//...
//敵
func enemies(){
self.enemy = SKShapeNode.init(circleOfRadius: 50)
if let enemy = self.enemy {
enemy.position = CGPoint(x: CGFloat.random(in: -self.size.width/2 + 100 ... self.size.width/2 - 100), y: self.size.height/2 + enemy.yScale)
enemy.fillColor = SKColor.blue
enemy.lineWidth = 5
enemy.strokeColor = SKColor.white
enemy.run(SKAction.sequence([SKAction.move(by: CGVector(dx: 0, dy: -self.size.height - 100), duration: 10),SKAction.removeFromParent()]))
self.addChild(enemy)
}
}
//...
//一定時間毎の処理
override func update(_ currentTime: TimeInterval) {
//...
if (lastUpdateTime2 == 0) {
self.lastUpdateTime2 = currentTime
}
if (lastUpdateTime2 + 1 <= currentTime) {
//1秒毎に敵を表示
self.enemies()
lastUpdateTime2 = currentTime
}
}
##衝突判定
物理的な挙動にかかる処理にはSKPhysicsBody
を使用します。衝突判定にはSKPhysicsBody
のプロパティとして
categoryBitMask
collisionBitMask
contactTestBitMask
を使用します。これらの詳細については以下の記事が参考になると思います。
- SpriteKitの衝突処理について(categoryBitMask collisionBitMask contactTestBitMask 使い方)
- SpriteKitの CategoryBitMask、CollisionBitMask、ContactTestBitMask まとめ
contactTestBitMask
で指定したNode(正確にはcategoryBitMask)と接触した際には、
didBegin(_ contact: SKPhysicsContact)
didEnd(_ contact: SKPhysicsContact)
のメソッドが呼ばれます。これらのメソッドを利用するためにはあらかじめSKPhysicsContactDelegate
を追加しておく必要があります。
コードは次のようになります。
class MyScene: SKScene, SKPhysicsContactDelegate {
//...
override func sceneDidLoad() {
//...
//Delegateの指定
physicsWorld.contactDelegate = self
}
//自機から発射する弾
func repeatShoots(){
self.enemy = SKShapeNode.init(circleOfRadius: 50)
if let shoot = self.shoot {
shoot.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 30))
shoot.physicsBody?.affectedByGravity = false
shoot.physicsBody?.categoryBitMask = 0b0001
shoot.physicsBody?.collisionBitMask = 0b0000
shoot.physicsBody?.contactTestBitMask = 0b0001
//...
}
}
//敵
func enemies(){
self.enemy = SKShapeNode.init(circleOfRadius: 50)
if let enemy = self.enemy {
enemy.physicsBody = SKPhysicsBody(circleOfRadius: 50)
enemy.physicsBody?.affectedByGravity = false
enemy.physicsBody?.categoryBitMask = 0b0001
enemy.physicsBody?.collisionBitMask = 0b0000
enemy.physicsBody?.contactTestBitMask = 0b0001
//...
}
}
func didBegin(_ contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == self.enemy?.physicsBody!.categoryBitMask || contact.bodyB.categoryBitMask == self.enemy?.physicsBody!.categoryBitMask){
self.removeChildren(in: [contact.bodyA.node!,contact.bodyB.node!])
}
}
didBegin(_ contact: SKPhysicsContact)
で衝突したNodeは.bodyA
、.bodyB
で取得することができます。ただし、AとBの順番は保証されないので注意が必要です。またself.removeChildren(in: )
は取り除くNodeが1つの場合でも配列の形で引数を与える必要があります。
##まとめ
ここまでで
- SpriteKitSceneファイル
- SKView
- SKScene
- SKSpriteNode
- SKShapeNode
- SKAction
- SKPhysicsBody
- TimeInterval
- タッチ操作
について扱いました。これらだけでもアイデア次第でいろんなゲームが作れそうですね。
次回はまだ扱っていないSKEmitterNode
の使い方について解説します。
次回は一度に発射する弾の数を増やしてみようと思います。
###参考
この記事は以下の情報を参考にして執筆しました。