s13. sin,cosって何? シューティングの基本概念

中学の頃数学で「サインコサイン」って習ったと思います。

数学が苦手な人にとってはサインコサインと聞くだけで寒気がしてしまうかもしれません。

「あの時勉強しとけばよかった・・。シューティング作れないじゃん」と思ってる人もいらっしゃるかもしれません。

しかしサインコサインの概念なんて超簡単です。

「難しそう」という数学の固定概念を捨てて解説をみてみてください。



今上のような直角三角形があるとします。

サインとはR分のYのことです。

コサインとはR分のXのことです。

ただそれだけのことです。

だから何?

はい。1分のYってYのことですよね。

ここでRを1とすると、サインθはまさにYのことになりますよね。

同様にコサインθはXのことになります。

これをシューティングに応用してみましょう。

今aの位置にいるとしますね。角度θで飛んでいる弾は次の瞬間bまで移動したいとします。

弾の座標はxとyであらわしているわけですから、xとyそれぞれ値を移動に合うように加算してやればいいのです。

ではx,yそれぞれいくら足してやればいいでしょうか?

Rが1の時Yはサインθでした。じゃ長さがRの時は「サインθ×R」ですよね。つまりYの移動分はサインθ×R。

同様にXの移動分は「コサインθ×R」ですね。これで角度からX,Yの移動分が計算できました。

これを加算してやればその方向に移動できますね。

ここで円周率という言葉を思い出してください。3.1415926...と覚えたと思います。

円を360度とする度数法と円を2×円周率とする弧度法という2種類の表し方があったの覚えているでしょうか。

プログラムで使う角度はこの後者、弧度法を使います。

ですから180度はπ、90度はπ/2、45度はπ/4と表します。1度はいくらでしょうか?

π/180ですね。

弾の構造体にx,yそして先ほどの例で言うRであるスピード、θであるangleを定義し、弾情報を作り、描画してみましょう。

サンプルはZキーが押されるたびに初期位置(画面中央)に戻り、PI/5ずつ角度を変化させてとんでいきます。

10回キーをおして1周するごとにスピードが1増えていきます。

↓コピー&コンパイル用サンプルプログラム↓


#include "DxLib.h"
#include <math.h>
 
//円周率
#define PI 3.14159265358979323846
 
//弾の構造体
typedef struct{
    double x,y;  //座標
    double speed;//スピード
    double angle;//角度
}bullet_t;
//弾
bullet_t bullet;
//キー
int Key[256];
 
//キー入力監視関数
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key[i]==1) GetHitKeyStateAll_InputKey[i]++;
        else                            GetHitKeyStateAll_InputKey[i]=0;
    }
    return 0;
}
 
//初期化
void ini(){
    static int count=0;
    static double angle=0;
    static double speed=1;
    bullet.x = 320;    bullet.y = 240;//座標代入
    bullet.angle = angle;//角度代入
    bullet.speed = speed;//スピード代入
    count++;
    angle += PI/5;//π/5ずつ回転
    if(count % 10 == 0)
        speed++;
}
 
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
 
    int image[16];
    LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image );//画像を分割してimage配列に保存
 
    ini();//初期化
 
    while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
 
        bullet.x += cos( bullet.angle ) * bullet.speed ; //x座標計算
        bullet.y += sin( bullet.angle ) * bullet.speed ; //y座標計算
 
        if( Key[KEY_INPUT_Z] == 2 )//Zキーが押されたら初期化
            ini();
 
                //描画
        DrawRotaGraphF( (float)bullet.x , (float)bullet.y , 1.0 , bullet.angle+PI/2 , image[8] , TRUE );
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}

実行結果

→掲示板で質問する



- Remical Soft -