2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++の勉強しながらDxLibで2Dゲーム作ってみない?(実践編)②

Last updated at Posted at 2020-11-29

今回の目標

変数を扱えるようになったところで今回はc++では条件分岐、DxLibではキー入力を使えるように頑張りましょう!
変数が使えることが前提の内容になるので前回の内容は習得しておくとスムーズに進むと思います(*'▽')
前回の記事 : C++の勉強しながらDxLibで2Dゲーム作ってみない?(実践編)①

この記事の対象

・Dxlibを使いゲーム開発をしてみたい方
・C++を始めたばかりの初心者の方で作りながら覚えたい方
・何かしらのライブラリやツールを使ってゲーム開発をしてみたい人方

#前回のおさらい
前回は変数と描画関数について触れました。
その中でint型(整数型)というのが出てきましたがこれは宣言して代入や四則演算ができましたね?
またインクリメントやでクリメントなんて使い方もありました。
具体的に変数はこのように扱います。
※前回も当たり前のように登場していた///**/ですがこれはコメントアウトといいプログラムにコメントを追加する機能です。(説明不足)

//int型のxという変数を宣言し0で初期化(代入)
int x = 0;

//int型のyという変数を宣言し10で初期化(代入)
int y = 10;

//int型変数xにint型変数yを加算
x += y;

//int型変数xをインクリメント(+1)
x++;

今回はこれらの変数と条件分岐を使い"スクリーンセーバーのあれ"を作りましょう。
おそらく作ってたら気づきます。

条件分岐(if-else文)

C++ではifという条件分岐が存在します。
このifは基本的にこのような使い方になります。

if(/*条件式*/){
   //処理
}

if( )内に書かれた条件式がtrue(真)の場合{ }内の処理がされます。
例えば変数xが100より大きくなった場合のif文はこのように書きます。

if(x > 100){
   //処理
}

このコードではx100より大きくならないと実行されませんが、そうじゃない場合の処理も書く場合はこのようになります。

if(x > 100){
   //処理
}
else{
   //処理
}

この場合はif文で条件がtrueにならなかった場合else内の処理が実行されます。
また、このif文での条件式に使われる記号は演算子といいます。
C++ではいくつかの演算子が存在しますが変数より数が少なく説明しやすいので今回は記事中で説明してみます。
以下の表では式が成立した場合true(真)を、そうでなかった場合はfalse(偽)を返します

演算子 意味
< x < y xがyより小さい場合
> x > y xがyより大きい場合
<= x <= y xが以下の場合
>= x >= y xがy以上の場合
== x == y xとyが等しい場合
!= x != y xよyが等しくない場合

ここまで使えるようになると"スクリーンセーバーのあれ"が作れるようになります。
まずはこのようなコードを書いてみてください。
else ifがでてきますが 後程説明します。

main.cpp
#include "DxLib.h"

const char *TITLE = "Untitled";
const int WIN_WIDTH = 960;
const int WIN_HEIGHT = 540;

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
	ChangeWindowMode(true);
	SetWindowSizeChangeEnableFlag(false, false);
	SetMainWindowText(TITLE);
	SetGraphMode(WIN_WIDTH, WIN_HEIGHT, 32);
	SetWindowSizeExtendRate(1.0);
	SetBackgroundColor(35, 35, 35);
	SetDrawScreen(DX_SCREEN_BACK);

	if (DxLib_Init() == -1) { return -1; }

	int speed_x = 5;
	int speed_y = 5;
	int x = 100;
	int y = 100;
	int size = 50;

	while (true) {
		ClearDrawScreen();

		if (x <= 0) {
			speed_x = -speed_x;
		}
		else if (x >= WIN_WIDTH - size) {
			speed_x = -speed_x;
		}
		if (y <= 0) {
			speed_y = -speed_y;
		}
		else if (y >= WIN_HEIGHT - size) {
			speed_y = -speed_y;
		}

		x += speed_x;
		y += speed_y;

		DrawBox(x, y, x + size, y + size, GetColor(255, 255, 255), true);

		ScreenFlip();
		WaitTimer(20);
		if (ProcessMessage() == -1) { break; }
		if (CheckHitKey(KEY_INPUT_ESCAPE) == 1) { break; }
	}

	DxLib_End();
	return 0;
}

