2017-07-17 90 views
0

我正在C#中進行一個簡單的RPG類型的遊戲,它主要是一個原型,只是測試想法(我知道代碼可以改進並且在地方很粗糙,它的工作)。c#RPG從列表中移除

我目前遇到了與戰鬥系統的障礙。

當前,您控制1個字符。你可以面對3個敵人。這是一個基於回合的ATB系統,這部分工作正常。一旦玩家轉向,他們可以選擇攻擊並使用它。

我想添加一個新功能來對時間造成影響。但是,這打破了戰鬥。

我做了一個類來表示一個DOT效果:

public class DoT 
{ 
    public int Duration { get; set; } 
    public int Elapsed { get; set; } 
    public int Damage { get; set; } 
    public Enemy Target { get; set; } 
    public String DName { get; set; } 
    public DoT() 
    { 
     Duration = 3; 
     Elapsed = 0; 
     DName = ""; 
    } 
    public void Tick() 
    { 
     Elapsed++; 
    } 

} 

這被添加到能力在創建時,而這部分的工作,我可以添加一個DOT效果的能力。

在戰鬥系統中,當選擇攻擊時,我創建了一個名爲DOTS的DOT效果列表。當用戶選擇的攻擊,如果攻擊具有附着到其上的DOT效果,將被添加到的DOT效果列表:

try 
     { 
      string s = ((Control)sender).Text;//Stores name of label that triggered the event 
      int i = s.Length;//can't remember why I added this 

      if (playerTarget != null)//check that we have a target 
      { 
       if (currentTurn.owner == c && canAttack)//if the current turn is ours and we can attack 
       { 
        if (c.GetAbility(s).AbilityCost <= c.currentMP)//if we have enough MP for the attack 
        { 
         if(c.GetAbility(s).DamageOverTime!=null)//checks if the attack has a DOT effect 
         { 
          c.GetAbility(s).DamageOverTime.Target = playerTarget;//the DOT now targets the target 
          AddDOT(c.GetAbility(s).DamageOverTime);//Adds the DOT effect to DOTS 
          //Trace statements I was using for debugging 
          UpdateTest("Added "+ c.GetAbility(s).AbilityName + " to DOT"); 
          UpdateTest("Time left- " + (c.GetAbility(s).DamageOverTime.Duration-c.GetAbility(s).DamageOverTime.Elapsed).ToString()); 
         } 
         currentTurn.ability = c.GetAbility(s);//Sets the current ability to be used 
         UseTurn();//Executes a turn 
        } 
        else 
        { 
         MessageBox.Show("Not enough MP!"); 
        } 
       } 
      } 
      else 
      { 
       MessageBox.Show("You must select a target!"); 
      } 


     } 
     catch (Exception ex) 
     { 
      MessageBox.Show("Error" + ex.ToString()); 
     } 

,增加了一個DOT效果的方法是這樣的:

