23.角色被击中后——状态模式

角色扮演游戏和战争策略游戏的确不太一样,在战争游戏中,每个单元要不就正常运行,要不就是被摧毁;而在角色扮演游戏中,由于角色们有很多必杀技,在被这些必杀技击中后,有会出现的不同的影响,如攻击力下降、不能行动等等。

在这一章里,我们将要实现这个功能。

 

刚接到这个任务时,你可能会考虑根据不同的必杀技的参数来修改每个单位的各种动作的相关方法,比如:

l         如果被冰封必杀技击中,则角色的状态就是锁定,这时角色不能移动,也不能攻击其他目标;

l         如果被水淹七军必杀技击中,则攻击力和速度下降;

l         ……

 

这样,我们必需创建这些状态的常量:

Public Const StateNormal = 0

Public Const StateLocked = 1

Public Const StateSlowly = 2

 

或者,我们使用枚举来表示这些状态:

Public Enum EState

Normal = 0

Locked = 1

Slowly = 2

End Enum

 

然后,我们需要在CUnit类中添加一个值作为角色状态。

最后,我们需要修改每个角色的Move()方法和Attack()方法,比如,当关羽被冰封后,他就不能移动,我们必须在Move()方法内针对三种状态进行编程,代码可能会是这个样子:

''关羽

Public Class CGuanYu

Inherits CUnitDecorator

Protected myState As EState

    Public Sub New()

        myName = "关羽"

        myLife = 200

        myPower = 100

        UnitId = EUnit.GuanYu

End Sub

Public Sub Move(ByVal x As Integer, ByVal y As Integer)

    Select Case myState

        Case EState.Normal

            Console.Write("{0}移动到位置({0}, {1})",myName,x,y)

        Case EState.Locked

            Console.Write("{0}不能移动",myName)

        Case EState.Slowly

            Console.Write("{0}慢速移动到位置({0}, {1})",myName,x,y)

    End Select

End Sub

End Class

 

然后,针对Attack()方法也应用做出相应的修改;但这样一来,每一个角色类都需要做出修改;原有的代码将被修改的面目全非。你真的想这样吗?

请注意,设计模式的基本概念之一就是“多扩展、少修改”,我们再想想别的办法吧。

 

在前面是不是多次提到了“状态”两个字,好像有个模式就是状态模式,我们何不在这里试试呢?好的,那我们就开始……

 

使用状态模式

状态模式(State Pattern)的定义如下:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

好吧,一切如故,这也是一种模式,J。我们首先创建状态接口IState,代码如下:

''游戏状态接口

Public Interface IState

    Property Description As String

    Sub Move(ByVal x As Integer, ByVal y As Integer)

    Sub Attack(ByVal x As Integer, ByVal y As Integer)

    '还可有更多的动作影响

End Interface

(项目:StatePatternDemo    文件:Interfaces.vb)

 

然后,就是每一种可能的角色状态类,本例为我们依然使用三种状态:正常状态(CNormalState)、锁定状态(CLockedState)和慢速状态(CSlowlyState)。下面是正常状态类的定义:

''正常状态

Public Class CNormalState

    Implements IState

    Protected myUnit As IUnit '状态影响的角色

Protected myDescription As String = "角色状态正常" '状态描述

Public Sub New(ByVal unit As IUnit)

    myUnit=unit

End Sub

    '状态描述

    Public Property Description As String Implements IState.Description

        Get

            Return myDescription

        End Get

        Set(ByVal value As String)

            myDescription = value

        End Set

    End Property

    '攻击

Public Sub Attack(ByVal x As Integer, ByVal y As Integer)  _

Implements IState.Attack

        Console.WriteLine("<{0}>正常攻击位置({1},{2})  攻击力:{3}",  _

myUnit.Name, x, y, myUnit.Power)

    End Sub

    '移动

    Public Sub Move(ByVal x As Integer, ByVal y As Integer) Implements IState.Move

        Console.WriteLine("<{0}>正常移动到({1},{2})", myUnit.Name, x, y)

    End Sub

End Class

(项目:StatePatternDemo    文件:States.vb)

 

下面是锁定状态类(CLockedState)和慢速状态类(CSlowlyState)的代码:

''锁定状态

Public Class CLockedState

    Implements IState

    Protected myUnit As IUnit '状态影响的角色

Protected myDescription As String = "角色被锁定" '状态描述

Public Sub New(ByVal unit As IUnit)

    myUnit=unit

End Sub

    '状态描述

    Public Property Description As String Implements IState.Description

        Get

            Return myDescription

        End Get

        Set(ByVal value As String)

            myDescription = value

        End Set

    End Property

    '攻击

Public Sub Attack(ByVal x As Integer, ByVal y As Integer)  _

Implements IState.Attack

        Console.WriteLine("<{0}>无法攻击目标", myUnit.Name)

    End Sub

    '移动

    Public Sub Move(ByVal x As Integer, ByVal y As Integer) Implements IState.Move

        Console.WriteLine("<{0}>无法移动", myUnit.Name)

    End Sub

End Class

 

''慢速状态

Public Class CSlowlyState

    Implements IState

    Protected myUnit As IUnit '状态影响的角色

