無題
投稿者 : RT(y238088.dynamic.ppp.asahi-net.or.jp)
- 2012/10/07(Sun) 02:29
No.13596
|
|
|
|
|
こんにちは。私は中学生です
質問なんですが、今の座標(x,y)から(tx,ty)までt[frame]で「なめらか」に移動するメゾットってどうやって作るのでしょうか。案外難しくて作れませんでした。
「なめらか」というのは、速度が一定ではなくて、最初は速度0、だんだん早くなり、真ん中では最速で、それからは遅くなって座標が(x2,y2)になったときにちょうど速度が0になるものです。
私が作ってみた「なめらかでない」プログラムは以下です。
extends SpriteChar;
/* 初期化 */ x=100; y=100; dx=0; dy=0; targetx=0; targety=0;
/* 移動先、時間を設定(更新) */ function target_set(tx,ty,t) { targetx=tx; targety=ty; dx=(tx-x)/t; dy=(ty-y)/t; }
/* 実際に動く */ function move() { /* dx,dy(速度)を加算 */ x+=dx; y+=dy; /* 終了条件は、指定した座標中心の半径1の円の内来た時 */ if ((targetx-x)*(targetx-x)+(targety-y)*(targety-y)<1) { dx=0; dy=0; } }
/* 今の座標から(200,200)へ100frameかけて等速移動するよう設定 */ target_set(200,200,100);
/* メインループ */ while(1) { move(); //実際に移動 update(); }
(まだ幼稚なプログラムだと思いますがお見逃しを。。。) プログラムを見ればわかるように、target_setで目標を指定、moveで目標に向かって動く、という感じにしたいです。
|
Re: 無題
投稿者 : RT(y238088.dynamic.ppp.asahi-net.or.jp)
- 2012/10/07(Sun) 02:32
No.13597
|
|
|
|
すみません、修正です。 誤:(x2,y2)になったときに 正:(tx,ty)になったときに
読みづらくてすみません>< お願いします。
|
等加速度運動
投稿者 : リセッタ(ai126213132121.5.tss.access-internet.ne.jp)
- 2012/10/07(Sun) 06:35
No.13598
|
|
|
|
この手の問題は、速度と時間(フレーム数)のグラフをイメージすると解り易いです。
等速運動なら長方形に、等加速度運動なら直角三角形になります。 d=L/(1*T) // 速度 M+=d*1 // 移動 中央で減速になるので加速し続けた場合の半分の三角形がイメージできたでしょうか? d=L/((T*T)/4) // 加速度 M+=d*dt // 移動
ソース
/* 初期化 */ x=100; y=100; dx=0; dy=0; targetx=0; targety=0; tc=0; fc=0; // 追加
/* 移動先、時間を設定(更新) */ function target_set(tx,ty,t) { targetx=tx; targety=ty; //dx=(tx-x)/t; //dy=(ty-y)/t; dx=(tx-x)/(t*t/4); // 変更 dy=(ty-y)/(t*t/4); tc=t; // 追加 }
/* 実際に動く */ function move() { /* dx,dy(速度)を加算 */ //x+=dx*fc; //y+=dy*fc; fc++; // 追加 if(fc<tc/2) { // 加速 x+=dx*fc; y+=dy*fc; } else { // 減速 x+=dx*(tc-fc); y+=dy*(tc-fc); } ///* 終了条件は、指定した座標中心の半径1の円の内来た時 */ //if ((targetx-x)*(targetx-x)+(targety-y)*(targety-y)<1) { /* 終了条件は、指定したフレーム数移動した時 */ if(fc>=tc) { dx=0; dy=0; fc=0; tc=0; // 追加 } }
/* 今の座標から(300,300)へ100frameかけて等速移動するよう設定 */ target_set(300,300,100);
/* メインループ */ while(1) { move(); //実際に移動 update(); }
|
等加速度運動
投稿者 : RT(y238088.dynamic.ppp.asahi-net.or.jp)
- 2012/10/07(Sun) 20:08
No.13599
|
|
|
|
13599.zip
リセッタ様、ありがとうございます!! なるほど、グラフで考えれば簡単ですね。学校の物理で習ったv-tグラフみたいなやつですよね。完全に(?)理解しました!
そう来ると、一般化したくなってきて、してしまいました。ついでに文字も物理っぽくしました。 需要があるかどうかはわかりませんが、ご自由にお使いください。
添付ファイルのpngにあるような等加速運動ができるモジュールです。簡単に話すと、目的地と初速度、加速、等速、減速の3つの時間を指定するとあとは勝手になめらかに動いてくれます。 導出過程もまとめました。
コードは以下です。
extends SpriteChar;
/* 初期化 */ x=300; //初期位置[px] y=300; //初期位置[px]
/************************
なめらか移動モジュール(?)始まり
************************/
target_x=0; //目的x座標[px] target_y=0; //目的y座標[px] first_vx=0; //x方向の初速度[px/frame] first_vy=0; //y方向の初速度[px/frame] max_vx=0; //x方向の最大速度[px/frame] max_vy=0; //y方向の最大速度[px/frame] distance_x=0; //(target_setが呼ばれた時の)目標までのx方向距離[px] distance_y=0; //(target_setが呼ばれた時の)目標までのy方向距離[px] kasoku_t=0; //加速する時間[frame] tousoku_t=0; //等速運動する時間[frame] gensoku_t=0; //減速する時間[frame] t=0; //なめらか移動用時間カウンタ[frame] moving=0; //なめらか移動中フラグ(1…移動中 0…停止中)
/* 移動先、時間を設定(更新) tx,ty…目的のx座標、y座標[px] v0…初期速度[px/frame](x方向とy方向に分解されます) t1…加速する時間(0〜)[frame] t2…等速運動時間(0〜)[frame] t3…減速する時間(0〜)[frame] */ function target_set(tx,ty,v0,t1,t2,t3) { //ゼロ除算防止・マイナス時間禁止 if (dist(tx-x,ty-y)==0) return; if (t1<0 || t2<0 || t3<0) return; //初速度設定 first_vx = v0 * (tx - x) / sqrt( (tx - x)*(tx - x) + (ty - y)*(ty - y) ); first_vy = v0 * (ty - y) / sqrt( (tx - x)*(tx - x) + (ty - y)*(ty - y) ); //距離設定(符号付き) distance_x = tx-x; distance_y = ty-y; //max速度計算 max_vx = ( 2*distance_x - t1*first_vx ) / (t1 + 2*t2 + t3); max_vy = ( 2*distance_y - t1*first_vy ) / (t1 + 2*t2 + t3); //加速・等速・減速時間設定 kasoku_t=t1; tousoku_t=t2; gensoku_t=t3; //カウント時間設定 t=0; //移動中フラグON moving=1; }
/* target_setで設定したように動く */ function move() { t++; if (t<=kasoku_t) { //等加速度運動(加速) x += first_vx + (max_vx-first_vx) * t / kasoku_t; y += first_vy + (max_vy-first_vy) * t / kasoku_t; } else if (t<=kasoku_t+tousoku_t) { //等速運動 x += max_vx; y += max_vy; } else if (t<=kasoku_t+tousoku_t+gensoku_t){//等加速度運動(減速) x += max_vx - max_vx*( t-kasoku_t-tousoku_t ) / gensoku_t; y += max_vy - max_vy*( t-kasoku_t-tousoku_t ) / gensoku_t; } else { moving=0; } }
/* 移動中なら1、停止中なら0を返す */ function is_moving() { return moving; }
/************************
なめらか移動モジュール(?)終わり
************************/
randomize();
/* メインループ */ while(1) { if (is_moving()==0) target_set(rnd($screenWidth),rnd($screenHeight),rnd(5)-2,rnd(60),rnd(60),rnd(60)); //移動が終わったら次の移動情報を設定 move(); //実際に移動 update(); }
リセッタさん、ありとうございました。
|
Re: 無題
投稿者 : RT(y238088.dynamic.ppp.asahi-net.or.jp)
- 2012/10/07(Sun) 20:20
No.13600
|
|
|
|
↑これだと、target_x,target_yの意味がありませんね。ちょっと改造してみました。
extends SpriteChar;
/* 初期化 */ x=300; //初期位置[px] y=300; //初期位置[px]
/************************
なめらか移動モジュール(?)始まり
************************/
target_x=0; //目的x座標[px] target_y=0; //目的y座標[px] first_vx=0; //x方向の初速度[px/frame] first_vy=0; //y方向の初速度[px/frame] max_vx=0; //x方向の最大速度[px/frame] max_vy=0; //y方向の最大速度[px/frame] distance_x=0; //(target_setが呼ばれた時の)目標までのx方向距離[px] distance_y=0; //(target_setが呼ばれた時の)目標までのy方向距離[px] kasoku_t=0; //加速する時間[frame] tousoku_t=0; //等速運動する時間[frame] gensoku_t=0; //減速する時間[frame] t=0; //なめらか移動用時間カウンタ[frame] moving=0; //なめらか移動中フラグ(1…移動中 0…停止中)
/* 移動先、時間を設定(更新) tx,ty…目的のx座標、y座標[px] v0…初期速度[px/frame](x方向とy方向に分解されます) t1…加速する時間(0〜)[frame] t2…等速運動時間(0〜)[frame] t3…減速する時間(0〜)[frame] */ function target_set(tx,ty,v0,t1,t2,t3) { //ゼロ除算防止・マイナス時間禁止 if (dist(tx-x,ty-y)==0) return; if (t1<0 || t2<0 || t3<0) return; //初速度設定 first_vx = v0 * (tx - x) / sqrt( (tx - x)*(tx - x) + (ty - y)*(ty - y) ); first_vy = v0 * (ty - y) / sqrt( (tx - x)*(tx - x) + (ty - y)*(ty - y) ); //距離設定(符号付き) distance_x = tx-x; distance_y = ty-y; //max速度計算 max_vx = ( 2*distance_x - t1*first_vx ) / (t1 + 2*t2 + t3); max_vy = ( 2*distance_y - t1*first_vy ) / (t1 + 2*t2 + t3); //加速・等速・減速時間設定 kasoku_t=t1; tousoku_t=t2; gensoku_t=t3;
target_x=tx; target_y=ty; //カウント時間設定 t=0; //移動中フラグON moving=1; }
/* target_setで設定したように動く */ function move() { t++; if (t<=kasoku_t) { //等加速度運動(加速) x += first_vx + (max_vx-first_vx) * t / kasoku_t; y += first_vy + (max_vy-first_vy) * t / kasoku_t; } else if (t<=kasoku_t+tousoku_t) { //等速運動 x += max_vx; y += max_vy; } else if (t<=kasoku_t+tousoku_t+gensoku_t){//等加速度運動(減速) x += max_vx - max_vx*( t-kasoku_t-tousoku_t ) / gensoku_t; y += max_vy - max_vy*( t-kasoku_t-tousoku_t ) / gensoku_t; } else { x=target_x; y=target_y; moving=0; } }
/* 移動中なら1、停止中なら0を返す */ function is_moving() { return moving; }
/************************
なめらか移動モジュール(?)終わり
************************/
randomize();
/* メインループ */ while(1) { if (is_moving()==0) target_set(rnd($screenWidth),rnd($screenHeight),rnd(5)-2,rnd(60),rnd(60),rnd(60)); //移動が終わったら次の移動情報を設定 move(); //実際に移動 update(); }
長くなってすみません。m(_ _)m
|
Re: 無題
投稿者 : RT(y238088.dynamic.ppp.asahi-net.or.jp)
- 2012/10/07(Sun) 20:54
No.13601
|
|
|
|
↑これだと、target_x,target_yの意味がありませんね。ちょっと改造してみました。
extends SpriteChar;
/* 初期化 */ x=300; //初期位置[px] y=300; //初期位置[px]
/************************
なめらか移動モジュール(?)始まり
************************/
target_x=0; //目的x座標[px] target_y=0; //目的y座標[px] first_vx=0; //x方向の初速度[px/frame] first_vy=0; //y方向の初速度[px/frame] max_vx=0; //x方向の最大速度[px/frame] max_vy=0; //y方向の最大速度[px/frame] distance_x=0; //(target_setが呼ばれた時の)目標までのx方向距離[px] distance_y=0; //(target_setが呼ばれた時の)目標までのy方向距離[px] kasoku_t=0; //加速する時間[frame] tousoku_t=0; //等速運動する時間[frame] gensoku_t=0; //減速する時間[frame] t=0; //なめらか移動用時間カウンタ[frame] moving=0; //なめらか移動中フラグ(1…移動中 0…停止中)
/* 移動先、時間を設定(更新) tx,ty…目的のx座標、y座標[px] v0…初期速度[px/frame](x方向とy方向に分解されます) t1…加速する時間(0〜)[frame] t2…等速運動時間(0〜)[frame] t3…減速する時間(0〜)[frame] */ function target_set(tx,ty,v0,t1,t2,t3) { //ゼロ除算防止・マイナス時間禁止 if (dist(tx-x,ty-y)==0) return; if (t1<0 || t2<0 || t3<0) return; //初速度設定 first_vx = v0 * (tx - x) / sqrt( (tx - x)*(tx - x) + (ty - y)*(ty - y) ); first_vy = v0 * (ty - y) / sqrt( (tx - x)*(tx - x) + (ty - y)*(ty - y) ); //距離設定(符号付き) distance_x = tx-x; distance_y = ty-y; //max速度計算 max_vx = ( 2*distance_x - t1*first_vx ) / (t1 + 2*t2 + t3); max_vy = ( 2*distance_y - t1*first_vy ) / (t1 + 2*t2 + t3); //加速・等速・減速時間設定 kasoku_t=t1; tousoku_t=t2; gensoku_t=t3;
target_x=tx; target_y=ty; //カウント時間設定 t=0; //移動中フラグON moving=1; }
/* target_setで設定したように動く */ function move() { t++; if (t<=kasoku_t) { //等加速度運動(加速) x += first_vx + (max_vx-first_vx) * t / kasoku_t; y += first_vy + (max_vy-first_vy) * t / kasoku_t; } else if (t<=kasoku_t+tousoku_t) { //等速運動 x += max_vx; y += max_vy; } else if (t<=kasoku_t+tousoku_t+gensoku_t){//等加速度運動(減速) x += max_vx - max_vx*( t-kasoku_t-tousoku_t ) / gensoku_t; y += max_vy - max_vy*( t-kasoku_t-tousoku_t ) / gensoku_t; } else { x=target_x; y=target_y; moving=0; } }
/* 移動中なら1、停止中なら0を返す */ function is_moving() { return moving; }
/************************
なめらか移動モジュール(?)終わり
************************/
randomize();
/* メインループ */ while(1) { if (is_moving()==0) target_set(rnd($screenWidth),rnd($screenHeight),rnd(5)-2,rnd(60),rnd(60),rnd(60)); //移動が終わったら次の移動情報を設定 move(); //実際に移動 update(); }
長くなってすみません。m(_ _)m
|
|