惰性Log

技術系の話題を中心に書いています

ゲーム制作向けライブラリを公開した

ドキュメントも何もないし一人で使う予定なので公開と言えるのか分からないが、ゲーム制作に使う用のライブラリを公開した。

github.com

sinenの名前の由来は「思念」から。あとアイヌ語で「一人」の意味もあるらしいので丁度良かった。 DXライブラリよりも少し抽象度の低いあたりを目指している。主にSDL2を中心としており、描画部分はOpenGLかVulkanが担う.

DockerでFactorioサーバーを建てるメモ

結論

sudo mkdir -p /opt/factorio
sudo chown 845:845 /opt/factorio
sudo docker run -d \
  -p 34197:34197/udp \
  -p 27015:27015/tcp \
  -v /opt/factorio:/factorio \
  --name factorio \
  --restart=always \
  factoriotools/factorio

何故わざわざDockerで?

Factorioサーバーを建てるためには、公式サイトからHeadless Serverをダウンロードして起動する必要がある。
Factorioサーバー起動時にはglibc2.18が必要となるが、CentOS7では標準でglib2.17が使用されている。
glibcとはGNUC言語実装ライブラリであるが、安易にglibcを導入するとカーネルが起動しなくなる恐れがある(なった)。
そのため、次の手段としてdockerを使用することにした。

サーバー構築

以下で紹介するのはCentOS7での方法である。

ポート開放

Dockerを入れる前に、ポートの開放とファイアウォールを通す必要がある。Factorioで使用するポートは34197(UDP)だ。

# firewall-cmd --add-port=34197/udp --zone=public --permanent  

Dockerの導入

# yum -y install docker
# systemctl start docker

Factorioイメージの導入

今回は一番メンテナンスがされているfactoriotoolsのコンテナを使用する。

https://hub.docker.com/r/factoriotools/factorio/

公式のガイドに沿って進めれば基本的に問題ない。

sudo mkdir -p /opt/factorio
sudo chown 845:845 /opt/factorio
sudo docker run -d \
  -p 34197:34197/udp \
  -p 27015:27015/tcp \
  -v /opt/factorio:/factorio \
  --name factorio \
  --restart=always \
  factoriotools/factorio

ただし、気をつけるべき点は上記のままでは最新版になってしまう。安定版では無いということで、すなわち公式サイトのExperimentsを含む最新のバージョンのことである。
例えば執筆時点のFactorioの最新バージョンは1.1.21だが、Experiments版は1.1.25だ。もし1.1.21のサーバーを建てるには、

sudo mkdir -p /opt/factorio
sudo chown 845:845 /opt/factorio
sudo docker run -d \
  -p 34197:34197/udp \
  -p 27015:27015/tcp \
  -v /opt/factorio:/factorio \
  --name factorio \
  --restart=always \
  factoriotools/factorio:1.1.25

のように末尾に「:」とバージョンを書けば良い。

実行

ドキュメントの通り、

# docker start factorio

停止

# docker stop factorio

動作確認(log)

# docker logs factorio

独自の問題?

私の環境だけの問題かもしれないが、初回実行時にPermission deniedが出た。ディレクトリの権限を変えたりなど色々試したが駄目だったので、一時的にセキュリティを外した。
一時的に外すためには、

# setenforce 0

とする。
ただしこれは最後の手段であるのでおすすめしない。
サーバーを建て終わったら、

# setenforce 1

SELinuxを再度有効化しておく。

VisualStudioのプロジェクトをコマンドラインからビルドする

新年です。だからなにって訳ではないですが。

最近、コマンドラインからビルドしたいなーと思っていて調べたところMSBuildというのが使えるらしい。 はてなブログタグに登録されているくらい。 場所は

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\

にある。(2019は任意のバージョン) 面倒なのでとりあえず環境変数に打ち込んだ。

MSBuild.exeをターミナルから実行できるのを確認したら、↓こんな感じにビルドすることができる。