今回はx方向に5、y方向に5を加算し、壁に当たったら跳ね返るという処理を書きました。
x,yどちらも処理がたいして変わらないためxだけ説明していきます。
x方向の条件式ではこのように書かれています。

if (x <= 0) {
   speed_x = -speed_x;
}
else if (x >= WIN_WIDTH - size) {
   speed_x = -speed_x;
}

この部分ではspeed_xという変数をxが壁に当たったら反転する処理をしています。
最初のifではx0以下になった場合(左側の壁に当たった場合)変数speed_xをの値を反転します。
こうすることで壁に当たった場合壁とは反対側に四角形を移動するようにしています。

次のelse ifというのは上のifがfalse(偽)であり、なおかつelse if()()内の条件がtrue(真)の場合に実行されます。
elseにただifがくっついただけです。
そしてこのelse ifでは右側の壁に当たった場合の処理をしています。
WIN_WIDTHが画面サイズなので画面サイズから四角形の一辺のサイズを引くことで左上をもとに描画しているため右の壁に四角形の右側の辺が当たった場合変数speed_xを反転し反対側に四角形を移動するようにしています。
そしてこのコードを実行するとこのような動きになります。
ScreenSave.gif
これ、見たことありませんか?
"スクリーンセーバーのあれ"です。
条件分岐を使えるとこんなことができるようになります。
それでは次のキー入力でさらに応用していきましょう。

キー入力

おそらく多くのゲームではキーボードやマウス、それにコントローラーなどキー入力をしてプレイヤーを操作しますよね。
ゲームにおいてキー入力は必須といっても過言ではないかと思います(一部そうではないゲームはありますが...)
ですのでこのキー入力と条件分岐を応用してプレイヤーの操作をしていきましょう。

・CheckHitKey関数

CheckHitKeyはDxLibで用意されている関数でこれを使うことによりキー入力を知ることができます。
そして便利なことにDxLibではキーがマクロ登録されているのでスペースキーが押されているか知りたい場合はCheckHitKeyKEY_INPUT_SPACEというマクロを引数で渡してあげるだけでわかります。
先ほどのコードを一部変えてこのようなコードを書いてみてください。

main.cpp
#include "DxLib.h"

const char *TITLE = "Untitled";
const int WIN_WIDTH = 960;
const int WIN_HEIGHT = 540;

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
	ChangeWindowMode(true);
	SetWindowSizeChangeEnableFlag(false, false);
	SetMainWindowText(TITLE);
	SetGraphMode(WIN_WIDTH, WIN_HEIGHT, 32);
	SetWindowSizeExtendRate(1.0);
	SetBackgroundColor(35, 35, 35);
	SetDrawScreen(DX_SCREEN_BACK);

	if (DxLib_Init() == -1) { return -1; }

	int speed_x = 5;
	int speed_y = 5;
	int x = 100;
	int y = 100;
	int size = 50;

	while (true) {
		ClearDrawScreen();

		if (x <= 0) {
			speed_x = -speed_x;
		}
		else if (x >= WIN_WIDTH - size) {
			speed_x = -speed_x;
		}
		if (y <= 0) {
			speed_y = -speed_y;
		}
		else if (y >= WIN_HEIGHT - size) {
			speed_y = -speed_y;
		}

		if (CheckHitKey(KEY_INPUT_SPACE)) {
			x += speed_x;
			y += speed_y;
		}

		DrawBox(x, y, x + size, y + size, GetColor(255, 255, 255), true);

		ScreenFlip();
		WaitTimer(20);
		if (ProcessMessage() == -1) { break; }
		if (CheckHitKey(KEY_INPUT_ESCAPE) == 1) { break; }
	}

	DxLib_End();
	return 0;
}

このコードでは以下の部分でスペースが押されると座標xやyに変数speed_xや変数speed_yを加算し、動かす処理をしています。

if (CheckHitKey(KEY_INPUT_SPACE)) {
   x += speed_x;
   y += speed_y;
}

ですがいちいちCheckHitKeyを呼び出しのも"なんだかなぁ..."と思うのです。
ですのですべてのキー情報を格納する変数を作りすべてのキー情報を教えてくれる関数で格納していきましょう。

・GetHitKeyStateAll関数

