Swiftで遊ぼう! on Hatena

あしたさぬきblogでやってた初心者オヤジのiOSプログラミング奮闘記がHatenaに来ました

Swiftで遊ぼう! - 758 - Sprite Kit やっとSKPhysicsJointFixed

少し複雑なSKSpriteKitのチュートリアルに取り組んでいます。

www.raywenderlich.com

GameSceneにノードを設定するメソッドをまだ書いています(^^;)

func newProjectile () {
    let beaker = SKSpriteNode(imageNamed: "beaker")
    beaker.name = "beaker"
    beaker.zPosition = 5
    beaker.position = CGPoint(x: 120, y: 625)
    let beakerBody = 
    SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 40))
    beakerBody.mass = 1.0
    beakerBody.categoryBitMask = 
        PhysicsT
    beakerBody.collisionBitMask = 
        PhysicsType.wall | PhysicsType.cat
    beaker.physicsBody = beakerBody
    addChild(beaker)

ここでやっと「SKPhysicsJointFixed」が出てきます。昨日説明した「addChild()」メソッドがどこ(どのSKNode)から発動されているのか分かっていないので、次に出てくる「childNode()」メソッドの発動先がどこか分かりません。「addChild()」と同じSKNodeだと思います。直感的にGameScene.sksで設定している「bk」のような気もします。GameScene.sksに設置している「player」ノードと「arm」ノードを融合させるために「childNode()」メソッドを使っているのですが、その関係性がイマイチ分かってないです(^_^;)

以下の説明をしていこうと思っていたのですが、もう少し「addChild()」と「childNod()」の関係性を勉強して出直します。

    if let armBody = 
        childNode(
            withName: "player")?.childNode(
                withName: "arm")?.physicsBody {
        pinBeakerToZombieArm = 
            SKPhysicsJointFixed.joint(withBodyA: armBody, 
                                          bodyB: beakerBody, 
                                         anchor: CGPoint.zero)
        physicsWorld.add(pinBeakerToZombieArm!)
        beakerReady = true
    }
}

Swiftで遊ぼう! - 757 - Sprite Kit ノードを作ればボディー

質問

今日の記事内で疑問を呈していますが、SKNodeのメソッド「addChild()」はどのオブジェクトから発動しているのでしょうか?

        • -

少し複雑なSKSpriteKitのチュートリアルに取り組んでいます。

www.raywenderlich.com

GameSceneにノードを設定するメソッドを書いています。

func newProjectile () {
    let beaker = SKSpriteNode(imageNamed: "beaker")
    beaker.name = "beaker"
    beaker.zPosition = 5
    beaker.position = CGPoint(x: 120, y: 625)

ここまででSKSpriteNodeオブジェクト(インスタンス)が1つできました。

今日はノードに物理(physics)世界を組み込むのですが、それがSKPhsicsBodyの設定です。

// まずノード(ビーカー)の位置に四角(時に丸く)のボディを着せるような感じです。
    let beakerBody = 
    SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 40))

// 重量と密度もプロパティとして持っています。「mass」は重量になります。
// CGFloat型で「kg」を意味します。
    beakerBody.mass = 1.0

// ここから「カテゴリー」の設定です。カテゴリーはノードの「contact」を
// 判定するために状態を設定します。「PhysicsType.beaker」は、
// グローバル定数としてStruct型で与えられています。
    beakerBody.categoryBitMask = 
        PhysicsType.beaker

GameSceneクラス宣言の前に次のグローバル定数を宣言します。前にも話しましたが、このようなカテゴリーを設定する場合、struct型よりenum型を使った方がいいと思うのですが、ベテランプログラマーの皆さん、どうでしょうか?

struct PhysicsType  {
  static let none            :UInt32  =   0
  static let player          :UInt32  =   1
  static let wall            :UInt32  =   2
  static let beaker          :UInt32  =   4
  static let explosionRadius :UInt32  =   8
  static let cat             :UInt32  =   16
  static let zombieCat       :UInt32  =   32
}

このカテゴリー設定ですが、非常に重要な概念が「bitMask」です。この値は「UInt32」が設定されているんですが、基本的に2進法で表現するので32桁のパターン、要するに32通りの設定ができます。当然、10進法で見れば、2の倍数で表します。2進法を用いるのは、論理計算(ANDやOR)で結果を求める為です。
01 = 0b000001
02 = 0b000010
04 = 0b000100
08 = 0b001000
16 = 0b010000
32 = 0b100000

// ビーカーが衝突判定をしたいのは、ターゲットの猫と壁です。
// ということで「collisionBitMask」は「PhysicsType.cat」
// と「PhysicsType.wall」になります。
    beakerBody.collisionBitMask = 
        PhysicsType.wall | PhysicsType.cat

// 単純ですが、ビーカーの物理世界ができあがったので
// ビーカーに設定してからノードをシーンに追加します。
// 「addChild」はSKSceneのメソッドだと勘違いしていました。
// 実はSKNodeの持ているメソッドです。
// ちょっと疑問点があります。
// どのSKNodeのメソッドが発動しているのでしょうか?
// たぶんGameScene.sksで設定しているSKNodeのどれかだと
// 思います。1番ベースの階層に設定している「bk」
// でしょうか? どなたか教えてくださいm(_ _)m
    beaker.physicsBody = beakerBody
    addChild(beaker)

