• ベストアンサー

線と点の当り判定

(ax,ay)と(bx,by)を結ぶ線上に点(cx,cy)があるかを判定するプログラムを教えてください。

  • Flash
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
noname#35109
noname#35109
回答No.2

#1です。 > (ax,ay)と(bx,by)を“結ぶ”線上に点(cx,cy)が > あるかの判定をしたい場合はどうしたらよいでしょう? それは簡単と言えば簡単ではないでしょうか。 次の通りなのですから。    Y  □■□□□回□□□□□回□□□□□□  □■□□□回□□□□□★□□□□□□  □■□□□回□□□□■回□□□□□□  □■□□□回□□□■□回□□□□□□  □■□□□回□□■□□回□□□□□□  □■□□□回□■□□□回□□□□□□  □■□□□回■□□□□回□□□□□□  □■□□□●□□□□□回□□□□□□  □■□□□回□□□□□回□□□□□□  ■■■■■■■■■■■■■■■■■■ X  □■□□□回□□□□□回□□□□□□        x=ax      x=bx cx >= ax で cx <= bx という条件が増えるだけです。 if (c._y == (b._y-a._y)*(c._x-a._x)/(b._x-a._x)+a._y && c._x>=a._x && c._x<=b._x) ただし, ax<bx の場合です。 ただ, どういう状況で使うかによって工夫(=ごまかし)のしかたが変わると思いますよ。 ※以下 この #2 の「工夫」とは,   「ごまかし」の意味も多々多々含むとして見てください。 上のままでいいかもしれないしダメかもしれません。 ax<bx の場合に限定できなければ, 大きいほうの値を返す, Math.max(a._x,b._x) や 小さいほうの値を返す, Math.min(a._x, b._x) を使用するべきかもしれません。 if (c._y == (b._y-a._y)*(c._x-a._x)/(b._x-a._x)+a._y && c._x>=Math.min(a._x, b._x) && c._x<=Math.max(a._x, b._x)) 使用例  #1と同じインスタンスの条件で使用方法を 工夫 した場合。 ///////////////////////////////////////////////////////////////////////////////// on (press) { // ドラッグ開始 this.startDrag(); } on (release, releaseOutside) { // ドラッグ終了 this.stopDrag(); } onClipEvent (mouseMove) { if (_root.c._y+2>=(_root.b._y-_root.a._y)*(_root.c._x-_root.a._x)/(_root.b._x-_root.a._x)+_root.a._y && _root.c._y-2<=(_root.b._y-_root.a._y)*(_root.c._x-_root.a._x)/(_root.b._x-_root.a._x)+_root.a._y && _root.c._x>=Math.min(_root.a._x, _root.b._x) && _root.c._x<=Math.max(_root.a._x, _root.b._x)) { trace("ヒット"); } } ///////////////////////////////////////////////////////////////////////////////// 一応実験のために使用例も書いていますが, このような使い方で良いのか悪いのかはわかりません。 どういう状況で使うかによって 工夫 のしかたが変わると思います。 ±2 などを使用しているのも 工夫 です。 とにかく, if (c._y == (b._y-a._y)*(c._x-a._x)/(b._x-a._x)+a._y && c._x>=Math.min(a._x, b._x) && c._x<=Math.max(a._x, b._x)) で理想上の直線と点の当たり判定にはなります。 他は色々な条件が加わると思います。 その都度 工夫 してください。 -・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・-・ そもそも当たり判定は 工夫 の美学(ちょっと言い過ぎ!)です。 厳密に考えていると, 人間の脳みその CPU も,PCのCPUもフルに使いすぎてオーバーフローを起こしてしまいます。 もとから, (ax,ay) も (bx,by) も決まっている定点であれば, #1のような複雑な一次方程式の変形もしないで良いわけですし, 傾きだけは決まっていて,切片だけが変わるものでしたら, もっと数式はシンプルになります。 #1の回答は, 単に (ax,ay)と(bx,by)を結ぶ線上(直線上と解釈) に点がヒットするかしないかというスクリプトを, 大まじめに考えたものです。 しかし,本当に大まじめに考えすぎると, 本来の当たり判定ができないので, 勝手に 工夫(←注:ごまかしですよ) したサンプルスクリプトを書いてみただけです。 どんなものを作ろうとされているのかがわからないので, 究極のところ,工夫 のしかたもわかりません。 場合によりますが,私が自分で作るなら, > (ax,ay)と(bx,by)を“結ぶ”線上に点(cx,cy)が > あるかの判定 ということをそもそも考えないような気がします。 Flashゲーム講座&ASサンプル集【当たり判定について】  →点とインスタンスとで当たり判定を取る http://hakuhin.hp.infoseek.co.jp/main/as/hittest.html#HITTEST_00 ここにあるように↑, 星形と点の当たり判定が hitTest で取れるのですから, 線( 工夫 した場合は 長方形)と点の当たり判定くらい簡単に取れるでしょう。 ですから > (ax,ay)と(bx,by)を“結ぶ”線上に点(cx,cy)が > あるかの判定 ではなく, ムービークリップの中に長方形をなんらかの形で作図して, その長方形と点との hitTest を使うと思います。 ですから, 根本的に (ax,ay) や (bx,by) を出す方法自体を変えてしまいます。 しかし, 作ろうとされているものがどういうものかがわからないので, 工夫 のしかたがわからないのです。 上記と同じサイトにこんな当たり判定サンプルもあります↓。 「円同士の衝突を計算する」 http://hakuhin.hp.infoseek.co.jp/flash/as/collide_00_00.html 見てスゴイと思いませんか? もし,思えばそれで良いのです。 円同士の当たり判定を真面目にすると, 人間の脳みそ CPU も,PCのCPUも使い切ってしまって, 動作が超重くなってしまいます。 そこで,工夫 しまくっています。 上のURLのリンク元はこちら↓。 hakuhin.hp.infoseek.co.jp/main/as/collide.html#COLLIDE_00 動きを見て, 人間が見てスゴイと思えばそれで良いのです。 工夫 に 工夫 を重ねた 工夫 の美学です。 そんなものですよ。 「よく見るとミサイルが当たる前に爆発している敵キャラ」 とかをゲームで多々見ませんか? 普通のゲームも工夫(←注:ごまかですよ)しまくっています。 昔々, hitTest など無い時代それも CPU の超スペック時代に, ゴキブリたたきゲームを Flash で作ったことがあります。 ランダムなときにゴキブリがランダムに出没して, 定点に置いてあるゴキブリたたきをクリックすると, ゴキブリたたきが振り下ろされて, ゴキブリに命中したら,ゴキブリが死んで得点が加算されるというような内容のものです。 hitTest などなくても, また,座標計算などしなくても, 工夫次第で当たり判定は取れます。 種を明かせば原理は簡単で, 「ゴキブリが出は消える」 というムービークリップをたくさん作って ランダムな時間に出没させるのです。 ゴキブリ自体は, ムービークリップの中でモーショントゥイーンによって動いているだけです。 ですから, 最初から,ゴキブリたたきにゴキブリがヒットするムービークリップもあれば, ゴキブリたたきにゴキブリがヒットしない(ゴキブリたたきが届く寸前でゴキブリが逃げるようにモーショントゥイーンさせている)ムービークリップもあるのです。 ゴキブリたたきにゴキブリがヒットするムービークリップは, そのムービークリップが出没してから, ゴキブリたたきがあるタイミングでクリックされないと, ゴキブリにヒットしないというフレームもわかっています。 ゴキブリがヒットするムービークリップの場合は, そのゴキブリムービークリップの○フレームから△フレーム内で, ゴキブリたたきがクリックされたとき, 「ゴキブリが死ぬ」というフレームに gotoAndPlay すれば良いのです。 原理は簡単ですが実際の 工夫 は難しいですよ。 でも, そういう手の込んだ 工夫 をすれば, そもそも当たり判定自体も不要になる可能性はあります。 変な話も書きましたが,以上で...。

