お茶漬けびより

"あなたに教わったことを、噛んでいるのですよ" 五等分の花嫁 7巻 「最後の試験が五月の場合」より

抽象基本クラス(Abstract Base Class : ABC)の復習

ファクトリーメソッドを復習しようと思ったら、抽象基本クラスの復習をする羽目になったので、 調べて学んだことをメモ書きします。

抽象クラスとは

概念的なもの。このクラスから実態を持つことは出来ないが、抽象クラス型へのポインタと参照は使用できる。だそうです。

抽象クラス (C++)

実態を持たないので、継承しないと意味がありません。なので、抽象基本クラスとも言うそうです(自分が読んだ本には、抽象基本クラスと書いてあった)。今後、抽象基本クラスは ABC(Abstract Base Class) と表記します。

じゃあ、どういうものが ABC かというと、純粋仮想メンバ関数を持つクラスのことを ABC といいます。純粋仮想メンバ関数というのは、以下の様なものです。

virtual void Method() = 0;

純粋仮想メンバは、継承先で必ずオーバーライドしないといけません。つまり継承先で必ず実装しないといけません。ですが、ABC 側で実装をしてはいけないという意味ではありません。Method().cpp ファイルで実装するとコンパイルは通り、呼ぶことが可能です。

ABC は実態を持つことは出来ませんが、ABC 型へのポインタを作ることが可能です。
このポインタを使って、ABC を継承した様々なクラスのインスタンスへのポインタを入れることが出来ます。つまり、以下のように書きます。

IBase *instance = new Derived();

IBase は、ABC です。Derived は、 IBase を継承したクラスです。
instance->method() のように使えば、継承したインスタンスを呼ぶことが出来ます。上記は、Derived のみですが、他に IBase を継承したクラスがあれば、同じように使うことが出来ます。

コンストラクタ、デストラクタ

コンストラクタを仮想化することは出来ませんが、デストラクタは可能です。 つまり以下のように書けます。

virtual ~IBase();

これは、ABC で必ず必要になります。ABC は、実態を持つことはないので、必ず継承されて使われます。しかし、書かなくてもコンパイルは通ります。このときコンパイラは、デフォルトデストラクタを作成しますが、この状態で ABC を継承した Derived 型のポインタを delete すると、大変なことが起こります。コードで示すと以下のようになります(コンパイルは通らないかもしれません……)。

// 抽象基本クラス
class IBase
{
public:
    virtual void Method() = 0;
};
// 抽象基本クラスを継承したクラス
class Derived : public IBase
{
public:
    ~Derived(){};
    void Method() {};
};

int main()
{
    IBase *instance = new Derived();
    instance->Method();
    delete instance;
    
    return 0;
}

このとき、delete で呼ばれるデストラクタは、IBase のデフォルトデストラクタです。継承先のデストラクタは呼ばれません。どうしてかは詳しく説明できないですが、IBase のデストラクタが実態を持っていることが原因であることは分かると思います。 ですので、抽象基本クラスを作るときは、必ずデストラクタに virtual を付けるように気を付けましょう。

キーワード:override

デストラクタには virtual を付けるように気をつけましょうと言いましたが、このミスをコンパイル時に見つける方法があります。それが、override 指定子です。
こいつを付けることで、コンパイラに「今からオーバーライドするよ」と教えることが出来ます。つまり以下のようになります。

// 抽象基本クラスを継承したクラス
class Derived : public IBase
{
public:
    ~Derived() override {};
    void Method() {};
};

~Derived() の後に override を付けることで、コンパイル時にエラーが発生するようになります(Visual Studio 2017 だとコンパイルする前に赤い波線が出ました)。
もちろんデストラクタだけでなく、メソッドにも付けることが可能です。オーバーライドをするときには、必ず override を付けるようにしましょう。

override 指定子

キーワード:final

今度は、逆にオーバーライドをして欲しくないときの対処法です。override と同じようにメソッドの後ろに final を付けます。以下のようになります。

