27. ジャンプの考え方1(物理)
物理大好き!な人の為のページです。
物理的な知識は無くてもプログラムを作る事には困らないので、27章、28章は興味のある方のみ見て頂ければと思います。
では、節の内容をはじめます。
マリオのようにジャンプするアクションを作る事がありますよね。
ジャンプを厳密な方法で表現しようとすると物理の知識が必要ですね。
物理にはとっても有名な@式とA式がありますね(下図参照)。この2式を用いて計算します。
プログラムでは常にyの座標を計算する必要が出てきますね。
@式ように時間とともに変化するyの値を常に計算する必要があります。
しかし@式のままではVo(初速度)を代入する必要があります。
描きたい放物線がある時、地点0から頂点までの距離はわかっても、初速度はわからないですよね。
プログラムで描きたい放物線は例えば「2m上まで投げ上げた時の時間とともに変化するy」とかいうときですよね。
つまり初速度はわかっておらず、初速度を代入しなければならない式はふさわしくないわけです。
ですからA式から@式に代入して、Voの無い式にしましょう。
すると図からB式が作り出せますね。
これはプログラムではこのように表せます。
y = sqrt ( 2.000 * g * y_max) * t - 0.500 * g * t * t;
今回の設定では縦が480ピクセル(のうちキャラが32ピクセル)ですから、480−32=448
y = (int) ((sqrt ( 2.000 * g * y_max) * t - 0.500 * g * t * t) * 448.000
/ y_max);
こう書くことで、画面の縦のドット数と放物線のt=0の地点から頂点までの幅がピッタリになります。
それではプログラムの解説をします。
if( Key[ KEY_INPUT_RETURN ] == 1 ){
time1 = GetNowCount();
flag=1;
}
もしエンターが押されたら、飛び上がりフラグflag=1をたてる。
time1 = GetNowCount();によってエンターの押した時間をミリ秒で取得する。
if(flag==1){
time2 = GetNowCount() ; // 現在経過時間を得る
t = (double)(time2 - time1) / 1000.000;
y = (int)((sqrt ( 2.000 * g * y_max) * t - 0.500 * g * t * t ) * 480.000
/ y_max);
飛び上がりフラグが立っている時、time2に今の時間を格納し、tにミリ秒を秒に変換してdoubleで格納。
yは先ほど紹介したとおり代入する。
if(y>=0)
DrawGraph( x , 480-y , image[13] , TRUE );
else
flag=0;
}
また、y>=0の時に描画し、画面の外に出たら、飛び上がりフラグを戻す。
これらをまとめてサンプルプログラムを書いたので見てください。
#include "DxLib.h" #include <math.h> #define g 9.8067 #define y_max 2.000 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ ChangeWindowMode( TRUE ) ; // ウインドウモードに変更 if( DxLib_Init() == -1 ) return -1; //DXライブラリ初期化 エラーが起きたら終了 int x=320,y=480,image[16],time1,time2,flag=0; double t; char Key[256]; SetDrawScreen( DX_SCREEN_BACK ) ;//描画先を裏画面に設定 LoadDivGraph( "char.png" , 16 , 4 , 4 , 32 , 32 , image ) ;//画像を分割してimage配列に保存 while(1){ ClearDrawScreen();//裏画面のデータを全て削除 GetHitKeyStateAll( Key ) ; // すべてのキーの状態を得る if( ProcessMessage() == -1 ) break ; //異常がおきたら終了 if( Key[ KEY_INPUT_RETURN ] == 1 ){ //エンターが押されたら time1 = GetNowCount(); //time1にエンターが押された時の時間を格納 flag=1; //飛び上がりフラグを立てる。 } if(flag==1){ time2 = GetNowCount() ; // 現在経過時間を得る t = (double)(time2 - time1) / 1000.000; // ミリ秒を秒に変換して、エンターが押されてからの経過時間を計算 y = (int)((sqrt ( 2.000 * g * y_max) * t - 0.500 * g * t * t ) * 480.000 / y_max);//y座標を計算 if(y>=0) // 1回目に回って来たか、画面内にy座標がある時 DrawGraph( x , 480-y , image[8] , TRUE );//画像を描画 else flag=0; // 画面外に来ると、飛び上がりフラグを戻す } if( Key[ KEY_INPUT_ESCAPE ] == 1 ) break; //Escボタンが押されたらブレイク ScreenFlip() ; //裏画面データを表画面へ反映 } DxLib_End() ; // DXライブラリ使用の終了処理 return 0 ; // ソフトの終了 }
実行結果
注意:黄色い線と文字は表示されません。
- Remical Soft -