MSBuild C:/hoge/fuga/piyo.sln /t:build /p:Configuration=Debug;Platform="x86"

ソリューションに複数のプロジェクトがある場合は/t:にbuild、任意のプロジェクトをビルドしたいときにはプロジェクト名に変更することでビルド可能。
その他ConfigurationとPlatformは見ての通りで、これでおそらく最低限はビルド可能になる。

それ以外のコマンドは公式ドキュメントを読んでください。結局デバッガなどを使用するとなるとVisual Studioを起動する羽目にはなると思います。

docs.microsoft.com
毎回打つのは面倒なのでaliasに登録してるんですが、makefileみたいになんかもっとスマートに出来ると思うのでよければ教えて下さい。

追記:調べたところ、nmakeというのがやっぱりあるらしい。書き方もmakefileに似ているので、今後書く予定。

Vulkanメモ

この記事は落書きです.
Vulkanに関する日本語の情報が少ないので、落書きでももしかしたら需要あるかもしれんので公開することに.
とはいえ、仕様書を読んだわけではないので信頼性は低い。

初期化

インスタンスの生成

ウインドウの生成やらをしておく. 私はSDL2.0を使った. vkCreateInstance()でインスタンスの生成が可能.
検証レイヤの有効化もこの時点で行う.
生成に成功したかどうかはVk_Resultを使うのが良い.成功時のVK_SUCCESSは0を返すので, ポインタの感覚で判定すると痛い目に合う.

物理デバイスの選択.

GPUを列挙して選ぶ. vkEnumeratePhysicalDevices()で列挙できる.
特に理由が無ければ一番最初のデバイスを選んどけば問題ないと思う.

バイスキューインデックスの選択.

CPUとGPU間のキュー.
vkGetPhysicalDeviceQueueFamilyProperties()で列挙.

論理デバイスの生成.

コマンドプールの準備.

サーフェスの生成.

スワップチェインの生成.

デプスバッファの生成.

レンダパスの生成.

コマンドバッファの準備.

ディスクリプタ周りの準備.

パイプラインレイアウトなどの生成

ループ

レンダパスの開始.

コマンドバッファの開始.

コマンド発行.

レンダパスの終了.

コマンドバッファの終了.

コマンドの送信.

Present処理.

終了処理

各種解放処理

開放する順番が決まっているので面倒くさい. もしレンダラを一つしか生成しないのであればOSに任せてしまってもいいかもしれない.

やることがめちゃ多い. 取り合えず枠だけ書いた.気が向いたら更新予定.

Visual Studio Code のターミナルでDeveloper Command Prompt を起動する

なぜ?

いちいちVisual Studio を毎回起動するのがめんどくさくなってきた。だらだらアニメでも見ながらプログラムを組みたいときだってある。
MSBuild使えばコマンドラインからビルドできるので、VSCodeのターミナルから起動すれば色々便利!

結論

 "settings": {
        "terminal.integrated.shell.windows": "C:\\Windows\\Sysnative\\cmd.exe",
        "terminal.integrated.shellArgs.windows": [
            "/k",
            "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\Common7\\Tools\\VsDevCmd.bat"
        ]
    }

パスが異なる場合適宜書き換えてください。これをsettings.jsonなり.code-workspaceに貼り付けてください。
"&&"で起動後のコマンドを書くこともできます。なので例えば

     "terminal.integrated.shellArgs.windows": [
            "/k",
            "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\Common7\\Tools\\VsDevCmd.bat",
            "&&",
            "doskey",
            "/macrofile=macros.txt"
        ]

と書いてmacros.txtにマクロを書くことができます。マクロについてはMicrosoftのドキュメントを参照してください。

docs.microsoft.com

QtでUpdate関数を実装する

目的

C++向けGUIライブラリ Qt には毎回実行されるような関数は用意されていない。