virtual int value() final { return value_; };

このように書くことで、継承先がオーバーライドをしようとすると、コンパイラはエラーを発します。処理が今後変わることがないときは、 final を付けるようにしましょう。

final 指定子

キーワード:delete

最後に delete を紹介します。これは、delete 演算子ではありません。何と言うのかちょっと調べただけでは分からないですが、このキーワードを使うことで、メソッドやコンストラクタ、デストラクタを削除することが出来ます。 以下のように書きます。

public:
IBase() = delete;

public 側で書くことをお勧めします。これはコンパイラが delete であるかどうかよりもアクセスの可否を先に見るためです。private で delete されたメソッドをユーザが使おうとすると メソッドが private であることだけをエラーとして吐くそうです。また他にも利点があるのですが、ここでのメインの話ではないので省きます。詳細は、Effective Modern C++ の項目 11 を見てください。

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

Effective Modern C++ ―C++11/14プログラムを進化させる42項目

おわり

以上、抽象基本クラスの復習でした。 C++11 から使えるようになったキーワードを混ぜることで、安全に継承をすることが出来るようになりそうです。

ここで記載したコードは、以下に上げています。

github.com

最後に、参考にした(復習する羽目になった)書籍を貼っておきます。

C++のためのAPIデザイン

C++のためのAPIデザイン

C# と .Net Framework で 他の Windows アプリを操作するアプリ

簡単にですが作りました。

経緯

最近、C# を学び始めて .Net Framework を使うようになったのですが、これがけっこう便利で楽しくて、 ふと、WindowsAPI なら ハンドル取ってこれそうだなと思い、調べるとすでにやってる人がいたので、 マネをしてみました。

目的

アプリ一つ一つに割り当てられているハンドル(ウィンドウハンドル)を取得して、 外部のアプリからハンドル先に値を送ることでアプリを操作することが目的です。
まだ可能かどうかは分かりませんが、ゲームのテストや同じ操作の繰り返しをプログラムで 制御できればいいなと思って作りました。

こちらを参考にしたので、試したい方はこちらを見た方が早いかと思います。

普通、アプリだと複数のウィンドウやボタンがあるので、操作をするのは難しいのですが、 自分の場合は、ゲームの操作が目的だったので、ハンドルを取ってしまえばあとはコントローラの キーにあたる値を送ることで操作することが可能です。

操作するためのキーの値はこちらを見ればいいかと
Virtual-Key Codes (Windows)

環境

環境は以下です。

以下は、今回使う言語やフレームワーク、その他出てくる技術です。
もし読んでて分からないところがあれば、以下のキーワードを加えて検索するといいかも……?

GUI の作成

WPFGUI を作ります。 重要な部分ではないので飛ばします。以下のように作りました。

f:id:pickles-ochazuke:20170326231753p:plain

各ボタンの処理

Get Handle というボタンは、隣にある Process Name の入力内容を元に関係するアプリを探して、ウィンドウハンドルを取得します。Process Name は、タスクマネージャを開き、詳細タブに並んでいる .exe を除いたアプリの名前を入力します。

ボタン入力時の処理は以下です。

private void GetHandleButton_Click(object sender, RoutedEventArgs e)
{
    process = System.Diagnostics.Process.GetProcessesByName(ProcessName.Text);
    foreach (System.Diagnostics.Process ps in process) {
        LogBox.Text += ps.Id + ps.MainWindowTitle + ps.MainWindowHandle + "\n";
    }
}

GetProcessesByName でアプリのハンドルを取得します。 取得したら、内容をテキストボックスに出力します(これは確認用)。

Button というボタンは、Message の内容をハンドル先に送ります。つまり、Message に操作用の値を書き、 Button を押すことでアプリを操作します。が、これはまだ未実装です。現状は、予め用意した値を送るようにしています。

