LoginSignup
0
1

More than 3 years have passed since last update.

DXライブラリでライフゲーム

Posted at

概要

DXライブラリを使用して何か動くものが作りたかったので、ライフゲームを作成してみました。
基本的にはwikipediaに書いてあるルールを参考にしています。
wikipedia ライフゲーム
プログラム初心者な為おかしい部分が多々あると思いますが、大目に見て頂ければと思います。

ソースコード

実際のソースコードは以下になります。

main.cpp
#include <DxLib.h>
#include "Cells.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    SetOutApplicationLogValidFlag(FALSE);//Log.txtを生成しないように設定
    if (DxLib_Init() == 1) { return -1; }//初期化に失敗時にエラーを吐かせて終了
    ChangeWindowMode(true);

    Cells cells;
    cells.Initialize();
    while (ProcessMessage() == 0)
    {
        ClearDrawScreen();//裏画面消す
        SetDrawScreen(DX_SCREEN_BACK);//描画先を裏画面に

        cells.Update();
        cells.Draw();

        ScreenFlip();//裏画面を表画面にコピー
    }

    DxLib_End();
    return 0;
}
Cells.h
#pragma once
#include <vector>
class Cells
{
private:

    // セルの状態
    enum State
    {
        Life,   // 生存
        Dead,   // 死
        Disable,
    };

    std::vector<std::vector<State>> m_cells;
    std::vector<std::vector<State>> m_nextCells;

    int m_frameCnt;
    int m_updateInterval;
    int m_nowGeneration;

public:
    Cells();
    void Initialize();
    void Update();
    void Draw();


private:
    void UpdateGeneration();

    int GetRinsetuCnt(int x, int y);
};
Cells.cpp
#include <DxLib.h>
#include <iterator>
#include <algorithm>
#include "Cells.h"

namespace
{
    const int CellSize = 10;        // セルの大きさ
    const int CellDistance = 2;     // セルの間隔
    const int MaxCountX = 50;       // 最大個数(X)
    const int MaxCountY = 35;       // 最大個数(Y)
    const int InitUpdateInterval = 60;  // 更新間隔
}

Cells::Cells() :
    m_cells(MaxCountY, std::vector<State>(MaxCountX)),
    m_nextCells(MaxCountY, std::vector<State>(MaxCountX))
{
    m_frameCnt = 0;
    m_updateInterval = InitUpdateInterval;
    m_nowGeneration = 0;
}

// 初期状態設定
void Cells::Initialize()
{
    for (int y = 0; y < m_cells.size(); y++)
    {
        for (int x = 0; x < m_cells[y].size(); x++)
        {
            // 端っこは全部壁にしとく
            if ((y == 0) || (x == 0) || (y == MaxCountY-1) || (x == MaxCountX-1))
            {
                m_cells[y][x] = State::Disable;
            }
            else
            {   // 生存・死のセルを半々にする
                if (GetRand(1) == 0)
                {
                    m_cells[y][x] = State::Life;
                }
                else
                {
                    m_cells[y][x] = State::Dead;
                }
            }
        }
    }
}

// 更新
void Cells::Update()
{
    m_frameCnt++;

    // 速度早くする
    if (CheckHitKey(KEY_INPUT_LEFT) != 0)
    {
        if (m_updateInterval > 1)
        {
            m_updateInterval--;
        }
    }   

    // 速度遅くする
    if (CheckHitKey(KEY_INPUT_RIGHT) != 0)
    {
        m_updateInterval++;
    }

    // 世代更新
    if (m_frameCnt % m_updateInterval == 0)
    {
        UpdateGeneration();
    }
}

// 描画
void Cells::Draw()
{
    int yPos = 0;
    for (int y = 0; y < m_cells.size(); y++)
    {
        yPos += CellSize + CellDistance;
        int xPos = 0;
        for (int x = 0; x < m_cells[y].size(); x++)
        {
            xPos += CellSize + CellDistance;
            if (m_cells[y][x] == State::Life)
            {
                DrawBox(
                    xPos,
                    yPos,
                    xPos + CellSize,
                    yPos + CellSize,
                    GetColor(255, 255, 255),
                    TRUE
                );
            }
        }
    }

    char str[128];
    sprintf_s(str, sizeof(str),"現在%d世代目 速度:%dフレーム毎に更新", m_nowGeneration, m_updateInterval);
    DrawStringF(0, 0, str, GetColor(255, 255, 255));

}

// 次の世代の更新
void Cells::UpdateGeneration()
{
    for(int y = 0; y < m_cells.size(); y++)
    {
        for(int x = 0; x < m_cells[y].size(); x++)
        {
            if (m_cells[y][x] == State::Disable)
            {
                m_nextCells[y][x] = State::Disable;
                continue;
            }

            int rinsetu = GetRinsetuCnt(x, y);

            // 現在死亡存状態
            if (m_nextCells[y][x] == State::Dead)
            {
                // 誕生判定
                if (rinsetu == 3)
                {
                    m_nextCells[y][x] = State::Life;
                }
            }

            // 現在生存状態
            if (m_nextCells[y][x] == State::Life)
            {
                // 生存判定
                if (rinsetu == 2 || rinsetu == 3)
                {
                    m_nextCells[y][x] = State::Life;
                }

                // 過疎判定
                if (rinsetu <= 1)
                {
                    m_nextCells[y][x] = State::Dead;
                }

                // 密です判定
                if (rinsetu >= 4)
                {
                    m_nextCells[y][x] = State::Dead;
                }
            }
        }
    }

    m_cells = m_nextCells;
    m_nowGeneration++;
}

// 隣接するセルを取得
int Cells::GetRinsetuCnt(int x, int y)
{
    int rinsetu = 0;
    if(m_cells[y-1][x] == State::Life)   rinsetu++;
    if(m_cells[y-1][x+1] == State::Life) rinsetu++;
    if(m_cells[y][x+1] == State::Life)   rinsetu++;
    if(m_cells[y+1][x+1] == State::Life) rinsetu++;
    if(m_cells[y+1][x] == State::Life)   rinsetu++;
    if(m_cells[y+1][x-1] == State::Life) rinsetu++;
    if(m_cells[y][x-1] == State::Life)   rinsetu++;
    if(m_cells[y-1][x-1] == State::Life) rinsetu++;

    return rinsetu;
}

簡単な説明

セルの状態は二次元配列(コンテナ?)で持つようにしています。
Cells::UpdateGeneration()関数で、次の世代でセルが生きるか死ぬかを決めています。
最初の状態は良く分からなかったので、50%で生、50%で死の状態にしています。
また、for文の部分で警告が多々ありますが、まだ改善していません。
方向キーで、更新速度を変更できるようにしています(操作し辛いですが)

実行結果

1世代目は以下のような感じになって
1.jpg

ちょっとするとこんな感じになって
2.jpg

最終的には以下のような感じになりました。
3.jpg

ん~、画像だけでは分からないと思いますが、それっぽく動いている気はします…が、よく分からん…
固定物体の例や振動子の例などは一部見られますが、移動物体の例の宇宙船などは出来ていない気がする…
wikipediaのライフゲームのルールだけ見て作ったので、他に改善しないと行けない点があるかも知れない為、今後出来れば改善していきたいと思います。

以上になります。
こんな記事を見て頂き、ありがとうございました。

0
1
1

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
0
1