19937


当方Swift初心者です。  
現在、SpriteKitを使ってアプリを作っています。  
タップした場所に、Nodeを移動するところまでできたのですが、画面の中心からNodeまでベジェ曲線（放物線）を描画したいのですが、方法がわかりません。  
どなたかご教授ください。

現在の階層は、  
Node  
背景  
の順になっているので、

Node  
曲線  
背景  
の順にしたいと思っています。

現在まで完成しているコードは下記になります。

以下GameScene

[code]

    import UIKit
    import SpriteKit
    
    class GameScene: SKScene {
        var myImage : SKSpriteNode!
    
        override func didMoveToView(view: SKView) {
            //背景画像。SKSPriteNodeで画像を読み込む。
            let backGround = SKSpriteNode(imageNamed:"背景")
    
            //背景を画面の中央に配置する
            backGround.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
    
            //画像のサイズを画面に合わせる
            backGround.size = self.size
    
            //画像を最下層に設置
            backGround.zPosition = -CGFloat.infinity
    
            // シーンに追加.
            self.addChild(backGround)
    
            // GameSceneの背景色を青色にする.
            self.backgroundColor = UIColor.blueColor()
    
            // Node画像を生成.
            myImage = SKSpriteNode(imageNamed:"Node")
    
            // Node画像の描画場所を指定.
            myImage.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
    
            // シーンに追加.
            self.addChild(myImage)
        }
    
        override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
            for touch: AnyObject in touches {
                // タッチされた場所の座標を取得.
                let location = touch.locationInNode(self)
    
                //座標獲得
                let pointXY = (location.x,location.y)
                print(pointXY)
    
                // タッチされた場所に画像を移動.
                myImage.position = location
            }
        }
    }
    
[/code]

以上GameScene

以下ViewController

[code]

    import UIKit
    import SpriteKit
    
    class ViewController: UIViewController {
        override func viewWillAppear(animated: Bool) {
            let skView = self.view as! SKView
            // 画面サイズと同じ大きさのscene作成
    
            // ストーリーボードでviewのクラスをSKViewに設定しているので、SKViewのインスタンスとして取得できる
            let scene = GameScene(size: skView.bounds.size)
    
            // SKView上にsceneを設定
            skView.presentScene(scene)
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }
    
[/code]

以上ViewController

よろしくお願いします。


CC BY-SA 3.0
2015-12-07T09:32:28.820
19706
2015-12-13T10:57:03.517
2015-12-07T13:17:34.113
13156
13156
question
swift
Nodeと背景の間に、タップした場所でベジェ曲線を描画したい。


コメント欄に、「ベジエ曲線で放物線は描けない」と書きましたが、その後調べたところ、ベジエ曲線で正確な放物線が描けるという情報をネット上で多数見つけました。なので、既出の回答は撤回して、新しく回答を掲載することにしました。

* * *

一般的な描画方法は、ネット上の情報に委ねることにして、ここでは「ボールを放り上げた時の軌跡を、ベジエ曲線で描く」ことに特化して説明しようと思います。

まず、以下のプログラムを、Playgroundで実行してみてください。

[code]

    import UIKit
    
    class MyView: UIView {
        override func drawRect(rect: CGRect) {
            // CGContextを取得
            let context = UIGraphicsGetCurrentContext()
            // 原点を左上から左下に座標変換
            CGContextTranslateCTM(context, 0.0, 200.0)
            CGContextScaleCTM(context, 1.0, -1.0)
    
            // 投球角度45度、距離400.0で放物線を赤色で描画
            CGContextMoveToPoint(context, 0.0, 0.0)
            for i in 1...20 {
                CGContextAddLineToPoint(context, CGFloat(i * 20), CGFloat(i * 20) * CGFloat(i * 20) / -400.0 + CGFloat(i * 20))
            }
            CGContextSetRGBStrokeColor(context, 0.7, 0.3, 0.3, 1.0)
            CGContextSetLineWidth(context, 2.0)
            CGContextStrokePath(context)
    
            // 距離と、ベジエ曲線のコントロールポイントのx座標の、割合を、rateとする。
            let rate: CGFloat = 0.5
            // let rate: CGFloat = 1.0 / 3.0
            // ベジエ曲線を白色で描画
            CGContextMoveToPoint(context, 0.0, 0.0)
            CGContextAddCurveToPoint(context, 400.0 * rate, 400.0 * rate, 400.0 - 400.0 * rate, 400.0 * rate, 400.0, 0.0)
            CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0)
            CGContextSetLineWidth(context, 2.0)
            CGContextStrokePath(context)
        }
    }
    
    let myView = MyView(frame: CGRect(x: 0.0, y: 0.0, width: 400.0, height: 200.0))
    myView.backgroundColor = UIColor.lightGrayColor()
    
[/code]

この結果はこうなります。

[![画像の説明をここに入力](https://i.stack.imgur.com/nQB2D.png)](https://i.stack.imgur.com/nQB2D.png)

赤い線は、二次関数を20分割して、直線でつないだもの。白色の線がベジエ曲線です。  
プログラム中の変数`rate`の値を変えて、`1.0/3.0`（ようするに3分の1）にすると、こうなります。

[![画像の説明をここに入力](https://i.stack.imgur.com/gBWgg.png)](https://i.stack.imgur.com/gBWgg.png)

完全に二次関数とベジエ曲線が重なります。

ということで、 **結論：**  
ボールを放り上げて、到達した地点までの距離をmとした場合、mの3分の1をx成分とする開始点のコントロールポイントとし、それを左右反転したものを終点のコントロールポイントとすると、放物線が描ける。

[![画像の説明をここに入力](https://i.stack.imgur.com/uL4S3.png)](https://i.stack.imgur.com/uL4S3.png)

ここでは、ボールを放り上げる角度を45度としていますが、その角度に関係なく、コントロールポイントのx成分が、mの3分の1は変わりありません。


CC BY-SA 3.0
2015-12-13T10:57:03.517
19937
2015-12-13T10:57:03.517
7362
19706
answer