IntPtr hWnd = process[0].MainWindowHandle; 
LogBox.Text += SendMessage(hWnd, 0x0100, 0x20, 0x00);

SendMessage() で、どう操作したいかを指示しています。その後、確認用にテキストボックスに出力しています。 SendMessage(ハンドル, イベント, 内容1, 内容2) のように指定します。
イベントは、キーが押されたキーが離されたマウスのボタンがクリックされたなどです。内容1,2はイベントに合わせて指定します。何もない場合は 0x00 でいいと思います。 上記だと、hWnd に、スペースキー押されたという情報を送ります。 SendMessage は、.Net FrameworkAPI ではなく、Win32APIAPI です。これは、以下のように宣言することで使えるようになります。

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

DllImport という属性(Attribute)を使うことで、外部のライブラリを使えるようにしています。 ここら辺は、以下を参照してください。(正直、自分はちゃんと理解出来ていません……)

@IT:.NET TIPS Win32 APIやDLL関数を呼び出すには? - C#
キーワード:Attribute, Reflection, Annotation

これだけのコードで、別のアプリにプログラムで好きなキー入力を行うことができます。

コード

XAML 側のコードがないので、これだけでは動かないのですが、一応全文載せておきます。

using System;
using System.Windows;

namespace GetHandle
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        System.Diagnostics.Process[] process;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void GetHandleButton_Click(object sender, RoutedEventArgs e)
        {
            process = System.Diagnostics.Process.GetProcessesByName(ProcessName.Text);
            foreach (System.Diagnostics.Process ps in process) {
                LogBox.Text += ps.Id + ps.MainWindowTitle + ps.MainWindowHandle + "\n";

            }
        }

        private void MessageButton_Click(object sender, RoutedEventArgs e)
        {
            IntPtr hWnd = process[0].MainWindowHandle; 
            LogBox.Text += SendMessage(hWnd, 0x0100, 0x20, 0x00);
        }

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
    }
}

デモ

UE4 で http 通信を行う

少し前に UE4 で http 通信をしようと思い、ネットで方法を探していたのですが、 バージョンの違いか、手順が悪いのか、上手くいかず悩んだ末、UE4 の公式ドキュメントの方法で出来たので、その方法をまとめます。

以下、自己責任で行って下さい。

UE4.10 How To Make HTTP GET Request in C++ - Epic Wiki

上記のURLの方法をそのまま行えば出来ます。

ただ、php 周りの説明が分かっている前提なので、その辺補足出来たらいいなと思い、この記事を書くことにしました。

環境

  • Windows 10
  • UE4.14.3
  • VisualStudio 2015
  • XAMPP 3.2.2

プロジェクトの作成

まず、新規プロジェクトでC++のタブを選択します。 そして、基本コード(BASIC CODE)を選択します。

f:id:pickles-ochazuke:20170213214210p:plain

すると、VisualStudio が立ち上がると思います。気長に全ファイルを読み込むのを待ちます。
読み込めました? では、ビルドしましょう。
とくに問題が起こらないとは思うので、次に進みます。

アクタの作成

UE4 のエディタで http を取得するアクタを作ります。
まず、コンテンツブラウザの新規追加を選び、新規 C++ファイル… を選択します。親クラスは、Actorを選択します。
ファイル名は何でもいいです。今回は、GetHttpActorとしました。あと、パブリック、プライベートは特に選択しませんでした。
クラスを作成をクリックして、リコンパイルが終わるのを待ちます。

ソースコードの編集

では、プロジェクトの中身をいじっていきます。

Build.cs

”プロジェクトファイル名”.Build.cs という名前のファイルが VisualStudio のソリューションエクスプローラーにあると思います。
今回、自分のプロジェクト名は、MyProject(つまりデフォルトの名前)にしたので、MyProject.Build.cs というファイルがあるはずです……ありました。

f:id:pickles-ochazuke:20170213220228p:plain

