|
|
|
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 ;繰り返し
| |
|
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
の部分を書き換えてください
| |
|
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さんに感謝いたします。おかげさまで少し前進しました。
| |
|
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
| |
|
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
暇人さんいままでお付き合い有難うございます。
返信がかなり遅れてしまいすみません・・・。
これからもプログラムを書くのを精進していきます!
|
|