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


HSPTV!掲示板


未解決 解決 停止 削除要請

2012
1203
ベリル群行動プログラムの書き方について18解決


ベリル

リンク

2012/12/3(Mon) 12:15:15|NO.51019

今、群知能についてほ本を読んでいて
興味強く思ったので。プログラムを作ってみたいと思いました。

集団で動く場合に
・回避
・集団の平均の方向に移動する
・集団の平均の位置からあまりはなれないようにする

というプログラムをつくっており、今回避行動を実装中なのですが、
回避してくれません。イメージとしては点の近くに点があった場合、
45度回転をして回避するというプログラムです。

今は回避は45度回転にしてますが、よりよい回避方法があればそれも教えていただければ幸いです

問題は、下記のプログラムだと点が点滅してしまい、回避してくれません。
どうかご鞭撻お願いいたします。


;初期化 *initialize screen 0,1000,1000,0 ;ウィンドウの作成 tama = 100;弾の数 dim x,tama,y,tama;弾の座標の配列 repeat tama,1 x(cnt)=rnd(1000):y(cnt)=rnd(1000) loop dim vx,tama,vy,tama;ボール速度の配列 repeat tama,1 vx(cnt)=rnd(3):vy(cnt)=rnd(3) ;ボールの速度初期化 loop ;モデル部分 *model ;[ボールの移動] repeat tama,1 ;壁に当たったら跳ね返る x(cnt)+=vx(cnt) ;ボールの位置を移動 y(cnt)+=vy(cnt) ;(位置に速度を加える) if x(cnt)<0 :if vx(cnt)<0 :vx(cnt)=vx(cnt)*-1 ;左の壁に当たった場合、ボールのX速度反転(跳ね返る) if x(cnt)>1000 :if vx(cnt)>0 :vx(cnt)=vx(cnt)*-1 ;右の壁に当たった場合、ボールのX速度反転 if y(cnt)<0 :if vy(cnt)<0 :vy(cnt)=vy(cnt)*-1 ;上の壁に当たった場合、ボールのY速度反転 if y(cnt)>1000 :if vy(cnt)>0 :vy(cnt)=vy(cnt)*-1 ///////解決中/////// ;他の弾が近くにあったら避ける(旋回) i=1 stt = cnt repeat tama,1 if stt!i && stt!i { if abs(x(stt)-x(i))<vx(stt) && abs(y(stt)-y(i))<vy(stt){ vx(stt)= (x(stt)+y(stt))/1.4142 vy(stt)= (y(stt)-x(stt))/1.4142 break } i++ } loop /////////////////// loop ;[パソコンが今の状況を出力] redraw 0 ;ここから画面更新スタート color 0,0,0:boxf ;画面を黒で初期化 foreach x color 255,255,255:boxf x(cnt)-1,y(cnt)-1,x(cnt)+1,y(cnt)+1 ;ボールを描く loop redraw 1 ;画面更新終了 ;繰り返し wait 0.2 ;少し時間を置く goto *model ;繰り返し



この記事に返信する


kanahiron

リンク

2012/12/3(Mon) 16:46:51|NO.51020

全体的に見づらいところがあったので、勝手にいろいろ変えてしまいました ごめんなさい
変更点
1.弾がマイナス方向に動いてないので、-3〜+3に動くようにした
2.スクリーンサイズと弾の大きさを変数で管理
3.全体のインデントを自分なり(標準的なはず)に変更
です


randomize ;初期化 *initialize scrx = 1000 scry = 800 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) tama = 100 //弾の数 hanteikyori = 7 //弾の中心から他の弾の中心までの判定距離 ballsize = 1 hanteikyori_ = hanteikyori * hanteikyori screen 0,scrx,scry ;ウィンドウの作成 dim x,tama,y,tama;弾の座標の配列 dim vx,tama,vy,tama;ボール速度の配列 repeat tama x(cnt)=rnd(scrx):y(cnt)=rnd(scry) vx(cnt)=rnd(7)-3:vy(cnt)=rnd(7)-3 ;ボールの速度初期化 loop ;モデル部分 repeat;[ボールの移動] redraw 0 ;ここから画面更新スタート boxf ;画面を黒で初期化 repeat tama ;壁に当たったら跳ね返る x(cnt)+=vx(cnt) ;ボールの位置を移動 y(cnt)+=vy(cnt) ;(位置に速度を加える) if x(cnt)<0 :if vx(cnt)<0 :vx(cnt) *= -1 ;左の壁に当たった場合、ボールのX速度反転(跳ね返る) if x(cnt)>scrx :if vx(cnt)>0 :vx(cnt) *= -1 ;右の壁に当たった場合、ボールのX速度反転 if y(cnt)<0 :if vy(cnt)<0 :vy(cnt) *= -1 ;上の壁に当たった場合、ボールのY速度反転 if y(cnt)>scry :if vy(cnt)>0 :vy(cnt) *= -1 ///////解決中/////// ;/* cnt_ = cnt repeat tama if cnt != cnt_ { kyori = ((x(cnt_) - x(cnt))*(x(cnt_) - x(cnt))) + ((y(cnt_) - y(cnt))*(y(cnt_) - y(cnt)))//二点間の距離の公式 if kyori <= hanteikyori_{ //↓45度旋回の方法がわからなかったので近いものを互いに跳ね返るようしています vx(cnt_) *= -1 vy(cnt_) *= -1 vx(cnt) *= -1 vy(cnt) *= -1 break } } loop ;*/ /////////////////// loop color 255,255,255 repeat tama boxf x(cnt)-ballsize,y(cnt)-ballsize,x(cnt)+ballsize,y(cnt)+ballsize ;ボールを描く loop color redraw 1 ;画面更新終了 await 33 ;少し時間を置く(30fps) loop

判定の部分が若干重くなってしまいました

処理としては、自座標をx(cnt_)、y(cnt_)とし、
(弾の数)回ループの中でx(cnt)、y(cnt)との距離を求め、hanteikyoriより近かったら
跳ね返しの処理、ブレイクです

自分の環境(dual core 2.2GHz)await 33で30fpsを維持できるのは、
弾の数が130個くらいまでです(HSP3MTのランタイムなら155位まで)

また角度を変えるという部分はわかりませんでしたので、跳ね返るという動作になっています
三角関数をまだちゃんと使えないので…
45度進行を変えたい時は、

//↓45度旋回の方法がわからなかったので近いものを互いに跳ね返るようしています vx(cnt_) *= -1 vy(cnt_) *= -1 vx(cnt) *= -1 vy(cnt) *= -1
の部分を書き換えてください



@key

リンク

2012/12/3(Mon) 18:09:01|NO.51022

ベリルさんの方法は三個以上の弾が集まった時変に動いてしまいます

旋回する方法で複数個以上が集まった時正しく動くようにするのは至難の業なので、
互いに近づいた時なめらかに反発するようにするのが一般的でしょうか
磁石が反発するような処理で、最高速度以上にはならないようにするといいでしょう

