代码之家  ›  专栏  ›  技术社区  ›  user164226

需要一种在层次结构中/跨层次结构自动传播值的方法(游戏的派系系统)

  •  1
  • user164226  · 技术社区  · 16 年前
    public static class Global
    {
        public static List <Faction> Factions;
        public static Dictionary <Faction, FactionRelation> FactionRelationships;
    }    
    
    public class Faction
    {
        public Faction Parent;
    }
    
    public class FactionRelation
    {
        public Faction ForeignFaction; //The enemy or friend of this faction
        public decimal Multiplier; //Standings gain/loss with the faction get applied to ForeignFaction by this percentage. Ex: I get +100 with NativeFaction. If multiplier is -0.1M, then I'll get -10 with ForeignFaction
    }
    public class Player
    {
        public Dictionary <Faction, decimal> Standings;
    
        public void SetStandings(decimal mod)
        {
            foreach (Faction f in Global.Factions)
            {
    
            }
        }
    }
    

    上面的代码表示游戏的基本派系系统。全局类初始化游戏,从一些数据定义创建派别对象。它还包含一组派系和十进制值,这些值表示派系之间的关系。

    派系 假设我们有两个主要派别:DirectionFock和ColorFock。他们没有亲族。

    我们也有上下两个派别,其母派别都是方向派克。最后,我们有红人和蓝人两个派别,他们的父母派别都是有色人。

    所以,

    • 定向民谣
      • 上流社会的人
      • 下流民族
    • 有色人种
      • 红人
        • 乡下佬
        • 斯佳丽
      • 蓝人

    这种筑巢可能要深入得多;例如,红人可能会把松饼和金龟子作为子行动。

    任何派系的任何长期收益都应该在树上上下传播,直到达到树的两端筑巢极限。该集合的嵌套深度决定了应该在任何级别发生的持续修改量。为了使它更简单,我们假设它是均匀分布的。因此,如果我直接与有色人种站在一起获得100分,我应该与红人和蓝人站在一起获得50分,与松鸡和斯卡勒特人站在一起获得25分。如果我直接和红人站在一起得到100分,我应该和蓝人站在一起得到50分,和松饼和斯卡勒特人站在一起得到25分。其观点是,直接与最低层的派系修改比最高层的更为明显。所以,用松饼做朋友或敌人比用有色人种更容易。

    如果这个算法有名字,我不知道它是什么。

    此外,任何没有父母的派系都可以与另一个没有父母的派系有关系。所以,假设DirectionFock和ColorFock是敌人。任何一个与色人结盟的派系都会导致与方向人成比例的结盟失败。由于只有无父派别才能有跨派系关系(正乘数或负乘数),这种持续的损失总是发生在相关派系链的顶部,并逐渐下降。

    理想情况下,我希望能够为派系关系(包括跨父派系和父级的子操作)分配更有趣的值。因此,对某些子操作的持续修改可能会传播到 一些 其他派系依赖于乘数,并且与树中的父派系一起获得的站姿将更加精细。

    球员 玩家对象有一个列表,代表他们与每个派别的立场。很简单-一个派别和一个十进制值。这是我将要修改的值,因为每个玩家都持有代表其派系地位的数据。(各派别本身不知道玩家在这个意义上)。

    ——

    我的问题是,我是应该通过一些嘶哑的递归过程直接在播放器对象中设置一组值,还是有一种优雅的方法可以简单地基于播放器存储的非常少的值来计算这些值?

    另外,这会让事情变得更有趣——比如说,有些派别之间是中立的,即使在同一棵树上(比如,红人和蓝人不关心彼此),或者把分布混在一起,这样就不是严格的均匀——这类事情会严重地使事情复杂化吗,或者有可能设计一种算法吗?哪一个更不可知论?

    我真的只是想找一个关于如何把我的头围绕在这个问题上的开始。如果有人设计了类似的东西,我想听听你对它的看法。

    2 回复  |  直到 16 年前
        1
  •  3
  •   Kylotan    16 年前

    我看到的问题是,您还没有确切定义希望传播规则是什么。事实上,你给出了两个相互矛盾的例子:

    “因此,如果我直接与有色人种站在一起获得100站,我应该与红人和蓝人站在一起获得50站[等等]。” -这个例子只沿着树传播,而不是传播给兄弟姐妹。(未提及对DirectionFock的增益。)

    “如果我直接和红人站在一起,我应该和蓝人站在一起,得到100分,和松鸡站在一起,得到50分,和斯卡勒特人站在一起,得到25分。” -然而这个例子 做 传播给兄弟姐妹。

    很明显,如果没有一个以上的规则来决定它为什么会传播给某些兄弟姐妹而不是其他兄弟姐妹,这两种情况都不可能是真的。尤其是,如果站在一旁传播给兄弟姐妹,那么编写递归算法来实现这一点非常困难,因为您的两个子派别将得到两次更新,一次是从父派别更新,一次是从兄弟派别更新。

    如果需要,可以改为运行通用传播算法:

    void propagateStanding(amount)
    {
        // calculate relative weightings
        totalWeighting = 0.0;
        for (relationship in faction.relationships)
        {
            totalWeighting += relationship.weight;
        }
    
        // propagate value    
        for (relationship in faction.relationships)
        {
            amountToGive = amount * relationship.weight / totalWeighting;
            relationship.otherFaction.standing += amountToGive;
        }
    }
    

    注意,这只包括传播,而不是原始派别的增加。

        2
  •  2
  •   Paolo Tedesco    16 年前

    我不知道这是否有名字,但我会使用一个迭代的方法,给派系类,它知道派系结构,任务更新玩家的立场。
    像这样:

    using System;
    using System.Collections.Generic;
    
    class Faction { 
        // the parent faction
        protected Faction _parent;
        // list of children factions
        protected List<Faction> _children = new List<Faction>();
    
        // the Faction knows the structure, so this approach is iterative but not
        // for this difficult to maintain.
        public void ModifyStanding(Player p,Decimal amount) {
            p[this] += amount;
            foreach (Faction child in _children) {
                child.ModifyStanding(p, amount / 2);
            }
        }
    }
    
    class Player {
        // standings
        Dictionary<Faction, Decimal> _standings = new Dictionary<Faction,decimal>();
        // get / set standing indexing on faction
        public Decimal this[Faction f] {
            get { return _standings[f]; }
            set { _standings[f] = value; }
        }
    }