C++
Android
game
アプリ
ゲーム制作

手軽に遊べるスマホゲームを作った話

はじめに

こんにちは。がっちょです。
"クソアプリ Advent Calendar 2017"の枠が空いていましたので飛び入り参加です。

この機会に以前3時間で作ったアプリ(ゲーム)を紹介します。

その名は"食材フィーバー"

ルールは簡単。

上から落ちてくる食材やお金を集めよう。
それ以外のアイテムをひろうとゲームオーバー。

より多くのスコアを出そう!

こんなゲームです。
syoku.png

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

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

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

操作方法

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

ただ、それだけです。

コード

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

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)     // DXライブラリ初期化処理
    {
        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();                // DXライブラリ使用の終了処理

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

おわりに

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

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

These codes are licensed under CC0.
CC0

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