ついでに言うと全方向の弾が互いに判定がある場合は、
「角度」と「速度」の二つの変数で飛ばした方がいろいろ処理がしやすいです



ベリル

リンク

2012/12/3(Mon) 23:47:30|NO.51026

弾はforeachよりrepeatで描画したほうがよろしいのでしょうか?
書き方が綺麗にかけないので本当に勉強になります!ありがとうございます。
いま回避条件など考えて書いているのですがどうもうまくいかないので助力していただければ幸いです。



ベリル

リンク

2012/12/3(Mon) 23:52:09|NO.51027

kanahironさん お礼にお名前を入れ忘れてしまい、すみません・・・。

@keyさん おっしゃるとおり、単純に角度を変えるだけでは回避は難しそうでした。
ですのでクーロンの法則を利用して、近くに寄ったら離れる力が出るようにつくりましたが。
除数が0になりエラーがでてしまいます。
除数が0になった場合は無視して飛ばすように書いてもエラーがでます、お助けください。

;初期化 *initialize scrx = 1000 scry = 800 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) tama = 100 //弾の数 hanteikyori = 5//弾の中心から他の弾の中心までの判定距離 ballsize = 1 hanteikyori_ = hanteikyori * hanteikyori screen 0,scrx,scry ;ウィンドウの作成 dim x,tama,y,tama ;弾の座標の配列 dim tobu_kaku,tama ;弾の飛ぶ角度(0度から360度) dim tobu_soku,tama dim hx,tama,hy,tama ;ボールの旋回運動のためのデータ保持 dim hanpatu_soku,tama;斥力 seki_F= 4 ;弾の斥力(反発力 repeat tama x(cnt)=rnd(scrx):y(cnt)=rnd(scry) //弾の初期位置 tobu_kaku(cnt)=rnd(360) //弾の飛ぶ角度初期設定 tobu_rad = tobu_kaku(cnt) * 3.14151 / 180.0 //度からラジアンに変換 tobu_soku(cnt)=rnd(3)+1 //弾の飛ぶ速度初期設定 vx(cnt) = (cos(tobu_rad) - sin(tobu_rad))*tobu_soku(cnt) vy(cnt) = (sin(tobu_rad) + cos(tobu_rad))*tobu_soku(cnt) loop ;モデル部分 repeat;[ボールの移動] redraw 0 ;ここから画面更新スタート boxf ;画面を黒で初期化 repeat tama ;壁に当たったら跳ね返る x(cnt)+=vx(cnt) ;ボールの位置を移動 y(cnt)+=vy(cnt) ;(位置に速度を加える) if x(cnt)<0 :if vx(cnt)<0 :vx(cnt) *= -1 ;左の壁に当たった場合、ボールのX速度反転(跳ね返る) if x(cnt)>scrx :if vx(cnt)>0 :vx(cnt) *= -1 ;右の壁に当たった場合、ボールのX速度反転 if y(cnt)<0 :if vy(cnt)<0 :vy(cnt) *= -1 ;上の壁に当たった場合、ボールのY速度反転 if y(cnt)>scry :if vy(cnt)>0 :vy(cnt) *= -1 ///////解決中/////// ;/* cnt_ = cnt repeat tama if cnt != cnt_ { kyori = ((x(cnt_) - x(cnt))*(x(cnt_) - x(cnt))) + ((y(cnt_) - y(cnt))*(y(cnt_) - y(cnt)))//二点間の距離の公式 if kyori > 0{ ;重なってる点があったら無視する hanpatu_soku(cnt_)=-(seki_F*seki_F)/(kyori * kyori)//クーロン力の法則より、互いに反発する力を計算 //二点間の方向を求める dx=x(cnt_)-x(cnt) dy=y(cnt_)-y(cnt) kaihi_rad = atan(dy,dx) ;二点間の角度を求める vx(cnt_) = (cos(kaihi_rad) - sin(kaihi_rad))*tobu_soku(cnt_) vy(cnt_) = (sin(kaihi_rad) + cos(kaihi_rad))*tobu_soku(cnt_) } } loop ;*/ /////////////////// loop color 255,255,255 repeat tama boxf x(cnt)-ballsize,y(cnt)-ballsize,x(cnt)+ballsize,y(cnt)+ballsize ;ボールを描く loop color redraw 1 ;画面更新終了 await 30 ;少し時間を置く(30fps) loop

重ね重ねkanahironさんに感謝いたします。おかげさまで少し前進しました。



@key

リンク

2012/12/4(Tue) 01:15:54|NO.51028

角度と速度で飛ぶようにして最適化しただけのもの
言っておいてなんですが反発とか、反射とかは自分の頭では無理です・・・

randomize
#define scrx 400 #define scry 300 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) #define tama 60 //弾の数 #define hanteikyori 7 //弾の中心から他の弾の中心までの判定距離 #define ballsize 1 #define hanteikyori_ hanteikyori * hanteikyori screen 0,scrx,scry ;ウィンドウの作成 dimtype x,3,tama dimtype y,3,tama;弾の座標の配列 dimtype spe,3,tama;ボール速度の配列 dimtype ang,3,tama;ボール角度の配列 //初期値の代入 repeat tama x(cnt)=0.0+rnd(scrx*10)/10:y(cnt)=0.0+rnd(scry*10)/10 spe(cnt)=rnd(30)/10+1 ang(cnt)=rnd(M_PI*2) loop *main ;ループ処理 redraw 0 color : boxf color 255,255,255 repeat tama x(cnt)+=cos(ang(cnt))*spe(cnt) ;ボールの位置を移動 y(cnt)+=sin(ang(cnt))*spe(cnt) boxf x(cnt)-ballsize,y(cnt)-ballsize,x(cnt)+ballsize,y(cnt)+ballsize if x(cnt)<0 :ang(cnt) =(ang(cnt)+M_PI)*-1 ;左の壁に当たった場合、ボールのX速度反転(跳ね返る) if x(cnt)>scrx :ang(cnt) =(ang(cnt)+M_PI)*-1;右の壁に当たった場合、ボールのX速度反転 if y(cnt)<0 :ang(cnt) *= -1 ;上の壁に当たった場合、ボールのY速度反転 if y(cnt)>scry :ang(cnt) *= -1 ///////解決中/////// cnt_ = cnt repeat tama if cnt != cnt_ { kyori = ((x(cnt_)-x(cnt))*(x(cnt_)-x(cnt)))+((y(cnt_)-y(cnt))*(y(cnt_)-y(cnt)))//二点間の距離の公式 if kyori <= hanteikyori_{ break } } loop if sp(num)>3 : sp(num)=3 /////////////////// loop redraw 1 ;画面更新終了 await 32 ;少し時間を置く(30fps) goto *main

kanahiron様のものを流用したので、いろいろ変数名は自分好みです・・・



ベリル

リンク

2012/12/4(Tue) 11:12:13|NO.51029

