|
7.キャラ(画像)の移動と制御文 |
上下左右斜めに移動するプログラム。プログラム全体は最後に書いています。 |
|
#define PLAYER_MOVE_SPEED 5
int joypad_state=0; //ジョイスティック&キー入力 joypad_state=GetJoypadInputState(DX_INPUT_KEY_PAD1);
if((joypad_state&PAD_INPUT_UP)!=0)player_position_y-=PLAYER_MOVE_SPEED;
if((joypad_state&PAD_INPUT_DOWN)!=0)player_position_y+=PLAYER_MOVE_SPEED;
if((joypad_state&PAD_INPUT_LEFT)!=0)player_position_x-=PLAYER_MOVE_SPEED;
if((joypad_state&PAD_INPUT_RIGHT)!=0)player_position_x+=PLAYER_MOVE_SPEED;
|
変数の説明 |
#define PLAYER_MOVE_SPEED 5
プレイヤーが動くスピードを定数に
int joypad_state=0;
ジョイパッドの状態を入れる変数
|
[関数の説明1] |
|
GetJoypadInputState(DX_INPUT_KEY_PAD1)
main関数のように()が付いているので関数だとわかると思います。
前回の説明で DX_INPUT_KEY_PAD1が定数だとわかるでしょう。
DXライブラリを使いやすくするために、識別コードを文字列として宣言してくれています。
あとは、英単語の意味を和訳すると、
ジョイパッドの入力状態をゲット(キー ジョイパット1)となります。
リファレンスを読まなくてもこれだけのことがわかります。
関数や定数・変数の記述ルールを覚えたおかげで、
ソースの理解力が上がっていることを実感できるのではないでしょうか。
Cなどの書籍で、いろいろな関数を解説していますが、すべて覚える必要などありません。
使わない関数がたくさんあると思います。
へそ曲がりな関数でない限り、見ただけでそれなりに何をする関数かわかるのです。
使うときにリファレンスを見て、見れば使い方がわかります。
一度使った関数は、名前を見ただけでどんな使い方をするのか思い出すでしょう。
|
|
|
[宣言] 宣言書式
関数の型やパラメータを読み取る事ができます。
[概略] 簡単な説明
[引数] どんなパラメータを関数の()内に入れるか。
関数内部の変数に渡す初期値
[戻り値]どんなパラメータが戻ってくるか。
関数内部から持って帰ってくる数字(処理結果)
[宣言]で宣言されている型の変数が戻ってきます。
[解説] 詳しい解説
|
[宣言] |
変数の宣言を説明しましたが、今回は全般的な宣言です。
C++では何を使うにしても、使う前に基本的に宣言しなければなりません。
一部、 C++内部で宣言されているものがあります。
例えば、TRUE定数やmain()関数・if()関数などです。
関数も例に漏れず、宣言しなければなりません。
GetJoypadInputState() は、 どこで宣言されているのでしょうか?
実は #include "DxLib.h"で宣言されたDxLib内で宣言されているのです。
宣言されたそのまた中で宣言されているのです。
外部で宣言されているものは、#(プリプロセッサ)で宣言できます。
#include "DxLib.h"で、まとめて宣言してるって感じです。
内部では int GetJoypadInputState(int InputType);と宣言されています。
見てわかるとおり関数もある意味変数みたいなものです。
変数だということは、数字をもてます。それが戻り値です。
この場合戻り値はintになります。
受け取る変数(joypad_state)もintにしなければなりません。
注意
#include "DxLib.h"を使っていると言う事は、
逆にDxLib.h内で宣言された定数や関数はグローバルです。
同じ名前の定数や関数はダブルので新たに宣言できません。
ソース上でダブって作っているものがないのに、
宣言エラーが出た場合、リファレンスを見てみましょう。
使われている名前かもしれません。
|
制御文 ( if ) ( while ) |
|
判断(分岐)をする文章です。
if( )文とwhile( )文とfor( )文が代表的なもので、ほとんどの場合この三つしか使いません。
他に、swith( )文やgoto文がありますが、goto文にいたっては、使わないことが推奨されています。ソースが読みにくくなるからです。
ベーシックは、プログラムが大きくなると解読が難しいプログラムになっていきます。
goto文が多用されるのが、その理由に含まれているでしょう。
ここでは、if( )文とwhile( )文の説明をしていきます。
|
制御文( if ) |
if ( A )
{
B
}
else
{
C
} |
もし(A)が真実ならば{ B }を実行。
(A)が誤りならば{ C }を実行します。
この文章は、
if ( A ) B
else C
と書くこともできます。
else は、いらなければ省略できます。省略したものが下です。
[例]
if( DxLib_Init()==-1) return-1;
DXライブラリの初期化は、 DxLib_Init(); と書くだけでいいのですが、もし初期化に失敗したままプログラムが実行されると、予想もつかないことになるかもしれません。保険としていつもつけましょう。
そのため、if文を使って判断しているのです。
ですから、 if( DxLib_Init()==-1) return-1; は変更の必要がないのです。
DxLib_Init() は、初期化を実行します。初期化に失敗すると、戻り値が「-1」になります。
DxLib_Init() が-1になると、( )内が真実になり、 return-1; が実行され、プログラムが終了するのです。 (下記表参照) |
|
制御文( while ) |
while( A )
{
// B ここに
//アルゴリズムを書く
} C |
(A)が真実でい続ける間、すっと{ B }を実行する。
{ }の最後まで行くと、またwhile(A)から実行されます。
ぐるぐる回り続けます(ループする)。
(A)が真実でなくなると、Cの位置にループから脱出します。
|
|
いままで、
while(ProcessMessage()==0) { }
にお世話になっていました。解説します。
ProcessMessage() は、16ミリ秒程度に一度、実行しなければなりません。
システムに関わる事なので、あまり気にすることはありません。
ProcessMessage() は、戻り値を持っています。
システムでエラーが発生すると-1を返してきます。
ProcessMessage()が-1になると、真実ではなくなるので、ループを脱出します。(下記表参照)
すると、上に書かれた }C の部分に出てきます。
そのあと、終了処理をするので、正常にプログラムを終了できます。 |
実際には、 ProcessMessage() がエラーを持って帰ることはほとんどありません。
すると、無限ループ(暴走ともいえる)になります。
なので、このループから抜けるために、 break; をどこかに書かなければなりません。
break; は、ループから抜ける命令です。
if(CheckHitKey(KEY_INPUT_ESCAPE)==TRUE)break;
が書かれています。
見てすぐ理解できそうですね^^。
ESCキーが押されれば、ループから脱出するって事です。
while(ProcessMessage()==0)
{
if(CheckHitKey(KEY_INPUT_ESCAPE)==TRUE)break;
}
は、1セットになっていると考えたほうがいいでしょう。
|
演算子 |
代表的な演算子を表にします。
演算子は、数学を勉強していればそんなに覚えることはありません。
演算子には、優先度と、方向があります。
下の表では、 優先度の高い順 に書いています。
方向は、左と書かれていれば左から右へ演算されます。
演算子
| 解説
| 例
| 方向 |
()
| ()で囲まれている場所を先に演算せよ
| (x+y)
| |
++
| 左の変数に1を足せ x++;は、x=x+1;と同じ意味
| x++
| 左 |
--
| 左の変数に1を引け x--;は、x=x-1;と同じ意味
| y--
| 左 |
&
| 右の変数のアドレス
| &x
| 右 |
*
| 右のポインタ変数の指すアドレス内にある内容
| *x
| 右 |
計算式
|
*
| 掛け算
| x * y
| 左 |
/
| 割り算
| x / y
| 左 |
%
| 左から右を割ったときの余り
| x % y
| 左 |
+
| 足し算
| x + y
| 左 |
-
| 引き算
| x - y
| 左 |
比較演算子 真実であれば「1」になる
|
<
| 左より大きい
| x < y
| 左 |
<=
| 左と同じ、もしくは大きい
| x <= y
| 左 |
>
| 左より小さい
| x > y
| 左 |
>=
| 左と同じ、もしくは小さい
| x >= y
| 左 |
==
| 等しい
| x == y
| 左 |
!=
| 等しくない
| x != y
| 左 |
|
&
| ビット毎のAND 低レベルビット演算
|
x&y
| 左 |
&&
| 左が真実で右が真実。左右両方が真実
| x && y
| 左 |
||
| 左か右が真実。どちらかが真実
| x || y
| 左 |
代入演算子 ( 「=」は、数学の「=」とは違います。数学の「=」は「==」のほうが近いでしょう )
|
=
| 右の数字(もしくは変数)を左に代入
| x = y
| 右 |
+=
-=
*=
/=
%=
| 知らなくてもよいことではありますが、他人のソースに出てくるときがよくあります。
ソースを読むためにも、頭のすみにおいておきましょう。
x=x+1; と x+=1; は同じです。
右の数字に左の数字を足して、左に代入する
| x += y
x -= y
x *= y
x /= y
x %= y
| 右 |
|
演算子の例題 読み流しゾーン |
if((joypad_state&PAD_INPUT_UP)!=0)player_position_y-=PLAYER_MOVE_SPEED;
わかりにくい演算子が3個使われています。
joypad_state&PAD_INPUT_UP
2進数(ビット単位)で積演算します。
下に説明を書きますが理解する必要はありません。
「&はこんなことをしているのか」程度でいいです。
例えば、0000の4桁目を上・3桁目を下・2桁目を左・1桁目を右とします。
すると PAD_INPUT_UPは上ですから、1000になります。
joypad_stateは押されているボタンの結果をビット単位で持っています。
上右が押されると1001になります。
1001&1000で1ビットずつ比較して、両方にセットされているビットを返します。
上の場合1000になります。10進数の8になります。
何も押されていなければ、0000になります。
PAD_INPUT_UPを宣言してくれているので、ビットを気にすることなく使用できます。 |
(joypad_state&PAD_INPUT_UP)!=0
ボタンが押されていなければ0になります。
0は0と等しいので誤りとなり、後ろの文章が実行されません。
ボタンが押されていれば上の例では8になります。
等しくなくなるので真実になり、後ろの文章が実行されます。 |
player_position_y-=PLAYER_MOVE_SPEED
player_position_y=player_position_y-PLAYER_MOVE_SPEED
と同じ意味です。
|
「 = 」と「 == 」 |
「 = 」と「 == 」はまったく別のもので、 覚えていてもたまに間違えるので気をつけましょう。
「 = 」は、数学の「 = 」とは別物です。
右の数字を、左に代入する命令です。
感覚的には「 x<-Y 」というイメージです。 「 -> 」は別の命令で使いますので、間違って覚えないように。
「 == 」は、比較演算子で(A == B)であれば、AとBが同じ時、「1」(真実)になります。
[例]
AとBを比較して分岐するとき
if( A=B )
とすると、 AにBが代入されることになります。
正しくは、
f( A==B )
です。
|
キャラ(画像)を上下左右斜めに移動するプログラム(C++サンプルプログラムソース) |
|
//ライブラリ宣言
#include "DxLib.h"
//定数の宣言
#define PLAYER_SIZE 50
#define PLAYER_SIZE_HALF PLAYER_SIZE/2
#define PLAYER_MOVE_SPEED 5
//WinMain関数
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// DXライブラリの設定
// SetOutApplicationLogValidFlag(TRUE);
SetGraphMode(640,480,16);
ChangeWindowMode( TRUE ) ;
if( DxLib_Init()==-1) return-1;
// SetMouseDispFlag( TRUE ) ;
SetDrawScreen(DX_SCREEN_BACK);
//変数の宣言と初期化
int player_position_x=320;
int player_position_y=240;
int player_graph=LoadGraph("Player.png");
int joypad_state=0;
//メインループ
while(ProcessMessage()==0)
{
//ジョイスティック&キー入力
joypad_state=GetJoypadInputState(DX_INPUT_KEY_PAD1);
if((joypad_state&PAD_INPUT_UP)!=0)player_position_y-=PLAYER_MOVE_SPEED;
if((joypad_state&PAD_INPUT_DOWN)!=0)player_position_y+=PLAYER_MOVE_SPEED;
if((joypad_state&PAD_INPUT_LEFT)!=0)player_position_x-=PLAYER_MOVE_SPEED;
if((joypad_state&PAD_INPUT_RIGHT)!=0)player_position_x+=PLAYER_MOVE_SPEED;
//キャラの描画
ClsDrawScreen() ;
DrawGraph(player_position_x-PLAYER_SIZE_HALF,
player_position_y-PLAYER_SIZE_HALF, player_graph,TRUE);
ScreenFlip();
// ESCキーが押されたらループから抜ける
if(CheckHitKey(KEY_INPUT_ESCAPE)==TRUE)break;
}
//終了処理
DxLib_End();
return 0;
} |