#include"dglib.h"
#include <math.h>
char_far gvram;
char_far bb;
// 座標
typedef struct Point
{
double x; // 座標X
double y; // 座標Y
}Point;
// ベクトル
typedef struct Vector
{
double x; // X成分
double y; // Y成分
}Vector;
Point Org; // 座標原点
Point Start; // 投射位置
Point Bullet; // 弾
Point Target; // 目標
Vector nextvect; // 初回ベクトル
Vector gravity; // 重力ベクトル
Vector shot[2]; // 次の移動ベクトル保存用
int enable[2]; // 有効なベクトルか
// 0 : 届かない 1 : 届く
// 二つ確保してるのは角度が二つあるため
#define PI 6*asin( 0.5 ) // πを求めています。 3.141592・・・・のあれの事
void OnChangeTarget( Point targetPos, double energy );
//--------------------------------------------//
// 初期化 //
//--------------------------------------------//
void Init()
{
Org.x = 50; // 画面内に表示するために座標を
Org.y = 800; // オフセットする値(適当)
Start.x = 50; // 開始位置(要は弾の発射位置、砲台)
Start.y = 300; //
gravity.x = 0; // 重力(x成分はありませんがあえてベクトルで表現しています。)
gravity.y = -9.8; // 重力加速度ですよー
Target.x = 370; // 目標位置
Target.y = 390; //
nextvect.x = 0; // 次の移動量
nextvect.y = 0; //
// 投射ターゲットセット
OnChangeTarget( Target , 80 ); // 目標座標とベクトルの大きさ(スピードみたいなもん)
// 届かない場合はenableが0を
// 表示するので値を変えて見よう!
nextvect.x = shot[0].x - gravity.x * 0.5; // 初回ベクトル 、重力の半分を加算
nextvect.y = shot[0].y - gravity.y * 0.5; // shot[1] も試してみてね(少し水平に飛ぶはず)
Bullet.x = Start.x; // 弾座標初期化
Bullet.y = Start.y; //
}
//--------------------------------------------//
// ターゲット変更 //
//--------------------------------------------//
void OnChangeTarget( Point targetPos, double energy )
{
Vector distVct; // ベクトル
int toback; // 後ろ方向か?
double dist_y,dist_x;
double a,b,c; // 計算用
double root, ts;
double agl[2]; // 角度保存用
// 角度は二つ出るので
// 試して見てください。
double maxHgt; // 最大位置
int i = 0;
Target.x = targetPos.x; // 目標座標セット
Target.y = targetPos.y; //
//ターゲットへの相対処理(ベクトルを求めています)
distVct.x = Target.x - Start.x;
distVct.y = Target.y - Start.y;
// 前方へ撃つことが前提になってる計算なので、後ろ撃つ場合に入れ替える。
dist_y = distVct.y;
dist_x = fabs( distVct.x ); // fabs() : double型の絶対値を返す
// 正か負どちらに飛ばすかでフラグをセット
if( distVct.x < 0 )
{
toback = 1; // true
}
else
{
toback = 0; // false
}
// 真上にも対応しておく
if ( distVct.x == 0 )
{
if ( distVct.y > 0 )
{
//真上
Vector v;
v.x = 0;
v.y = energy;
// Vt=V0+gtの式と y=V0t+1/2(gt^2)を使って
// 速度Vtが0になったときが最大高さとなる。
maxHgt = - ( energy * energy ) / ( 2 *gravity.y );
if ( maxHgt < dist_y )
{
//届かない
enable[0] = 0;
enable[1] = 0;
}
else
{
shot[0] = v;
shot[1] = v;
enable[0] = 1;
enable[1] = 0;
}
}
else
{
//真下
shot[0].y = energy;
shot[1].y = -energy;
enable[0] = 1;
enable[1] = 1;
}
}
else
{
//-----------------------------------
// 主に公式で計算してるのはここらへん
//-----------------------------------
a = (gravity.y * dist_x * dist_x) / ( 2.0 * energy * energy );
b = dist_x / a;
c = ( a - dist_y ) / a;
// pow()はべき乗を求めます
// 0.5乗と言うことは平方根ですね
root = pow( -c + ( b * b ) / 4.0 , 0.5 );
ts = (b*b/4) - c;
if ( ts < 0.0 )
{
//届かない
enable[0] = 0;
enable[1] = 0;
}
else
{
// 角度を求める
// 平方根の中の値で条件を満たす解は二つでる
agl[0] = atan( ( -b / 2.0 ) + root );
agl[1] = atan( ( -b / 2.0 ) - root );
// 角度から次の移動ベクトルを求める
// ここはわかるよね?
for ( i = 0; i < 2; i++ )
{
shot[i].x = energy * cos(agl[i]);
shot[i].y = energy * sin(agl[i]);
// 後ろに飛ぶなら符号を入れ替える
if ( toback == 1 )
{
shot[i].x = -shot[i].x;
}
enable[i] = 1; // true
}
}
}
}
//--------------------------------------------//
// 移動(ループ内で処理) //
//--------------------------------------------//
void Move()
{
dg_printf(50,80,255, "Enable = %d",enable[0] ); // このflgで指定した目標に届くか
// どうか調べることが可能
nextvect.y = nextvect.y + gravity.y; // あとは重力を足していく(つまり重力がかかる)
Bullet.x += nextvect.x; // 弾座標にベクトルを足して移動
Bullet.y += nextvect.y; //
}
//--------------------------------------------//
// メイン //
//--------------------------------------------//
int main(){
double by,ty,sy;
dg_setscreen(10,10,700, 700, 0, "bez");
bb = dg_createBB();
// 初期化
Init();
do{
dg_gcls(bb, 0);
// 移動処理
Move();
//------------------------------------------------------------
// Y軸が計算系と逆向きなので見やすく原点位置を足し
// Y軸方向を逆にしてます
//------------------------------------------------------------
by = -Bullet.y;
ty = -Target.y;
sy = -Start.y;
dg_pset(bb, Org.x + Bullet.x , Org.y + by , RGB(255, 255, 255));
dg_pset(bb, Org.x + Target.x, Org.y + ty , RGB(255, 255, 255));
dg_pset(bb, Org.x + Start.x, Org.y + sy , RGB(255, 255, 255));
//------------------------------------------------------------
// 本来の表示
//------------------------------------------------------------
//dg_pset(bb, Bullet.x , Bullet.y , RGB(255, 255, 255));
//dg_pset(bb, Target.x , Target.y , RGB(255, 255, 255));
//dg_pset(bb, Start.x , Start.y , RGB(255, 255, 255));
//------------------------------------------------------------
// 座標が一定値以下で初期化
if( by >= 700 )
{
Init();
}
dg_flip(gvram, bb);
ML();
Sleep(30);
}while(getch3('E') != 1);
dg_deleteBB(bb);
return 0;
}
COMMENT