雰囲気的に回避のように見えるようになってきました。
まだまだ挙動が変ですが・・・自然によけるためにはどうするのがいいでしょうか・・・
計算を早くするために、近くのマスしか計算しなくしました。
また、回避しやすいようにフレーム1とフレーム2の差分で差分が短くなったものだけを
回避させるようにしてみました。

#define scrx 1000 #define scry 800 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) #define tama 100 //弾の数 #define hanteikyori 20 //弾の中心から他の弾の中心までの判定距離 #define ballsize 1 #define hanteikyori_ hanteikyori * hanteikyori #define sikai 100;個々弾の範囲、範囲に入ると距離を計算する screen 0,scrx,scry ;ウィンドウの作成 dimtype x,3,tama dimtype y,3,tama;弾の座標の配列 dimtype f_x,3,tama dimtype f_y,3,tama dimtype spe,3,tama;ボール速度の配列 dimtype ang,3,tama;ボール角度の配列 //初期値の代入 repeat tama x(cnt)=0.0+rnd(scrx*10)/10:y(cnt)=0.0+rnd(scry*10)/10 spe(cnt)=rnd(30)/10+1 ang(cnt)=rnd(M_PI*2) loop *main ;ループ処理 redraw 0 color : boxf color 255,255,255 repeat tama x(cnt)+=cos(ang(cnt))*spe(cnt) ;ボールの位置を移動 y(cnt)+=sin(ang(cnt))*spe(cnt) f_x(cnt)=x(cnt)+cos(ang(cnt))*spe(cnt) ;次のターンのボールの位置 f_y(cnt)=y(cnt)+sin(ang(cnt))*spe(cnt) boxf x(cnt)-ballsize,y(cnt)-ballsize,x(cnt)+ballsize,y(cnt)+ballsize if x(cnt)<0 :ang(cnt) =(ang(cnt)+M_PI)*-1:x(cnt)=0.0 ;左の壁に当たった場合、ボールのX速度反転(跳ね返る) if x(cnt)>scrx :ang(cnt) =(ang(cnt)+M_PI)*-1:x(cnt)=0.0+scrx;右の壁に当たった場合、ボールのX速度反転 if y(cnt)<0 :ang(cnt) *= -1:y(cnt)=0.0;上の壁に当たった場合、ボールのY速度反転 if y(cnt)>scry :ang(cnt) *= -1:y(cnt)=0.0+scry ///////解決中/////// cnt_ = cnt repeat tama if cnt != cnt_ {//同じ弾を計算しないように if x(cnt) < 0.0+x(cnt_)+sikai && x(cnt) > 0.0+x(cnt_)-sikai && y(cnt) < 0.0+y(cnt_)+sikai && y(cnt) > 0.0+y(cnt_)-sikai{//近い弾だけ判定する kyori_a = ((x(cnt_)-x(cnt))*(x(cnt_)-x(cnt)))+((y(cnt_)-y(cnt))*(y(cnt_)-y(cnt)))//二点間の距離の公式 if kyori_a <= hanteikyori_{ //次のターンの距離を求める kyori_b= ((f_x(cnt_)-f_x(cnt))*(f_x(cnt_)-f_x(cnt)))+((f_y(cnt_)-f_y(cnt))*(f_y(cnt_)-f_y(cnt))) if kyori_b < kyori_a{//AとBを比べて距離が広がってるようならなにもしない //二点間の方向を求める dx=x(cnt_)-x(cnt) dy=y(cnt_)-y(cnt) kaihi_rad = atan(dy,dx) ;二点間の角度を求める x(cnt_)+=cos(ang(cnt_)-kaihi_rad)*(spe(cnt_)) ;ボールの位置を移動 y(cnt_)+=sin(ang(cnt_)-kaihi_rad)*(spe(cnt_)) ang(cnt_)+=-kaihi_rad/5 } break } } } loop // if sp(num)>3 : sp(num)=3 /////////////////// loop redraw 1 ;画面更新終了 await 32 ;少し時間を置く(30fps) goto *main



暇人

リンク

2012/12/6(Thu) 19:16:54|NO.51044

進行方向のどっち側に判定相手の弾が有るかで左右振り分け
正面に有るほど大きく回転して
速度と距離で更に回転角度調整って感じのやり方


#define scrx 1000 #define scry 800 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) #define tama 100 //弾の数 #define hanteikyori 30 //弾の中心から他の弾の中心までの判定距離 #define ballsize 1 #const hanteikyori_ hanteikyori * hanteikyori #define sikai 100;個々弾の範囲、範囲に入ると距離を計算する #const M_PI2 M_PI*2 screen 0,scrx,scry ;ウィンドウの作成 dimtype x,3,tama dimtype y,3,tama;弾の座標の配列 dimtype f_x,3,tama dimtype f_y,3,tama dimtype spe,3,tama;ボール速度の配列 dimtype ang,3,tama;ボール角度の配列 //初期値の代入 repeat tama x(cnt)=0.0+rnd(scrx*10)/10:y(cnt)=0.0+rnd(scry*10)/10 spe(cnt)=double(rnd(30)/10+1) ang(cnt)=deg2rad(rnd(360)) loop buffer 1,scrx,scry boxf gsel 0 *main ;ループ処理 redraw 0 ;color : boxf ;color 255,255,255 pos 0,0 gmode 3,,,25 gcopy 1,0,0,scrx,scry //残像残し repeat tama x(cnt)+=cos(ang(cnt))*spe(cnt) ;ボールの位置を移動 y(cnt)+=sin(ang(cnt))*spe(cnt) color 100,200 line x(cnt),y(cnt),x(cnt)+cos(ang(cnt))*hanteikyori,y(cnt)+sin(ang(cnt))*hanteikyori //進行方向表示 color 255,255,255 boxf x(cnt)-ballsize,y(cnt)-ballsize,x(cnt)+ballsize,y(cnt)+ballsize if x(cnt)<0 :ang(cnt) =(M_PI-ang(cnt)+M_PI2)\M_PI2:x(cnt)=0.0 ;左の壁に当たった場合、ボールのX速度反転(跳ね返る)(0〜M_PI*2にする) if x(cnt)>scrx :ang(cnt) =(M_PI-ang(cnt)+M_PI2)\M_PI2:x(cnt)=0.0+scrx;右の壁に当たった場合、ボールのX速度反転 if y(cnt)<0 :ang(cnt) =(M_PI+(M_PI-ang(cnt)))\M_PI2:y(cnt)=0.0;上の壁に当たった場合、ボールのY速度反転 if y(cnt)>scry :ang(cnt) =(M_PI+(M_PI-ang(cnt)))\M_PI2:y(cnt)=0.0+scry ///////解決中/////// cnt_ = cnt x_=x(cnt_) y_=y(cnt_) repeat tama if cnt != cnt_ {//同じ弾を計算しないように dx=x_-x(cnt) dy=y_-y(cnt) kyori_a = (dx*dx)+(dy*dy) //二点間の距離の公式 if kyori_a <= (spe(cnt)*hanteikyori_){//速度が速い程判定範囲を広げる kaihi_rad = atan(dy,dx)+M_PI ;二点間の角度を求める(0〜M_PI*2にする) k=(150.0*spe(cnt))/sqrt(kyori_a) //速度が速く距離が近いほど大きくなるように r=(( kaihi_rad-((ang(cnt_))) )+M_PI2)\M_PI2 //進行角度を0にした時の判定相手の弾の方向を0〜M_PI*2にする if r<M_PI{//進行方向右側に弾がある ang(cnt_)=( ang(cnt_) - ((M_PI-r)/220.0)*k +M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い) }else{//進行方向左側に弾がある ang(cnt_)=( ang(cnt_) + ((r-M_PI)/220.0)*k +M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い) } } } loop /////////////////// loop redraw 1 ;画面更新終了 await 32 ;少し時間を置く(30fps) goto *main
どう移動してるか見やすい様に残像と進行方向表示したら
魚が動いてるように見えてきた・・・