kingfruits
質問者

お礼

作りたいもの作れました。 moveToとlineToで書いた線なので、hitTestでは上手く出来なかったので、質問しました。 ありがとうございました。

その他の回答 (1)

noname#35109
noname#35109
回答No.1

(ax,ay) と (bx,by) とを結ぶ一次方程式を導き出して, その一次関数の直線上に点(cx,cy)があるかないかを判定すれば良いと思いますよ。    Y  □■□□□□□□□□□□□□□□□□  □■□□□□□□□□□★□□□□□□  □■□□□□□□□□■□□□□□□□  □■□□□□□□□■□□□□□□□□  □■□□□□□□■□□□□□□□□□  □■□□□□□■□□□□□□□□□□  □■□□□□■□□□□□□□□□□□  □■□□□●□□□□□□□□□□□□  □■□□□□□□□□□□□□□□□□  ■■■■■■■■■■■■■■■■■■ X  □■□□□□□□□□□□□□□□□□  仮に ● を (ax,ay)   ★ を (bx,by) とします。  一次方程式を Y=AX + B として,  傾き A は (by-ay)/(bx-ax)  したがって,  Y=(by-ay)X/(bx-ax)+B  (ax,ay) を通る直線であることから切片 B は  ay=(by-ay)ax/(bx - ax)+B  B=ay-(by-ay)ax/(bx - ax)  よって,  Y=(by-ay)X/(bx-ax)+ay-(by-ay)ax/(bx-ax)  Y=(by-ay)(X-ax)/(bx-ax)+ay ---実際のFlash-------------------- インスタンス名 「a」 の MC(ムービークリップ) と インスタンス名 「b」 の MC があって, インスタンス名「c」の MC をドラッグして動かすとします。  if (c._y == (b._y-a._y)*(c._x-a._x)/(b._x-a._x)+a._y) これが true になれば,直線 (ax,ay) (bx,by) 上に「c」があることになります。 しかし,これは理想上のはなしで, 実際に直線にピッタリ重なるということは普通はありません。 余分にプラスマイナスの範囲を少し取って,次のようにすれば,実験ができます。 ステージ上にインスタンス名「a」と「b」と「c」という 小さめのムービークリップを任意の位置に作成します。 そして, 「c」に次のようなスクリプトを書きます。 /////////////////////////////////////////////////////////////////////////// on (press) { // ドラッグ開始 this.startDrag(); } on (release, releaseOutside) { // ドラッグ終了 this.stopDrag(); } onClipEvent (mouseMove) { if (_root.c._y+2 >= (_root.b._y-_root.a._y)*(_root.c._x-_root.a._x)/(_root.b._x-_root.a._x)+_root.a._y && _root.c._y-2 <= (_root.b._y-_root.a._y)*(_root.c._x-_root.a._x)/(_root.b._x-_root.a._x)+_root.a._y) { trace("ヒット"); } } /////////////////////////////////////////////////////////////////////////// 「修正」→「ムービープレビュー」で, ムービークリップ「c」をドラッグしてみると, 直線「a」-「b」上に「c」を移動させたとき, 「ヒット」がトレースされます。 if文内の _root.c._y+2 と _root.c._y-2  の ±2 が,余分の範囲です。 ※私は数学が苦手なので,   さらに何かを求められても回答できない自信があります。

