見出し画像

時間芸術としての天丼(190224)

本日の日報記です。

7時半:
ネットカフェで起床。
前日、弟と従妹と飲みに行って終電を逃したのでブラックラグーン読んで寝た。二人とも頑張ってた。弟が強烈な絵面の黒人の話をしていた。

9時:
帰宅。
リンゴを食べたあと、ベッドで気絶。

13時半:
こないだやり残してたStrategyパターンの勉強。
とりあえず実践プログラムを書いた。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/////////////////////////////////////
/////////BattleSystem's User/////////
/////////////////////////////////////
public class BattleWithAttribute : MonoBehaviour {

    private void Start()
    {

        Charactor braveMan = new Player(1000,10);
        Charactor evilMan = new Enemy(1000,20);
        BattlePhase battlePhase = new BattlePhase(braveMan, evilMan);

        evilMan.SetAttribute(CharacterAttributes.Darkness);
        battlePhase.ReSetBattleCharactor(braveMan, evilMan);//バグ:属性変更が起きた時に、現状だとbattlePhase内のインスタンスに変更が適用されないので用意したメソッド
        battlePhase.Battle();

        braveMan.SetAttribute(CharacterAttributes.Thunder);
        battlePhase.ReSetBattleCharactor(braveMan, evilMan);
        battlePhase.Battle();
    }

}

//////////////////////////////
/////////BattleSystem/////////
//////////////////////////////
#region interfaces
interface IAttack
{
    void Attack(int damage, Charactor target);
}

interface IDecideDamageWithAttribute
{
    int Decide(int damage , CharacterAttributes enemyAttribute);
}
#endregion

#region abstract classes
public abstract class Charactor : IAttack
{
    private int _HP;
    private int _Power;
    private CharacterAttributes _myAttribute;
    private AttributeDamageStrategy _myAttributeDamageStrategy;

    public int HP
    {
        get { return _HP; }
        set
        {
            _HP = value;
            if(_HP < 0)
            {
                _HP = 0;
            }
        }
    }
    public int Power
    {
        get { return _Power; }
        set
        {
            _Power = value;
            if (_Power < 0)
            {
                _Power = 0;
            }
        }
    }
    public CharacterAttributes MyAttribute
    {
        get { return _myAttribute; }
    }
    public AttributeDamageStrategy MyAttributeDamageStrategy
    {
        get { return _myAttributeDamageStrategy; }
    }

    public Charactor(int hp, int power)
    {
        _HP = hp;
        _Power = power;
        _myAttribute = CharacterAttributes.Normal;
        _myAttributeDamageStrategy = new NormalDamageStrategy();
    }

    public void SetAttribute(CharacterAttributes gotAttribute)
    {
        _myAttribute = gotAttribute;
        SetAttributeDamegeStrategy();
    }

    public void Attack(int initialDamage, Charactor target)
    {
        int editedDamage = _myAttributeDamageStrategy.Decide(initialDamage,target.MyAttribute);
        target.HP -= editedDamage;
        Debug.Log(target+"に"+editedDamage+"のダメージ!");
    }
    private void SetAttributeDamegeStrategy()
    {
        if (_myAttribute == CharacterAttributes.Normal)
        {
            _myAttributeDamageStrategy = new NormalDamageStrategy();
        }
        if(_myAttribute == CharacterAttributes.Fire)
        {
            _myAttributeDamageStrategy = new FireDamageStrategy();
        }
        if (_myAttribute == CharacterAttributes.Water)
        {
            _myAttributeDamageStrategy = new WaterDamageStrategy();
        }
        if (_myAttribute == CharacterAttributes.Nature)
        {
            _myAttributeDamageStrategy = new NatureDamageStrategy();
        }
        if (_myAttribute == CharacterAttributes.Thunder)
        {
            _myAttributeDamageStrategy = new ThunderDamageStrategy();
        }
        if (_myAttribute == CharacterAttributes.Darkness)
        {
            _myAttributeDamageStrategy = new DarknessDamageStrategy();
        }
    }
}

public abstract class AttributeDamageStrategy : IDecideDamageWithAttribute
{
    public abstract int Decide(int initialDamageValue, CharacterAttributes enemyAttribute);
}
#endregion

