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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

5151閲覧

楕円の軌道上を等速で移動するn個の点の計算について

8beat0405

総合スコア12

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

3クリップ

投稿2015/03/02 04:24

編集2015/03/02 04:26

楕円の中心点、大きさは以下です。

CENTER_X = 0,
CENTER_Y = 25,
RADIUS_X = 280,
RADIUS_Y = 75

この楕円の軌道上をn個のスプライトを等速で動かしたいです。
スプライトは1個〜15個です。

updateで以下の計算をしています。
float newX = (CENTER_X + cos(m_theta) * RADIUS_X);
float newY = (CENTER_Y + sin(m_theta) * RADIUS_Y);

sprite->setPosition(newX, newY);
m_theta += 100.0f;

加算するm_thetaの算出方法が知りたいです。
スプライト12個の時にm_theta +=100.0fで丁度良い速度になるので、同じ速度を他の個数の時にも再現したく思います。

何卒よろしくお願いします。

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

数学的な話をするなら,速さv=sqrt((dx/dt)^2+(dy/dt)^2)を求めて,
微分方程式dv/dt=0を解いてm_thetaと時間tの関係式を求めることになると思います.
ただ私も最後まで解けないですし,実用上プログラムに組めるのか,という疑問もあります.
途中まで解いて

![方程式]WIDTH:300
ただし
![theta式]WIDTH:300
(xr = RADIUS_X, yr = RADIUS_Y)
という式になりました

追記

自己満足ですが,近似を使ってグラフを描いてみました
近似の方法は,ある時点でのθをθn,その時の求めるθの差分をΔθnとします.
また,時間差分はΔtで一定だとします.
Δθnが微小なら,dθ/dt≒Δθn/Δt
θの2階微分はΔθ/Δtの差分をΔtで割ったもの,
すなわち((Δθn/Δt)-(Δθn-1/Δt))/Δt = (Δθn - Δθn-1)/Δt^2
で近似できます(Δθn-1は前回のΔθの計算結果で既知である).
これらを適用すると,
![差分方程式]WIDTH:400
という方程式が得られます.
これをΔθnについて解くと,f'(θn)≠0,すなわちsin2θn≠0の場合
![近似解]WIDTH:400
sin2θn=0の場合は Δθn=Δθn-1

この結果を使い,θ=0の時から始めて,最初のΔθを設定して順次足しあわせて行きました

θ-t
![θ-t]WIDTH:558
Δθ-t(初期Δθ=0.02rad)
![Δθ-t]WIDTH:560
この粗い精度(Δθがθ=0,π,2πで揃わない)でも計算回数が100回単位になります(2π回るのに770回以上).
速く動かそうとすると厳しいですね.
だんだん誤差が大きくなると途中でルートの中がマイナスになるエラーになりますし.

追記2
度々の追記すみません.
上の計算の精度は,最初に与えるΔθの値が0に近づくほど上がります.
初期Δθ=0.001radで,θ=πでのΔθの誤差は0.2%以下になりました(π回るまでの計算回数が8000回に達しましたが).
あらかじめこの計算をしておいて,θの配列を作っておく,と言うのはどうでしょうか.
θが0からπ/2までの情報があれば,残りの範囲は比較的単純な計算で求められます.
そのままでは数が多すぎるので,必要に応じて例えば100回ごとの値をピックアップしておきます.
スプライトごとに時間を示すインデックス番号(0からθ配列の最大数-1)と象限の情報(1-4)を入れておいて,

lang

1double[] theta; 2int i; //インデックス 3int quadrant; //象限 4 5//以下メソッド内のイメージ 6//インデックスと象限の操作 7/*updateでiを一定値増加させたあと*/ 8if(i >= theta.length){ 9 i -= theta.length; 10 quadrant += 1 11 if(quadrant > 4) 12 quadrant -= 4; 13} 14 15//座標を求めるためのm_thetaを求める 16switch(quadrant){ 17 case 1: 18 m_theta = theta[i]; 19 break; 20 case 2: 21 m_theta = Math.PI - theta[theta.length - i]; 22 break; 23 case 3: 24 m_theta = Math.PI + theta[i]; 25 break; 26 case 4: 27 m_theta = 2 * Math.PI - theta[theta.length - i]; 28 break; 29}

このようにm_thetaを求めることができます.
速さはインデックスの変化の速さでコントロールすることができます.

投稿2015/03/03 03:08

編集2015/03/08 10:15
swordone

総合スコア20649

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

8beat0405

2015/03/03 04:55

