んぐのルーズリーフ

んぐの日記。最近はScrapBoxが主

プログラミング初心者にSiv3Dを布教した話

この記事はSiv3D Advent Calendar 2018 11日目の記事です。


どちらかというと日記的な記事になってしまいそうなので、ブログの方に書きます。

なんか途中からSiv3D紹介記事みたいになったけど許して。

はじめに

自己紹介とか状況説明

  • 高専3年生
  • プログラミングは高専に入ってからはじめました
  • コンピュータ系クラブに所属
  • 今年(も)部活動で一年生の教育係を担いましたので、2ヶ月ほどC言語の講座を開きました
  • 一年生は高専祭(学園祭)に向けてゲームを作ることにしていますので、定番のDXライブラリを使ってゲーム開発をさせようとしていました。
  • が、進捗がよろしくなくSiv3Dを勧めてみました
  • 一年生はC言語の基礎構文はある程度理解していましたが、C++にはほとんど馴染みがありません。

Siv3D導入の理由

私は普段からSiv3Dを愛用していました。そのゆえSiv3Dのパワフルさを知っていました。 しかし、わけあって一年生には始め導入していませんでした。


というのも、昨年も私は一年生教育係を務めていました。

そしてそのときは、特に使いたいものがなければ、 DXライブラリ + Visual Studio という構成でゲームを作成するよう指示していました。

当時もSiv3Dの存在は知っていましたが、C言語の知識だけで理解できるという点でDXライブラリを推奨しました。(本当の理由は学校のPCがWin10じゃなかったから。Win7だとランタイムインストールしないといけない。まあでも今年Win10になったんで…はい) が、想定していなかったわけではないですが、Visual Studioの環境構築でつまずいてしまう部員がちらほら。


また、Visual Studioは重いです。PCスペックが足りずに起動まで分単位で待たないといけない、ストレスMAX~みたいな状況の部員も散見しました。


というわけでその年は、Visual Studioは諦めて、超軽量IDEのBccDeveloperに鞍替えしてしました。

IDEとして機能が充実していることも大事だけど、初心者にとっては、気軽に開発ができる環境であることも大事なんだなーと学びました。


と、いうこともあって、最初は現一年生には DXライブラリ + BccDevを推奨していたんですが、これはこれで問題発生。


「DXライブラリ、難しい」


まず、「正しい」Mainにたどり着くまでが長い。

#include "DxLib.h"

int My_DxLib_Init(bool bWindowMode, int Window_X, int Window_Y, int ColorBitNum, const char *MainWindowText) {
    ChangeWindowMode(bWindowMode);
    SetGraphMode(Window_X, Window_Y, ColorBitNum);
    SetWindowIconID(100);
    SetMainWindowText(MainWindowText);
    DxLib_Init();
    SetDrawScreen(DX_SCREEN_BACK);
    return 0;
}

