; ; 着弾予測 ; ;弾道、飛距離、の予想。弾丸の発射が行えます。 ; #include "hspmath.as" ; asinで使用 ; 定数 #const BULLET_FRAME 50 groundTop = 400.0 ; 地面の高さ gravity = -1.0 ; 重力 velocity = 20.0 ; 初速 ; 初期値 bulletPosX = 50.0 ; 弾丸座標 bulletPosY = 0.0 ; 弾丸座標 firingAngle = 45.0 * M_PI / 180.0 ; 発射角度[rad] setHikyori = 200.0 ;設定飛距離(この飛距離を出すための発射角度を算出します。) flgShot = 0 ; ショットフラグ vx = 0.0 vy = 0.0 ddim courseOfBullet, BULLET_FRAME, 2 ; 弾道座標データ ;----------------------------------------------------------- ; ; メインループ ; *main redraw 1 : await 16 : redraw 0 : color 255, 255, 255 : boxf : color 0,0,0 : pos 0,0 stick key, 1|2|4|8|128 ; -------------- ; 終了 ; -------------- if key&128 : end ; -------------- ; 発射角度 ; -------------- if key&2 : firingAngle += 1.0 * M_PI / 180.0 if key&8 : firingAngle -= 1.0 * M_PI / 180.0 ; -------------- ; 発射 ; -------------- if key&16 : flgShot = 1 ; -------------- ; 物理計算 ; -------------- ; 重力 if int(bulletPosY) > 0 { vy += gravity } else { vx = 0.0 vy = 0.0 } ; ショット if flgShot = 1 { ; 初速 vx = velocity * cos(firingAngle) vy = velocity * sin(firingAngle) + gravity / 2.0 ;微調整のため適当に1/2しています。最初だけ1/2倍しないと計算が大きくずれるようです。 ;射出時は地面に付いているのでってことで、詳細な考察は省略。 flgShot = 0 } ; 予備計算 px = bulletPosX py = bulletPosY px += vx py += vy ; 地面 if py < 0.0 { ;予測地点が地面にめり込む場合 bulletPosX += vx * bulletPosY/-vy bulletPosY = 0.0 } else { bulletPosX += vx bulletPosY += vy } ; 弾道計算 gosub *CalcDandou ; 飛距離予測計算 gosub *CalcHikyori ; -------------- ; 描画 ; -------------- line 0, groundTop, ginfo_winx, groundTop gosub *PlotDandou gosub *PlotBullet pos 0, 0 : color 0,0,0 mes "現在の座標:" + bulletPosX + ", " + bulletPosY mes "予想飛距離:" + yosouHikyoriX mes "予想座標 :" + (bulletPosX + yosouHikyoriX) + ", 0.0" mes "予想角度(距離 " + setHikyori + "):" + rad2deg(yosouKaku) + " [deg] or " + (90.0-rad2deg(yosouKaku)) + " [deg]" goto *main ;----------------------------------------------------------- ; ; 弾道軌道描画 ; *PlotDandou ; -------------- ; 弾道軌道 ; -------------- color 200, 200, 200 x = courseOfBullet(0, 0) y = courseOfBullet(0, 1) * -1 + groundTop pos x, y repeat BULLET_FRAME-1, 1 x = courseOfBullet(cnt, 0) y = courseOfBullet(cnt, 1) * -1 + groundTop line x, y loop return ;----------------------------------------------------------- ; ; 弾丸描画 ; *PlotBullet ; -------------- ; 発射角度 ; -------------- x = bulletPosX y = -bulletPosY + groundTop r = 30.0 dx = r * cos(firingAngle) + x dy = -r * sin(firingAngle) + y color 0,0,255 line x, y, dx, dy mes strf("%.2f", (firingAngle*180.0/M_PI) ) + " [deg]" mes "Up:↑/Down:↓" ; -------------- ; 弾丸 ; -------------- x = bulletPosX y = -bulletPosY + groundTop r = 5 color 0,0,0 circle x-r, y-r, x+r, y+r return ;----------------------------------------------------------- ; ; 弾道予想計算 ; *CalcDandou cvx = velocity * cos(firingAngle) cvy = velocity * sin(firingAngle) + gravity/2.0 ;0フレーム目 courseOfBullet(0, 0) = bulletPosX courseOfBullet(0, 1) = bulletPosY ;1フレーム目 repeat BULLET_FRAME-1, 1 courseOfBullet(cnt, 0) = courseOfBullet(cnt-1, 0) + cvx courseOfBullet(cnt, 1) = courseOfBullet(cnt-1, 1) + cvy + gravity * (cnt-1) loop return ;----------------------------------------------------------- ; ; 飛距離予想計算 ; *CalcHikyori ;重力加速度:g ;t秒後の移動距離:x,y ;ただし上向きを正とする ;したがって重力加速度gは g<0 である。 ;着弾点は射出点との高低差0とする。 ; ;時刻tのときの距離座標x,yは次式のようになる。 ; ; x = vx0 * t ; y = 1/2*g*t^2 + vy0 * t ; ;着弾点と射出点は高低差0なので y = 0 のときの t を求める ;(なお高低差0以外ならy=高低差として計算すれば良い。) ; ; 0 = 1/2*g*t^2 + vy0 * t ; = t(1/2*g*t + vy0) ; ; (1/2*g*t + vy0) = 0 ; 1/2*g*t = -vy0 ; t = -vy0 * 2/g ; ;y = 0となるtは、 ; t = 0 ; t = -vy0 * 2/g ;t = 0は射出時なので、t = -vy0 * 2/g となる。 ;このときxは ; ; x = vx0 * t ; = vx0 * -vy0 * 2/g ; ;射出角をrとしたとき ; vx0 = v0 * cos(r) ; vy0 = v0 * sin(r) ; ;したがってxは次のようになる。 ; ; x = -v0^2 * cos(r) * sin(r) * 2/g ; ;xがそのまま距離なので yosouHikyoriX = -1.0 * velocity * velocity * cos(firingAngle) * sin(firingAngle) * 2.0 / gravity ; ;xを任意の値に決めたい場合のrを求める。 ; x = -v0^2 * cos(r) * sin(r) * 2/g ; cos(r) * sin(r) = x / (-v0^2) * g/2 ; ;ここで加法定理 ; sin(x+y) = sin(x) * cos(y) + cos(x) * sin(y) ; y=xの場合 ; sin(2*x) = 2 * sin(x) * cos(x) ; 1/2 * sin(2*x) = sin(x) * cos(x) ; ;したがって ; cos(r) * sin(r) = x / (-v0^2) * g/2 ; 1/2 * sin(2*r) = x / (-v0^2) * g/2 ; sin(2*r) = x / (-v0^2) * g ; 2 * r = asin( x / (-v0^2) * g ) ; r = 1/2 * asin( x / (-v0^2) * g ) ;となり角度を求めることができる。rは複数でるがどれを用いても良い。 ; yosouKaku = asin( setHikyori / (-velocity * velocity) * gravity ) / 2.0 return