しかし、Qtにはシグナルとスロットという仕組みが存在し、それを使って自前で簡単に実装することが可能であることを知ったので記しておく。

シグナルとスロット

シグナル及びスロットを詳しく知りたい場合は、Qtの公式リファレンスか、Qiitaなどにいくつかサイトを見つけたのでそちらを参照すると良い。 doc.qt.io 簡単に言えば、シグナルはスロットを作動させるための信号で、スロットは関数である。

実装

今回のupdate関数は、一定時間ごとに呼び出すのでQTimerクラスを使って時間を計測し、シグナルを送信させる。

まずは適当なクラスにQTimerクラスのポインタを作る。

//QtWidgetApplication1.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication1.h"

class QtWidgetsApplication1 : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication1(QWidget *parent = Q_NULLPTR);
    ~QtWidgetsApplication1();
private:
    Ui::QtWidgetsApplication1Class ui;
    class QTimer* my_timer;
};

今回は、プロジェクトを作成したときの最初のクラスに作る。

次にスロットのプロトタイプを作成する。

//QtWidgetApplication1.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication1.h"

class QtWidgetsApplication1 : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication1(QWidget *parent = Q_NULLPTR);
    ~QtWidgetsApplication1();
    
public slots:
    void update();

private:
    Ui::QtWidgetsApplication1Class ui;
    class QTimer* my_timer;
};

真ん中のvoid update();がスロットである。public にslotsを加えなければならない事に注意が必要である。

update関数には一定周期で実行したい処理を実装しておく。試しに今回は、QLineEditウィジェットを作成し、経過時間を表示させる。

f:id:astomih:20200814162130p:plain

次に、中身を書く。

コンストラクタには、my_timerの実体を生成と、シグナルとスロットの接続 ( connect ) を行っている。

connectの引数は第一引数から順番に(シグナル送信元、シグナル、シグナル送信先(受信者)、スロット)である。

今回の場合、my_timerがシグナルが送信元となり、timeout()が呼ばれるタイミングで送信される。timeout()は、QTimerが0になった時に呼ばれる。

シグナルの受信者はQtWidgetApplication1クラス、スロットはupdate()である。

つまり、これでmy_timerが0になるたびにupdate()が呼ばれるようになった。

次にmy_timerをスタートさせる。引数にはタイマーの時間 (ms) をセットする。my_timerはtimeout()が呼ばれるたびに100になり、以後自動的にスタートする。

//QtWidgetApplication1.cpp
#include "QtWidgetsApplication1.h"
#include <QtGui>
#include <iostream>

QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    my_timer = new QTimer();
    connect(my_timer, SIGNAL(timeout()), this, SLOT(update()));
    my_timer->start(100);
}
QtWidgetsApplication1::~QtWidgetsApplication1()
{
    delete my_timer;
}
void QtWidgetsApplication1::update()
{
    static uint32_t time = 0;
    time += 100;
    ui.lineEdit->setText(std::to_string(time).c_str());
}

実行させると以下のように値が増加し、update関数が完成した。 f:id:astomih:20200814162136p:plain

書籍「ゲームプログラミングC++」を軽くレビュー

Amazonレビューにでも書けば良かった気もしますが、ブログの方が気楽なのでここにレビューを書きます。

アフィだと思われないようにAmazonのリンクは控えますが、5000円程度です。

この本を買った目的

私がC++をちまちま書き始めてからだいぶ経ち、それなりにライブラリに頼ってゲームを作ることも出来るようになったのでさらなる高み(?)へ行くために手を取ってみました。あと単純にエンジンとかライブラリに頼らずに作りてえなという意地もありまして、この本の中でOpenGLを扱っているという情報を入手しました。

 買ったのは今年の4月の頭だったので、丁度2月にDirectX12の書籍も出ていたので迷ってはいたものの、流石に基礎もまともに身についてないのにわざわざクッソ低レイヤなDirectX12に手を出す訳にもいかず。それに本の厚さは同じくらいですが、DX12の本はレンダリングに関することしか載ってないのに対してゲームプログラミングC++はオーディオとか入力処理といったゲーム全般について書かれているのでC++一本でゲーム作るならこっちだなという結論を自分の中で出しました。

