Swift  ,SpriteKit ,SKPhysicsBody について (physicsBodyのきせ方篇)


ノードに物理シミュレーションを追加するオブジェクトです。

##宣言　：　Declaration
```Swift
class SKPhysicsBody : NSObject
```
##概要　：　Overview
ノードに物理シミュレーションを追加するには、SKPodeオブジェクトをSKNodeオブジェクトのphysicsBodyプロパティに割り当てます。シーンが新しいフレームを処理すると、シーン内のノードにアタッチされている物理ボディに対して物理計算が実行されます。これらの計算には、重力、摩擦、および他の物体との衝突が含まれます。自分の力や衝動を体に加えることもできます。シーンがこれらの計算を完了すると、ノードオブジェクトの位置と方向が更新されます。

・重要
物理ボディは、力や衝撃を加える前にノードに関連付ける必要があります。

SpriteKitは2種類の物理ボディ、ボリュームベースボディとエッジベースボディをサポートします。physicsBodyを作成するとき、その種類、サイズ、および形状は、呼び出すコンストラクタメソッドによって決まります。エッジベースのボディは質量や体積がなく、システム内の力や衝撃の影響を受けません。エッジベースのボディは、物理シミュレーションで体積のない境界線や中空の空間を表すために使用されます。対照的に、ボリュームベースのボディは、質量とボリュームでオブジェクトを表現するために使用されます。 isDynamicプロパティは、ボリュームベースのボディが重力、摩擦、他のオブジェクトとの衝突、および直接適用する力または衝撃の影響を受けるかどうかを制御します。
SKPhysicsBodyクラスは、ボディがシーンによってシミュレートされるときのボディの物理的特性を定義します。体積ベースのボディでは、最も重要な特性は質量特性です。体積ベースの物体は一様な密度を持つと仮定されます。質量プロパティを直接設定することも、体の密度プロパティを設定して物理学本体に独自の質量を計算させることもできます。 Sprite Kitのすべての値は、国際単位系（SI単位）を使用して指定されています。実際の力と質量の値は、ゲームが一貫した値を使用している限り重要ではありません。
物理を使用するゲームを設計するときは、シーンに表示される物理オブジェクトのさまざまなカテゴリを定義します。最大32の異なるカテゴリの物理学本体を定義し、本体は必要に応じてこれらのカテゴリの多くに割り当てることができます。それ自身のカテゴリーを宣言することに加えて、物理学の本体はまたそれが相互作用するボディのどのカテゴリーを宣言します。衝突と連絡先の操作を参照してください。同様のメカニズムを使用して、どの物理フィールドノード（SKFieldNode）が物理ボディに影響を与える可能性があるかを宣言します。
ボリュームベースのボディでは、ボディが力や衝突によってどのように影響を受けるかを動的に制御できます。力が物理体に与える影響の定義を参照してください。

##トピック：Topics

###First Steps:はじめのステップ
フィジックスボディ入門
物理学を有効にするための物理学本体を作成して割り当てます。

概要
SKPhysicsBodyオブジェクトは、システム内の物理学本体の形状とシミュレーションパラメータを定義します。シーンが物理をシミュレートすると、シーンツリーに接続されているすべての物理ボディの計算が実行されます。つまり、SKPhysicsBodyオブジェクトを作成し、そのプロパティを設定してから、それをノードのphysicsBodyプロパティに割り当てます。
物理学には3種類あります。
ダイナミックボリュームは、システム内の力や衝突の影響を受ける可能性があるボリュームと質量を持つ物理オブジェクトをシミュレートします。動的ボリュームを使用して、動き回り衝突する必要があるシーン内のアイテムを表します。
静的ボリュームは動的ボリュームに似ていますが、その速度は無視され、力や衝突の影響を受けません。ただし、まだボリュームがあるため、他のオブジェクトがバウンスしたり相互作用したりする可能性があります。シーン内のスペースを占めるアイテムを表すために静的ボリュームを使用しますが、それはシミュレーションによって移動されるべきではありません。たとえば、迷路の壁を表すために静的ボリュームを使用することができます。静的ボリュームと動的ボリュームを別々のエンティティとして考えることは有用ですが、実際には、これらはボリュームベースの物理学本体に適用できる2つの異なるモードです。ボディの効果を選択的に有効または無効にできるため、これは便利です。
エッジは静的なボリュームのないボディです。エッジがシミュレーションによって動かされることは決してなく、それらの質量は関係ありません。エッジは、シーン内のネガティブスペース（別のエンティティの内側の中空スポットなど）または不可視の見えないほど細い境界を表すために使用されます。たとえば、エッジはシーンの境界を表すためによく使用されます。エッジとボリュームの主な違いは、エッジはそれ自体の境界内での移動を可能にし、ボリュームはソリッドオブジェクトと見なされることです。エッジが他の方法で移動された場合、それらはボリュームとのみ相互作用し、他のエッジとは相互作用しません。
SpriteKitはいくつかの標準的な形状を提供します - それらは任意のパスに基づくものとテクスチャのアルファチャンネルから生成されたものです。次の図は、利用可能な図形を示しています。

