;
; 着弾予測
;
;弾道、飛距離、の予想。弾丸の発射が行えます。
;
#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