スマホゲーム制作記

#その名は["食材フィーバー"](https://play.google.com/store/apps/details?id=com.gaccho)

ルールは簡単。
>上から落ちてくる食材やお金を集めよう。
>それ以外のアイテムをひろうとゲームオーバー。
>
>より多くのスコアを出そう！

こんなゲームです。
![syoku.png](https://qiita-image-store.s3.amazonaws.com/0/213065/d39179d3-87c4-7a61-ec69-e98ae8c6f954.png)

とにかく沢山の食材(+お金)を集めるゲームです。

プラットフォームはWindows(.exe)~~(Windows版は諸事情により公開していません)~~とAndroid(.apk)です。
開発はVisualStudio2017、C++、DXライブラリです。

https://play.google.com/store/apps/details?id=com.gaccho
↑ダウンロードURLはこちら

#操作方法
画面左半分をタッチすると左に移動、
画面右半分をタッチすると右に移動します。

ただ、それだけです。

#コード
このコードはCの構造体を学習している時期に作ったものなので、とても汚いです……。~~今でも汚いけど~~

```cpp:main.cpp
#include "DxLib.h"
#define PIXELX 1920
#define PIXELY 1080
#define MUSIC_COUNT 32
#define RL_ITEM_EMPTY 0
#define RL_ITEM_MONEY 1
#define RL_ITEM_RED_MUSHROOM 6
#define RL_ITEM_BLUE_MUSHROOM 7

#define RL_MONSTER_IKARI 1 //イカリー;;;;;;;;;;


#define RL_ITEM_SEAWEED 15
#define RL_ITEM_STONE 16
#define RL_ITEM_CHESTNUT 17
#define RL_ITEM_DRUG 18

#define RL_ITEM_BLACK_GLASSES 30
#define RL_ITEM_ROUND_GLASSES 31
#define RL_ITEM_MONEY_GLASSES 32

#define PI 3.14159265358979323846
#define WHITE GetColor(255,255,255) //白

#define ITEM_SE 1
#define IMPORTANT_SE 2
#define END_SE 3

struct Eat_MG
{
	int score = 0; //ゲームのスコア
	int playerX = 0; //プレイヤーのX座標
	int playerY = 0; //プレイヤーのY座標(頭の高さ)
	int playerSpeed = 10; //プレイヤーの速さ
	int playerItemCount = 0; //プレイヤーが持っているアイテムの数
	unsigned char itemCount = 0; //降ってくるアイテムの数
	unsigned char gameoverNumber = 0; //降ってくるゲームオーバーアイテムの数

	int safeareaStart = 0;
	int safeareaEnd = 0;

	//int itemY = 0; //持っているアイテムの高さ
	int widthX = 1920; //ゲーム内のX軸の長さ
	int widthY = 1080; //ゲーム内のY軸の長さ

	double probability = 5; //1fps間でアイテムが出る確率
	double probability2 = 2;
	int itemNumberData = 5; //出る個数
	int itemNumber = 0; //

	unsigned char playerItem[1024]; //持っているアイテムの数
	unsigned char playerItemS[1024]; //持っているアイテム向き
	int playerItemX[1024]; //持っているアイテムのX座標
	int playerItemY[1024]; //持っているアイテムのY座標

	unsigned char item[256]; //降ってくるアイテムのID
	unsigned char itemS[256]; //降ってくるアイテムの向き
	int itemX[256]; //降ってくるアイテムのX座標
	int itemY[256]; //降ってくるアイテムのY座標
};

int gacha(double kakuritu)
{
	if (kakuritu >= 100) {
		return 1;
	}
	if (kakuritu <= 0) {
		return 0;
	}
	int bangou = (int)(20000000 * kakuritu);
	int atari = 1 + GetRand(1999999999);
	if (bangou >= atari) {
		return 1;
	}

	return 0;
}

#ifdef __ANDROID__
//Android版のコンパイルだったら android_main
int android_main() 
#else
//Windows版のコンパイルだったら WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
#endif
{
	//logの出力を無しにする
	if (SetOutApplicationLogValidFlag(FALSE)) return -1; 

#ifndef __ANDROID__
	// Windows版のコンパイルだったら ChangeWindowMode を実行する
	if (ChangeWindowMode(TRUE)) return -1; 

	//タイトル文字
	if (SetMainWindowText("Food Fever")) return -1;
#endif

	SetGraphMode(1920, 1080, 32);
	if (DxLib_Init() == -1)     // ＤＸライブラリ初期化処理
	{
		return -1;          // エラーが起きたら直ちに終了
	}

	SetDrawScreen(DX_SCREEN_BACK);

	struct Eat_MG eat;
	int mainBGM = LoadSoundMem("Music/BGM/stage09.ogg");
	PlaySoundMem(mainBGM, DX_PLAYTYPE_LOOP);
	for (int i = 0; i < 256; i++) {
		eat.item[i] = 0;
		eat.itemS[i] = 0;
		eat.itemX[i] = 0;
		eat.itemY[i] = 0;
	}
	for (int i = 0; i < 1024; i++) {
		eat.playerItem[i] = 0;
		eat.playerItemS[i] = 0;
		eat.playerItemX[i] = 0;
		eat.playerItemY[i] = 0;
	}

	//比率に関する変数宣言
	int pixelX2 = PIXELX >> 1; //X座標の半分の画面解像度
	int pixelY2 = PIXELY >> 1; //Y座標の半分の画面解像度
	int pixelX32 = PIXELX >> 5; //X座標の1/32の画面解像度
	int pixelX64 = PIXELX >> 6; //X座標の1/64の画面解像度


	eat.playerX = eat.widthX / 2; //プレイヤーのX座標
	eat.playerY = (int)(eat.widthY*0.7); //プレイヤーのY座標

	int softSE[MUSIC_COUNT];
	int mainSE[MUSIC_COUNT];

	softSE[ITEM_SE] = LoadSoftSound("Music/SE/item.wav");
	mainSE[ITEM_SE] = LoadSoundMemFromSoftSound(softSE[ITEM_SE]);

	softSE[END_SE] = LoadSoftSound("Music/SE/end.wav");
	mainSE[END_SE] = LoadSoundMemFromSoftSound(softSE[END_SE]);

	int back = LoadGraph("Picture/Run/back.png");
	int basket = LoadGraph("Picture/Eat/basket.png");
	int ground = LoadGraph("Picture/Eat/ground.png");
	int test3 = LoadGraph("Picture/Run/test3.png");
	int brush = LoadGraph("Picture/Run/brush.png");
	int brush2 = LoadGraph("Picture/Run/brush2.png");
	int keisanX = 0;

	int mapChipItem[256];
	//アイテム画像をロード
	mapChipItem[RL_ITEM_MONEY] = LoadGraph("Picture/RogueLike/Item/money.png");
	mapChipItem[RL_ITEM_RED_MUSHROOM] = LoadGraph("Picture/RogueLike/Item/mushroom.png");
	mapChipItem[RL_ITEM_BLUE_MUSHROOM] = LoadGraph("Picture/RogueLike/Item/mushroom2.png");
	mapChipItem[RL_ITEM_SEAWEED] = LoadGraph("Picture/RogueLike/Item/seaweed.png");
	mapChipItem[RL_ITEM_STONE] = LoadGraph("Picture/RogueLike/Item/stone.png");
	mapChipItem[RL_ITEM_CHESTNUT] = LoadGraph("Picture/RogueLike/Item/chestnut.png");
	mapChipItem[RL_ITEM_DRUG] = LoadGraph("Picture/RogueLike/Item/drug.png");

	mapChipItem[255] = LoadGraph("Picture/Eat/gameover.png");

	int monsterPicture[2][64];//16個の画像を格納する配列
	LoadDivGraph("Picture/RogueLike/Player/ikari.png", 64, 8, 8, 120, 120, monsterPicture[RL_MONSTER_IKARI]);

	eat.safeareaStart = GetRand(eat.widthX - 300);
	eat.safeareaEnd = eat.safeareaStart + 300;

	unsigned char direction = 3; //mobの向き
	unsigned char move = 0; //mobの動き(パラパラ漫画)
	unsigned char moveTime = 0; //

	int FontHandle = CreateFontToHandle("メイリオ", pixelX32, 10, DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
	int FontHandle2 = CreateFontToHandle("メイリオ", pixelX64, 10, DX_FONTTYPE_ANTIALIASING_EDGE_8X8);

	int moveCount = 0; //動いているか
	int rand = 0;

	int gameCount = 0;

	int timeCount = 0;

	int x[10] = { 0,0,0,0,0,0,0,0,0,0 };
	int y[10] = { 0,0,0,0,0,0,0,0,0,0 };

	int left = 0, right = 0;

	while (1)
	{
		/*エラー処理////////////////////////////////////////////////////////////////////////*/
		if (ProcessMessage() != 0) {
			break;
		}
		if (ClearDrawScreen() != 0) {
			break;
		}
		//if (updateKey() != 0) {//CheckHitKey(KEY_INPUT_ESCAPE)
		//	break;
		//}
		/*終了処理////////////////////////////////////////////////////////////////////////*/

		DrawRotaGraph(pixelX2, pixelY2, 1.0, 0.0, back, TRUE);
		DrawRotaGraph(pixelX2, pixelY2, 1.0, 0.0, ground, TRUE);
		moveCount = 0;

		for (int i = 0; i < GetTouchInputNum(); i++) {
			GetTouchInput(i, &x[i], &y[i]);
			if (x[i] < (PIXELX >> 1)) {
				left++;
			}
			else {
				right++;
			}
		}


		switch (gameCount)
		{
		case 0:
			eat.playerX += (eat.playerSpeed*(right + (-1 * left)));
			if (right + (-1 * left) != 0) {
				moveCount++;
			}
			break;
		}

		right = 0;
		left = 0;

		switch (timeCount)
		{
		case 120:
			eat.safeareaStart = GetRand(eat.widthX - 300);
			eat.safeareaEnd = eat.safeareaStart + 300;
			timeCount = -1;
			break;
		default:
			timeCount++;
			break;
		}


		if (eat.playerX >= eat.widthX) {
			eat.playerX = eat.widthX;
		}
		else if (eat.playerX <= 0) {
			eat.playerX = 0;
		}

		/*プレイヤーの向きや移動系*/
		if (moveCount >= 1) {
			if (moveTime >= 7) {
				if (move >= 16) {
					move = 0;
				}
				else {
					move += 8;
				}
				moveTime = 0;
			}
			else {
				moveTime++;
			}
			direction = move;
		}
		else {
			direction = 0;
		}

		if (gacha(eat.probability2) == 1) {
			eat.gameoverNumber = GetRand(eat.score >> 9);

			for (int i = 0; i < eat.gameoverNumber; i++) {
				for (int j = 0; j < 256; j++) {
					if (eat.item[j] == 0) {
						eat.item[j] = 255;
						eat.itemS[j] = GetRand(179);
						eat.itemX[j] = GetRand(eat.widthX);
						eat.itemY[j] = -100;

						if (eat.safeareaStart <= eat.itemX[j] && eat.safeareaEnd >= eat.itemX[j]) {
							eat.item[j] = 0;
						}
						break;
					}
				}
			}
		}

		if (gacha(eat.probability) == 1) {
			eat.itemNumber = 1 + GetRand(eat.itemNumberData - 1);


			for (int i = 0; i < eat.itemNumber; i++) {
				for (int j = 0; j < 256; j++) {
					if (eat.item[j] == 0) {
						rand = GetRand(4);
						switch (rand)
						{
						case 1:
							eat.item[j] = RL_ITEM_RED_MUSHROOM;
							break;
						case 2:
							eat.item[j] = RL_ITEM_BLUE_MUSHROOM;
							break;
						case 3:
							eat.item[j] = RL_ITEM_SEAWEED;
							break;
						case 4:
							eat.item[j] = RL_ITEM_CHESTNUT;
							break;
						default:
							eat.item[j] = RL_ITEM_MONEY;
							break;
						}

						eat.itemS[j] = GetRand(179);
						eat.itemX[j] = GetRand(eat.widthX);
						eat.itemY[j] = -100;
						break;
					}
				}
			}
		}


		for (int i = 0; i < 256; i++) {
			switch (eat.item[i]) {
			case 0:
				break;
			default:
				switch (gameCount)
				{
				case 0:
					eat.itemY[i] += 5;
					break;
				}
				if (eat.playerItemCount < 1024 && eat.itemY[i] + 30 <= eat.playerY + 50 - eat.playerItemCount * 2 && eat.itemY[i] >= eat.playerY - eat.playerItemCount * 2 && eat.itemX[i] >= eat.playerX - 60 && eat.itemX[i] <= eat.playerX + 60) {
					switch (eat.item[i]) {
					case 255:
						PlaySoundMem(mainSE[END_SE], DX_PLAYTYPE_BACK); //ゲームオーバー音を流す
						gameCount = 1;
						break;
					default:
						PlaySoundMem(mainSE[ITEM_SE], DX_PLAYTYPE_BACK); //アイテム音を流す
						break;
					}

					eat.playerItem[eat.playerItemCount] = eat.item[i];
					eat.playerItemS[eat.playerItemCount] = eat.itemS[i];
					eat.playerItemX[eat.playerItemCount] = eat.itemX[i] - eat.playerX;
					eat.playerItemY[eat.playerItemCount] = eat.itemY[i] - eat.playerY;
					switch (eat.item[i])
					{
					case RL_ITEM_RED_MUSHROOM:
						eat.score += 10;
						break;
					case RL_ITEM_BLUE_MUSHROOM:
						eat.score += 50;
						break;
					case RL_ITEM_SEAWEED:
						eat.score += 20;
						break;
					case RL_ITEM_CHESTNUT:
						eat.score += 15;
						break;
					default:
						eat.score += 60;
						break;
					}
					eat.item[i] = 0;
					eat.itemS[i] = 0;
					eat.itemX[i] = 0;
					eat.itemY[i] = 0;
					eat.playerItemCount++;
				}

				if (eat.itemY[i] - 30 >= eat.widthY) {
					eat.item[i] = 0;
					eat.itemS[i] = 0;
					eat.itemX[i] = 0;
					eat.itemY[i] = 0;
				}
				else {
					DrawRotaGraph((int)(eat.itemX[i]), (int)(eat.itemY[i]), 0.5, eat.itemS[i] / 90.0*PI, mapChipItem[eat.item[i]], TRUE);
				}
				break;
			}
		}

		for (int i = eat.playerItemCount - 1; i >= 0; i--) {
			DrawRotaGraph((int)((eat.playerX + eat.playerItemX[i])), (int)((eat.playerY + eat.playerItemY[i])), 0.5, eat.playerItemS[i] / 90.0*PI, mapChipItem[eat.playerItem[i]], TRUE);
		}

		if (CheckHitKey(KEY_INPUT_ESCAPE) && gameCount == 0 && eat.score > 0)
		{
			break;
		}

		switch (gameCount)
		{
		case 1:
			DrawFormatStringToHandle((int)((PIXELX >> 1) - 250), (int)((PIXELY >> 1) - 100), WHITE, FontHandle, "ゲームオーバー");
			DrawFormatStringToHandle((int)((PIXELX >> 1) - 250), (int)((PIXELY >> 1)), WHITE, FontHandle, "スコア: %d円相当", eat.score);
			DrawFormatStringToHandle((int)(PIXELX - 540), (int)(PIXELY - 50), WHITE, FontHandle2, " Produced by Gaccho , Music tsuzu");

			if (CheckHitKey(KEY_INPUT_ESCAPE))
			{
				gameCount = 0;
				eat.score = 0;
				for (int i = 0; i < 256; i++) {
					eat.item[i] = 0;
					eat.itemS[i] = 0;
					eat.itemX[i] = 0;
					eat.itemY[i] = 0;
				}
				for (int i = 0; i < 1024; i++) {
					eat.playerItem[i] = 0;
					eat.playerItemS[i] = 0;
					eat.playerItemX[i] = 0;
					eat.playerItemY[i] = 0;
				}
				eat.playerX = eat.widthX / 2; //プレイヤーのX座標
				eat.playerY = (int)(eat.widthY*0.7); //プレイヤーのY座標

				eat.playerSpeed = 10; //プレイヤーの速さ
				eat.playerItemCount = 0; //プレイヤーが持っているアイテムの数
				eat.itemCount = 0; //降ってくるアイテムの数
				eat.gameoverNumber = 0; //降ってくるゲームオーバーアイテムの数

			}

			break;
		}

		DrawRotaGraph((int)(eat.playerX), (int)((eat.playerY + 60)), 1.0, 0.0, monsterPicture[RL_MONSTER_IKARI][direction], TRUE);
		DrawRotaGraph((int)(eat.playerX), (int)((eat.playerY + 60)), 1.0, 0.0, basket, TRUE);
		DrawFormatStringToHandle(0, 0, WHITE, FontHandle, "スコア: %d円相当", eat.score);
		if (ScreenFlip() != 0) {
			break;
		}
	}
	DxLib_End();				// ＤＸライブラリ使用の終了処理

	return 0;					// ソフトの終了 
}
```

#おわりに
こんな形でゲームを紹介しましたが、何か疑問点や改善点などがあれば教えてください。
最後までお付き合いいただきありがとうございました。
「いいね！」していただけると、とても励みになります。

##ソースコードのライセンス

These codes are licensed under CC0.
[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg "CC0")](http://creativecommons.org/publicdomain/zero/1.0/deed.ja)

ソースコードは自由に使用してください。