public void AddDOT(DoT d) 
    { 
     int exists = 0; 
     if (DOTS.Count > 0) 
     { 
      foreach (DoT dot in DOTS) 
      { 
       if (dot.Equals(d)) 
       { 
        dot.Elapsed = 0; 
        exists++; 
       } 
      } 
      if(exists==0) 
      { 
       DOTS.Add(d); 
      } 
     } 
     else 
     { 
      DOTS.Add(d); 
     } 

這是爲了停止應用相同DOT的倍數,如果它已經在那裏,我們只是重置當前DOT流逝的時間。

我也必須在每一輪申請DOT效果的方法:

public void UpdateDots() 
    { 
     try 
     { 
      if (DOTS.Count > 0)//Check that we have a DOT 
      { 
       foreach (DoT d in DOTS)//Loop through each DOT 
       { 
        DotDamage(d);//Apply the DOT damage to the DOT's target 
        d.Tick();//call the tick method of DOT to add 1 to elapsed 
        //Trace statement to help debug 
        UpdateTest("Duration on " + d.DName + " is " + (d.Duration - d.Elapsed).ToString()); 
        if (d.Elapsed == d.Duration)//Check if we have ticks left 
        { 
         DOTS.Remove(d);//If not, remove the DOT effect        
        } 
       } 
      } 
      else 
      { 
       UpdateTest("No DOTS active");//Trace statement 
      } 
     } 
     catch(Exception ex) 
     { 
      MessageBox.Show(ex.ToString()); 
     } 

的UpdateDots方法在這裏被稱爲在代碼中使用轉:

public void UseTurn() 
    { 
     UpdateDots();//Execute any DOT effects 
     pause.Tick += new EventHandler(PauseTick);//just a timer to delay each turn, I need to move this 
     UpdateTest("Owner is..."+currentTurn.owner.characterName);//Trace statement 

     if (currentTurn.owner == c)//Checks if the current turn is by the player (c=player) 
     { 
      if (currentTurn.ability.DamageOverTime == null)//if we aren't applying a DOT 
      { 
       if (currentTurn.ability.MultiTarget == false)//If it is single target 
       { 
        Attack(c, playerTarget, currentTurn.ability);//Single target attack 
       } 
       else 
       { 
        MultiAttack(playerTargets, currentTurn.ability);//Multi target attack 
       } 

      } 

      lblPlayerTimer.Width = 0;//Resets the label showing the players ATB bar 
      currentTurn.owner = null;//Free the current owner to be claimed by other characters 
      canAttack = false;//Can no longer attack 
      playerTimer.Start();//Start the players timer again 
      UpdateAbilities();//Simply used to update the display of abilities 
     } 
     else if(currentTurn.owner is Enemy)//If an enemy is attacking 
     { 
      Enemy en = (Enemy)currentTurn.owner;//Get the details of the enemy attacking 
      string n = en.characterName;//this was from previous code    
      Label l = new Label(); 
      l = Controls.Find(en.timer.lblName ,true).FirstOrDefault() as Label;//Get the label being used as the enemy timer 
      PickEnemyAttack(en);//Select an attack for the enemy 
      Attack(en, c, currentTurn.ability);//Execute attack for enemy 
      l.Width = 0;//Reset the enemy ATB bar 
      currentTurn.owner = null;//Free up the current turn 

      //This part is just used to cause a short delay before the next turn 
      pause.Start(); 
      enemyCanAttack = false;     
      en.timer.Start();    

     } 
     ShowTurn();//Updates display of the current turn 
     turnCount += 1; 
     CheckWinner();//Checks if the player has won, or lost 
    } 

問題時,我申請了一個DOT,它被應用並且傷害了敵人。它繼續打勾,直到DOT到期,此時所有定時器都停止。如果沒有DOT效果,那麼戰鬥正常。

這似乎是從DOTS中刪除DOT時造成的。它拋出一個無效操作異常,指出該集合已被修改。是因爲我刪除了一個項目,但是因爲我在ForEach循環中,使用枚舉來刪除這些混亂?

正如你所看到的,我不是一個列表專家,我看不到這個問題,我希望有一個更專業的眼睛可以幫助我解決這個問題。

謝謝。

+0

[InvalidOperationException移除arrayList中的元素後可能的重複](https://stackoverflow.com/questions/12987799/invalidoperationexception-after-re- moving-an-element-in-an-arraylist) – mjwills

回答

0

在使用foreach時不能修改數組。改爲使用。

+0

謝謝,那固定它。 – rm46

1

foreach不會讓你修改集合,但你可以用一個簡單的for循環手動循環它,然後修改你喜歡的任何東西(因爲你控制迭代)。因此,而不是這樣的:

foreach (DoT d in DOTS) 
{ 
    // do things with d 
} 

你必須這樣:

for (var i = 0; i < DOTS.Count; i++) 
{ 
    // do things with DOTS[i] 
} 

就注意到,這個手動控制來對您的部分多一點責任。如果你想繼續在從中移除一個元素後迭代DOTS,你需要手動修改i(遞減1),以反映你現在正在重新迭代到相同索引的事實,因爲該集合已被修改。但是,如果從集合中刪除項目後,只需退出循環,那麼這不是問題。事情是這樣的:

DOTS.Remove(DOTS[i]); 
break; 
+2

假設處理物品的順序並不重要,當您移除某個物品時必須更改爲「i」值的替代方法是將物品從最後一次迭代到第一次。這樣,當您刪除當前項目時,只會影響已經處理且不再關注的項目的位置,並且您可以繼續進行下一次迭代,以瞭解仍然處理的項目的索引沒有受到影響。 –

0

一個值得考慮的選擇是改變:

foreach (DoT d in DOTS) 

到:

foreach (DoT d in DOTS.ToList()) 

這樣,你迭代的事情是不同的「原始'DOTS數組/列表。這意味着你可以改變DOTS(添加/刪除項目等)。