2017-07-17 87 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(添加/删除项目等)。