具体的な操作でバイナリの文字/アイテムの操作を行うにはどうすればよいですか?


8

次の問題があります。

アイテムは多くの状態を持つことができます:

NORMAL  = 0000000
DRY     = 0000001
HOT     = 0000010
BURNING = 0000100
WET     = 0001000
COLD    = 0010000
FROZEN  = 0100000
POISONED= 1000000

アイテムは同時にいくつかの状態を持つことができますが、すべてではありません

  • 同時にドライとウェットになることは不可能です。
  • ウェットアイテムをコールドすると、冷凍に変わります。
  • ウェットアイテムをホットにすると、通常に変わります
  • アイテムはバーニングとポイズンにすることができます

等。

バイナリフラグを状態に設定し、ANDを使用してさまざまな状態を組み合わせたり、可能かどうかを事前に確認したり、別のステータスに変更したりしました。

新しい状態ごとにすべての状態をチェックするスイッチがなくても、この問題を効率的に解決するための具体的なアプローチはありますか?

2つの異なる状態をチェックすることは比較的簡単ですが、3番目の状態が存在する場合、それを行うのは簡単ではありません。


3番目の状態が2のチェックと同じくらい簡単なはずなので、なぜそれが簡単ではないと思うのか理解できません。現在の方法の例と3つの状態を使用した例を投稿できますか。
ジョン、

多分あなたはそれが多くの状態を持っているなら宣言を解決するための最良の解決策をチェックすることができます:stackoverflow.com/q/13385744/1077364
vgonisanz

回答:


6

フラグを使用する必要があるとき、私は通常これらの線に沿って何かをします。

enum obj_state
{
    NORMAL      = 0x00000;
    DRY         = 0x00002;
    HOT         = 0x00004;
    BURNING     = 0x00008;
    WET         = 0x00010;
    COLD        = 0x00020;
    FROZEN      = 0x00040;
    POISONED    = 0x00080;
};

int objFlags;

void DryOn() { objFlags |= DRY; }
void HotOn() { objFlags |= HOT; }
// etc...

void DryOff() { if (FlagOn(DRY)) objFlags ^= DRY; }
void HotOff() { if (FlagOn(HOT)) objFlags ^= HOT; }
// etc...

bool isDryOn() { return FlagOn(DRY); }
bool isHotOn() { return FlagOn(HOT); }
// etc...


// If the given Bit is on this will return true.
bool FlagOn(obj_state s) { return (objFlags & s) == s; }

// returns -1 if failed, 1 if successful
int apply_cold(Object obj)
{
    if (obj.isWetOn())
    {
        obj.ColdOff();
        obj.WetOff();
        obj.FrozenOn();
    }
    else
        return -1;

    return 1;
}


//---------------------------------
// alt way of doing DryOn and WetOn
// since these conditions can not be
// active at the same time.
void DryOn() 
{ 
    if (isWetOn()) 
        return;
    else
        objFlags |= DRY; 
}

void WetOn() 
{ 
    if (isDryOn())
        return;
    else;
        objFlags |= WET; 
}

これにより、apply_cold()のようなものにそれらを使用することが非常に簡単になり、ドライやウェットなどの状態条件でビルドできることは明らかです。


多分あなたはそれが多くの状態を持っているなら宣言を解決するための最良の解決策をチェックすることができます:stackoverflow.com/q/13385744/1077364
vgonisanz

7

2つの観察:

  1. 条件システムには、温度と毒物という2つの直交軸があるようです。そのように表現します。
  2. これについて考えるとき、状態から遷移を分離する必要がありますCOLDそしてHOTあなたがそれらを言及する形で遷移である、と述べていません。

これらの観察を組み合わせると、次のような結果になります。

// These is the representation of the two axes.
int temperature; // can be between -2 and +2, 0 is normal, 1 is hot, 2 is burning, -1 is cold, -2 is frozen
bool poisoned;

// These methods represent state transitions.
void applyHeat() {
    if ( temperature <= 2 ) {
        ++temperature;
    }
}

void applyCold() {
    if ( temperature >= -2 ) {
        --temperature;
    }
}

void applyPoison() {
    poisoned = true;
}

void removePoison() {
    poisoned = false;
}

ポイントは、直交ではなく状態を追加することですが、可能ですか?HOTも状態です。通常= 30ºC、高温= 70ºC低温= 5ºC。しかし、熱を加えて熱くなっていると、それは燃えるようになります。
vgonisanz

温度をブール値の「高温」または「低温」ではなく、摂氏の整数値としてモデル化しませんか?
フィリップ

もちろん、私の回答でわかるように、温度状態をさらに追加することができます。私はすでに高温状態を表しています。フィリップが言うことは、摂氏すべてを状態として見ることを意味します。これは問題ありませんが、ゲームデザインの観点からは、これが望ましいものではない可能性があります。
Eric

3

書くように状態をビットマスクとして表すと、制約の説明をコードに変換できます。

if ( (state & HOT) && (state & COLD) ) {
    state &= ~HOT;
    state &= ~COLD;   // reset both HOT and COLD flags if both are set
}

if ( (state & COLD) && (state & WET) ) {
    state &= ~WET;    // cold items can't be wet
    state |= FROZEN;  // instead, they're frozen
}

if ( (state & HOT) && (state & WET) ) {
    state &= ~WET;    // hot and wet items dry up...
    state &= ~HOT;    // ...and cool down
}

// add other constraints here...

これをmakeStateConsistent()、状態ビットをテストする前に呼び出すことができるにラップして、状態が適切であることを確認できます。

ただし、このアプローチの1つの制限は、状態変化の順序を考慮できないことです。あなたが熱くなって濡れ項目よりも濡れホットアイテムごとに異なる結果を持っている場合たとえば、あなたはこのようにそれを行うことはできません。すべてのmakeStateConsistent()メソッドは、見ている方法についての情報なしで、ホットとウェットオブジェクトでありますそれはそのようにする必要があります。

代わりに、あなたは何ができるかISは、アイテムの状態をプライベートに(少なくとも概念的には)などのメソッドのセットを介してそれを操作coolItem()heatItem()wetItem()dryItem()などなど。これにより、状態変更メソッド自体が追加の変更を処理できます。たとえば、heatItem()メソッドは次のようになります。

if ( state & COLD ) {
    state &= ~COLD;    // cold items become normal temp when heated
    if ( state & FROZEN ) {
        state &= ~FROZEN;  // ...and melt if they were frozen
        state |= WET;
    }
} else if ( state & WET ) {
    state &= ~WET;    // wet items dry up when heated, stay normal temp
} else {
    state |= HOT;     // dry normal temp items become hot
}

もちろん、makeStateConsistent()状態変更メソッドにバグがある場合に備えて、バックアップとしてメソッドを使用することもできます。

また、場合によっては、不要な状態を排除することでコードを簡略化できる場合があります。たとえば、本当に別のFROZEN状態が必要なのでしょうか、それとも、冷たいものや濡れたものを冷凍したものとして扱うだけで十分でしょうか?

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.