見つかりましたか? よく探してくださいね。ソリューションエクスプローラーの検索を利用するといいかもしれません。例えば、.Build.cs で検索してみましょう。Games のフォルダ内を探して下さい。もう見つかった? お疲れ様です。では、次に行きましょう。

先ほど見つけたファイル(画像だと MyProject.Build.cs)を開いてください。

MyProject.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"});

"Http", "Json", "JsonUtilities" という一文があると思います。バージョンによっては違うかも……。 PublicDependencyModuleNames.AddRange を探すといいかもしれません。見つけたら、{}内に以下を追加します。
すると以下のようになると思います。

MyProject.Build.cs

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Http", "Json", "JsonUtilities" });

このファイルはこれで以上です。

Engine.ini

次は、Engine.ini ファイルを探します。VisualStudio は使いません。そこには表示されないからです。 プロジェクトフォルダが保存されている場所に移動してください。そして、今回のプロジェクト名のフォルダの中に移動します。Saved/Config/Windows と移動して下さい。もしかしたら Windows がないかもしれません。Config 以下まで移動したら、Engine.ini を探して下さい。自分は、MyProject/Saved/Config/Windows の下に Engine.ini がありました。そして、てきとうなテキストエディタで開きます。

そして、一番下に以下を追加します。

Engine.ini

[HTTP]
HttpTimeout=300
HttpConnectionTimeout=-1
HttpReceiveTimeout=-1
HttpSendTimeout=-1
HttpMaxConnectionsPerServer=16
bEnableHttp=true
bUseNullHttp=false
HttpDelayTime=0

追加したら、保存して閉じて下さい。またVisualStudio に戻ります。

GetHttpActor.h

http を取得するアクタを作ったと思います。そのヘッダファイルを開きます。
今回だと、GetHttpActor.h です。 まず、以下のようにインクルードファイルを追加します。

GetHttpActor.h

#include "Runtime/Online/HTTP/Public/Http.h"

public: 以下に次の内容を追加します。

FHttpModule* Http;

/* The actual HTTP call */
UFUNCTION()
void MyHttpCall();
 
/*Assign this function to call when the GET request processes sucessfully*/
void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);

ヘッダファイルは以上です。

GetHttpActor.cpp

次は、ソースファイル GetHttpActor.cpp をいじります。まず、コンストラクタ AGetHttpActor() に以下を追加します。

Http = &FHttpModule::Get();

そして BeginPlay() に以下を追加します。

MyHttpCall();

以下のメンバメソッドを追加します。

GetHttpActor.cpp

/*Http call*/
void AGetHttpActor::MyHttpCall()
{
TSharedRef<IHttpRequest> Request = Http->CreateRequest();
Request->OnProcessRequestComplete().BindUObject(this, &AGetHttpActor::OnResponseReceived);
//This is the url on which to process the request
Request->SetURL("http://localhost:8081/WebApi/getint.php");
Request->SetVerb("GET");
Request->SetHeader(TEXT("User-Agent"), "X-UnrealEngine-Agent");
Request->SetHeader("Content-Type", TEXT("application/json"));
Request->ProcessRequest();
}

/*Assigned function on successfull http call*/
void AGetHttpActor::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{

 //Create a pointer to hold the json serialized data
 TSharedPtr<FJsonObject> JsonObject;

 //Create a reader pointer to read the json data
 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Response->GetContentAsString());

 //Deserialize the json data given Reader and the actual object to deserialize
 if (FJsonSerializer::Deserialize(Reader, JsonObject))
 {
 //Get the value of the json object by field name
 int32 recievedInt = JsonObject->GetIntegerField("customInt");

 //Output it to the engine
 GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, FString::FromInt(recievedInt));
 }
}

ひとまずは、コピペで構いません。
お疲れ様です。C++ に追加することは以上で終了です。
ビルドが通るか確認しましょう。

これで、GetHttpActor をレベル上に置けば http を取得してくれるのですが、今の状態で行っても http は取得できません。http を発行してくれるサーバがないからですね。では、サーバの準備をしましょう。

