代码之家  ›  专栏  ›  技术社区  ›  Jeffrey Kern

RPG游戏中的类层次结构数据设计(VB.Net)

  •  1
  • Jeffrey Kern  · 技术社区  · 15 年前

    我在如何组织我正在制作的RPG项目中的类时遇到了麻烦。我试过实现一个作战系统,但我对我最初的结果不满意。

    clscharcater>clsTeam>克莱斯巴特尔


    clsCharacter公司

    CLS蒸汽 包含多个clschracter,以及团队中每个clschracter可以使用的项的列表。

    包含两个蒸汽。一队是球员,另一队是电脑。


    此外,我觉得在clschracter类中包含调用以下内容的方法的代码非常混乱:MyTeam.MyBattle.DoAction(). 另外,clscharcater可能在那时还没有投入战斗-我不想让这个类陷入困境,因为它的代码是专门用于战斗的,当我还需要关心在地图上移动、保存/加载数据等问题时。

    有什么建议吗?现在,我已经没有主意了。到目前为止,我的一个想法是为clschracter包含一个函数,该函数导出角色可以执行的所有可能移动的列表,如果角色是CPU,则选择最佳移动,如果是人类,则将其包装在一些漂亮的GUI中,以便他们可以选择要执行的操作。但同时,我如何在战斗中使用这些信息呢?

    3 回复  |  直到 15 年前
        1
  •  3
  •   Community Mohan Dere    8 年前

    你考虑过在你的设计中使用接口吗?我想他们会帮上大忙的。我 asked a question

    使用接口,您可以避免思考“我需要什么样的数据容器来执行此操作?”而是思考“我需要什么样的操作?”下面是一个简单的示例,说明如何对代码进行建模,以便在战斗中提取攻击方法:

    Public Interface IAttacker
        Function GetAttackDamage() As Double 
        Property Name As String
    End Interface 
    
    Public Class Character
        Implements IAttacker
    
        Public Property Name As String Implements IAttacker.Name
        Public Property Weapons As List(Of IWeapon)
        Public Property SpecialTeamAttackMove As IWeapon
    
        Public Function GetAttackDamage() As Double _
          Implements IAttacker.GetAttackDamage()
            'Get the sum of the damage in the weapons list'
            Return Weapons.Select(Function(iw) iw.Damage).Sum()
        End Function
    End Class
    
    Public Class Team
        Implements IAttacker
    
        Public Property Characters As List(Of Character) = _
            New List(Of Character)()
        Public Property Name As String Implements IAttacker.Name
    
        Public Function GetAttackDamage() As Double _
          Implements IAttacker.GetAttackDamage()
            'Get the sum of the damage of the SpecialTeamAttackMove'
            'of each character on the team'
            Return Characters.Select(Function(c) _
                c.SpecialTeamAttackMove.Damage).Sum())
        End Function
    End Public
    
    Public Class Battle
        Public Property AttackerA As IAttacker
        Public Property AttackerB As IAttacker
    
        Public Sub New(attackerA As IAttacker, attackerB As IAttacker)
            Me.AttackerA = attackerA
            Me.AttackerB = attackerB
        End Sub
    
        'This function returns the "winner" of the fight, unless it is a tie'
        Public Function Fight() As IAttacker
            If Me.AttackerA.GetAttackDamage() = Me.AttackerB.GetAttackDamage() Then
                Return Nothing
            ElseIf Me.AttackerA.GetAttackDamage() > _
                   Me.AttackerB.GetAttackDamage() Then
                Return Me.AttackerA
            Else
                Return Me.AttackerB
            End If
        End Function
    
     End Class
    

    在上述代码中 Battle 类只知道它需要一个实现 IAttacker . 它不关心对象如何实现 GetAttackDamage() ,只是它可以在需要时调用方法。这个 Name 属性也被抽象到接口中。请参阅以下有关如何工作的程序示例:

    Public Sub BattleBetweenTwoCharacters()
      'In this example, two characters are instantiated. Assume the "..." is where'
      'you add weapons and other properties. The characters fight and the winning'
      'IAttacker is returned'
        Dim charA As Character = New Character() With {...}
        Dim charB As Character = New Character() With {...}
    
        Dim winningChar As IAttacker = New Battle(charA, charB).Fight()
    
        If winningChar Is Nothing Then
            Console.WriteLine("It was a tie.")
        Else
            Console.WriteLine("{0} was the winner",winningChar.Name)
        End If
    End Sub
    
    
    Public Sub BattleBetweenTwoCharacters()
      'In this example, several characters and a team are instantiated. '
      'Assume the "..." is where you add weapons and other properties. A '
      'fight takes place and the winner is returned.'
        Dim charA As Character = New Character() With {...}
        Dim charB As Character = New Character() With {...}
        Dim charC As Character = New Character() With {...}
    
        Dim teamAB As New Team()
        teamAB.Characters.Add(charA)
        teamAB.Characters.Add(charB)
    
        'Here, a team fights a character. The Battle.Fight method will call '
        'GetAttackDamage() on each object, even though a team implements'
        'it differently than a single character.'
        Dim winner As IAttacker = New Battle(teamAB, charB).Fight()
    
        If winningChar Is Nothing Then
            Console.WriteLine("It was a tie.")
        Else
            Console.WriteLine("{0} was the winner",winningChar.Name)
        End If
    End Sub    
    

    希望您能从这个(非常冗长的)示例中看到使用接口来帮助封装特定功能的优势。这允许您将期望从类中获得的功能与类本身分离,并允许使用该类的对象通过接口直接调用它所需的功能。

    在我展示的例子中 战斗 不在乎它是否有个性。它所需要知道的是,它有一些可以攻击的东西,也就是实现 内塔克勒 接口。因为我们是这样写的,我们并没有把战斗局限于 Character s。我们还提供 只反对战斗所必需的东西。这个 内塔克勒 可能会以不同的方式实现,但这没关系,只要 战斗 对象获取所需的信息。

    如果在设计中将接口与基类混合使用,那么在构建类层次结构方面就有了一个很好的开端。

        2
  •  0
  •   Dylan    15 年前

    然后你可以对战斗中的团队成员执行一些方法,例如。

     var dwarfs = _teamA.Players.Where(p => p.CharacterType == Character.Dwarf);
     foreach(var dwarf in dwarfs)
        AddHealth(dwarf);
    

        3
  •  0
  •   Alexandros Spyropoulos    11 年前

    实际上是文明5号数据库里的。它是用XML编写的,很容易理解。我的回答主要是为了支持本的回答,但我强烈建议你在其他游戏中制作一个或两个mod,让它们的代码暴露出来以查看体验,或者至少可以使用暴露代码的modding工具。相信我,这会很有帮助的,

    <?xml version="1.0" encoding="utf-8"?>
    <!-- edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by MBeach (Firaxis Games)  -->
    <GameData>
    <!-- Table data -->
    <Units>
        <Row>
            <Class>UNITCLASS_LONGSWORDSMAN</Class>
            <Type>UNIT_DANISH_BERSERKER</Type>
            <PrereqTech>TECH_STEEL</PrereqTech>
            <Combat>16</Combat>
            <Cost>120</Cost>
            <Moves>3</Moves>
            <HurryCostModifier>20</HurryCostModifier>
            <CombatClass>UNITCOMBAT_MELEE</CombatClass>
            <Domain>DOMAIN_LAND</Domain>
            <DefaultUnitAI>UNITAI_ATTACK</DefaultUnitAI>
            <Description>TXT_KEY_UNIT_DANISH_BERSERKER</Description>
            <Civilopedia>TXT_KEY_CIV5_DENMARK_BERSERKER_TEXT</Civilopedia>
            <Strategy>TXT_KEY_CIV5_DENMARK_BERSERKER_STRATEGY</Strategy>
            <Help>TXT_KEY_CIV5_DENMARK_BERSERKER_HELP</Help>
            <MilitarySupport>true</MilitarySupport>
            <MilitaryProduction>true</MilitaryProduction>
            <Pillage>true</Pillage>
            <ObsoleteTech>TECH_RIFLING</ObsoleteTech>
            <GoodyHutUpgradeUnitClass>UNITCLASS_RIFLEMAN</GoodyHutUpgradeUnitClass>
            <AdvancedStartCost>25</AdvancedStartCost>
            <XPValueAttack>3</XPValueAttack>
            <XPValueDefense>3</XPValueDefense>
            <Conscription>3</Conscription>
            <UnitArtInfo>ART_DEF_UNIT_U_DANISH_BERSERKER</UnitArtInfo>
            <IconAtlas>HARALD_UNIT_ATLAS</IconAtlas>
            <UnitFlagAtlas>HARALD_UNIT_FLAG_ATLAS</UnitFlagAtlas>
            <UnitFlagIconOffset>0</UnitFlagIconOffset>
            <PortraitIndex>0</PortraitIndex>
            <MoveRate>HEAVY_BIPED</MoveRate>
        </Row>
        <Row>
            <Class>UNITCLASS_RIFLEMAN</Class>
            <Type>UNIT_DANISH_SKI_INFANTRY</Type>
            <PrereqTech>TECH_RIFLING</PrereqTech>
            <Combat>25</Combat>
            <Cost>225</Cost>
            <Moves>2</Moves>
            <CombatClass>UNITCOMBAT_GUN</CombatClass>
            <Domain>DOMAIN_LAND</Domain>
            <DefaultUnitAI>UNITAI_DEFENSE</DefaultUnitAI>
            <Description>TXT_KEY_UNIT_DANISH_SKI_INFANTRY</Description>
            <Civilopedia>TXT_KEY_CIV5_DENMARK_SKI_INFANTRY_TEXT</Civilopedia>
            <Strategy>TXT_KEY_CIV5_DENMARK_SKI_INFANTRY_STRATEGY</Strategy>
            <Help>TXT_KEY_CIV5_DENMARK_SKI_INFANTRY_HELP</Help>
            <MilitarySupport>true</MilitarySupport>
            <MilitaryProduction>true</MilitaryProduction>
            <Pillage>true</Pillage>
            <IgnoreBuildingDefense>true</IgnoreBuildingDefense>
            <ObsoleteTech>TECH_REPLACEABLE_PARTS</ObsoleteTech>
            <GoodyHutUpgradeUnitClass>UNITCLASS_INFANTRY</GoodyHutUpgradeUnitClass>
            <AdvancedStartCost>30</AdvancedStartCost>
            <XPValueAttack>3</XPValueAttack>
            <XPValueDefense>3</XPValueDefense>
            <Conscription>5</Conscription>
            <UnitArtInfo>ART_DEF_UNIT_U_DANISH_SKI_INFANTRY</UnitArtInfo>
            <IconAtlas>HARALD_UNIT_ATLAS</IconAtlas>
            <UnitFlagAtlas>HARALD_UNIT_FLAG_ATLAS</UnitFlagAtlas>
            <UnitFlagIconOffset>1</UnitFlagIconOffset>
            <PortraitIndex>1</PortraitIndex>
        </Row>
    </Units>
    

    在这里你可以看到如何单位电线到人工智能

    <Unit_AITypes>
        <Row>
            <UnitType>UNIT_DANISH_BERSERKER</UnitType>
            <UnitAIType>UNITAI_ATTACK</UnitAIType>
        </Row>
        <Row>
            <UnitType>UNIT_DANISH_BERSERKER</UnitType>
            <UnitAIType>UNITAI_DEFENSE</UnitAIType>
        </Row>
        <Row>
            <UnitType>UNIT_DANISH_SKI_INFANTRY</UnitType>
            <UnitAIType>UNITAI_ATTACK</UnitAIType>
        </Row>
        <Row>
            <UnitType>UNIT_DANISH_SKI_INFANTRY</UnitType>
            <UnitAIType>UNITAI_DEFENSE</UnitAIType>
        </Row>
        <Row>
            <UnitType>UNIT_DANISH_SKI_INFANTRY</UnitType>
            <UnitAIType>UNITAI_EXPLORE</UnitAIType>
        </Row>
    </Unit_AITypes>
    

    <Unit_ClassUpgrades>
        <Row>
            <UnitType>UNIT_DANISH_BERSERKER</UnitType>
            <UnitClassType>UNITCLASS_RIFLEMAN</UnitClassType>
        </Row>
        <Row>
            <UnitType>UNIT_DANISH_SKI_INFANTRY</UnitType>
            <UnitClassType>UNITCLASS_INFANTRY</UnitClassType>
        </Row>
    </Unit_ClassUpgrades>
    <Unit_FreePromotions>
        <Row>
            <UnitType>UNIT_DANISH_BERSERKER</UnitType>
            <PromotionType>PROMOTION_AMPHIBIOUS</PromotionType>
        </Row>
        <Row>
            <UnitType>UNIT_DANISH_SKI_INFANTRY</UnitType>
            <PromotionType>PROMOTION_SKI_INFANTRY</PromotionType>
        </Row>
    </Unit_FreePromotions>
    <Unit_ResourceQuantityRequirements>
        <Row>
            <UnitType>UNIT_DANISH_BERSERKER</UnitType>
            <ResourceType>RESOURCE_IRON</ResourceType>
        </Row>
    </Unit_ResourceQuantityRequirements>