2012-10-11 61 views
-2

我想了解如何實現基於打勾的系統。實施基於刻度線/圓形的戰鬥系統

玩家或非玩家獲得的每一個動作都有一個初始時間和一個冷卻時間。一旦生物冷卻時間過去了,它就會選擇一個新的動作。如果玩家必須選擇一個動作,遊戲將「暫停」。

實施例:

1:球員揮杆重(50只蜱來執行,50只蜱降溫)

2:遊戲的推移50只蜱。

3:NPC可以設置動作。

4:玩家擺動並冷卻50滴。 5:NPC可以設置動作。

6:遊戲爲玩家暫停。

我目前的工作,但效率不高。我有一個類,每個動作都是靜態方法。這些方法輸出一個包含所有數據的結構。這將被傳遞給個體生物的行動。

每個更新循環調用提示並開始倒計時攻擊時間,如果玩家已經進行了操作。一旦攻擊應該解決,我再次在操作類中調用靜態方法。我開始倒計時的冷卻時間。

因此,我應該有的可能是一個列表,其中包含所有操作和排序列表,跳過不必要的時間/滴答並直接進入下一個操作。但是會有不同類型的動作,比如移動,攻擊,能力和我無法將我的頭圍繞在這個好的實現上。

當一個生物進行基本攻擊這個被調用(攻擊是生物自身實例化的攻擊結構)

attack = Actions.BasicAttack(this, player, rand); 

這是操作類的樣子。

public struct Attack 
    { 
     public int Damage; 
     public string Type; 
     public int Time; 
     public int Cooldown; 
     public Creature target; 
     public bool solved; 
    } 




    public static Attack BasicAttack(Creature attacker, Creature defender, Random rand) 
    { 
     Attack attack = new Attack(); 

     attack.Damage = rand.Next(attacker.MinBaseDmg, attacker.MaxBaseDmg + 1); 
     attack.Type = "Melee"; 
     attack.Time = 50; 
     attack.Cooldown = 30; 
     attack.target = defender; 
     attack.solved = false; 

     return attack; 
    } 

當玩家有動作提示時,這會在每個生物的更新方法中被調用。如果玩家沒有動作提示,則Tick = 0;當玩家有動作提示時,Tick = 1。

protected void ActionCue(int tick) 
    { 
     if (attack.target != null) 
     { 
      if (attack.Time > 1) 
      { 
       Console.WriteLine(attack.Time); 
       attack.Time -= tick; 
       this.free = false; 
      } 
      else if (!attack.solved) 
      { 
       Actions.SolveAttack(attack.Damage, attack.Type, attack.target); 
       attack.solved = true; 
      } 
      else if (attack.solved && attack.Cooldown > 1) 
      { 
       //Console.WriteLine(attack.Cooldown); 
       attack.Cooldown -= tick; 
      } 
      else 
       free = true; 
     } 
    } 
+0

粘貼在代碼中。從一個甚至不使用實際類名的描述中推導出你正在做的事情是一種痛苦 –

+0

我很可能需要一種完全不同的方式來完成它。但我嘗試粘貼一些代碼,讓你們看到我目前有什麼。 – Madmenyo

+0

當我需要不同類型的動作時,我也遇到了問題,如移動。我需要一種方法讓事情變得更加靈活,然後直接計算下一步要執行的操作。 – Madmenyo

回答

1

考慮這樣的事情(我將使用僞 - 它遠未優化等,但它可能只是速度不夠快,或者設置你的方式來優化什麼youre試圖做)

class CombatEventList 
{ 
    public static AddEvent(CombatEvent event, int ticksTillHappens) 
} 

virtual class CombatEvent 
{ 
    public virtual void CombatAction() 
} 

class PlayerActionChoice : ComabtEvent 
{ 
    public void CombatAction 
    { 
     var playerAction = GetUserDecision();//returns i.e CombatEvent PlayerMeeleAttack 
     CombatEventList.AddEvent(playerAction, 0); 
    } 
} 

class PlayerMeeleAttack : CombatEvent 
{ 
    int cooldownInTicks = 50; 

    public void CombatAction 
    { 
     MakeAttack()//damages the moster etc - all the stuff the attack is supposed to do 
     var nextEvent = new PlayerActionChoice(); 
     CombatEventList.AddEvent(nextEvent, cooldownInTicks); 
    } 
} 

那麼,這是如何工作的?

我們收到了一系列活動。

該列表檢查所有現在應該發生的事件並執行他們的CombatAction。

在他們的CombatAction中,事件將新事件添加到列表中。例如,PlayerMeeleAttack事件會在適當的冷卻時間後設置PlayerActionChoice事件,以便稍後再採取其他操作。