XAMPP

サーバを立てる方法はいろいろありますが、今回は XAMPP を使います。 インストールの方法は、ネット上にたくさんあるので、そちらにお任せします。 例えばこれを見るといいでしょう。

XAMPP を立てるときにセキュリティが気になる人は、セキュリティの設定を行うか、ネット回線を切ってしまいましょう。

たぶん XAMPP を使って Apache を立てるとエラーが発生すると思います。 その場合、以下の記事を見ると解決するかもしれません。

余裕があれば、別記事にまとめたいと思います……。

PHP ファイルの作成

XAMPP を上手く入れることが出来ましたでしょうか? お疲れ様です。あと少しで完了です。では、XAMPP を無事インストールしたので、PHP のファイルを作ります。

以下の内容をコピペして下さい。

getint.php

<?php
    //Create a variable to be used in 
    $theVar = array('customInt' => 5);
 
    //Set the headers
    header('Content-Type: application/json');
 
    //Encode the variable, and save the encoded string
    $encoded = json_encode($theVar);
 
    //Output it
    echo $encoded;
?>

そして、getint.php というファイル名にして保存します。 このファイルを以下に置いて下さい。

C:\xampp\htdocs\WebApi

WebApi フォルダは作る必要があると思います。XAMPP をインストールするときに、保存場所を変更した場合は、 C:\ の下にないかもしれません。getint.php ファイルを置くことが出来たら、少しだけ C++ ファイルをいじります(Apache のポート番号を変えていなかったら必要ないかも)。

C++ 側の URL を編集

GetHttpActor.cpp を開いて下さい。 そして、void AGetHttpActor::MyHttpCall() の中を見ます。

Request->SetURL("http://localhost:8081/WebApi/getint.php");

という一文があると思いますが、この SetURL の中身を変えます。 見ると分かるかもしれませんが、中身は URL を表しています。 注意してほしいのは、 localhost:8081 の 8081 です。Apache のポート番号とここのポート番号が合っていないと、正しく処理することが出来ません(URLの場所が見つからないからです)。

サーバを立てる

SetURL の中身を書き換えたら、XAMPP の Apache の Start のボタンをクリックして下さい。すると Apache の文字の周りが黄緑色みたいになると思います。黄色や赤色だと何か問題が発生していると思います。エラーの内容をコピペして検索してみましょう。

問題がない場合、サーバを立てることに成功しています。実際に確認してみましょう。ブラウザを開いて、以下のように入力します。

例えば、http://localhost:94/ とします(ポート番号は人によって異なります)。すると以下のような画面が表示されます。

f:id:pickles-ochazuke:20170214230230p:plain

SetURL と同じURLを指定してみましょう

http://localhost:94/WebApi/getint.php

すると以下のような文章が出ると思います。

{"customInt":5}

これが出ていれば成功です。
では、VisualStudio の方でビルドをします。成功したら、UE4 エディタに戻り、GetHttpActor を選択します。右クリックをして、「GetHttpActor に基づくブループリントクラスを作成します。」 を選択します。そして、てきとうなファイル名(自分は、MyGetHttpActor にしました)を設定し、てきとうな場所に作って下さい。そして、 MyGetHttpActor を開きます。開いたら、コンポーネントを追加で視覚的に置いてあることが分かるようなものを追加しましょう。自分はキューブを追加しました。そしてコンパイルをして、レベル上に配置します。

確認

最後に確認です。

  • XAMPP は正常に動作していますか?
  • Apache は正常に動作していますか?
  • ブラウザを開いて、http://localhost:94/WebApi/getint.php にアクセスすると、php のコードが正しく動いていますか? PHP のコードをコピペしていたら {“customInt”:5} のように表示されるはずです。
  • VisualStudio は正しくビルド出来ていますか?
  • SetURL の中身は http://localhost:94/WebApi/getint.php になっていますか?
  • UE4 のレベル上に GetHttpActor を継承したブループリントクラスのインスタンスが置かれていますか?