GetHitKeyStateAll関数を使えばすべてのキー情報が分かります。
この関数に引数をとしてchar型の配列を渡すことでキー情報を格納できるのですが、この仕組みを説明するとポインタアドレス、配列の仕組みやアドレスと配列の関係性を説明しなけれならないのでもう少し先に進んだら説明します。
まずはこうすることによって格納できるという事だけわかっていただければ十分です。
では以下のコードを書いてみてください。

main.cpp
#include "DxLib.h"

extern const char *TITLE = "Untitled";
extern const int WIN_WIDTH = 960;
extern const int WIN_HEIGHT = 540;

int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
	ChangeWindowMode(true);
	SetWindowSizeChangeEnableFlag(false, false);
	SetMainWindowText(TITLE);
	SetGraphMode(WIN_WIDTH, WIN_HEIGHT, 32);
	SetWindowSizeExtendRate(1.0);
	SetBackgroundColor(35, 35, 35);
	SetDrawScreen(DX_SCREEN_BACK);

	if (DxLib_Init() == -1) { return -1; }

	int x = 100;
	int y = 100;
	const int speed = 5;
	const int size = 50;

	char keys[256];

	while (true) {
		ClearDrawScreen();

		//すべてのキー情報を格納
		GetHitKeyStateAll(keys);

		//キー操作
		if (keys[KEY_INPUT_A]) {
			x -= speed;
		}
		else if (keys[KEY_INPUT_D]) {
			x += speed;
		}

		if (keys[KEY_INPUT_W]) {
			y -= speed;
		}
		else if (keys[KEY_INPUT_S]) {
			y += speed;
		}

		//四角形描画
		DrawBox(x, y, x + size, y + size, GetColor(255, 255, 255), true);

		ScreenFlip();
		WaitTimer(20);
		if (ProcessMessage() == -1) { break; }
		if (CheckHitKey(KEY_INPUT_ESCAPE) == 1) { break; }
	}

	DxLib_End();
	return 0;
}

んふwそれっぽくなってきましたね!(キモい)
早速説明です。
keys[256]というchar型の変数がありますが今はおまじないです。
簡単に説明すると256個のchar型の変数がこれです。
そしてGetHitKeyStateAll(keys)keysにキーの情報を格納しています。
こうすることによって後のコードがすっきりしますしいちいちCheckHitKey関数を呼ばずに済むようになります。
そしてこの変数たちを使いキー入力でキャラクターを操作している部分がこちらです。

if (keys[KEY_INPUT_A]) {
   x -= speed;
}
else if (keys[KEY_INPUT_D]) {
   x += speed;
}

if (keys[KEY_INPUT_W]) {
   y -= speed;
}
else if (keys[KEY_INPUT_S]) {
   y += speed;
}

一目瞭然のコードなので説明はいりませんねw
まぁ簡単に説明すると

押されているキー 処理
W y方向にspeed分減らし上に移動
A x方向にspeed分減らし左に移動
S y方向にspeed分増やし下に移動
D x方向にspeed分増やし右に移動
これだけです。
これだけでキャラクターの操作ができます。
いらないとは思いますがGIF置いときます()
Operation.gif
このようにWASDで操作することによって自分が動かしたい方向にオブジェクトを動かすことができました。
これをキャラクターに置き換えるだけでキャラクター操作ができるようになります(実際はこれだけではないですがw)

次回

とうとう条件分岐とキー入力ができるようになりましたね!
ここまで来たら次回は一度変数に戻り配列をやるか当たり判定をやるか悩むところですが次回までに考えておきますw
当たり判定の場合は数学的要素が加わるので√(平方根)アレルギーの方は覚悟しておいてくださいw
まぁ自分で計算するわけではないので身構えなくても大丈夫ですがw...
次回まで少々お待ちください!

あとがき

正直プログラミングって変数と条件分岐を習得すると一定以上のものが作れるようになるので応用していろいろ作ってみたり動作を確認してみるといいかもしれません(*'▽')
これから難しくなってきますがね...フ フ フ フ フ フ
(フ フ フ フ フ フがわかるプログラマーはこの記事読んでないでデバッグやら頑張ってください)

###作者について
詳しくはわんころメソッド();HPにどうぞ(*'▽')

わんころメソッド();HP
Twitter(まゆC#)
GitHub(まゆC#)

コミュニティ
Discordで雑談から質問まで様々なチャンネルがあるまゆC#のコミュニティサーバーがあります!
わからないことがあればこちらでもお答えするのでぜひ!

Discordサーバー : わんころメソッド(雑談);

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?