質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

swiftにおける計算結果nanについて

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,451

tamago0224

score 59

今回、タップすることでボールを生成し、画面下に落下するというアプリを作りました。
また、他の機能としてスライドした方向にスライド時間とスライド距離によってボールの初速を変化させるものも追加しました。
今回問題となっているのがこの機能です。
何回かスライドさせてボールを生成させてみているのですが、下記に記したプログラムの下のgetVector()関数内のdiagonal変数がときたまnanとなって値が取得できません。
同関数内の他の変数は正しく取得できているのですが、diagonal変数のみ正しい値がとれないことがあります。原因がわかる方がいらしたら解決策の方をお願いします。

import SpriteKit

class ViewController: UIViewController {

    var sWidth: CGFloat!
    var sHeight: CGFloat!
    var canvasWidth: UInt32!
    var canvasHeight: UInt32!
    var scene: SKScene!

    var beganPos: CGPoint!//タップの開始位置座標
    var endPos: CGPoint!//タップの終了位置座標

    var startTime: NSDate!


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        //画面の大きさを取得
        sWidth = self.view.bounds.width
        sHeight = self.view.bounds.height

        canvasWidth = UInt32(sWidth)
        canvasHeight = UInt32(sHeight)

        //SpriteKitのviewを生成
        let skView: SKView = SKView(frame: CGRectMake(0, 0, sWidth, sHeight))

        //シーンを生成し、設定を施す
        scene = SKScene(size: CGSizeMake(sWidth, sHeight))
        scene.backgroundColor = SKColor.whiteColor()
        skView.presentScene(scene)


        //sceneの物理エンジンの設定
        scene.physicsWorld.gravity = CGVectorMake(0, 0)
        scene.physicsBody = SKPhysicsBody(edgeLoopFromRect:CGRect(x:0, y:0, width:sWidth, height:sHeight))

        self.view.addSubview(skView)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if let touch = touches.first {
            let pos = touch.locationInView(self.view)
            print("touch began position is \(pos)")
            beganPos = pos//開始位置の取得
            startTime = NSDate()
        }
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if let touch = touches.first {
            let pos = touch.locationInView(self.view)
            endPos = pos//終了位置の取得
            let speed = getVector()
            print("touch end position is \(pos)")
            drawOval(px: pos.x, py: pos.y, speed: speed)
        }
    }

    func drawOval(px x: CGFloat, py y: CGFloat, speed sp: CGVector) {
        let radius:CGFloat = 20
        let shape = SKShapeNode(circleOfRadius:radius)
        shape.fillColor = randomColor()
        shape.position = CGPoint(x: x, y: sHeight - y)
        //print("shape position is \(shape.position)")
        scene.addChild(shape)

        shape.physicsBody = SKPhysicsBody(circleOfRadius: radius)

        shape.physicsBody!.mass = 1.0
        shape.physicsBody!.friction = 0.8
        shape.physicsBody!.restitution = CGFloat(getRandomNumber(Min: 0, Max: 1.0))
        shape.physicsBody!.velocity = CGVectorMake(sp.dx, sp.dy)
    }

    func randomColor() -> SKColor {
        let rand1 = CGFloat(getRandomNumber(Min: 0, Max: 1.0))
        let rand2 = CGFloat(getRandomNumber(Min: 0, Max: 1.0))
        let rand3 = CGFloat(getRandomNumber(Min: 0, Max: 1.0))
        let rand4 = CGFloat(getRandomNumber(Min: 0, Max: 1.0))

        let randColor = SKColor(red: rand1, green: rand2, blue: rand3, alpha: rand4)

        return randColor
    }

    func getRandomNumber(Min _Min : Float, Max _Max : Float)->Float {

        return ( Float(arc4random_uniform(UINT32_MAX)) / Float(UINT32_MAX) ) * (_Max - _Min) + _Min
    }

    func getDistance(began bp: CGPoint, end ep: CGPoint) -> CGFloat {
        return sqrt((bp.x - ep.x) * (bp.x - ep.x) - (bp.y - ep.y) * (bp.y - ep.y))
    }

    func getVector() -> CGVector {
        let diagonal = Double(getDistance(began: beganPos, end: endPos))
        let base = Double(abs(endPos.x - beganPos.x))
        let height = Double(abs(endPos.y - beganPos.y))

        let cos: Double = Double(base / diagonal)
        let sin: Double = Double(height / diagonal)

        let time = Double(NSDate().timeIntervalSinceDate(startTime))

        let speed: Double = diagonal / time
//        print("diagonal is \(diagonal)")
//        print("time is \(time)")
//        print("speed is \(speed)")

        let vector: CGVector = CGVector(dx: cos * speed, dy: sin * speed)

        print("\(vector)")

        return vector
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

getDistance()関数の引数bpとepで、x方向の移動量よりもy方向の移動量の方が大きいと、計算結果がnanになります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/05 17:24

    に点間の距離の求め方が間違ってましたね。ご指摘ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る