HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2016
0511
Sadosin cosの使い方、数学12解決


Sado

リンク

2016/5/11(Wed) 00:25:25|NO.75451

もはやhsp関係ありません。
雑談という形で質問させて下さい。
(検索が下手くそ過ぎて、逆三角関数しかヒットしなかった)



以前から気になっていましたが、sin cosが逆に使われる事がしばしばあります。
http://wiki.hsp.moe/DevMagazin%EF%BC%8F%E4%B8%89%E8%A7%92%E9%96%A2%E6%95%B0.html

サインとコサインが-1〜1の値をとることは、弾速を決める際にとても便利です。なぜならば、 X方向の速さ = スピード * サイン Y方向の速さ = スピード * コサイン で決定できるためです。
まだ習っていませんが、数3の極座標の考え方なのでしょうか。
中学の時にhspに触れ、数学の解説サイトを見よう見まねでxs = speed*cos(rad)と
組み立ててバグが発生した時は混乱しました。
いえ、高校生の今も混乱しています。

これについて解説をお願いできませんか?



この記事に返信する


Sado

リンク

2016/5/11(Wed) 02:35:59|NO.75452

すみません 自己解決しました。

x=-sinθ・r
y=-cosθ・r
でグラフのθ=0.0の軸を上向きにしていただけでした。

なぜ、こんなことをする必要があったのか、中学生の時の自分に問い詰めたいです。
画像の回転か何かで軸を変えたかったのかな???
よくわからない……



Sado

リンク

2016/5/11(Wed) 02:43:06|NO.75454

角度が0.0の時にキャラをy軸-方向に直進させたいから…
なのか。

それだと、x軸を反転させる意味が分からない…あれ?ん?ん???
謎い。



GENKI

リンク

2016/5/11(Wed) 21:47:40|NO.75461

> X方向の速さ = スピード * サイン
> Y方向の速さ = スピード * コサイン

普通はX軸を0度とするんですが、Y軸を0度として計算しているのであればこの式であってますね。

しかしこの後の「sin&cos&atan複合サンプル」を見ると、
 X方向の速さ = スピード * コサイン
 Y方向の速さ = スピード * サイン
という感じの式になってるので単なる記載ミスだと思います。

ところで、このページの一番絵の図はなんでsinとcosの補助線をこの色(青と緑)で描いちゃったんでしょうね。
これだと文字色と同じ色の線分が同じ長さと勘違いしてしいますね。
線の色は黒にするか逆にするべきです。
wikiじゃないから編集できない…。

> 数3の極座標の考え方なのでしょうか。
気にしなくて大丈夫です。まずは平面(2次元の極座標)になれましょう。


> それだと、x軸を反転させる意味が分からない…あれ?ん?ん???
過去の自分は自分でもよくわからない勘違いをしていたりします。それで最後にはなぜかつじつまが合っているという不思議な現象が起きていることもよくあります。
スクリプトも分かりやすく書いてくれてませんしね!

こういう時は解読に励むよりも、過去の自分を呪いつつ新規に作りなおしたほうがいいですよ。
そして新たに作るときは来年か10年後の自分に見られてもいいように書きましょう。



cats

リンク

2016/5/11(Wed) 22:04:57|NO.75462

とにかく物体の移動のためだけのsin, cosについて説明します。
物体の移動は以下のようなイメージです。
http://web.mit.edu/4.441/1_lectures/1_lecture7/1_lecture7_pic3.gif
ある場所から黒色の矢印だけ移動したいとします。
示された式で求めているのは、この赤色の矢印の大きさです。
プログラムで斜めに移動するためには、今の位置(x, y)に
移動したいΔx, Δyを足して、(x+Δx, y+Δy)にしますよね?
そのために黒色の矢印の長さからΔx, Δyの長さを求めます。
そこで使われるのが三角関数です。
図に示したように、角度θの向きに1だけ進むには
Δx = cos(θ)
Δy = sin(θ)
となります。
角度θの基準(0度)は、一般的に正のX方向から反時計回りに変化します。
つまり図の右向きの赤矢印は0度です。
そして、黒矢印がθ度、上向きの赤矢印では90度になります。
で、実際には角度θの向き(黒矢印)にspeedだけ進みたいので、
Δx = speed * cos(θ)
Δy = speed * sin(θ)
となります。
したがって、(x, y)から角度θにspeedだけ進むと、
自分は(x + speed*cos(θ), y + speed*sin(θ))
にいることになります。

x = 1.0 y = 1.0 speed = 5.0 t = deg2rad(60.0) // 60度 mes strf("(%f, %f)から%fに向かって%f動くと", x, y, t, speed) mes "x = " + (x + speed * cos(t)) mes "y = " + (y + speed * sin(t)) mes "の座標に移動したことになります。"



GENKI

リンク

2016/5/12(Thu) 19:23:45|NO.75467

> いえ、高校生の今も混乱しています。

