亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

コマンドバトルをもうちょっと考えてました。

前回一度話題にしたコマンドバトルもどきの設計もちょこちょこやっています。まぁどちらかっていうとC++に苦しめられているのですが。ていうか体系的に勉強してないので全然ダメです。特に引数や関数にconstつくのが整理できなくて大変です。

前回の最終結果はこんなのでした。
f:id:posaunehm:20120220004602p:image

でもこれ、C#ならともかくC++なら循環参照で普通はちゃんとビルドできません。やっぱもうちょっと考えないとダメです、はい。

んで、まずICharacterの存在自体が怪しくなって来ました。もうクラスで良いじゃん、と。んで、そのクラスにコマンドのターゲットなるようなインターフェースクラスを継承させます。すると依存関係は一方向で綺麗に回ります。

f:id:posaunehm:20120229010739p:image

そいじゃこれをC++にしてみましょうか。まぁ、とりあえず形だけ作ってみます。

まず、Battleクラスは直接メンバを持つのはいかがなものかと思うので(バトルはゲー雨の一部でしか無いから本来は上位オブジェクトから渡されるはず)、ポインタで持ちます。

ダメです。危ないです。なので、shared_ptrですよ、はい。
なので、こんな感じになりますね。

#include <memory>
#include "Character.h"

using namespace std;

namespace ComamndBattle{
    class Battle{
    private:
        shared_ptr<Character> _player;
        shared_ptr<Character> _enemy;
    public: 
        Battle(shared_ptr<Character> player, shared_ptr<Character> enemy)
        :_player(player),_enemy(enemy){
            
        }
    };
}

そして、当たり前のようにインターフェースを使ってますが、C++だとそんなのは無いので、純粋仮想関数で作っていきます。
まず、ICommandTargetから。

class ICommandTarget {
    
public:
    virtual void CauseDamage(int) = 0;
};

とりあえずは、ダメージを喰らわせるインタフェースだけで大丈夫だろうという判断ですが、これは普通どんどんづえていくとは思います、ハイ。

次にICommand。なんかMVVMっぽいですね。

#include "ICommandTarget.h"

class ICommand {
public:
    virtual void Execute(ICommandTarget&) = 0;
};

コマンドの適用先は外部から与えてもらうようにしています。この場合は多分Battleクラス内に実装があるんでしょうね。

んで、まずはICommandTargetを実装し、ICommandを保持するCharacterクラスです。

#include <vector>
#include <memory>
#include <string>
#include "ICommand.h"
#include "ICommandTarget.h"

using namespace std;

class Character : public ICommandTarget {
public:
    Character(){
    }

    //ICommandTarget->    
    void CauseDamage(int damage){
        _hitPoint -= damage;
    }
    //<-ICommandTarget

private:
    string _name;
    unsigned int _hitPoint;
    vector<shared_ptr<ICommand>> _commands;
};

_commandsメンバ変数は、どうにかして外部から与えてやらないといけないですね。ちょっと後回し。

んで、Commandの具体的な実装はこんな感じになります。

#include "ICommand.h"
#include "ICommandTarget.h"

class AttackCommand : public ICommand{
private:
    int _attackPoint;
    
public:
    AttackCommand(int attackPoint):_attackPoint(attackPoint){
    }
    // ICommand ->
    void Execute(ICommandTarget &target){
        target.CauseDamage(_attackPoint);
    }
    // <- ICommand
};

さて、後は中身を頑張って書くだけでしょ、多分。。。