public enum CharacterAttributes
{
    Normal,
    Fire,
    Water,
    Nature,
    Thunder,
    Darkness
}
class NormalDamageStrategy : AttributeDamageStrategy
{

    public override int Decide(int initialDamageValue, CharacterAttributes enemyAttribute)
    {        
        return initialDamageValue;
    }
}
class FireDamageStrategy : AttributeDamageStrategy
{

    public override int Decide(int initialDamageValue, CharacterAttributes enemyAttribute)
    {
        int editingDamegeValue = initialDamageValue;
        if(enemyAttribute == CharacterAttributes.Nature)
        {
            editingDamegeValue *= 3;
        }
        return editingDamegeValue;
    }
}
class WaterDamageStrategy : AttributeDamageStrategy
{

    public override int Decide(int initialDamageValue, CharacterAttributes enemyAttribute)
    {
        int editingDamegeValue = initialDamageValue;
        if (enemyAttribute == CharacterAttributes.Thunder)
        {
            editingDamegeValue *= 3;
        }
        return editingDamegeValue;
    }
}
class NatureDamageStrategy : AttributeDamageStrategy
{

    public override int Decide(int initialDamageValue, CharacterAttributes enemyAttribute)
    {
        int editingDamegeValue = initialDamageValue;
        if (enemyAttribute == CharacterAttributes.Water)
        {
            editingDamegeValue *= 3;
        }
        return editingDamegeValue;
    }
}
class ThunderDamageStrategy : AttributeDamageStrategy
{

    public override int Decide(int initialDamageValue, CharacterAttributes enemyAttribute)
    {
        int editingDamegeValue = initialDamageValue;
        if (enemyAttribute == CharacterAttributes.Darkness)
        {
            editingDamegeValue *= 3;
        }
        return editingDamegeValue;
    }
}
class DarknessDamageStrategy : AttributeDamageStrategy
{

    public override int Decide(int initialDamageValue, CharacterAttributes enemyAttribute)
    {
        int editingDamegeValue = initialDamageValue;
        if(enemyAttribute != CharacterAttributes.Thunder)
        {
            editingDamegeValue *= 2;
        }
        return editingDamegeValue;
    }
}

public class Player : Charactor
{
    public Player(int hp_player,int power_player) : base(hp_player, power_player)
    {

    }

}
public class Enemy : Charactor
{
    public Enemy(int hp_enemy, int power_enemy) : base(hp_enemy, power_enemy)
    {

    }
}

public class BattlePhase
{
    private Charactor _c1;
    private Charactor _c2;

    public BattlePhase(Charactor c1, Charactor c2)
    {
        _c1 = c1;
        _c2 = c2;
    }
    public void Battle()
    {
        _c1.Attack(_c1.Power,_c2);
        _c2.Attack(_c2.Power,_c1);
    }
    public void ReSetBattleCharactor(Charactor c1, Charactor c2)
    {
        _c1 = c1;
        _c2 = c2;
    }
}
    


このパターン、SOLID原則の「オープン・クローズドの原則」に関わってくるらしいんだけど、それがどれだけ実現できてるのかって言われるとちょい微妙なとこがある。属性とそれに伴う振る舞いが追加しやすいのがこのコードの肝のはずなんだけど、結局Strategyを追加してもそれを属性に合わせてセットするif文の羅列は修正しなきゃいけないので。。どうすりゃいいんじゃ。
あと、今は各属性によって変わるダメージ量の変動をStrategyクラスとしてるけど、これに関してはまだ抽象化の余地があるというか、攻撃に関わらず、素早さだったり、マグマとか毒環境ではダメージ受けないみたいなステータス異常とかのStrategyも想定しとかないといけなさそうだからそれも改善点かもしれない。正直システムがこの程度の規模感だとパターンを採用してもわかりづらいだけのコードっぽくなっちゃうので、なんでもかんでもこういうの書くのはよくないなと思った。臨機応変にってことっぽい。

21時:
アライグマのモデリング。

埋まってた首回りをキュッとさせて、尻尾もでっかく猫じゃらしみたいにして、足を延ばした後にO脚っぽくした。おなか周りをもうちょい丸くしなきゃいけない。あとなんか足が生々しくてなんかアレ。

明日もよろしくお願いします。

この記事が気に入ったらサポートをしてみませんか?