先生に聞くのが一番わかりやすく教えてもらえますよ。そして速い。しかも無料。
次点で数学得意な同級生か先輩。こっちは有料(現物支給など)の場合があります。
自習教材としては、数学の教科書とノート。
練習教材として参考書と問題集。あと過去に受けた数学のテスト。

せっかく近くに聞ける人がいる環境なので活用することをおすすめします。
卒業したら今以上の良い環境が手に入ることはありえませんので是非に。



Sado

リンク

2016/5/12(Thu) 21:22:07|NO.75468

>GENKIさん

>普通はX軸を0度とするんですが、Y軸を0度として計算しているのであればこの式であってますね。
「0度の軸を変えている」という認識で間違っていないみたいですね。
それを、過去の自分は何を思ったのか、更にマイナスを掛けた。
もう。
過去の自分を恨みつつ、コードを書き直します。



>catsさん
流石にそれは理解できているつもりです……



冷静に考えてみると、割と単純な話でしたね。



Sado

リンク

2016/5/12(Thu) 21:34:52|NO.75470

三角関数関連で。

今日まで、三角比テーブルの使い方が分からず
ループ処理中にsin,cos,atan関数を利用していました。

先日、stgプログラム解説サイトで三角関数はとても重いという記述を目にして
改めて三角比テーブルを利用したいと思いました。



0~π/2(三角関数の値0.00~1.00)だけ配列に書き出せば良いと聞きますが、
三角関数の実際の値を利用した計算が苦手で、
(アナログではラジアンぐらいしか計算に使わない使えない)
いまいちどう組み立てて良いのか……



配列に256方向分(π/2までなら64方向分)書きだした後は、
ラジアン値(-3.14~3.14)を0~256に換算しなければならないと思うのですが、
型変換の計算はあまり頻繁にやってはいけないと聞いたことが有ります。
他にやり方があるのでしょうか?



Sado

リンク

2016/5/12(Thu) 21:42:27|NO.75471

>三角関数の実際の値を利用した計算が苦手で、
>(アナログではラジアンぐらいしか計算に使わない使えない)

三角関数の値が√3/2や1/√2になるもの以外(30,45,60度以外)、
まともに練習したことがなくて、上手く、実際の数値やグラフを想像できない。



GENKI

リンク

2016/5/12(Thu) 22:50:44|NO.75474

> 先日、stgプログラム解説サイトで三角関数はとても重いという記述を目にして
> 型変換の計算はあまり頻繁にやってはいけないと聞いたことが有ります。

実際に重いと感じてから対策した方がいいですよ。
そう簡単には重くならないし、重くなった場合でもボトルネックが三角関数や四則演算であることはまず遭遇しませんよ。

なるべく簡単で理解しやすいスクリプトで作ることをおすすめします。
先ずはゴール(完成)にたどり着いてから質を上げるようにしないと、無限にゴールが遠のき、モチベーションも維持できません。

私はシューティング作ったことないですが、三角関数がボトルネックになったことはないですね。描画関連がよくボトルネックになります。
弾幕系シューティングとかだと三角関数が効いてくることもあるんでしょうか。


> 0~π/2(三角関数の値0.00~1.00)だけ配列に書き出せば良いと聞きますが、

0〜90度。後の角度はプラスマイナスが変わるだけですからね。
図を手書きすれば、どこからどこまでがプラスでどこからどこまでがマイナスかすぐわかると思います。


> 三角関数の値が√3/2や1/√2になるもの以外(30,45,60度以外)、
0度、90度…。
いや、まあ、角度しか情報がない場合、手計算で出すのはそれで十分です。
後の角度の時は皆さん関数電卓かExcelか計算尺だと思いますよ。



KA

リンク

2016/5/13(Fri) 06:49:28|NO.75477

>>型変換の計算はあまり頻繁にやってはいけないと聞いたことが有ります。
換算なので型変換とは異なります。

>>三角関数の値が√3/2や1/√2になるもの以外(30,45,60度以外)、
>>まともに練習したことがなくて、上手く、実際の数値やグラフを想像できない。
三角関数は各辺の比と角度の関数で、斜辺に相当する長さを1とした値です。

原点を中心とした半径1の円を考えます。
円周上の点に対して
角度がθ
Xに相当するのがcosθ
Yに相当するのがsinθ
また
1=√(X^2+Y^2)

この図は単純ですが、三角関数の基本的な考え方になります。



3k

リンク

2016/5/14(Sat) 11:30:21|NO.75484

> 先日、stgプログラム解説サイトで三角関数はとても重いという記述を目にして
> 改めて三角比テーブルを利用したいと思いました。
GENKIさんも仰ってますが「実際にそういう状況になってから考えた方が良いですよ」というのと、
三角比テーブル(というかテーブル引き)はHSPだと十中八九逆に遅くなります。