int LoopProcess(void) {
    if (ScreenFlip()) return -1;
    if (ProcessMessage()) return -1;
    if (ClearDrawScreen()) return -1;
    if (Key_Input()) return -1;
    if (Mouse_Input())    return -1;
    return 0;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{
    My_DxLib_Init(true, 850, 680, 32, "ブロック崩し");

    while( !LoopProcess() )
    {
        if(Key_chk[KEY_INPUT_ESCAPE] >= 1)break;
    }


    DxLib_End() ;
    return 0 ;
}

言語文法の知識は足りてても、「裏画面ってなに?」とか「Whileの中に突っ込んでるLoopProcessの中身なに?」とか本質のプログラム書く前の関門が多いんですよね。

省略しましたが、Key_Inputあたりの定義もしないといけません。


また、例えば「敵と弾丸とのあたり判定を作りたい!」と思ったとき、DXライブラリだと「まず、敵を四角形だと近似してだな。四角形と円があたっているかの条件はごにゃごにゃ内積外積ガーごにゃごにゃ…」と、やりたいことに対して考えないといけないことが多いんですよね。



というわけで、一年生がゲームづくりに対して辟易としてしまったので、C++はそんなに教えていかったんですが、「Siv3D、これ enemy.intersects(bullet) で書けるよ」と誘い、Siv3Dを導入しました。



Siv3Dを導入してよかったこと

Mainまでの道のりが早い

Siv3DのMainはこうです

# include <Siv3D>
void Main()
{
    while(System::Update())
    {
        
    }
}

簡潔。Visual Studioからプロジェクトのプロパティをいじるような初期設定なんかもありません。



当たり判定などの処理が簡単に書ける

DXライブラリ上がりの身としては .intersects() は革命ですよ。 Siv3D公式サンプルにある画像をPolygon型に変換するプログラムを使えば、任意の画像に対して、ほぼ正確な当たり判定をつけることもできます。

その他にも、ああいうことやりたい!と思ったら大抵もう実装されています。



TextureがTextureとして書ける、RectがRectとして書ける

DXライブラリだと、画像の表示はこんな感じに実装するんではないでしょうか。

int image_id = LoadGraph(path);
DrawGraph(x, y, image_id, true);

しかし、画像がint型ってよくわからないですよね。今回は _id という変数名にしたのでまあ理解できないこともないですが。

Siv3Dだと、こうかけます。

Texture texture(path);
texture.draw(0, 0);

Textureを示すTexture型の変数を用意して、それをdraw()する。

状況を的確に表してわかりやすいです。これはオブジェクト指向言語のよさでもありますね。



困ったらそれっぽいこと書いてみる・ピリオド、::を打ってみる

ピリオドを押せば、IDEがメンバ変数名・メソッド名を羅列してくれる

オブジェクト指向言語を使うことで得られる恩恵でもっとも素晴らしいことが、このことだと思っています。

例えば、imageを回転させたい。そう思ったら、image.と打ってみるのです。そうすれば、メソッド名が羅列されて、その中にきっとimage.rotate()みたいなメソッドがあるはずです。リファレンスをみなくてもピリオドを押して探してみればいいんです。Windowのサイズを変えたければ、とりあえず、 Windowsと打ってみるのです。するとVisual StudioWindowっていう名前空間があるよって教えてくれて、Window::と押せばこれまたいろんな関数が出てきて、その中からResize的なのを探せばいいわけです。

基礎的な英単語力と賢いIDE、そして充実したライブラリがあれば、初心者でも比較的容易にもクラスは(作るのでなく利用する分には)扱えてしまうわけですね。

事実、一年生も意外とすんなりこのクラスという概念に馴染んでくれました。



充実したサンプル

本当にありがたいことに、Siv3Dはたくさんのサンプルが公開されています。 ラムダ式やら三項演算子ばりばり使ってたりイテレーター使ってたりやらで、初学者には難しいサンプルも多いですが、それでも、とりあえずコピペしたらちゃんと動くものがある、というのはやっぱり安心です。



Siv3Dを導入して悪かったこと

環境構築でつまずく可能性がある

Siv3Dを導入は、

の2ステップでできます。


しかし、まあエラー続出で。


多くの原因はWindows 10 SDKが導入されていないことだったんですが、始めの一歩でつまずくというのはなかなか心が折れますよね。



Visual Studioが重い・容量も使う

パワフルであるがゆえ、です。しょうがないですね。上でも書きましたが、気軽に立ち上げられないって結構初心者にとってモチベの低下につながります。 まあ最近は家電量販店にもSSD搭載PCが結構置かれていますし、動作の不快適さは気にならなくなるかもですね。

容量もまあ、それなりの大きさのものを買っていれば、入らないなんてことは無いでしょう。たぶん。



なんだかんだC++の知識は必要

Siv3Dって結構モダンなC++で書かれていますよね。

それゆえ、ぱっと見の簡潔さはあるのですが、よくよく考えると難しいコードも多いです。

// どちらも()のオーバーロード
vec.moveBy(Vec2(5, 0));
font(L"Hello, world!").draw();

// どっちで書く?
Vec2 vec = Vec2(10, 20);
Vec2 vec(10, 20);

// なにこのfor文
for (auto& enemy : Enemy) { }
for (auto it = enemy.begin(); it != enemy.end(); ++it) { }

// 返り値の書き方が。。。
Vec2 func()
{
    return {0, 0};
}

言われたら(一部は)わかるんですけど、慣れないうちは慣れないです。

あと、Siv3DのPoint型とVec2型とSize型の違いに困惑している例もありましたね。



まとめ

実は初心者への導入記事ってそんなにないかなーという気がして書いてみました。

Siv3Dは素晴らしいライブラリ・フレームワークです。初心者にもおすすめできるわかりやすいライブラリです。事実、一年生たちはSiv3Dを使っていろんな楽しいゲームを作ってくれました。

完全に使いこなすにはC++の知識が必要になりますが、そうでなくても簡単なゲームならぱぱっと作れちゃいます。

OpenSiv3Dの開発も着々と進んでおり今後の展望にも大期待ですね!



ちなみに余談ですが、弊部の高専祭ゲーム展示。殆どがSiv3D製でした。やっぱり、きてますね、Siv3D。