![スクリーンショット 2019-05-04 16.43.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359032/9a5eb842-a42e-df90-1ed7-a7a3952af01a.png)

次のコードは、上記の4つの物理学本体を生成する方法を示しています。

```swift

let spaceShipTexture = SKTexture(imageNamed: "spaceShip.png")
   
// Spaceship 1: circular physics body
let circularSpaceShip = SKSpriteNode(texture: spaceShipTexture)
circularSpaceShip.physicsBody = SKPhysicsBody(circleOfRadius: max(circularSpaceShip.size.width / 2,
                                                                  circularSpaceShip.size.height / 2))
   
// Spaceship 2: rectangular physics body
let rectangularSpaceShip = SKSpriteNode(texture: spaceShipTexture)
rectangularSpaceShip.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: circularSpaceShip.size.width,
                                                                     height: circularSpaceShip.size.height))
   
// Spaceship 3: polygonal physics body
let polygonalSpaceShip = SKSpriteNode(texture: spaceShipTexture)
let path = CGMutablePath()
path.addLines(between: [CGPoint(x: -5, y: 37), CGPoint(x: 5, y: 37), CGPoint(x: 10, y: 20),
                        CGPoint(x: 56, y: -5), CGPoint(x: 37, y: -35), CGPoint(x: 15, y: -30),
                        CGPoint(x: 12, y: -37), CGPoint(x: -12, y: -37), CGPoint(x: -15, y: -30),
                        CGPoint(x: -37, y: -35), CGPoint(x: -56, y: -5), CGPoint(x: -10, y: 20),
                        CGPoint(x: -5, y: 37)])
path.closeSubpath()
polygonalSpaceShip.physicsBody = SKPhysicsBody(polygonFrom: path)
  
// Spaceship 4: physics body using texture’s alpha channel
let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
texturedSpaceShip.physicsBody = SKPhysicsBody(texture: spaceShipTexture,
                                              size: CGSize(width: circularSpaceShip.size.width,
                                                           height: circularSpaceShip.size.height))
```

物理体の形状はパフォーマンスに影響します。 円形の物理体は最高の性能を発揮し、他の物理体よりもかなり高速になります。 シミュレーションに多数の物理体が含まれている場合は、円形体が最善の解決策です。 長方形および多角形は、速度を落として衝突精度を向上させます。 テクスチャのアルファチャンネルから作成された物理ボディは、最高のパフォーマンスコストで最高の忠実度を提供します。

##Creating a Body from a Shape: 図形からボディーを作成する
```Swift 
init（circleOfRadius：CGFloat）
//所有ノードの原点を中心とした円形の物理ボディを作成します。
init（circleOfRadius：CGFloat、中央：CGPoint）
//任意の点を中心とする円形の物理体を作成します。
init（RectangularOf：CGSize）
//所有ノードの原点を中心とした長方形の物理ボディを作成します。
init（RectangularOf：CGSize、center：CGPoint）
//任意の点を中心とした長方形の物理体を作成します。
init（polygonFrom：CGPath）
//多角形の物理学本体を作成します。
```

##Creating a Body from a Texture:テクスチャからボディを作成する

衝突の正確さと性能の正しいブレンドのためにあなたのグラフィックスに物理学本体を形作ってください。
**概要**
ほとんどの場合、物理体は対応するノードの視覚的表現に非常に近いサイズと形状を持つべきです。 例えば、下に示すロケットは、円形でも長方形でも表されていない狭い形状をしています。 凸多角形の形状は、スプライトのアートワークに合うように選択され、フィットされます。
![スクリーンショット 2019-05-04 17.10.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359032/36b96170-fb5d-8bbb-d442-8022e9282549.png)

テクスチャのアルファチャンネルを使用して物理ボディを形成する
独自の形状を作成したくない場合は、SpriteKitを使用してスプライトのテクスチャに基づいて形状を作成できます。

```swift
let sprite = SKSpriteNode(imageNamed: "Spaceship")
sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!,
                                   size: sprite.texture!.size())
```
**単純な幾何学物理学ボディ形状を選択してください**
あなたの物理学の体の形状を選ぶとき、過度に正確にならないでください。より複雑な形状は、適切にシミュレートするためにより多くの作業を必要とします。ボリュームベースのボディの場合は、次のガイドラインを使用してください。
・円が最も効率的な形状です（init（circleOfRadius :)）
・パスベースの多角形は最も効率の悪い形状で、計算作業は多角形の複雑さに比例します（init（polygonFrom :)）。