Protected myDescription As String = "角色速度减缓" '状态描述

Public Sub New(ByVal unit As IUnit)

    myUnit=unit

End Sub

    '状态描述

    Public Property Description As String Implements IState.Description

        Get

            Return myDescription

        End Get

        Set(ByVal value As String)

            myDescription = value

        End Set

    End Property

    '攻击

Public Sub Attack(ByVal x As Integer, ByVal y As Integer)  _

Implements IState.Attack

        Console.WriteLine("<{0}>减缓攻击位置({1},{2})  攻击力:{3}",  _

myUnit.Name, x, y, myUnit.Power \ 2)

    End Sub

    '移动

    Public Sub Move(ByVal x As Integer, ByVal y As Integer) Implements IState.Move

        Console.WriteLine("<{0}>慢速移动到({1},{2})", myUnit.Name, x, y)

    End Sub

End Class

(项目:StatePatternDemo    文件:States.vb)

 

现在,我们需要将各种状态组合到角色单位中,首先修改单位接口IUnit,我们只需要添加一个IState接口类型的属性就可以了,代码如下:

''游戏角色接口

Public Interface IUnit

    Property Name As String '名称

    Property UnitId As EUnit '游戏类型ID

    Property Life As Integer '生命值

    Property Power As Integer '攻击力

    Property State As IState '角色状态

    Sub Move(ByVal x As Integer, ByVal y As Integer)

    Sub Attack(ByVal x As Integer, ByVal y As Integer)

End Interface

(项目:StatePatternDemo    文件:Interfaces.vb)

 

然后,我们修改CUnit类,添加State属性的实现,以及修改单位移动(Move)和攻击(Attack)的方法。代码如下:

''游戏单位基类

Public MustInherit Class CUnit

    Implements IUnit

    ...

    Protected myState As IState =New CNormalState(Me)

    ...

    '攻击

    Public Sub Attack(ByVal x As Integer, ByVal y As Integer) _

        Implements IUnit.Attack

        myState.Attack(x, y)

    End Sub

    '移动

    Public Sub Move(ByVal x As Integer, ByVal y As Integer) _

        Implements IUnit.Move

        myState.Move(x, y)

    End Sub

    '状态

    Public Property State As IState Implements IUnit.State

        Get

            Return myState

        End Get

        Set(ByVal value As IState)

            myState = value

        End Set

    End Property

End Class

(项目:StatePatternDemo    文件:CUnit.vb)

 

在这里,我们只给出了CUnit类需要修改和添加的代码,其它代码与上一章的CUnit类是一致的。此外,别忘了创建更多的人物和武器装备,下面是吕布和方天画戟的代码:

''吕布

Public Class CLvBu

    Inherits CUnitDecorator

    Public Sub New()

        myName = "吕布"

        myLife = 260

        myPower = 110

        UnitId = EUnit.LvBu

    End Sub

End Class

''方天画戟

Public Class CWeapon4

    Inherits CUnit

    Public Sub New()

        myName = "方天画戟"

        myLife = 0

        myPower = 60

        UnitId = EUnit.Weapon4

    End Sub

End Class

(项目:StatePatternDemo    文件:Units.vb)

 

好的,代码修改完毕,现在测试场景“三英战吕布”。代码如下:

Module Module1

    Sub Main()

        Console.WriteLine(">>>>出道时的吕布")

        Dim LvBu As New CLvBu

        LvBu.ShowInfo()

        Console.WriteLine()

        '

        Console.WriteLine(">>>>得意时的吕布")

        LvBu.AddUnit(New CWeapon4)

        LvBu.AddUnit(New CEquipper1)

        LvBu.ShowInfo()

        Console.WriteLine()

        '

        Console.WriteLine(">>>>场景:三英战吕布")

        Console.WriteLine(">>>>被关羽‘水淹七军’必杀技击中")

        LvBu.State = New CSlowlyState(LvBu)

        LvBu.Move(100, 100)

        LvBu.Attack(105, 105)

        Console.WriteLine()

        '

        Console.WriteLine(">>>>被刘备‘冰封’必杀技击中")

        LvBu.State = New CLockedState(LvBu)

        LvBu.Move(200, 200)

        LvBu.Attack(205, 205)

        '

        Console.ReadLine()

    End Sub

End Module

(项目:StatePatternDemo    文件:Module1.vb)

 

本场景运行结果如下图:

 

也许你已经注意到了,我们没有显示角色状态描述的代码,不过,你可以在需要的地主显示角色状态描述;比如,在上例的代码中显示吕布的状态描述只需要使用如下的代码就可以了:

Console.WriteLine("状态:{0}", LvBu.State.Description)

 

小结

状态模式一般用于当一个对象有很多方法,在这些方法中会因为对象的不同状态而有着不同的行为时。如果不使用状态模式,我们就需要在这些行为方法中使用条件语句(分支语句)去判断不同状态时的行为;然而,我们通过使用状态模式将“状态”从对象中解耦,就可以最大限度地保证原有对象代码的稳定,当状态改变时,只要修改状态类就可以了,而无需修改每个对象中的行为方法。让我们再看看使用状态模式下的代码结构:

 出自:http://www.caohuayu.com/books/B0003/B0003.aspx

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值