ここまでの話は、SpriteKitチュートリアルで説明した内容と同じなです。次のコードがノードの融合の話になりますが、明日説明します。

    if let armBody = 
        childNode(
            withName: "player")?.childNode(
                withName: "arm")?.physicsBody {
        pinBeakerToZombieArm = 
            SKPhysicsJointFixed.joint(withBodyA: armBody, 
                                          bodyB: beakerBody, 
                                         anchor: CGPoint.zero)
        physicsWorld.add(pinBeakerToZombieArm!)
        beakerReady = true
    }
}

Swiftで遊ぼう! - 756 - Sprite Kit ノードの「zPosition」

ちょっと複雑なSpriteKitを使ったゲームチュートリアルの勉強してます。

www.raywenderlich.com

GameSceneクラスの実装をしているところです。SKPhysicsJointFixed型のインスタンスを作りました。

そして初期設定のためのメソッドを用意します。モンスターがビーカーを投げるのですが、SKSpriteNodeオブジェクトのビーカーを用意するのですが、ここで個別のノードを融合させるテクニックを学びます。

func newProjectile () {

// まず前半部分は馴染みのあるコードです。
// プロジェクトに用意したpngイメージから
// SKSpriteNodeインスタンスを作ります。
    let beaker = SKSpriteNode(imageNamed: "beaker")

// インスタンスの属性を設定して行きます。
// まず「name」プロパティに名前を付けます。
    beaker.name = "beaker"

// そして今日の表題「zPosition」です。
    beaker.zPosition = 5

// これが本来画面上での位置(CGPoint型)を表します。
    beaker.position = CGPoint(x: 120, y: 625)

SKSpriteKitは2Dゲームのためのフレームワークなんで、平面だけ扱えばいいと思っていましたが当然のように奥行きのパラメータが用意されています。考えてみればオブジェクトの重なりを判断する必要があるからです。

そしてSKSpriteKitを使用する時に注意しなければならないことが1つあります。SKViewはUIViewの派生クラスですが、座標システムが異なります。画面下左隅が(0.0, 0.0)になります。
f:id:yataiblue:20160810211324j:plain

UIView座標システムの情報

// 以下の説明は翌日を参照
    let beakerBody = 
    SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 40))
    beakerBody.mass = 1.0
    beakerBody.categoryBitMask = 
        PhysicsType.beaker
    beakerBody.collisionBitMask = 
        PhysicsType.wall | PhysicsType.cat
    beaker.physicsBody = beakerBody
    addChild(beaker)
        
    if let armBody = 
        childNode(
            withName: "player")?.childNode(
                withName: "arm")?.physicsBody {
        pinBeakerToZombieArm = 
            SKPhysicsJointFixed.joint(withBodyA: armBody, 
                                          bodyB: beakerBody, 
                                         anchor: CGPoint.zero)
        physicsWorld.add(pinBeakerToZombieArm!)
        beakerReady = true
    }
}

Swiftで遊ぼう! - 755 - Sprite Kit 他の話題に移ります

じっくりとSwiftの勉強に取り組む時間が無いので、覚えたことが忘却の彼方に消え去っていくような気がします(^_^;)

なんとなく理解しているSKSpriteKitをもう少し勉強するために次のチュートリアルに取り組んでみます。

www.raywenderlich.com

こういうゲームのチュートリアルも取り組んでみると楽しいですね。

スタータープロジェクトが用意されているので、ゲームに使用するリソースを用意する必要がないので助かります。

しかし、βバージョンのチュートリアルなんでちゃんと動かないって問題に遭遇もしてます。「GameScene.sks」を選択すると「Xcode 8」が落ちやいます。

それでも少しずつ進めていきます。GameSceneクラスに次のプロパティを書きます。didMove()メソッドの前に加えるように指示があります。

var pinBeakerToZombieArm: SKPhysicsJointFixed?
var beakerReady = false

SKPhysicsJointFixed」型が初めてでできました。

2つのPhysicsBodyを融合したり分けたりするリファレンスオブジェクトになります。

このクラス・メソッドは次で、新しいphysics jointオブジェクトを作成します。

class func joint(withBodyA bodyA: SKPhysicsBody, 
                           bodyB: SKPhysicsBody, 
                          anchor: CGPoint) -> SKPhysicsJointFixed

この「anchor」を使って2つのオブジェクトをscene上で同時に動かせます。

今日はこれだけ。

Swiftで遊ぼう! - 754 - Sprite Kit チュートリアル改訂中 11

今日も少しだけ下のリンクを整理しました。

yataiblue.hatenablog.com

今日も昨日の続きでGameScene.swiftの内容を復習しています。

超スローペースです。仕事の合間に何やってんだか...(^_^;)

Swiftで遊ぼう! - 753 - Sprite Kit チュートリアル改訂中 10

今日も少しだけ下のリンクを整理しました。

yataiblue.hatenablog.com

今日はGameScene.swiftの内容を少しいじりました。

世間はお盆休みですが忙しい毎日です。

今日はこれだけ。

Swiftで遊ぼう! - 752 - Sprite Kit チュートリアル改訂中 9

SKNodeの気になる子クラスを少し勉強します。

SKCropNode

親クラスのフレームを残して内容を全て消し去り子クラスとして抜き出すのがSKCropNodeのようです。いわゆるMaskという奴ですね。

マスクフィルターを設定するプロパティを持っています。

var maskNode: SKNode?

なんとなく分かったところで今日のお勉強は終了(^^;)