kingfruits
質問者

お礼

ありがとうございます。 中学高で習った事で解けるのですね。 非常に判りやすい解説でした。 ベクトルの考え方でも解けるのでしょうか・・・

kingfruits
質問者

補足

試してみましたが、解答して頂いた方法ですと、(ax,ay)と(bx,by)の延長線上に(cx,cy)が存在しても「当り」と判定してしまいます・・・ (ax,ay)と(bx,by)を“結ぶ”線上に点(cx,cy)があるかの判定をしたい場合はどうしたらよいでしょう?

関連するQ&A

  • 斜線A・BにLの距離P点に斜線に直角の線C・Dを描く方程式を教えてくだ

    斜線A・BにLの距離P点に斜線に直角の線C・Dを描く方程式を教えてください。 点A(Ax,Ay),点B(Bx,By)を結ぶ線上に、点Aから距離Lの位置、点P(Px,Py)に斜線に直角の線を描く方程式を教えてください。 Ax=5000:Ay=4000 Bx=25000:By=22000 A点からP点まで距離 L=20000として Px=19865.883:Py=17379.295 CD線の長さをL2=3000として Cx= Cy= Dx= Dy= を求めたいのですが

  • 三角形OABの面積を求めるプログラム

    三角形OABの面積を求めるプログラムを作りました(課題ですがw)。が、うまく動かないんです。 どこが間違っているか教えてください。(VC++6.0) /*三角形OABの面積を求めるプログラム*/ #include <stdio.h> #include <math.h> void main(){ float ax,ay,bx,by,s; printf("点Aの座標を入力してください。\n"); scanf("%f%f",&ax,&ay); printf("点Bの座標を入力してください。\n"); scanf("%f%f",&bx,&by); s=(1/2)*abs(ax*by-ay*bx); printf("三角形OABの面積は%fです。\n",s); } ◇点A(ax,ay) 、点B(bx,by) 面積の公式s=(1/2)*|ax*by-bx*ay| と与えられています。 また、警告の意味もわからないんで、できればお願いします。

  • 三角関数の問題です。

    質問をさせていただきます。 二次元平面上に△ABCがあり、頂点の座標はそれぞれ (Ax,Ay)、(Bx,By)、(Cx,Cy)となっています。 また辺ACと辺BCの長さは等しく、二等辺三角形となっています。 (∠ACBの角度×1/4)の正接の値をTとした場合、 Cx、Cyの値をそれぞれ求めたいのですが、 どのようにすればよいでしょうか。 (ちなみに全ての辺は、X軸やY軸に必ず平行というわけではありません) Cx=~、Cy=~ といった形でご回答頂けると幸いです。 よろしくお願いいたします。

  • 行列 連立一次方程式

    a,b,c,d,が0でない実数であるとき、次の連立一次方程式を解け ax-by-az+bu=1 bx+ay-bz-au=0 cx-dy+cz-du=0 dx+cy+dz+cu=0 行列を使った解き方でお願いします。

  • 空間上の二点を結ぶ直線上に任意の点が存在するかどうかの関数

    Cの初心者です。 空間上に存在する2点間を結ぶ直線上に任意の点が存在するかどうかの 関数を作りたいのですがどのような公式を用いて評価すればいいのか分かりません。 どなたかご教示ください。 引数    始点 A(x,y,z)    終点 B(x,y,z)    直線上に存在するであろう任意の点       C(x,y,z)  関数のイメージ    boolean isOnLine (Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz); 配列でもよいです。 返り値    True、 False  ( 0 or 1 ) よろしくお願いします。

  • 3次元で回転させた座標値の計算方法

    点(Ax、Ay、Az)を3次元空間にある、点(Bx、By、Bz)から、点(Cx、Cy、Cz)に向かう直線を軸に任意の角度で回転させたときの、点(A’x、A’y、A’z)の座標値の計算方法を教えてください。ただし自分の数学レベルは中学生並でベクトルが少しだけ理解できるていどです。よろしくお願いします。

  • 斜線A・BにLの距離P点に斜線に直角の線を描く方程式を教えてください。

    斜線A・BにLの距離P点に斜線に直角の線を描く方程式を教えてください。 点A(Ax,Ay),点B(Bx,By)を結ぶ線上に、点Aから距離Lの位置、点P(Px,Py)に斜線に直角の線を描く方程式を教えてください。

  • 内積を用いた移動する線分と円の衝突判定について

    内積を用いた移動する線分と円の衝突判定について 作成しているプログラムはピンボールのフリッパーとボールとの衝突判定です。14歳からはじめるリアルに動くゲーム物理プログラミング教室C言語編と言う本を参考にプログラミングしています。左フリッパーが315度~360度、1度~45度の範囲を1度づつ移動する度に衝突判定をする関数を作成し、衝突した場合に関数から抜け、戻り値としてボールの情報を持つ構造体の中の反射スピードと反射座標を返すものです。 ここからが質問なのですが、ボールは全くフリッパーの衝突と関係の無い所で反射してしまいます。移動しない線分の両端の座標を与えた衝突判定(壁)では正しく判定するのですが、角度を与えて移動する線分(フリッパー)では上手くいきません。お分かりになる方いらっしゃいましたら、宜しくお願い致します。 関数に渡す引数はその時のボールの座標・速度などの構造体と左フリッパーの角度です。 以下ソースコード //左フリッパーの軸と成る座標 float hx_l = (cx_l*ZOOM); //フリッパーのx座標 float hy_l = (cy_l*ZOOM+HORIZ); //フリッパーのy座標 //ベクトル a の成分を求める float ax=xy.posx-hx_l; //線分始点からボール中心へのベクトル float ay=xy.posy-hy_l; //線分始点からボール中心へのベクトル //ベクトル b の成分を求める float bx=((cx_l+cos(ToRadian(angler_l))*clubr)*ZOOM)-hx_l; //線分始点から終点へのベクトル float by=((cy_l-sin(ToRadian(angler_l))*clubr)*ZOOM+HORIZ)-hy_l;//線分始点から終点へのベクトル float inpro=ax*bx+ay*by; //ベクトル a,b の内積を求める float bl=bx*bx+by*by; //ベクトル b の長さの二乗(線分始点から終点へのベクトル if(inpro>-ZERO1 && inpro<(bl+ZERO1)){ //フリッパーとの衝突判定 //ベクトル a の線分がボールの半径より小さければ交差している if((ax*ax+ay*ay)-pow(inpro/sqrt(bl),2) < pow(xy.radius,2)){ 以下判定後の処理‥‥ ベクトルbのbx,byを求める式でangler_lが引数として渡されるフリッパーの角度に成ります。ToRadian()は関数で角度をラジアンに変更します。

  • 斜線ABに平行に、Lの距離離れた斜線CDの座標を求める方程式を教えてく

    斜線ABに平行に、Lの距離離れた斜線CDの座標を求める方程式を教えてください。 斜線A(Ax,Ay),B(Bx.By)を平行にLの距離離れたC(Cx,Cy),D(Dx,Dy)の座標を求める方程式を教えてください。

  • 座標の和に関する証明

    原点をo(0,0)とし、a(ax,ay),b(bx,by)という点を取ります。 このとき、cという点を四角形oacbが平行四辺形になるように取ると、cは、c(ax+bx,ay+by)という、座標を取りますが、cが必ず、このような座標を取ることは、どの様に証明したら良いのでしょうか? どなたか解答お願いします。

専門家に質問してみよう