感想(本題)

読者の対象者として想定されているのが「そこそこC++が書ける人かつゲーム制作自体はあまりやっていない人」のようなので、難易度は丁度良かった(ただ個人的に数学や物理は難しい)です。しかし、所々コードが端折られている箇所がありました。書籍のソースコードは章ごとにGitHubリポジトリに入れられているのでそっちを見ればいいのですが、手を動かしながら読むように設計されているので買う時は注意してください。

本の構成

 全部で14の章の別れており、それぞれ内容が独立しています。各章と概要を書きます(問題があれば消します)。

  1. ゲームプログラミングの概要(クラス設計とかダブルバッファリング、初期化など)
  2. ゲームオブジェクトと2Dグラフィックスの基本(オブジェクト指向コンポーネント指向及びそのハイブリッド指向、SDL2による2Dレンダリングなど)
  3. ベクトルと基礎の物理(ベクトル、三角関数ニュートン力学オイラー積分、衝突判定など)
  4. 人工知能(ステートマシン、探索アルゴリズムなど)
  5. OpenGL(概要、初期化、行列、シェーダ基礎など)
  6. 3Dグラフィックス(3次元座標変換、オイラー角、クォータニオン、3Dモデル読み込み、Zバッファ法、ライティングシェーダなど)
  7. オーディオ(FMOD APIによるオーディオシステムの立ち上げ、ドップラー効果、オクルージョンなど)
  8. 入力システム(SDLの入力APIを用いたキーボード、マウス、コントローラー各種の入力処理)
  9. カメラ(一人称、追従カメラ、軌道カメラ、スプラインカメラの実装など)
  10. 衝突検知(3D空間での衝突検知。AABB、交差判定など)
  11. ユーザーインターフェース(フォント、スタック、ポーズメニュー、ボタン、HUD、ローカライゼーションなど)
  12. スケルタルアニメーション(スケルトンとポーズ、スキニングなど)
  13. 中級グラフィックス(最近傍フィルタリング、ミップマッピング、異方性フィルタリング、遅延シェーディング、Gバッファ、点光源など)
  14. レベルファイルとバイナリデータ(各種データの読み書き、バイナリの読み書き)

おまけ:中級C++の復習(参照、ポインタ、配列、クラス、演算子オーバーロードSTLコンテナ各種、range-based-for文など)

見ての通り、開発に必要な最低限の知識が盛り込まれています。また独立していると書きましたが、全てが完全に独立している訳ではなく、例えば4,5,8章は3章の知識を前提として書かれています。

特徴

  • ある程度の言語経験者向けに書かれている
  • ゲーム制作については未経験~初心者向け
  • 2Dから3Dまで幅広く、全部やれば相当な力がつくはず
  • 基本スタイルはGitHubソースコードと本の解説をにらめっこ
  • 設計手法はオブジェクト指向コンポーネント指向のハイブリッド型(Unreal Engine4でもこの手法らしい。しらんけど)

願望

できればマルチスレッドも取り入れてほしかった…

著者が言うには「おとなしくゲームエンジンアーキテクチャ読め」ということらしい。あんな鈍器買えるかーっ!

追記:ゲームエンジンアーキテクチャ第3版が出るそう(ソースはTwitter)なので多分買います。

さいごに

何か本の推薦文みたいでレビューとは違うような気がする。が、しかし疲れたのです。これが惰性クオリティであります。

とはいえこの本は個人的に名著でした。5000円とか高すぎだろと思っていましたが、読者層が被っていれば値段以上の情報を得られます。ネットで探し集めたくらいじゃ得られないことが載っていました。まあそのために5000円近く払うんですが。