暇人

リンク

2012/12/7(Fri) 19:15:45|NO.51052

ちょっと修正
> if kyori_a <= (spe(cnt)*hanteikyori_){//速度が速い程判定範囲を広げる
spe(cnt)じゃ無くてspe(cnt_)だった・・・
ループ前に計算して変数に入れたのを使った方が良いけど・・・



暇人

リンク

2012/12/9(Sun) 17:41:45|NO.51071

まだ見てるか分からないけど
ちょっと面白かったので群の動きも追加してみた

#define scrx 1000 #define scry 800 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) #define tama 100 //弾の数 #define hanteikyori 30 //弾の中心から他の弾の中心までの判定距離 #define ballsize 1 #const hanteikyori_ hanteikyori * hanteikyori // #define sikai 100;個々弾の範囲、範囲に入ると距離を計算する #const M_PI2 M_PI*2 #const SpeedMin 1.0 //最低速度 #const SpeedMax 3.0 //最高速度 screen 0,scrx,scry ;ウィンドウの作成 dimtype x,3,tama dimtype y,3,tama;弾の座標の配列 dimtype f_x,3,tama dimtype f_y,3,tama dimtype spe,3,tama;ボール速度の配列 dimtype ang,3,tama;ボール角度の配列 randomize //初期値の代入 repeat tama x(cnt)=0.0+rnd(scrx*10)/10:y(cnt)=0.0+rnd(scry*10)/10 spe(cnt)=double(rnd((SpeedMax-SpeedMin)*10))/10+SpeedMin ang(cnt)=deg2rad(rnd(360)) loop buffer 1,scrx,scry boxf gsel 0 Scroll_x=0.0 Scroll_y=0.0 objsize 64,18,18 gmode_t=3 vh=1 mh=1 button gosub "残像",*set : button gosub"方向表示",*set button gosub"群方向",*set pos scrx-96,0 ks=200 //距離速度による影響度(大きいほど影響も大きい) input ks,64.16 helm=0.009 //角度による影響度(大きいほど影響も大きい) input helm,64.16 gi=0.25 //群の目標位置までの角度差による影響度(大きいほど影響も大きい) input gi,64.16 *main ;ループ処理 redraw 0 pos 0,0 gmode gmode_t,,,25 gcopy 1,0,0,scrx,scry color 100,255,255 pos 64,0 if gmode_t=3 {mes "ON"}else{mes "OFF"} if vh {mes "ON"}else{mes "OFF"} if mh {mes "有効"}else{mes "無効"} pos scrx-32,0 mes "距速" mes "角度" mes "群角" cos_=0.0 sin_=0.0 repeat tama cos_+cos(ang(cnt)) sin_+sin(ang(cnt)) loop total_x=0.0 total_y=0.0 repeat tama if mh{ dx=x(cnt)-top_x //群の目標位置までの距離 dy=y(cnt)-top_y ang_2=((atan(dy,dx)-M_PI)+M_PI2)\M_PI2 //群の目標位置までの角度(0〜M_PI2) r=(ang_2-ang(cnt)+M_PI2)\M_PI2 //進行角度と群の目標位置までの角度の差 if r<M_PI{ ang(cnt)+=r*gi }else{ ang(cnt)+=(r-M_PI2)*gi } ang(cnt)=(ang(cnt)+M_PI2)\M_PI2 } x(cnt)+=cos(ang(cnt))*spe(cnt) ;ボールの位置を移動 y(cnt)+=sin(ang(cnt))*spe(cnt) x_=x(cnt) y_=y(cnt) if vh {color 100,200:line x_-Scroll_x,y_-Scroll_y,x_+cos(ang(cnt))*hanteikyori-Scroll_x,y_+sin(ang(cnt))*hanteikyori-Scroll_y }//進行方向表示 color 255,255,255 boxf x_-ballsize-Scroll_x,y_-ballsize-Scroll_y,x_+ballsize-Scroll_x,y_+ballsize-Scroll_y if x_<0 :ang(cnt) =(M_PI-ang(cnt)+M_PI2)\M_PI2:x(cnt)=0.0 :x_=0.0;左の壁に当たった場合、ボールのX速度反転(跳ね返る)(0〜M_PI*2にする) if x_>scrx :ang(cnt) =(M_PI-ang(cnt)+M_PI2)\M_PI2:x(cnt)=0.0+scrx :x_=0.0+scrx;右の壁に当たった場合、ボールのX速度反転 if y_<0 :ang(cnt) =(M_PI+(M_PI-ang(cnt)))\M_PI2:y(cnt)=0.0 :y_=0.0;上の壁に当たった場合、ボールのY速度反転 if y_>scry :ang(cnt) =(M_PI+(M_PI-ang(cnt)))\M_PI2:y(cnt)=0.0+scry :y_=0.0+scry ///////解決中/////// cnt_ = cnt total_x+x_ total_y+y_ hanteikyori_s=(spe(cnt)*hanteikyori_) repeat tama if cnt != cnt_ {//同じ弾を計算しないように dx=x_-x(cnt) dy=y_-y(cnt) kyori_a = dx*dx+dy*dy //二点間の距離の公式 if kyori_a <= hanteikyori_s {//速度が速い程判定範囲を広げる kaihi_rad = atan(dy,dx)+M_PI ;二点間の角度を求める(0〜M_PI*2にする) k=(spe(cnt)*ks)/sqrt(kyori_a) //速度が速く距離が近いほど大きくなるように r=(( kaihi_rad-((ang(cnt_))) )+M_PI2)\M_PI2 //進行角度を0にした時の判定相手の弾の方向を0〜M_PI*2にする if r<M_PI{//進行方向右側に弾がある ang(cnt_)=( ang(cnt_) - ((M_PI-r)*helm)*k +M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い) }else{//進行方向左側に弾がある ang(cnt_)=( ang(cnt_) + ((r-M_PI)*helm)*k +M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い) } } } loop /////////////////// loop Center_x=total_x/tama //群の中心座標 Center_y=total_y/tama if mh{ color 0,250,250 circle Center_x-10,Center_y-10,Center_x+10,Center_y+10,0 color 255 top_x=Center_x+cos_*SpeedMax //群の進行目標位置 top_y=Center_y+sin_*SpeedMax line Center_x,Center_y,top_x,top_y //群の平均方向表示 } redraw 1 ;画面更新終了 await 32 ;少し時間を置く(30fps) goto *main *set if stat=0 {gmode_t=(gmode_t+3)\6} if stat=1 {vh^1} if stat=2 {mh^1} return



捨てID

リンク

2012/12/9(Sun) 20:31:40|NO.51073

面白いですね。画面を小さくしたりして、楽しみました。

ところで、110行目の

k=(spe(cnt)*ks)/sqrt(kyori_a) //速度が速く距離が近いほど大きくなるように
で0除算で停止します。

0除算の不具合が出るか出ないかって、環境依存っぽいような気がしています…。



暇人

リンク

2012/12/9(Sun) 20:57:32|NO.51074

完全に弾同士が重なると距離が0になるので0除算エラーになります
dx,dyが両方0の時に判定をスルーすればとりあえずエラーは回避できる
今回は少しでも処理を少なくしたかったので省いた

0にならない影響度を設定しないと回避出来てない事になるし・・・
(回転だけで絶対に0にならないように出来るかは分かってないけど・・・)



べりる

リンク

2012/12/13(Thu) 09:25:48|NO.51122

返信おくれてしまい申し訳ありません!
暇人さん本当にすごいです!群行動まで実装してしまうとは・・・・
 回避行動プログラムつくっていてあまりに実装ができなく悩みすぎたので
一人でへこんでました・・・・

暇人さんの書き込みを見ながらもう一度考えて作って見ます!
本当にありがとうございます!



べりる

リンク

2012/12/13(Thu) 09:34:00|NO.51123

すみません・・・
if r<M_PI{//進行方向右側に弾がある
ang(cnt_)=( ang(cnt_) - ((M_PI-r)/220.0)*k +M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い)
}else{//進行方向左側に弾がある
ang(cnt_)=( ang(cnt_) + ((r-M_PI)/220.0)*k +M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い)
この計算の意味がわからないので教えていただけませんか?
¥の意味も教えていただければ幸いです。



べりる

リンク

2012/12/13(Thu) 12:13:42|NO.51125

自分なりに集まって移動するルールを考えました。
ある弾の周辺にどれだけ弾があるか密度を調べて
一番密度の高い場所へ移動する。というものです。
ある弾中心とし、4等分したエリアの弾数を数えます。


・・・ですがうまくいきませんでした。。。
お助けください。

///////////////////// // 群行動(集まる)// ///////////////////// //自弾周辺の密度を測り、一番密度の高い場所へ移動 //自弾周辺を4分割して分割エリアそれぞれにある他弾の数を計算し、一番多い方向へ移動 tama_mitu1=0//弾の密度 tama_mitu2=0 tama_mitu3=0 tama_mitu4=0 area=0 cnt_ = cnt x_=x(cnt_) y_=y(cnt_) repeat tama if cnt != cnt_ {//同じ弾を計算しないように if x(cnt_) <=x(cnt) && x(cnt_)+100>=x(cnt) && y(cnt_) <=y(cnt_) && y(cnt_)+100 >=y(cnt)//第一エリア(自弾を中心とした) tama_mitu1++ if x(cnt_) <=x(cnt) && x(cnt_)+100>=x(cnt) && y(cnt_)-100<=y(cnt_) && y(cnt_) >=y(cnt)//第二エリア tama_mitu2++ if x(cnt_)-100<=x(cnt) && x(cnt_) >=x(cnt) && y(cnt_) <=y(cnt_) && y(cnt_)+100 >=y(cnt)//第三エリア tama_mitu3++ if x(cnt_)-100<=x(cnt) && x(cnt_) >=x(cnt) && y(cnt_)-100<=y(cnt_) && y(cnt_) >=y(cnt)//第四エリア tama_mitu4++ } loop if (tama_mitu1!=0 || tama_mitu2!=0 || tama_mitu3!=0 || tama_mitu4!=0){ area = 1//エリア4つでどれが一番密度が高いか確認 if tama_mitu1 <= tama_mitu2:area = 2 if tama_mitu2 <= tama_mitu3:area = 3 if tama_mitu3 <= tama_mitu4:area = 4 }else{ goto *main } repeat tama if area ==1: dx= 100:dy= 100:kaihi_rad = atan(dy,dx)+M_PI ;二点間の角度を求める(0〜M_PI*2にする) if area ==2: dx= 100:dy=-100:kaihi_rad = atan(dy,dx)+M_PI if area ==3: dx=-100:dy= 100:kaihi_rad = atan(dy,dx)+M_PI //if area ==4: dx=-100:dy=-100:kaihi_rad = atan(dy,dx)+M_PI k=(150.0*spe(cnt_))/sqrt(1000) //速度が速く距離が近いほど大きくなるように r=(( kaihi_rad-((ang(cnt_))) )+M_PI2)\M_PI2 //進行角度を0にした時の判定相手の弾の方向を0〜M_PI*2にする if r<M_PI{//進行方向右側に弾がある ang(cnt_)=( ang(cnt_) - ((M_PI-r)/220.0)*M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い) }else{//進行方向左側に弾がある ang(cnt_)=( ang(cnt_) + ((r-M_PI)/220.0)*M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い) } loop /////////////////////



暇人

リンク

2012/12/13(Thu) 21:47:11|NO.51132

とりあえず遊びで作ったNO.51071の改良版
0除算エラーにならないようにして
スクロールと障害物追加

#const scrx 1000 #const scry 800 //スクリーンの大きさX,Y(自分の環境だと1000ではみ出すので) #define tama 100 //弾の数 #define ballsize 1 #const hanteikyori 30+ballsize //端から他の弾の中心までの判定距離 #const hanteikyori_ hanteikyori * hanteikyori #const M_PI2 M_PI*2 #const SpeedMin 1.5 //最低速度 #const SpeedMax 3.0 //最高速度 screen 0,scrx,scry ;ウィンドウの作成 dimtype x,3,tama dimtype y,3,tama;弾の座標の配列 dimtype f_x,3,tama dimtype f_y,3,tama dimtype spe,3,tama;ボール速度の配列 dimtype ang,3,tama;ボール角度の配列 randomize //初期値の代入 repeat tama x(cnt)=0.0+rnd(scrx*10)/10:y(cnt)=0.0+rnd(scry*10)/10 spe(cnt)=double(rnd((SpeedMax-SpeedMin)*10))/10+SpeedMin ang(cnt)=deg2rad(rnd(360)) if spe(cnt)>ss{ss=spe(cnt)} loop bgx=(scrx+200)/50+1 bgy=(scry+200)/50+1 buffer 1,bgx*50,bgy*50 repeat bgy _cnt=cnt repeat bgx color 25*(((cnt+_cnt)\2)=0),50*((cnt+_cnt)\2),50*((cnt+_cnt)\2);,0,100*((cnt+1+cnt/20)\2) boxf cnt*50,_cnt*50,cnt*50+50,_cnt*50+50 loop loop gsel 0 Scroll_x=0.0 Scroll_y=0.0 objsize 64,18,18 gmode_t=3 vh=1 mh=1 button gosub "残像",*set :bid(0)=stat button gosub"方向表示",*set :bid(1)=stat button gosub"群方向",*set :bid(2)=stat button gosub"スクロール",*set :bid(3)=stat pos scrx-96,0 //影響度が高い程機敏に方向を変える ri=1 //距離による影響度(大きいほど影響も大きい) input ri,64.16 si=0.5 //速度による影響度(大きいほど影響も大きい) input si,64.16 ai=1.0 //角度による影響度(1.0が最大影響度 0で回転しなくなる) input ai,64.16 gi=0.25 //群の目標位置までの角度差による影響度(大きいほど影響も大きい) input gi,64.16 objsize 16,16,18 gcy=ginfo_cy pos ginfo_cx,gcy button gosub"−",*set :bid(4)=stat pos ginfo_cx+18,gcy button gosub"+",*set :bid(5)=stat wt=32 //await Scroll_x=0.0 Scroll_y=0.0 RSize=25 //所為が異物初期サイズ ball_h=ballsize*ballsize*2 ball_h_sqrt=sqrt(ball_h) *main ;ループ処理 redraw 0 gmode gmode_t,,,30 pos 0,0 gcopy 1,100+(Scroll_x\100),100+(Scroll_y\100),scrx,scry stick st getkey SHIFT,16 if SHIFT {//シフトを押してる間マウスカーソル位置に障害物(リング)を表示 if st=256 {//シフト押しながら左クリックで障害物設置 Ring_cnt+ } mw=mousew RSize=limit(RSize-(mw>0)*4+(mw<0)*4,8,scrx/2) //マススホイールを回すと障害物の大きさが変る RingSize(Ring_cnt)= RSize //障害物半径 RingHitSize(Ring_cnt) =sqrt((RSize)*(RSize)) mouse_x(Ring_cnt)=Scroll_x+mousex mouse_y(Ring_cnt)=Scroll_y+mousey }else{ if st=256 {//障害物上で左クリック押すと障害物消去(シフト放してる状態) repeat Ring_cnt dx=mouse_x(cnt)-(Scroll_x+mousex) dy=mouse_y(cnt)-(Scroll_y+mousey) if sqrt(dx*dx+dy*dy)<(RingHitSize(cnt)){ Ring_cnt-- if Ring_cnt ! cnt { memcpy mouse_x(cnt),mouse_x(cnt+1),8*(Ring_cnt-cnt) memcpy mouse_y(cnt),mouse_y(cnt+1),8*(Ring_cnt-cnt) memcpy RingSize(cnt),RingSize(cnt+1),4*(Ring_cnt-cnt) memcpy RingHitSize(cnt),RingHitSize(cnt+1),8*(Ring_cnt-cnt) } break } loop } if (st=512) and (Ring_cnt>0){//右クリックで最後に設置した障害物から消去 Ring_cnt-- } } color 100,255,255 pos 64,0 if gmode_t=3 {mes "ON"}else{mes "OFF"} if vh {mes "ON"}else{mes "OFF"} if mh {mes "有効"}else{mes "無効"} if sf=0 {mes "OFF"}else{mes "ON"} pos scrx-32,0 mes "距離" mes "速度" mes "角度" mes "群角" pos scrx-64 mes "await"+strf("%3d",wt) pos scrx/2-100,20 mes "障害物 "+Ring_cnt+"個" cos_=0.0 sin_=0.0 repeat tama cos_+cos(ang(cnt)) sin_+sin(ang(cnt)) loop total_x=0.0 total_y=0.0 repeat tama x(cnt)+=cos(ang(cnt))*spe(cnt) ;ボールの位置を移動 y(cnt)+=sin(ang(cnt))*spe(cnt) x_=x(cnt) y_=y(cnt) if sf=0{ if x_<Scroll_x :ang(cnt) =(M_PI-ang(cnt)+M_PI2)\M_PI2 :x_=Scroll_x-(x_-Scroll_x) :x(cnt)=x_ ;左の壁に当たった場合、ボールのX速度反転(跳ね返る)(0〜M_PI*2にする) if x_>(Scroll_x+scrx) :ang(cnt) =(M_PI-ang(cnt)+M_PI2)\M_PI2 :x_=(Scroll_x+scrx)-(x_-(Scroll_x+scrx)):x(cnt)=x_ ;右の壁に当たった場合、ボールのX速度反転 if y_<Scroll_y :ang(cnt) =(M_PI+(M_PI-ang(cnt)))\M_PI2 :y_=Scroll_y-(y_-Scroll_y) :y(cnt)=y_ ;上の壁に当たった場合、ボールのY速度反転 if y_>(Scroll_y+scry) :ang(cnt) =(M_PI+(M_PI-ang(cnt)))\M_PI2 :y_=(Scroll_y+scry)-(y_-(Scroll_y+scry)) :y(cnt)=y_ } ///////解決中/////// if mh { dx=x_-top_x //群の目標位置までの距離 dy=y_-top_y ang_2=((atan(dy,dx)-M_PI)+M_PI2)\M_PI2 //群の目標位置までの角度(0〜M_PI2) r=(ang_2-ang(cnt)+M_PI2)\M_PI2 //進行角度と群の目標位置までの角度の差 if r<M_PI{ ang(cnt)+=r*gi }else{ ang(cnt)+=(r-M_PI2)*gi } ang(cnt)=(ang(cnt)+M_PI2)\M_PI2 } total_x+x_ total_y+y_ hanteikyori_s=(spe(cnt)*hanteikyori_)//速度が速い程判定範囲を広げる cnt_ = cnt rsi=spe(cnt)*si+ri repeat tama if cnt != cnt_ { dx=x_-x(cnt) dy=y_-y(cnt) kyori_a = dx*dx+dy*dy //二点間の距離の公式 if kyori_a <= hanteikyori_s {//程判定範囲内 if kyori_a>ball_h {//弾同士が重なってるか判定(距離判定なので角は重なってても無視) kaihi_rad = atan(dy,dx)+M_PI ;二点間の角度を求める(0〜M_PI*2にする) k=limitf(rsi/(sqrt(kyori_a)-ball_h_sqrt),0.025,0.9) //距離が近いほど大きくなるように r=(( kaihi_rad-((ang(cnt_))) )+M_PI2)\M_PI2 //進行角度を0にした時の判定相手の弾の方向を0〜M_PI*2にする if r<M_PI{//進行方向右側に弾がある ang(cnt_)=( ang(cnt_) - ((M_PI-r)*ai)*k +M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い) }else{//進行方向左側に弾がある ang(cnt_)=( ang(cnt_) + ((r-M_PI)*ai)*k +M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い) } }else{ ang(cnt_)+=0.5+0.01*rnd(50)//接触してるので適当に回転させる hit+//接触した数を数える } } } loop //障害物判定 spe_=spe(cnt) repeat Ring_cnt+SHIFT dx=x_-mouse_x(cnt) dy=y_-mouse_y(cnt) kyori_a = sqrt(dx*dx+dy*dy)-RingHitSize(cnt) //外輪からの距離距離 if kyori_a <= hanteikyori { kaihi_rad = atan(dy,dx)+M_PI ;二点間の角度を求める(0〜M_PI*2にする) r=(( kaihi_rad-((ang(cnt_))) )+M_PI2)\M_PI2 //進行角度を0にした時の障害物の方向を0〜M_PI*2にする if kyori_a>0 {//障害物の外側 k=0.03/(kyori_a/(spe_+hanteikyori)) //速度が速く距離が近いほど大きくなるように if r<M_PI{//進行方向右側に障害物がある ang(cnt_)=( ang(cnt_) - ((M_PI-r)*k) +M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い) }else{//進行方向左側に障害物がある ang(cnt_)=( ang(cnt_) + ((r-M_PI)*k) +M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い) } }else{//障害物に重なった if r<M_PI{//進行方向右側に障害物がある ang(cnt_)=( ang(cnt_) - ((M_PI-r)*0.9) +M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い) }else{//進行方向左側に障害物がある ang(cnt_)=( ang(cnt_) + ((r-M_PI)*0.9) +M_PI2)\M_PI2 //右に回転((r-M_PI)正面に近いほど回転量が多い) } } } loop color 230,230,230 boxf x_-ballsize-Scroll_x,y_-ballsize-Scroll_y,x_+ballsize-Scroll_x,y_+ballsize-Scroll_y /////////////////// if vh {color 100,200:line x_-Scroll_x,y_-Scroll_y,x_+cos(ang(cnt))*hanteikyori-Scroll_x,y_+sin(ang(cnt))*hanteikyori-Scroll_y }//進行方向表示 loop color 200,100,255 repeat Ring_cnt+SHIFT circle mouse_x(cnt)-Scroll_x-RingSize(cnt),mouse_y(cnt)-Scroll_y-RingSize(cnt),mouse_x(cnt)-Scroll_x+RingSize(cnt),mouse_y(cnt)-Scroll_y+RingSize(cnt),0 loop Center_x=total_x/tama //群の中心座標 Center_y=total_y/tama if sf {//スクロール計算 Scroll_x-=(Scroll_x-(Center_x+cos_*SpeedMax/2-scrx/2))/50 Scroll_y-=(Scroll_y-(Center_y+sin_*SpeedMax/2-scry/2))/50 } if mh { color 0,250,250 circle Center_x-Scroll_x-10,Center_y-Scroll_y-10,Center_x-Scroll_x+10,Center_y-Scroll_y+10,0 color 255 top_x=Center_x+cos_*SpeedMax //群の進行目標位置 top_y=Center_y+sin_*SpeedMax line Center_x-Scroll_x,Center_y-Scroll_y,top_x-Scroll_x,top_y-Scroll_y //群の平均方向表示 } if hit { hit_dat(hit_cnt)=hit hit_cnt++ hit_tim=0 hit=0 }else{ hit_tim + wt } if hit_cnt {//接触数表示 color 255,100,100 repeat hit_cnt pos scrx/2-100,scry-30-cnt*16 mes "接触 [個数="+hit_dat(cnt)+"]" loop if hit_tim>3000 {hit_cnt=0} } redraw 1 ;画面更新終了 await wt goto *main *set if stat=bid(0) {gmode_t=(gmode_t+3)\6:g_t=0} if stat=bid(1) {vh^1} if stat=bid(2) {mh^1} if stat=bid(3) { sf^1 if gmode_t=3 and sf=1{gmode_t=0:g_t=1} if g_t=1 and sf=0{gmode_t=3:g_t=0} } if stat=bid(4) {wt=limit(wt-1,0,1000)} if stat=bid(5) {wt=limit(wt+1,0,1000)} return /* 障害物(リング)設置削除方法 ・シフトを押してる間マウスカーソル位置に障害物を表示 ・シフト押しながら左クリックで障害物設置 ・シフト押しながらマススホイールを回すと障害物の大きさが変る ・障害物上で左クリック押すと障害物消去 ・右クリックで最後に設置した障害物から消去
障害物(リング)設置削除方法
・シフトを押してる間マウスカーソル位置に障害物を表示
・シフト押しながら左クリックで障害物設置
・シフト押しながらマススホイールを回すと障害物の大きさが変る
・障害物上で左クリック押すと障害物消去
・右クリックで最後に設置した障害物から消去


>NO.51123
>この計算の意味がわからないので教えていただけませんか?
相手のいる方向45度
自分の進行方向30度
45-30=15で進行方向より15ずれてるのが分かる

ただ
相手のいる方向5度
自分の進行方向350度
でも15度ずれてるが普通に引き算はできない
5-350+360 で15に出来るが45-30に360足すと375になってしまう

そこで \ を使って目的の角度として使う
\は余りを出す式
(5-350+360)\360なら15になる
(335-350+360)\360なら345になる

で、180度より大きいか小さいかで、進行方向右か左に弾があるか、見てる(if r<M_PI)
180度より小さい場合小さい程進行方向正面に弾があるって事になるので
180度から引く事で小さい程角度として、大きくなるようにしてる(M_PI-r)

180度より大きかった場合大きい程進行方向正面になるから180度を引いて180〜0になるようにしてる(r-M_PI)

/220.0)*k これは上で出来た角度を、適当に小さくして、現在の角度に与えられるようにしてるだけ
判定範囲に入ってる間毎フレーム角度変えるので小さくしてる



暇人

リンク

2012/12/15(Sat) 10:30:55|NO.51164

まずNO.51125の間違ってると思われるところ

> if (tama_mitu1!=0 || tama_mitu2!=0 || tama_mitu3!=0 || tama_mitu4!=0){
> area = 1//エリア4つでどれが一番密度が高いか確認
> if tama_mitu1 <= tama_mitu2:area = 2
> if tama_mitu2 <= tama_mitu3:area = 3
> if tama_mitu3 <= tama_mitu4:area = 4
> }else{
> goto *main
> }

これだとtama_mitu4よりtama_mitu2のが多くてもtama_mitu3がtama_mitu4より少ない場合
tama_mitu3 <= tama_mitu4 が成立してしまう

tama_mitu1=0 tama_mitu2=20 tama_mitu3=5 tama_mitu4=10 if (tama_mitu1!=0 || tama_mitu2!=0 || tama_mitu3!=0 || tama_mitu4!=0){ area = 1//エリア4つでどれが一番密度が高いか確認 if tama_mitu1 <= tama_mitu2:area = 2 if tama_mitu2 <= tama_mitu3:area = 3 if tama_mitu3 <= tama_mitu4:area = 4 } mes area
4と表示される

> ang(cnt_)=( ang(cnt_) - ((M_PI-r)/220.0)*M_PI2)\M_PI2 //左に回転((M_PI-r)正面に近いほど回転量が多い)
この式は目標角度との差が少ないほど大きく角度を変えるようにしてる(避ける用の式なので)
目標に向けたいならM_PI-rでは無くrにする
r-M_PIの方はM_PI*2-rになる


エリア振り分けのみのサンプル

#const Area_size 100 #const Area_range Area_size*Area_size dim Area_cnt,2,2 //アリア振り分けカウントを二次元配列で確保 dupptr dup_Area_cnt, varptr(Area_cnt),4*4,4 //Area_cntを一次元配列として扱えるようにクローンを作る AreaAngle=atan(-1,-1),atan(-1,1),atan(1,-1),atan(1,1) //エリアの角度(エリアナンバー) 左上(0)、右上(1)、左下(2)、右下(3) tama=100 *Reset cls button gosub"リセット",*Reset repeat tama x(cnt)=double(rnd(640)) y(cnt)=double(rnd(480)) loop repeat redraw 0 color 255,255,255 boxf color x_=mousex y_=mousey AreaCheck=0 //エリア内に一つでも弾があったかのフラグ memset Area_cnt,0,16 repeat tama boxf x(cnt)-1,y(cnt)-1,x(cnt)+1,y(cnt)+1 dx=x(cnt)-x_ dy=y(cnt)-y_ dxy=(dx*dx+dy*dy) if dxy<Area_range{//dx、dyが -Area_size〜Area_size 範囲内(以内では無い)だった if dxy {//重なって無い //Area_sizeが100だったとしてdxが-50か50ではエリアは左右に分かれるが //-50/100も50/100も0になってしまうので100の下駄を履かせて(100+50)/100として1になるようにしてる Area_cnt((Area_size+dx)/Area_size,(Area_size+dy)/Area_size)++ //エリア区分けに加算 AreaCheck++ }//重なってるのは無視 } loop circle x_-Area_size,y_-Area_size,x_+Area_size,y_+Area_size,0 //エリア範囲表示 if AreaCheck {//エリア内に弾があった AreaNo=0 //0が左上で右上、左下、右下の順で優先度が下がる(左上と右下が2個ずつ有った場合左上が選ばれる) repeat 4 //最大数を保存してる要素を探す count=dup_Area_cnt(cnt) for i,cnt+1,4 if dup_Area_cnt(i)>count { AreaNo=i continue i } next break loop color 255 line x_,y_,x_+cos(AreaAngle(AreaNo))*Area_size,y_+sin(AreaAngle(AreaNo))*Area_size } repeat 4 //エリアに振り分けられた数を表示 pos x_+cos(AreaAngle(cnt))*50,y_+sin(AreaAngle(cnt))*50 mes dup_Area_cnt(cnt) loop redraw 1 await 16 loop



暇人

リンク

2012/12/18(Tue) 20:42:25|NO.51262

dx、dyの算出方法をNO.51044等に合わせたから
NO.51164とはAreaAngleの値や扱いが少し違ってるけど

分割エリア内の弾数が多い方に進むサンプル

#const Area_size 100 #const Area_range Area_size*Area_size #const M_PI2 M_PI*2 dim Area_cnt,2,2 //エリア振り分けカウントを二次元配列で確保 dupptr dup_Area_cnt, varptr(Area_cnt),4*4,4 //Area_cntを一次元配列として扱えるようにクローンを作る AreaAngle=atan(-1,-1)+M_PI,atan(-1,1)+M_PI,atan(1,-1)+M_PI,atan(1,1)+M_PI //エリアの角度、右下(0)、左下(1)、右上(2)、左上(3) tama=30 scrx=1000 scry=800 screen 0,scrx,scry,0,200,0 *Reset cls repeat tama x(cnt)=0.0+rnd(scrx) y(cnt)=0.0+rnd(scry) spd(cnt)=(1.0*rnd(10))/10+1.0 ang(cnt)=deg2rad(rnd(360)) loop button "リセット",*Reset repeat redraw 0 color 255,255,255 boxf color repeat tama x_=x(cnt) y_=y(cnt) AreaCheck=0 //エリア内に一つでも弾があったかのフラグ memset Area_cnt,0,16 repeat tama dx=x_-x(cnt) dy=y_-y(cnt) dxy=(dx*dx+dy*dy) if dxy<Area_range {//dx、dyが -Area_size〜Area_size 範囲内(以内では無い)だった if dxy {//重なって無い //Area_sizeが100だったとしてdxが-50か50ではエリアは左右に分かれるが //-50/100も50/100も0になってしまうので100の下駄を履かせて(100+50)/100として1になるようにしてる Area_cnt((Area_size+dx)/Area_size,(Area_size+dy)/Area_size)++ AreaCheck++ }//重なってるのは無視 } loop if AreaCheck {//エリア内に弾があった AreaNo=0 //0が右下で左下、右上、左上の順で優先度が下がる(左上と右下が2個ずつ有った場合右下が選ばれる) repeat 4 //最大数を保存してる要素を探す count=dup_Area_cnt(cnt) for i,cnt+1,4 if dup_Area_cnt(i)>count { AreaNo=i continue i } next break loop r=(AreaAngle(AreaNo)-ang(cnt)+M_PI2)\M_PI2 if r<M_PI {//進行方向右側に群がある ang(cnt)+0.1//右に回転(今回は分かりやすいように一定の角度回転) }else{//進行方向左側に群がある ang(cnt)-0.1//左に回転 } ang(cnt)=(ang(cnt)+M_PI2)\M_PI2 //0以上、360度未満を超えてる可能性がるので計算に利用しやすい様に収める color repeat 4 //各エリア内の個数表示 if dup_Area_cnt(cnt) { pos x_+cos(AreaAngle(cnt))*16-8,y_+sin(AreaAngle(cnt))*16-8 mes dup_Area_cnt(cnt) } loop } x(cnt)+=cos(ang(cnt))*spd(cnt) y(cnt)+=sin(ang(cnt))*spd(cnt) boxf x(cnt)-1,y(cnt)-1,x(cnt)+1,y(cnt)+1 if AreaCheck>0 {color 255}else{color} line x(cnt),y(cnt),x(cnt)+cos(ang(cnt))*30,y(cnt)+sin(ang(cnt))*30 circle x(cnt)-Area_size,y(cnt)-Area_size,x(cnt)+Area_size,y(cnt)+Area_size,0 //エリア範囲表示 loop redraw 1 await 32 loop
実行して見れば分かるが
>一番密度の高い場所へ移動する。というものです。
このルールだけじゃ想像通りには動かないだろう
二つの弾が両方で引かれ合ってグルグル回ったり・・・



べりる

リンク

2013/1/28(Mon) 22:39:57|NO.52085

暇人さんいままでお付き合い有難うございます。

返信がかなり遅れてしまいすみません・・・。
これからもプログラムを書くのを精進していきます!



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