« 「ウェブ進化論 本当の大変化はこれから始まる」に引用していただいたみたい | main | 情報発電所を目指すなら、「はてなマトメ」みたいなサービスを作るべきだと思う »

2006年02月19日

正円周上の2点の小さい方の角度

blog.tokyoace4.com: 正円周上の2点の小さい方の角度

昔、散々悩んで書いたコードにそんなのがあったので晒し上げ。
ある特定の目標の方向を向きたいときに、右に回転するべきか左に回転するべきか判別する処理。頭よさげな追尾ミサイルとか敵とか作るのに使った気がする。

var angle0 = Math.atan2(mc0._y, mc0._x) * 180 / Math.PI 
var angle1 = Math.atan2(mc1._y, mc1._x) * 180 / Math.PI 
var angle = angle1 - angle0
if(angle > 180){
	angle = 360 - angle angle - 360
}else if(angle < -180){
	angle = 360 + angle
}

こんなので右(左)に何度進むべきか計算できた・・・はず
さらに可読性を無視して *180 / Math.PI を最後に持ってくるってのはあるけど、
これをもっとシンプルにできるんなら、僕もやり方教えて欲しいっす。 >muneさん、keyさんとかそこらへんの方々

投稿者 Taka : 2006年02月19日 02:44

book

dotfla.gif

bookmark

はてなブックマークに追加

del.icio.usに追加

trackbacks

this entry's trackback URL:
http://www.fladdict.net/cgi-bin/mt3/mt-tb.cgi/467

このリストは、次のエントリーを参照しています: 正円周上の2点の小さい方の角度:

» 正円周上の2点の小さい方の角度2 と Boid from blog.tokyoace4.com
前エントリーから続き イメソの花井さんから、すばらしい答えをくれたので、まとめ。 正円上の点c1からc2にいきたいとき。 それぞれのrは正円の中心を原点として、... [read more]

トラックバック時刻: 2006年02月20日 07:58

» 正円周上の2点の小さい方の角度2 と Boid from blog.tokyoace4.com
前エントリーから続き イメソの花井さんから、すばらしい答えをくれたので、まとめ。 正円上の点c1からc2にいきたいとき。 それぞれのrは正円の中心を原点として、... [read more]

トラックバック時刻: 2006年02月20日 07:59

» 正円周上の2点の小さい方の角度2 と Boid from blog.tokyoace4.com
前エントリーから続き イメソの花井さんがすばらしい答えをくれたので、まとめ。 正円上の点c1からc2にいきたいとき。 それぞれのrは正円の中心を原点として、X軸... [read more]

トラックバック時刻: 2006年02月20日 12:39

comment

angle0:-170 angle1:170 の時に逆方向に行っちゃうので
angle = 360 - angle
じゃなくて
angle = angle - 360
ですね。

それと、角度同士の引き算じゃなくて、Math.atan2 の引数レベルで
いきなり座標の引き算でいいと思います。
局所変数も2つ減らせるのでステキに。

by mune : 2006年02月19日 03:44

呼ばれました!
angle > 180のときの処理、360の倍数の加減算じゃないと別角度になっちゃうので、

var angle = angle1 - angle0;
if (angle > 180) {
angle -= 360;
} else if (angle < -180) {
angle += 360;
}

なのでは。
でも、シンプルにするなら弧度法を使うのが一番だと思います。

by key : 2006年02月19日 03:44

muneさん、keyさん
うわホントだ。恥ずか死い

by Taka : 2006年02月19日 03:47

投稿時間にも注目(ノ∀`)
夜分遅くまでお疲れ様です>みなさん

by key : 2006年02月19日 03:53

眠い頭で間違っていたら申し訳ございませんが、ラジアンに加えて%というかmodというか剰余(割った余り)を使うと条件判定式が消えて素敵になったりしませんでしょうか。

by hidetox : 2006年02月19日 06:52

-180から180の間に納めるだけなら。

angle = (180 + angle) mod 360 -180

by Anonymous : 2006年02月19日 11:54

右か左かだけを判別したいなら二次元ベクトルの外積?を使えばよさげです。
aとbのなす角度θ
|a||b|sinθ = ax * by - ay * bx
ans>0 ⇒ θ>0
参考↓
http://www7.plala.or.jp/kfb/program/stg2dvec.html
ベクトル便利杉

by ss : 2006年02月19日 14:48

ぁ、これじゃ何度進むのかはわかりませんね。。失礼

by ss : 2006年02月19日 14:58

あー嘘を書いちゃった。
座標の引き算していいのは、追尾ミサイルに限って。
というのも、追尾ミサイル自身の進行方向という要素が
入ってくるわけですが、進行方向を move_angle とすると

var d_angle = ( angle - move_angle ) % 360;
if ( angle > 180 ){
angle = angle - 360;
} else if ( angle < -180 ){
angle = 360 + angle;
}
move_angle += d_angle * accuracy; // accuracy:追尾精度(0-1)


ちなみに ActionScript の剰余では左項の符号を保持するので
angle に -180 未満の値を与えると計算が合わなくなりますね。

by mune : 2006年02月19日 15:45

このシチュエーションの場合だったら、
((Math.atan(vy/vx)/Math.PI+(vx<0))*180+720)%360
で向かわせる角度はだせますね。
徐々に方向を変えさせたいみたいな場合はBoid的にミサイルのもともとの進行方向ベクトルと、ミサイルからターゲットへのベクトルを割合を適当な割合であわせて正規化させたりしてます。僕の場合。この「適当な割合」を調整すればミサイルの追随精度を調整しやすかったり。

で、同じ円上にある2点で、かたっぽがかたっぽに向かうときに円周上をどちらの角度に向かえばいいのかというやつですが、
イメソの花井さんがスカッとした回答をくれました。

c1からc2にいきたいとき。
それぞれのrは正円の中心を原点として、X軸の+の方向が0度のときの角度。

var s = Math.sin((this.c2.r-this.c1.r)*Math.PI/180);
var direction = s/Math.abs(s);

ということです。2行!

by tohsaki : 2006年02月20日 07:16

求めたいのは「右or左」だったんですね。
でしたら var direction = Math.sin((this.c2.r - this.c1.r) * Math.PI / 180) > 0; でも良さそうですよ。1行!

by key : 2006年02月20日 13:56

行数はともかくとして、Math.abs(s) で割っちゃうと
0除算が発生するので、あまりよろしくないと思います。

direction の値をそのまま移動計算に組み込むこともあるので
三項演算子使って 1 と -1 を渡すようにした方がいいかも。

ってことで
var direction = ( Math.sin((this.c2.r - this.c1.r) * Math.PI / 180) > 0 ) ? 1 : -1;
でフィニッシュ。

by mune : 2006年02月20日 16:19

右向いた場合のベクトルと左向いた場合のベクトルをだし、それぞれと目標をしめす一ベクトルとの内積を取って、大きい方が近い側、というアルゴリズムでゲーム作ったことあります。
これなら三角関数不要ですよ。

by にゃ : 2006年02月21日 12:19

s/一ベクトル/位置ベクトル/ です……

by にゃ : 2006年02月21日 12:20

うぇ、みんなテラ頭ヨス。
なんかコメント欄まとめてちゃんとエントリーにしたい。

by Taka : 2006年02月22日 02:15

コメントしてください




保存しますか?