では、UE4 エディタのプレイをクリックしましょう。
以下の画像のように文字が表示されるはずです。

f:id:pickles-ochazuke:20170214231918p:plain

無事、http 通信をすることが出来ました。とても小さなことですが、これだけでもいろいろ幅が広がります。長くなりましたが、以上です。 お疲れさまでした。

おわりに

http 周りのソースコード調べないとなぁ……。
あと、分かりづらいところがあればコメントを下さい。

Amazon Prime Music の曲紹介

はじめに

Amazon Prime Music で聴ける曲で、気に入った曲を紹介していく記事。
別々の記事にすると面倒そうなので、計画としてはこの記事に追記していく形。 いつまでも聴けるとは限らないので、その点ご注意。 あと主にOSTです。自分、歌(日本語)は疲れるのであまり聴きません。

OST:オリジナルサウンドトラック

#1.GRAVITY DAZE/重力的眩暈:上層への帰還において、彼女の内宇宙に生じた摂動 OST

タイトル長い。これは、ずっと前から聴ける曲なので、今後も聴ける気がする。
SCE(現SIE)のゲーム。ゲームは癖があるけど、このOSTは本当に最高。Prime Music にはまったきっかけ。万有引力の発見GRAVITY DAZE/重力的眩暈は必聴。
あ、自分はこのゲーム好きです。2 はまだ終わってないけど(2017/03/04 現在)。 Prime で聴けるけどサントラ欲しい。

#2.仮面の勇者~心の迷宮RPGOST

また良曲を見つけてしまった。これだから Prime Music は止められない。
ゲーム自体はやったことないのだけど、Android アプリのゲームらしい。
聴いたらピンと来るかもしれないけど、作曲者は、景山将太(かげやま しょうた)さん。主にポケモンを作曲している人らしい。というのも自分は、スマブラの印象が強かった。
一部しか聴けないし、短いからループが鬱陶しいかもしれないけど、一度は聴いてみて。

仮面の勇者?心の迷宮RPG? オリジナルサウンドトラック

仮面の勇者?心の迷宮RPG? オリジナルサウンドトラック

C++ のエラー処理

本に書いてあったエラー処理の話がためになりそうだったので、ここにまとめておこうかと思います。

参考にした本は、以下の2冊です。

C++のためのAPIデザイン

C++のためのAPIデザイン

 

4.7.4 「エラーの処理方法」を参考にしました。

ゲームエンジン・アーキテクチャ 第2版

ゲームエンジン・アーキテクチャ 第2版

 

 ゲームエンジンアーキテクチャは、3.3 「エラーの補足と処理」を参考にしました。

また、自分が持っている本は第1版です。 

 

では、まとめていきます。

 

まず、C++のためのAPIデザインの内容です。

エラーが発生した場合に対処する方法は、主に3つです。

  • エラーコードを返す
  • 例外を投げる
  • プログラムを停止する

では、一つずつ見ていきます。

エラーコードを返す

これは、エラー内容を値に置き換えることで対処する方法です。単純でありながら非常に便利です。今回はC++なのでエラーの対処法の一つになりますが、純粋なCの場合だと唯一の方法になります。

また、関数自体が何か値を返したいときにどちらか片方しか返せません。この場合は、エラーコードを返し、引数に値を入れることで対処します。

boost::tuple を使うと複数の結果を返すことが出来るようです。

例外を投げる

これはC++の例外処理を使います。関数が投げてきたオブジェクトを受け取り、対処します。例外を使うとエラー処理と通常の処理を別に切り分けることが出来るので、コードが読みやすくなります。また、シンプルなエラーコードよりも多くの情報を持たせることができます。さらに、大抵のデバッガは例外が発生するとそこで処理が止まってくれる(ブレーク)ので、デバッグが行いやすくなります。しかし、想定外の例外が発生するとプログラムが停止する恐れがあります。また通常は一部でも例外を使用する場合、そのアプリ全体で例外処理を正しく行うようにする必要があります。

