8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

iOSAdvent Calendar 2022

Day 2

SpriteKitで2D横スクロールゲームをつくろう(その1)

Last updated at Posted at 2022-12-01

Xcode-14.1 iOS-16.0

はじめに

SpriteKit を使って 2D 横スクロールゲームをつくってみます。なぜ Unity を使わないんだ?と疑問を持つ方もいるかもしれませんがとくに意味はありません。なんか面白そうなので SpriteKit を使ってみます。

記事は3つくらいになる予定です(たぶん)。

今回は歩いたり跳ねたりするプレイヤーを実装していきます。

素材準備

クリスマスも近いのでチキンをプレイヤーにします:chicken:

歩き用

c1 c2
c1 c2

ジャンプ用

j1 j2
j1 j2

実装

View の表示については下記をご参考ください。本記事でやるのは基本的に SKScene の実装のみです。

SwiftUIでSpriteKit

表示

とりあえず画面にプレイヤーを表示します。

final class GameScene: SKScene {

    private let player = SKSpriteNode(texture: .init(imageNamed: "c1"), size: .init(width: 32, height: 32))
    override func didMove(to view: SKView) {
        backgroundColor = .init(red: 51/255, green: 51/255, blue: 51/255, alpha: 1.0)

        let floor = SKShapeNode(rectOf: .init(width: 1000, height: 10))
        floor.name = "floor"
        floor.position = .init(x: frame.midX, y: 0)
        floor.fillColor = .white
        floor.physicsBody = .init(rectangleOf: .init(width: 1000, height: 10))
        floor.physicsBody?.isDynamic = false
        addChild(floor)

        player.position = .init(x: frame.midX, y: frame.midY)
        player.physicsBody = .init(texture: player.texture!, size: player.size)
        // ころがらないように設定
        player.physicsBody?.allowsRotation = false
        addChild(player)
    }
}

こんな感じです。

chicken

歩行

歩行はボタンを押し続けている限り動作を継続したいので状態を保持して状態判定でプレイヤーを移動させるようにしました(都度アニメーションをつけるとカクカクしたので repeatForever にしてます)。

// プレイヤーの状態
enum PlayerStatus {
    /// 走行中
    case running
    /// ジャンプ準備中
    case prepareJump
    /// ジャンプ中
    case jumping
    /// 停止中
    case pause
}

final class GameScene: SKScene {

    // 追加
    private var status = PlayerStatus.pause
    private let runTextures: [SKTexture] = [
        .init(imageNamed: "c2"),
        .init(imageNamed: "c1"),
    ]

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        status = .running
        // アニメーション開始
        let action = SKAction.animate(with: runTextures, timePerFrame: 0.2)
        player.run(.repeatForever(action), withKey: "running")
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        // アニメーション停止
        player.removeAction(forKey: "running")
        status = .pause
    }

    override func update(_ currentTime: TimeInterval) {
        switch status {
        case .running:
            // プレイヤーを移動させる
            player.physicsBody?.velocity = CGVector(dx: 120, dy: 0)
        default:
            break
        }
    }
}

こんな感じです。

run

ジャンプ

2段ジャンプを防止しようと思ったらわりとややこしくなりました。

final class GameScene: SKScene {
    // 追加
    private let jumpTextures: [SKTexture] = [
        .init(imageNamed: "j1"),
        .init(imageNamed: "j2"),
    ]

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if status == .jumping || status == .prepareJump {
            return
        }
        status = .prepareJump
        et action = SKAction.group([
            .animate(with: jumpTextures, timePerFrame: 0.2),
            .sequence([
                .wait(forDuration: 0.2),
                .applyImpulse(.init(dx: 2, dy: 13), duration: 0.2)
            ])
        ])
        player.run(action) {
            self.player.run(.setTexture(self.runTextures[1]))
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
            self.status = .jumping
        }
    }

    override func update(_ currentTime: TimeInterval) {
        switch status {
        case .jumping:
            if player.physicsBody?.velocity.dy == 0 {
                status = .pause
            }
        default:
            break
        }
    }
}

こんな感じです。

jump

おわりに

てきとーにボタン配置するとこんな感じになります。

game

次回はステージを作ります!

SpriteKit あまりさわったことないのでもっといい方法あればぜひ教えて下さい:bow:

まとめ

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?