どういったサイトをご覧になったのかは分かりませんが、
恐らくC言語やそれに類する機械語が吐ける言語(あるいはJIT)を対象としたサイトではありませんでしたか?
sin、cosなど三角関数は確かにCPUにとって重い計算処理ですが、スクリプトの実行に比べれば目立って遅くはないです。
また、機械語を吐ける言語であっても、テーブル引きの方を十分最適化して書かないと早くならないという事情もあります。
(実行するCPUアーキテクチャにもよりますし、極端な話キャッシュにうまく乗るかの話とかもあります)

…ただ、これに関しては「やってみればいい」だけの話で、ちょっと長いですが論より証拠をば。


#include "winmm.as" //------------------------ // sinテーブル作成、分割数をあげれば精度はよくなる #define TABLE_DIV 256 ddim sTable, TABLE_DIV+1// 演算過程で右端点があり得るので一個余計に repeat TABLE_DIV+1 : sTable(cnt) = sin(deg2rad( 90.0 /TABLE_DIV *cnt )) : loop //------------------------ // サンプル点、-720-720まで等分割 #define TEST_NUM 1000000 ddim samples, TEST_NUM repeat TEST_NUM : samples(cnt) = deg2rad( 1440.0 /TEST_NUM *cnt ) -deg2rad(720) : loop //------------------------ // 通常のsinを使った場合 ddim resultSin, TEST_NUM timeGetTime : st = stat repeat TEST_NUM resultSin(cnt) = sin( samples(cnt) ) loop timeGetTime : ed = stat mes strf("sin[%d sample] : %d[ms] elapsed", TEST_NUM, ed-st ) //------------------------ // sinテーブルを使った場合 ddim resultTable, TEST_NUM timeGetTime : st = stat repeat TEST_NUM s = samples(cnt) /M_PI sign = 1.0 s -= double(int(s)/2)*2.0// 0 - 2 if ( s < 0.0 ) : s = -s : sign *= -1.0 if ( s > 1.0 ) : s = 2.0 -s : sign *= -1.0 if ( s > 0.5 ) { s = sign * sTable(int((1.0-s)*2.0*TABLE_DIV)) } else { s = sign * sTable(int(s*2.0*TABLE_DIV)) } resultTable(cnt) = s// 代入するところまで loop timeGetTime : ed = stat mes strf("table[%d sample] : %d[ms] elapsed", TEST_NUM, ed-st ) //------------------------ // 結果比較 diff = 0.0 repeat TEST_NUM : diff += absf( resultTable(cnt) -resultSin(cnt) ) : loop mes strf("total diff =%.16f, perSample =%.16f", diff, diff/TEST_NUM)

ひとまず手元では sin=498ms、テーブル引き=2909msぐらいになりました。
勿論私が書いたテーブル引きのHSPコードに最適化の余地はあると思いますが、三角関数の計算速度に勝てる気は(少なくとも私は)してません。

とはいえ、三角関数全体の最適化ではなく、極めて限定的な状況での最適化はスクリプトと言えど余地はあります。
例えば、θ=0付近ではsinθ≒θが成立する、とか使えばsinの計算自体がなくなるので早くなります。
(昔これを使って微妙に高速化させた記憶があるので、HSPとはいえ高速化したいところは色々調べてみると面白いかもしれません)

> それだと、x軸を反転させる意味が分からない…あれ?ん?ん???
> 謎い。
あー、私も似たようなことしたことあります。
ご自分で書かれてますが多分画像の回転軸と座標系の回転軸とが一致してなかったとかだと思いますよ。
…と思って私も古いソースコード掘り起こして見たら2回マイナスかけて箇所を発見、どういうことだ……。。。

> 私はシューティング作ったことないですが、三角関数がボトルネックになったことはないですね。描画関連がよくボトルネックになります。
> 弾幕系シューティングとかだと三角関数が効いてくることもあるんでしょうか。
個人的な感覚だと描画もそうですが、HSPだったら弾幕系シューティングは素直に弾数に依存しますね。
(というより、描画に関しては2DでDirectX使うならドローコール最適化すれば早くなるのでまだ頑張れる範疇だと思ってます)

当たり判定はおろか弾の位置移動のための加減算あたりでもう限界くるかなー、ぐらいに思ってます。
当たり判定も位置計算もそれぞれ他と独立した処理で、かつ処理として削減可能なところではないので、
有効打としてはマルチスレッドぐらいしか思い浮かばないんですよね…。


話がだいぶ逸れました。
ともかく私もGENKIさんと同じく「とにかく作ってみて、重くなったら考える、もうどうにも分からなくなったら誰かに聞く」スタンスがいいと思いますよ。
目的さえしっかりしていれば割と何とかなるもんですし、誰かが思わぬ奇策を答えてくれることも多いです。



Sado

リンク

2016/5/14(Sat) 14:02:36|NO.75486

うわぁ、hspでテーブル引きするとそんなにも重くなるんですね。
およそ6倍って、、、
三角関数の値のテーブル引きは、スクリプト言語で行うものではないと。

描画処理の工夫ですか……



ONION software Copyright 1997-2021(c) All rights reserved.