Gaming Life

一日24時間、ゲームは10時間

Siv3DとC++と近況と

 プログラマー志望なのにUE4のBPに頼り切りでほとんどコーディングしないのは如何なものかなーと思い最近時間が空いた時はC++ポケットリファレンスを読むようにしている。で、そろそろ何かC++で作りたいなーでもいきなりDirectX/OpenGL直で触るのはハードル高いなーと考えていた所TwitterでSiv3Dを紹介して頂いた。

play-siv3d.hateblo.jp

 CライクなDXライブラリと違いModern C++で書け、複雑なインタラクションをとても短いコードで書くことが出来るらしい。サンプルプログラムをざっと見た感じProcessingより難しい作りだがゲーム制作に特化されていると印象を受けた。これは今の自分の実力とやりたいことにマッチしていると感じたため、UE4での開発と並行してコレを使ってなんか作ろうと決めた。

 早速リファレンスに従いDL。VS2015にも認識されてサンプルプロブラムをビルドしよう、としたら失敗した。正確に言うとビルドは成功するが実行が出来なかった。「Siv3D Engine」のロゴは表示されるのだがウインドウがすぐに消えてしまう。

 Twitterでライブラリの開発者に質問した所これは珍しいバグでGPUが悪さしているのでは、と教えていただいた。パソコンの製造元にもメールで問い合わせたがこちらもGPUが悪い、ドライバが壊れているんじゃ(他社の製品でのバグは知ったこっちゃねぇと突き放されたが)と返信があった。

 結局Intel GraphicsとNVIDIAのドライバを両方再インストールすることで解決したのだが、これも2度のパソコン自体の初期化やら複数回に渡るドライバのクリーンインストールの末になんか知らない間に解決していたので結局何が悪さしてたのかはわからず仕舞い。とりあえず同じ現象に見舞われた人はドライバの再インストールから始めることをオススメする。

 上記の問題解決に1週間くらいかかった為解決した頃にはモチベが死に絶えていた、更に例のボクセルモデルをBlender上手くでアニメーションさせるアイデアが浮かんだこともあり暫くSiv3Dは触っていなかった。試行錯誤の末ボクセルモデルをアニメーションさせることが出来た(この詳細は来月中にブログにまとめる予定)のでつい三日前くらいから本格的にSiv3Dエンジンを触り始めた。

 今はとりあえずGUI周りを勉強中。こちらの記事 で紹介されているスピンボックスを改造してTextField + GUISliderのクラスを作った。

f:id:ai_gaminglife:20180530145356p:plain

# include <Siv3D.hpp>

//Text + TextField + Slider Class

template<typename T>
class TextSliderGUI
{
public:
    TextSliderGUI(T _value, T _min, T _max)
        :value(_value),min(_min), max(_max) {}

    using TagPtr = std::shared_ptr<s3d::GUIText>;
    using TextFieldPtr = std::shared_ptr<s3d::GUITextField>;
    using SliderPtr = std::shared_ptr<s3d::GUISlider>;

    T value;
    T min, max;
    s3d::String name;
    TagPtr tag;
    TextFieldPtr textField;
    SliderPtr slider;

private:
    //初期化
    void InitWidget()
    {
        {
            textField = std::make_shared<s3d::GUITextField>();
            textField->m_style.width = 56;
            textField->setMaxLength(5);
            textField->setText(s3d::Format(value));
        }
        {
            slider = std::make_shared<s3d::GUISlider>();
            slider->setLeftValue(min);
            slider->setRightValue(max);
            slider->setSliderWidth(max);
            slider->setSliderPosition(value);
        }

    }
    //GUIに登録する

public:

    void LinkGUI(const s3d::String& _name, s3d::GUI& _gui)
    {
        InitWidget();

        const bool linkOK = (textField != nullptr) && (slider != nullptr);
        if (linkOK)
        {
            _gui.add(s3d::GUIText::Create(_name));
            _gui.add(textField);
            _gui.addln(slider);
        }

    }
    //TextFieldの入力を終了したか
    bool InputComplete() const
    {
        return textField->hasChanged && (!textField->getActive());
    }

    void TextUpdate()
    {
        const auto currentVal = s3d::FromStringOpt<T>(textField->getText());
        if (currentVal)
        {
            if(currentVal >= min && currentVal <= max)  {this->value = *currentVal;}
            else                                      { textField->setText(s3d::Format(value)); }
        }
        else
        {
            textField->setText(s3d::Format(value));
        }
    }

    void SliderUpdate()
    {
        this->slider->setSliderPosition(Parse<double>(this->textField->getText()));
    }

    void readText()
    {
        if (textField->getActive() && Input::MouseL.clicked)
        {
            if (!textField->mouseOver)
            {
                TextUpdate();
                return;
            }
        }

        if (InputComplete())
        {
            TextUpdate();
            SliderUpdate();
        }

        return;
    }

    //ウィジェット更新
    void update() {
        assert(textField);
        assert(slider);
        if (slider->hasChanged)
        {
            this->textField->setText(Format(this->slider->_get_sliderPosition()));
        }
        readText();
    }

};

void Main()
{
    GUI gui(GUIStyle::Default);
    gui.setTitle(L"テスト");

    TextSliderGUI<uint32> ts_r(0, 0, 255);
    TextSliderGUI<uint32> ts_g(0, 0, 255);
    TextSliderGUI<uint32> ts_b(0, 0, 255);

    ts_r.LinkGUI(L"R", gui);
    ts_g.LinkGUI(L"G", gui);
    ts_b.LinkGUI(L"B", gui);

    while (System::Update())
    {
        ts_r.update();
        ts_g.update();
        ts_b.update();

    }

}

 templateだのスマートポインタだの使っているが正直な所何もわからず使っている。(だって元のコードで使ってるから……)それに実装にも気に食わない所があって特にmain関数内でupdate()を個別に三回呼ぶ所が気に食わない。std::vectorに格納して範囲for文でぶん回せばいいのかなーと思いつつ、しかし、自作テンプレートクラスをコンテナに格納する方法がわからず投げた。C++ほんとわからん。

 そうこう言いつつこれだけの機能を初学者でもあっさり1日程度(元になるコードを改造したに過ぎないが……)で実装できるのは素晴らしい。暫くはUE4VR開発も含め)とBlenderとSiv3Dをメインで触っていこうと思う。

 そんなことを考えていたら某社のインターン採用通知が届いた。Unityを使うようなので8月までにUnityを最低限使えるようにならなくてはいけなくなった。時間がほしい。

(5/31追記)一応vector使った方法でmain関数書き換えた。こんなものを当てにしてはいけない。

const String RGBTag(int i) 
{
    switch (i) {
    case 0:  return L"R";
    case 1: return L"G";
    case 2: return L"B";
    default: return L"Error";
    }
}
void Main()
{
    using TS_RGB =  TextSliderGUI<uint32>;

    GUI gui(GUIStyle::Default);
    gui.setTitle(L"テスト");

    std::vector<TS_RGB> vec_ts;

    for (int i = 0; i < 3; i++)
    {
        vec_ts.emplace_back(0, 0, 255);
        vec_ts[i].LinkGUI(RGBTag(i), gui);
    }

    while (System::Update())
    {
        for (auto& v : vec_ts)   {v.update();}
    }

}