アプリ版:「スタンプのみでお礼する」機能のリリースについて

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

A 回答 (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 …

ここにあるように↑,
星形と点の当たり判定が hitTest で取れるのですから,
線( 工夫 した場合は 長方形)と点の当たり判定くらい簡単に取れるでしょう。

ですから

> (ax,ay)と(bx,by)を“結ぶ”線上に点(cx,cy)が
> あるかの判定

ではなく,
ムービークリップの中に長方形をなんらかの形で作図して,
その長方形と点との hitTest を使うと思います。

ですから,
根本的に (ax,ay) や (bx,by) を出す方法自体を変えてしまいます。

しかし,
作ろうとされているものがどういうものかがわからないので,
工夫 のしかたがわからないのです。


上記と同じサイトにこんな当たり判定サンプルもあります↓。

「円同士の衝突を計算する」
http://hakuhin.hp.infoseek.co.jp/flash/as/collid …

見てスゴイと思いませんか?
もし,思えばそれで良いのです。


円同士の当たり判定を真面目にすると,
人間の脳みそ CPU も,PCのCPUも使い切ってしまって,
動作が超重くなってしまいます。

そこで,工夫 しまくっています。
上のURLのリンク元はこちら↓。

hakuhin.hp.infoseek.co.jp/main/as/collide.html#COLLIDE_00

動きを見て,
人間が見てスゴイと思えばそれで良いのです。
工夫 に 工夫 を重ねた 工夫 の美学です。


そんなものですよ。

「よく見るとミサイルが当たる前に爆発している敵キャラ」
とかをゲームで多々見ませんか?
普通のゲームも工夫(←注:ごまかですよ)しまくっています。



昔々,
hitTest など無い時代それも CPU の超スペック時代に,
ゴキブリたたきゲームを Flash で作ったことがあります。

ランダムなときにゴキブリがランダムに出没して,
定点に置いてあるゴキブリたたきをクリックすると,
ゴキブリたたきが振り下ろされて,
ゴキブリに命中したら,ゴキブリが死んで得点が加算されるというような内容のものです。

hitTest などなくても,
また,座標計算などしなくても,
工夫次第で当たり判定は取れます。

種を明かせば原理は簡単で,
「ゴキブリが出は消える」 というムービークリップをたくさん作って
ランダムな時間に出没させるのです。

ゴキブリ自体は,
ムービークリップの中でモーショントゥイーンによって動いているだけです。

ですから,
最初から,ゴキブリたたきにゴキブリがヒットするムービークリップもあれば,
ゴキブリたたきにゴキブリがヒットしない(ゴキブリたたきが届く寸前でゴキブリが逃げるようにモーショントゥイーンさせている)ムービークリップもあるのです。

ゴキブリたたきにゴキブリがヒットするムービークリップは,
そのムービークリップが出没してから,
ゴキブリたたきがあるタイミングでクリックされないと,
ゴキブリにヒットしないというフレームもわかっています。

ゴキブリがヒットするムービークリップの場合は,
そのゴキブリムービークリップの○フレームから△フレーム内で,
ゴキブリたたきがクリックされたとき,
「ゴキブリが死ぬ」というフレームに gotoAndPlay すれば良いのです。

原理は簡単ですが実際の 工夫 は難しいですよ。
でも,
そういう手の込んだ 工夫 をすれば,
そもそも当たり判定自体も不要になる可能性はあります。



変な話も書きましたが,以上で...。
    • good
    • 0
この回答へのお礼

作りたいもの作れました。

moveToとlineToで書いた線なので、hitTestでは上手く出来なかったので、質問しました。

ありがとうございました。

お礼日時:2007/04/04 01:16

(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 が,余分の範囲です。

※私は数学が苦手なので,
  さらに何かを求められても回答できない自信があります。

この回答への補足

試してみましたが、解答して頂いた方法ですと、(ax,ay)と(bx,by)の延長線上に(cx,cy)が存在しても「当り」と判定してしまいます・・・

(ax,ay)と(bx,by)を“結ぶ”線上に点(cx,cy)があるかの判定をしたい場合はどうしたらよいでしょう?

補足日時:2007/04/03 13:59
    • good
    • 0
この回答へのお礼

ありがとうございます。
中学高で習った事で解けるのですね。
非常に判りやすい解説でした。

ベクトルの考え方でも解けるのでしょうか・・・

お礼日時:2007/04/03 12:45

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!