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

# 今回の目標
④-⑤の間でかなり期間が開いてしまって申し訳... 
リアルの方でゲーム開発やらハードウェア開発がバタついていてQiitaに手が付けられませんでした><
さて、今回は前回の記事の最後に書いたアニメーションをやっていきます！！！

[前回 : C++の勉強しながらDxLibで2Dゲーム作ってみない?(実践編)④](https://qiita.com/mayu___cs/items/dc02e7053947e56644d3)

# この記事の対象
・Dxlibを使いゲーム開発をしてみたい方

・C++を始めたばかりの初心者の方で作りながら覚えたい方

・何かしらのライブラリやツールを使ってゲーム開発をしてみたい人方

# アニメーションといってもGIFなどではないお！！！
ではさっそくプログラミングをしていきましょう...とはいきません。
今回の目的はアニメーションですが、素材がないので作るところからです...
とは言ってもこの記事はプログラミングが目的なので今回は適当なのを用意しました。
![player_animation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390774/0b319fa0-1d6c-a928-5bdc-c54982ff6905.png)
これは`1764x245`サイズの一枚のPNG画像ファイルです。
多くの方はこの画像を見てどのような動きをするか予想できると思います。
ではこの画像をどうやってアニメーションにしていくかを考えていきましょう。

### まずは何フレームか知ろう
先ほどの画像はキャラクターが9つに分かれて描かれています。
すなわちこの画像を9枚に分割すると9フレームのアニメーションの素材ができます。
計算すると

```
X = 1764 / 9 = 196  
Y = 245(縦は変わらない)  
```
となります。
ただこの画像をペイントソフトで9枚に分割するのではありません。
これもプログラムから行うために`LoadDivGraph`というものを使います。

### LoadDivGraph
画像を分割読み込みするにはこの`LoadDivGraph`というDxLibの関数を使います。
この関数では分割した画像のハンドルをint型配列に格納します。
`LoadDivGraph`の引数は以下の通りです。

```cpp
int LoadDivGraph(char *FileName, int AllNum, int XNum, int YNum, int XSize, int YSize, int *HandleBuf);
```
`FileName` : 画像ファイルのパス
`AllNum`   : 画像の分割枚数
`XNum`     : X軸の分割数
`YNum`     : Y軸の分割数
`XSize`    : X軸の一枚の大きさ
`YSize`    : Y軸の一枚の大きさ
`HandleBuf`: int型配列

### とりあえず読み込んでみて表示までしてみる
さっそく分割読み込みから表示までやってみましょう！
`LoadDivGraph`に渡す引数はこのようになります。

```cpp
const int MaxFrame = 9;
int Ani_image[MaxFrame];
int LoadDivGraph("画像ファイルのパス", MaxFrame, MaxFrame, 1, 196, 245, Ani_image);
```
これを踏まえて前回覚えた`DrawGraph`を使用し表示してみましょう！

```cpp: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 Adjust_CenterX = (WIN_WIDTH / 2) - (196 / 2);
    int Adjust_CenterY = (WIN_HEIGHT / 2) - (245 / 2);

    //画像の分割読み込み
    const int MaxFrame = 9;
    int Ani_image[MaxFrame];
    LoadDivGraph("animation.png", MaxFrame, MaxFrame, 1, 196, 245, Ani_image);

    while (true) {
        ClearDrawScreen();

        //画像の表示
        DrawGraph(Adjust_CenterX, Adjust_CenterY, Ani_image[0], true);

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

    DxLib_End();
    return 0;
}
```
このコードではDrawDivGraphで分割読み込みをした画像の一枚目(配列の0番目)だけを画面中央に表示しています。
引数のファイルパスは前回同様ソースコードと同じフォルダにcharacterという名前で画像を保存したので`character.png`になっています。

### 実際にアニメーションを再生してみる
ではさっそくアニメーションにしてみましょう！
アニメーションとして再生するためには配列の要素を順に変えていけばいいだけなので簡単です！
コードは以下になります。

```cpp: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 Adjust_CenterX = (WIN_WIDTH / 2) - (196 / 2);
    int Adjust_CenterY = (WIN_HEIGHT / 2) - (245 / 2);

    //画像の分割読み込み
    const int MaxFrame = 9;
    int Ani_image[MaxFrame];
    LoadDivGraph("animation.png", MaxFrame, MaxFrame, 1, 196, 245, Ani_image);

    //アニメーション再生用変数
    int Frame = 0;
    int Frame_adjust = 0;

    while (true) {
        ClearDrawScreen();

        //画像の表示
        if (Frame_adjust == 5) {
            Frame++;
            Frame_adjust = 0;
        }
        if (Frame == MaxFrame - 1) {
            Frame = 0;
        }
        Frame_adjust++;
        DrawGraph(Adjust_CenterX, Adjust_CenterY, Ani_image[Frame], true);

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

    DxLib_End();
    return 0;
}
```
実行結果は以下のようになります
![animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390774/111678d9-a94a-3914-c78a-0c3371bc4483.gif)

このアニメーションのカギとなる変数は`Frame`というint型の変数です。
今回は変数`Frame_Adjust`が5回インクリメントされた場合に`Frame`がインクリメントされるif文でアニメーションを動かしています。
`Frame_Adjust`に関してはなくても大丈夫ですが、今回の場合60FPS想定でコードを書いているため、とても早く上下に動く謎のやつになると思います...w

### ざっくりした仕組み
一応仕組みを簡単に説明します。
このアニメーションの仕組みはパラパラ漫画と全く同じ仕組みで、複数の画像を連続して表示させることによってアニメーションにしています。
~~(まぁアニメーションってそういうものですが)~~
ですので別に9フレームじゃなければだめというわけではなく、多くなっても少なくなっても臨機応変に変数の値やら定数を変えてやればいいのです。
簡単ですね！

# 次回
全く考えてないので少々お待ちください...
そろそろ時間同期とか関数、ポインタ、クラスをやりたいと考えてます(早い)

# あとがき
お疲れ様でした！まゆC#です(*'▽')
今回の記事はいかがだったでしょうか?
おそらく「こいつ今回適当だな」って思われてるんじゃないかなと思いながら書いてましたw
まぁ実際、今回は若干適当です(アニメーション、踏み込むと長いので)
ではまた次回、近いうちにお会いしましょう！！！

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

[・わんころメソッド();HP](http://mayu-cs.xyz/)
[・Twitter(まゆC#)](https://twitter.com/mayu___cs)
[・GitHub(まゆC#)](https://github.com/mayu-cs)

### コミュニティ
Discordで雑談から質問まで様々なチャンネルがあるまゆC#のコミュニティサーバーがあります！
わからないことがあればこちらでもお答えするのでぜひ！
[Discordサーバー : わんころメソッド(雑談);](https://discord.com/invite/TZVTBkk)