これは凄い。 凄いのですがやはりこの方法だと実用的では無く、式を理解できる方がいるかいないかなので、他の作り方を検討します。 皆様、貴重なお時間を頂きありがとうございました。
swordone

2015/03/03 05:22

ついでに、この式のthetaはラジアンであることも付け加えておきます
hpfoon

2015/03/03 06:13

凄い! 数学的で一般式としては上記のように解くと思います。 角速度一定ならともかく、進む速度一定だと計算が異常に面倒になる気がするので、演出上許す範囲で、楽な方法を選択した方がいいと思います。 ゲームだとキラキラが回るような演出よくあるけど、どうやってるんですかね・・・フレームワークにないのかな
8beat0405

2015/03/10 09:22

いや、凄いですね。 hpfoonさんが仰るようにゲームでよくあるクルクル回るやつを作ろうとしてるのですが、 回る点の個数が可変するんで、苦労してるんですよねー。
swordone

2015/03/10 09:48

このグラフを書くときにθに対応するΔθを求めてそれをθに加えて 新たなθに対応するΔθを求めて・・・というのを繰り返しているんです. この過程で出てきた多数のθやΔθをつないでグラフを書いています. そして上記の計算ではΔtは一定として計算しているので, この計算で求められた,ある時点のθと次のθに対応する点では, どこをとってもほぼ等しい距離になります. いわば,楕円軌道を等間隔に細分化していることになります. なので,その細分化した軌道を同数ずつに分ければ,スプライトの位置を等間隔に分けられます. 問題は,θの配列をメモリに置くと相当データ量が大きいということなんですよね・・・ (javaのfloat型(16ビット=4バイト)で1000個並べただけで4キロバイト・・・)
guest

0

楕円の代わりに、次の形で考えれば、周を長さ N 等分することは簡単です。
http://www.shaku8.com/seika/figkoban0.gif
![イメージ説明]WIDTH:465

ここで求めた各分点の角度から 実際の楕円上の点を計算をしては?

上の図は 次のページからの引用です。

投稿2015/03/08 12:43

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

8beat0405

2015/03/10 09:19

ありがとうございます。 一番理解しやすい形で実装したいと思います。
guest

0

等速というのが、軌道上の移動速度なのか、見た目の速度?なのかで変わってきますね・・・
前者と仮定した場合、ちょっとずるいかもですが、
単位時間に進む距離が十分に小さいと仮定した場合、楕円は小さな移動ベクトルの集合と見ることができます。
なので、それらの値をあらかじめテーブルにぶっこんでおき、進んだ分だけ該当のとこの値を抜き出す、みたいな感じにするのはダメでしょうか・・・・・


追記ですが、自分もちょっと考えてみました。x,y,tの関係を考える方式で。

ある時間tにおける座標を(x,y)とし、そこから微小時間での変位を(dx,dy)と置きます。

式① 速度一定の式
![イメージ説明]WIDTH:178
式② 楕円の方程式
![イメージ説明]WIDTH:89
式③ 楕円の接線の式(ちょっと自信なしw)
![イメージ説明]WIDTH:83
①②③からyとdyを消去します。するとこんな式ができました。
式④ xとtの関係式
![イメージ説明]WIDTH:90
ただし、
![イメージ説明]WIDTH:183
④の両辺を時間tで積分します。
![イメージ説明]WIDTH:171
![イメージ説明]WIDTH:161
ただし、x0=移動前のx座標、x1=移動後のx座標、t=時間

多分どっか間違ってると思いますが、左辺の積分を解いてやればx1の解が出るような気がします(笑)

投稿2015/03/02 14:31

編集2015/03/05 09:59
hpfoon

総合スコア52

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

8beat0405

2015/03/03 02:17

なるほど。 参考にさせて頂きます。
swordone

2015/03/05 13:07

残念ながら式2が違います(分母は2乗です). 自ずとf(x)も変わってきます. これを使うとしたら,このf(x)が楕円の両端で不連続になること, 点がどの象限にあるかの管理が必要になることに注意が必要ですね
guest

0

何点か気になるところがありました。
0. タイミングを合わせる処理はどのようにやっているのでしょうか。ループ内の処理負荷でタイミングを合わせるような処理だと、動かすマシンや負荷などの環境が変われば速度も変化してしまいます。
0. 厳密に言えば、このままだと長い方向に行った時に速くなって、等速ではなくなっています。

投稿2015/03/02 07:41

maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

8beat0405

2015/03/02 08:05

回答ありがとうございます。 1〜15個のスプライトを楕円状に配置して、横方向にスワイプすると回転する処理を作っています。 Cocos2d-xで実装していますが、他の簡単な方法でも問題ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問