【SpriteKit】銃を撃つアクションを追加してみた

こんにちは、のっくんです。

SwiftのiPhoneゲーム開発も少しずつ慣れてきた感があります。

今回はプレイヤーが銃を撃てるようにしてみました。

反対向きにも対応しています。

ジャンプ後のスクショなので、弾が空中からも飛んでいます。

見えるようにあえて弾の速度を遅くしています。

弾のクラスを作る

銃を撃つアクションを追加するのに、まず考えたのは弾をどうやって実装するのか。

今までは、プレイヤーや地面のクラスを作って、ゲームシーンに追加してきました。

弾はプレイヤーから発砲されるものなのでプレイヤーのサブクラスとして実装するのもアリかと思いました。

しかし、プレイヤーのクラスの1部として実装すると、ゲームシーンに追加できなくなってしまいます。

弾をゲームシーンに追加しないと画面に追加されないため、やはり弾は1クラスとして実装することにしました。

弾の向きを変更する

弾は左向き、右向きがあります。

テキスチャの向きを変更するには、xScaleを変更します。

xScale = -1にするとx方向に反転します。

弾に重力は適用しない

重力を適用すると、発射後、途中で沈んでしまいます。

affectedByGravityで重力影響を受けないようにします。

数秒後に弾を消す

発射後に弾は画面から消えますが、スプライトノードとしては存在しています。

数秒待った後に消す処理を入れました。

コード

イニシャライザ

Shotクラスのinit処理を作ります。

イニシャライザにプレイヤーの位置、向きを設定します。

プレイヤーの位置や向きによって弾のポジションや向きが決定します。

var backword:Bool = false

init(pos:CGPoint,bw:Bool){
    super.init(texture: SKTexture(imageNamed: "shot"), color:.clear,size: CGSize(width: 10, height: 10))
    
    self.backword = bw
    
    self.zPosition = CGFloat(ZPositions.otherNodes.rawValue)
    
    self.physicsBody = SKPhysicsBody(texture: self.texture!, size:self.size)
    
    self.physicsBody?.mass = 0.5
    
    self.physicsBody?.affectedByGravity = false
    
    if self.backword {
        self.xScale = -1
        self.position = CGPoint(x:pos.x - 25, y:pos.y)
    }else{
        self.position = CGPoint(x:pos.x + 25, y:pos.y)
    }
}

弾を飛ばすための処理

弾を飛ばすにはapplyImpulseを使います。

 func fire(){
    
    if self.backword {
        self.physicsBody?.applyImpulse(CGVector(dx: -50, dy: 0))
    }else{
        self.physicsBody?.applyImpulse(CGVector(dx: 50, dy: 0))
    }
    //1秒経ったら弾を消す
    let wait = SKAction.wait(forDuration: 1)
    let endShot = SKAction.run {
        self.removeFromParent()
    }
    self.run(SKAction.sequence([wait,endShot]))
    
}

時間のインターバルを設ける

クラスを作ったところで、次はゲームシーンの中で呼び出します。

GameScene.swiftのGameSceneクラスに以下の変数を追加します。

var fireTime:Double = 0
var fireInterval:Double = 0.1

次に、GameScene.swiftのupdate関数に以下を追加します。

if self.nokman.firing {
    // インターバルを空けないと発砲できないようにする
    if fireTime == 0 || currentTime - fireTime > fireInterval {
        self.nokman.Fire()
        let shot = Shot(pos: self.nokman.position, bw:self.nokman.backward)
        self.addChild(shot)
        shot.fire()
        fireTime = currentTime
    }
}

プレイヤーが発砲中のフラグが立っているか確認し、その後インターバルが空いているか確認しています。

インターバルが短ければ短いほど高速に弾を連射できます。