忍者ブログ

神戸電子専門学校ゲームソフト学科の生徒が運営するGESのブログです。

   

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

目標を狙い撃つ!

どうも、たくあんですよ~
今回は目標を放射線状に狙い撃つプログラムです。


ある理由からこのコードは正直2Dではあんまり実用性ないかも知れないw

コードを理解し改造すれば使えるけどね!



拍手[0回]



このプログラムはC++で書かれていたものを無理やり私がC言語のdglib対応にしたモノです。
一応コード改良オーケーのソースだったので、色々いじってみました。

まぁ酷いコードですが、実験位にはなると思うので。

試してみてください。


簡単に言うと、仕様については、ターゲットの座標から、公式を使って発射角度を求める。


具体的な公式は斜方投射で調べればいくらでも見つかるので調べて下さい。
(ブログで平方根とか、分数を表しにくいんだよ。 ごめんねw)

その公式から atan() を使い( tan()の逆関数だっけ? )で角度を求めています。
※ atan() はアークタンジェントと読むんだよ。

んでその角度から初回移動ベクトルを求め、
あとはループ内でただ重力を足し続けるだけでおkです。


あとはもう解説しません。
コメントいっぱい書いたんで・・・・

//---------------------------------------------------------
 
#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;
}

//---------------------------------------------------------

ん~貼り付けたらガタガタになったから、なおしてみたけどうまくいかないなぁ


そうそう、ある理由を言ってなかった!
この計算はグラフ上で各ベクトルを考えた時のもので、Y軸の正が上方向になっています。

これはどういう事かわかるだろうか?

つまりdglibと逆になっている。
なので私のほうで無理やりなおして表示しています。


今回何故なおさなかったかと言うと、そのままコピペして使う人がでそうだったので、
しっかり理解して使わないと改造もできないだろうと考えたからです。


まぁ何とでもなりそうだけどねw

一度試して見て、色々実験してみて下さい!

以上!!


実はこれ、3Dなら速攻で実装できる。敵を狙う砲台とかを使いたいならどうぞ。
うまく行くかは保証しませんので、自己判断でお願いします。



PR

COMMENT

NAME
TITLE
MAIL(非公開)
URL
EMOJI
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
COMMENT
PASS(コメント編集に必須です)
SECRET
管理人のみ閲覧できます

TRACKBACK

Trackback URL:

ブログ内検索

最新コメント

[01/29 人面犬]
[10/01 8ch]
[09/12 uncle]
[09/10 某卒業生]
[06/07 uncle]

カレンダー

03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

テスト

Copyright ©  -- GESブログ --  All Rights Reserved
Design by CriCri / Photo by Geralt / powered by NINJA TOOLS / 忍者ブログ / [PR]