畢竟當前CombatEvents被解決,都增加了自己CombatEvents到列表,該列表檢查下一個事件(最低延遲)

名單休眠蜱指定數量(下一個事件的延遲)。一旦其完成睡覺,它降低了由適量的所有事件的冷卻時間,並處理當前的所有事件(那些剛打0延遲)

這正好在循環

名單與CombatStartEvent開始對此,這即將發生(延遲0)。它在CombatAction方法中設置PlayerActionChoice和MonsterActionChoice事件。

當然,這遠遠不是最佳選擇,它只是一個草圖或想法讓您思考。有可能會有更好的想法,我沒有給這個問題非常多的想法 - 但這顯然比你目前的解決方案更有效率:)

+0

非常感謝,我很喜歡我的新方法,但它看起來很麻煩,然後你的代碼。從來沒有進入事件,所以這是一個很好的時間來做到這一點。這看起來很清楚,謝謝! – Madmenyo

+0

爲了清楚起見 - 即時使用名爲Events的類,但它們實際上不是事件(語言結構)。這可能有點誤導 - 爲此感到遺憾。當然,你可以使用實際事件來實現這個功能!但這不是必要的;) –

+0

是的,我知道了,我知道類/方法的名稱和實際事件之間的區別,但感謝澄清:D – Madmenyo

0

好幾個小時後,似乎我得到了這個工作。這是任何需要它的人的代碼。我也接受反饋。

這是能力班,所需的一切都可以在這裏添加。對於基於tick的系統,時間變量很重要。

public string AbilityName { get; private set; } 
    public int minDamage { get; private set; } 
    public int maxDamage { get; private set; } 

    public int ActivationTime { get; private set; } 
    public int CooldownTime { get; private set; } 
    public int Timer; 

    public Ability(string AbilityName) 
    { 
     if (AbilityName == "attack") 
     { 
      this.AbilityName = AbilityName; 
      minDamage = 10; 
      maxDamage = 20; 
      ActivationTime = 20; 
      CooldownTime = 30; 
      Timer = ActivationTime; 

      iconPath = "ability/icon/attack"; 
     } 
    } 

這是任務類的能力,攻擊者和目標得到作爲參數傳遞,一個能力名稱或類型可用於執行不同類型/類型的能力,例如運動VS攻擊。

public Ability ability { get; private set; } 
    public bool onCooldown; 

    public Creature attacker { get; private set; } 
    List<Creature> targets = new List<Creature>(); 

    /// <summary> 
    /// Initiates a attack task 
    /// </summary> 
    /// <param name="attacker"></param> 
    /// <param name="defender"></param> 
    public Task(Creature attacker, List<Creature> targets, Ability ability) 
    { 
     this.ability = ability; 
     this.attacker = attacker; 
     this.targets = targets; 

     onCooldown = false; 
    } 

    public void Perform() 
    { 
     //performce abilty 
     Console.WriteLine(attacker.Name + " performce ability"); 
    } 

玩家或AI現在可以從他們擁有像這樣的能力,創建任務:

targets.Add(player); //This is just a basic attack so only one "creature" gets in the list 
       task = new Task(this, targets, abilityList[0]); //Task is created 
       taskList.Add(task); //Task is added to a list i manage in a main class 
       free = false; //creature is put on hold and cant do anything till task is completed 

這是大多數的奇蹟發生。在主類中,如果玩家不是「免費」,則此方法將被稱爲每次更新。我在更新任務之前更新了所有任務,因爲我不想在更新其狀態後編輯其統計信息。

private void TaskHandler() 
    { 
     int ticksToAdvance = 0; 
     // get the next task requiring a action 
     taskList.Sort((x, y) => x.ability.Timer.CompareTo(y.ability.Timer)); 

     //get the amount of cooldown left 
     ticksToAdvance = taskList[0].ability.Timer; 

     //Update all tasks 
     foreach (Task t in taskList) 
     { 
      t.ability.Timer -= ticksToAdvance; 
     } 

     //check if this task is on cooldown 
     if (taskList[0].onCooldown) 
     { 
      //Reset ability timer, free creature and remove task from the list. 
      taskList[0].ability.Timer = taskList[0].ability.ActivationTime; 
      taskList[0].attacker.free = true; 
      taskList.RemoveAt(0); 
     } 
     else 
     { 
      //perform ability 
      taskList[0].Perform(); 
      //set timer to cooldown 
      taskList[0].onCooldown = true; 
      taskList[0].ability.Timer = taskList[0].ability.CooldownTime; 
     } 
    }