エラーが発生した場合は、すぐに関数の処理を停止し、直前に割り当てられていたリソースを解放することが最善です。ただし、NULLなどの例外の値は返さないようにしましょう。関数を呼び出した側がさらにその例外の値をチェックする必要があるからです。この場合は、空のリストを返すようにするといいかもしれません。

エラー時に情報はなるべく多く、エラーの原因を早く突き止められるような情報を載せましょう。

 

次にゲームエンジンアーキテクチャの内容です。

エラーには、大きく分けて二つあります。ユーザエラーとプログラマエラーです。

ユーザエラーは、ソフトウェアを使うユーザが引き起こすエラーで、プログラマエラーはコード自体のバグです。ただし、ユーザにはさらに2種類に分けることができます。

一つは、ゲームをプレイしているユーザで、もう一つは、ゲームを制作しているユーザが引き起こすエラーです。

まとめると

ユーザエラー
  • プレイヤーエラー(ソフトウェア使用者)
  • 開発者エラー

プログラマエラー

大きく分けて2つ。細かく分けて3つのエラーの種類があります。

このユーザエラーとプログラマエラー、2つのタイプによってエラーの対処法は変わります。

ユーザエラーの場合、ゲームをプレイしていたりゲーム制作の作業をしているのでゲームや作業を止めるようなことはあってはいけません。処理を継続しながらも、ユーザの役に立つ情報を提供することが大事です。

逆にプログラマエラーの場合は、処理を止める必要があります。そして、デバッグを行うために必要な情報を提供します。

では、さらに細かく見ていきます。

プレイヤーエラー

ゲームをプレイしているときのエラーです。当然ゲームが止まるようなことはあってはいけません。そのような重度なエラーでなくとも、例えば、アイテムが0のときにアイテムを使用すると、そのアイテムは使用されずにプレイヤーに今は使うことが出来ないということを知らせる。これもプレイヤーエラーになるでしょう。

開発者エラー

これは、アーティストやアニメーターなどに起こるエラーです。例えばアセット(や画像)のようなデータを読みこませるときに、そのアセット自身が原因で起こるエラーです。このような問題のあるデータをエラーに気づかずまたは無視されていると、そのデータが入ったまま製品として出されることになります。かといって、問題があるから停止をさせると開発者の手が止まり、作業が進まなくなってしまいます。

なのでこの場合は、エラーであることを開発者に分かりやすく伝えながらも処理を継続させます。

プログラマーエラー

プログラマーエラーの場合は、本来あってはならないのですぐに処理を止めます。こうすることで、プログラマーは嫌でもバグを取り除くことになります。

 

では、エラーの検出、実装方法は何があるのでしょうか。

これはC++のためのAPIデザインにもあったエラーコードと例外。そして、アサートです。アサートは、式をチェックする命令行のことで、これを正しく使用することでプログラマはこれに引っかかると、引っかかった原因を取り除く必要があります。なので、上記の3つのエラーの中では、プログラマーエラーに使われるでしょう。またアサートは通常マクロで定義されるので、製品として出すときは取り除くことが出来ます。

以上、雑なまとめになりますが終わります。

今回のことで分かったのは、エラーの種類には複数あり、その種類によって対処の仕方は全然変わってくるということです。プログラマーのエラーには主にアサートを使い、開発者エラーの場合は、例外処理で処理を継続しつつエラーの情報を提供し、プレイヤーエラーのときは、エラーコードを使用して対処するという感じでしょうか。

そうすると統一性がなくぐちゃぐちゃになりそうですが……。アサートの使い道は分かりやすいですが、エラーコードと例外をどう使い分ければいいかがまだ分かりませんので、エラー処理の対処は、とにかく試行錯誤していくしかなさそうです……。