**必要な場合にのみエッジベースの物理体を使用する**
エッジベースのボディは、ボリュームベースのボディよりも計算コストが高くなります。これは、それが相互作用する物体が潜在的に開いた端のどちら側にあっても、閉じた形状の内側または外側にあってもよいためです。これらのガイドラインを使用してください。
・線と長方形は、最も効率的なエッジベースのボディです（init（edgeFrom：to :)およびinit（edgeLoopF​​rom :)）。
・エッジループとエッジチェーンは最も高価なエッジベースのボディであり、計算作業はパスの複雑さに比例します（init（edgeLoopF​​rom :)およびinit（edgeChainFrom :)）。

```swift
init(texture: SKTexture, size: CGSize)
```
//テクスチャの内容から物理学本体を作成します。

```swift
init(texture: SKTexture, alphaThreshold: Float, size: CGSize)
```
//指定された透明度の値を超えるテクセルだけをキャプチャして、テクスチャのコンテンツから物理学本体を作成します
 あなたのスプライトがあなたがその物理学本体で複製したい形を持っているとき、このメソッドを使ってください。テクスチャは新しいサイズに拡大縮小されてから分析されます。アルファ値がalphaThresholdパラメータ以上のテクスチャ内のすべてのテクセルを含む新しい物理ボディが作成されます。このボディの形状は、パフォーマンスと正確さの間で良いバランスをとるように試みます。たとえば、細部を保持するとパフォーマンスが大幅に低下する場合は、細部を無視してもかまいません。

##Creating a Body from a Collection of Bodies : ボディのコレクションからボディを作成する
```swift
init(bodies: [SKPhysicsBody])
```
引数の物理学の本体の結合のような形をした物理学の本体を作成します。


SKPhysicsBodyオブジェクトの配列。 オブジェクトはボリュームベースの物理体でなければなりません。 （このメソッドを使用して作成された複合体は配列内では使用できません。）

**Discussion**
このメソッドに渡された物理体の形状は、覆われた領域がその子の領域の和集合である新しい物理体を作成するために使用されます。 これらの領域は連続している必要はありません。 2つの部分の間にスペースがある場合は、他の体がこれらの部分の間を通過できる可能性があります。 ただし、物理的なボディは単一の接続されたボディとして扱われます。つまり、ボディに加えられた力やインパルスは、すべてのピースが破壊不可能なフレームで固定されているかのようにすべてのピースに影響します。
質量や摩擦などの子供の特性は無視されます。 子供の体の形だけが使われます。

##Creating an Edge-Based Physics Body : エッジベースの物理ボディの作成
**Creating an Edge Loop Around a Scene:シーンの周囲にエッジループを作成する**
物理学の体が貫通することができない障害物であなたのシーンを縁取ります。

アプリ内オブジェクトを特定の領域に限定したい場合は、エッジベースの物理体を使用して領域を定義します。 たとえば、プールテーブルをモデル化するアプリでは、ボールはアプリ内オブジェクトであり、テーブルの端はまとめてエッジループを作成します。 次のコードは、シーン内の端から端まで広がる不可解な境界を実装するためのエッジループの作成を示しています。

```swift
func createSceneContents() {
    self.backgroundColor = .black
    self.scaleMode = .aspectFit
    self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
}
```
-----------
```swift

init(edgeLoopFrom: CGRect)
```
矩形からエッジループを作成します。

物理学の体が貫通することができない障害物であなたのシーンを縁取ります。
アプリ内オブジェクトを特定の領域に限定したい場合は、エッジベースの物理体を使用して領域を定義します。 たとえば、プールテーブルをモデル化するアプリでは、ボールはアプリ内オブジェクトであり、テーブルの端はまとめてエッジループを作成します。 次のコードは、シーン内の端から端まで広がる不可解な境界を実装するためのエッジループの作成を示しています。

---
```swift
init(edgeFrom p1: CGPoint, 
  to p2: CGPoint)
```
2点間にエッジを作成します。

・P1
所有ノードの原点を基準とした、エッジの始点。
・P2
所有ノードの原点を基準とした、エッジの終点。

エッジには体積も質量もなく、常にisDynamicプロパティがfalseに等しいかのように扱われます。 エッジは、ボリュームベースの物理体としか衝突しない可能性があります。

---
```swift
init(edgeLoopFrom: CGPath)
```
パスからエッジループを作成します。

・パス
コアグラフィックパス。 ポイントは、所有ノードの原点を基準にして指定されます。 道はそれ自身と交差してはならない。

パスがまだ閉じられていない場合は、最後の点と最初の点を結ぶことによってループが自動的に作成されます。
エッジには体積も質量もなく、常にisDynamicプロパティがfalseに等しいかのように扱われます。 エッジは、ボリュームベースの物理体としか衝突しない可能性があります。

---
```swift
init(edgeChainFrom: CGPath)
```
パスからエッジチェーンを作成します。
エッジには体積も質量もなく、常にisDynamicプロパティがfalseに等しいかのように扱われます。 エッジは、ボリュームベースの物理体としか衝突しない可能性があります。