22、角色扮演游戏角色与NPC开发指南

角色扮演游戏角色与NPC开发指南

1. 角色类数据类型设计

在开发角色扮演游戏时,角色类的数据类型设计至关重要。为了使角色类具有可扩展性,可使用填充字符串和整数。以下是定义的 TCHARACTER 类型:

Public Type TCHARACTER
    name As String * 20
    classtype As String * 20
    experience As Integer
    level As Integer
    strength As Integer
    dexterity As Integer
    intellect As Integer
    charisma As Integer
    stamina As Integer
    fillerstr As String * 80
    fillerint(10) As Integer
End Type

这个数据类型包含角色的基本信息,如名称、类型、经验、等级和五项属性,同时使用填充字段,方便后续添加新属性。例如,若要添加跟踪角色总击杀数的字段,可从 fillerint 数组中取出一个值,并在数组前后添加该字段。添加家乡字段的示例如下:

Hometown As String * 20
fillerstr As String * 60
TotalKills As Integer
fillerint(9) As Integer
End Type
2. 二进制角色数据文件的读写

可以使用以下代码读写 TCHARACTER 类型的二进制数据文件。
- 加载角色二进制文件

Public Function LoadCharacterBinaryFile( _
    ByVal filename As String) As TCHARACTER
    Dim filenum As Integer
    Dim dude As TCHARACTER
    filenum = FreeFile()
    Open filename For Binary As filenum Len = Len(dude)
    Get filenum, , dude
    Close filenum
    LoadCharacterBinaryFile = dude
End Function
  • 保存角色二进制文件
Public Sub SaveCharacterBinaryFile( _
    ByVal filename As String, _
    ByRef dude As TCHARACTER)
    Dim filenum As Integer
    filenum = FreeFile()
    Open filename For Binary As filenum Len = Len(dude)
    Put filenum, , dude
    Close filenum
End Sub
3. 角色编辑器程序

有一个名为 Simple Character Editor 的程序,可用于创建不同的 NPC,如农民、邪恶生物、维京探险家等。该程序位于 \sources\chapter15 目录下,虽只是示例,但能处理 PC 和 NPC 的关键属性。角色数据文件的设计思路是为不同角色类创建文件,而非为每个角色单独创建文件。

4. NPC 相关概念
  • NPC 定义 :在角色扮演游戏中,NPC 是除玩家角色(PC)和动物外的所有角色。动物是游戏世界的本地生物,不参与战斗,因此不与 NPC 归为一类。
  • 主要话题 :本章主要讨论了以下内容:
    • 介绍 NPC
    • 创建可复用的 NPC
    • 初始化 NPC
    • 移动 NPC
    • 设置随机目的地
    • 绘制 NPC
5. NPC 起始位置和移动范围
  • 起始位置 :加载 NPC 图像后,最重要的是确定其起始位置,即游戏世界中的像素 X、Y 坐标。可根据 NPC 的行为子程序,将起始位置设置在城镇中心,使 NPC 移动后基本位于城镇中心。起始位置还决定了 NPC 被杀后的重生位置。
  • 移动范围 :NPC 的移动范围应使其相对靠近起始点,其行为基于移动状态,如停止、行走、奔跑等。可通过让 NPC 重生来保持游戏流畅性,还可考虑增加被杀 NPC 的经验和等级,使游戏更具挑战性。
6. 简单状态引擎

为控制 NPC 的行为,创建了一个简单的状态引擎,使用 NPCSTATES 枚举类型跟踪 NPC 的状态:

Public Enum NPCSTATES
    NPC_STOPPED = 0
    NPC_WALKING = 1
End Enum

后续可添加新状态,如 NPC_FLEEING NPC_TALKING NPC_ATTACKING

7. 友善与恶意 NPC

游戏中主要使用两种类型的 NPC:
| NPC 类型 | 特点 | 示例 |
| ---- | ---- | ---- |
| 友善 NPC | 无害,如村民、镇民、农民,甚至可能包括当地执法人员 | 村民、镇民、农民、当地执法人员 |
| 恶意 NPC | 与玩家对立,包括邪恶生物、不法分子、强盗等 | 邪恶生物、不法分子、强盗、维京人 |

8. 创建可复用的 NPC

NPC 基于标准角色类,通过添加一定的随机性使 NPC 更有趣。可给每个 NPC 随机分配经验和等级,但要控制在玩家经验和等级的一定范围内。使用自定义的 TNPC 结构跟踪每个 NPC 的状态、起始位置、当前位置等信息:

Public Type TNPC
    name As String
    state As NPCSTATES
    startpos As point
    curpos As point
    destpos As point
    classindex As Integer
    SpeedDelay As Integer
    SpeedCount As Integer
    Facing As Integer
End Type

游戏使用一系列数组管理 NPC,具体如下:

‘generic data for the character classes
‘images and data are shared by the NPCs
Const NUMCHARS As Long = 1
Dim charImages(NUMCHARS) As Direct3DTexture8
Dim charClasses(NUMCHARS) As TCHARACTER
‘unique data for each individual NPC
Const NUMNPCS As Long = 10
Dim charStates(NUMNPCS) As TNPC
Dim charSprites(NUMNPCS) As TSPRITE
9. 初始化 NPC

使用 InitCharacters 子程序初始化所有 NPC:

Public Sub InitCharacters()
    Dim p As point
    Dim n As Long
    ‘set up all the base character classes, sprites, and images
    ‘so far we’re only using a single type of character—Viking Warrior
    charClasses(0) = LoadCharacterBinaryFile(App.Path & “\warrior.dat”)
    Set charImages(0) = LoadTexture(d3ddev, App.Path & “\viking_walking.bmp”)
    ‘now create the individual characters used in the game
    ‘all of these will share the base data above
    For n = 0 To NUMNPCS - 1
        ‘initialize sprite data
        InitSprite d3ddev, charSprites(n)
        With charSprites(n)
           .FramesPerRow = 8
           .FrameCount = 8
           .AnimDelay = 2
           .width = 96
           .height = 96
        End With
        ‘start NPCs at the player’s location
        ‘(to test NPC movement at this stage)
        p.x = PLAYERSTARTX * TILEWIDTH
        p.y = PLAYERSTARTY * TILEHEIGHT
        ‘customize the Viking character
        With charStates(n)
            ‘this is the key! points to the base image/sprite/data
           .classindex = 0
           .name = “Viking”
           .startpos = p
           .curpos = p
           .SpeedDelay = 1
           .SpeedCount = 0
           .state = NPC_WALKING
            SetRandomDestination n
        End With
    Next n
End Sub
10. 移动 NPC

在主游戏循环中调用 MoveNPCs 子程序移动 NPC,建议在屏幕更新的 BeginDraw EndDraw 调用之间调用该子程序。使用 TNPC 中的 SpeedCount SpeedDelay 变量调整每个 NPC 的移动速度。

Public Sub MoveNPCs()
    Dim n As Long
    ‘loop through all of the NPCs and move them
    For n = 0 To NUMNPCS - 1
        MoveNPC n
    Next n
End Sub

Public Sub MoveNPC(ByVal num As Long)
    ‘moves a single NPC
    With charStates(num)
        ‘update movement rate—exit if not there yet
       .SpeedCount = .SpeedCount + 1
        If .SpeedCount < .SpeedDelay Then Exit Sub
        ‘okay, time to move, reset move counter
       .SpeedCount = 0
    End With
End Sub

通过以上步骤,可在角色扮演游戏中实现角色类的设计、数据文件的读写、NPC 的创建和管理等功能。在开发过程中,可根据需求对代码进行修改和扩展,以实现更丰富的游戏内容。

角色扮演游戏角色与NPC开发指南

11. 移动 NPC 的详细逻辑

MoveNPC 子程序虽然在前面有了基本框架,但其中移动的逻辑较为复杂。由于精灵每个有至少 64 帧,且有 8 个移动方向,所以需要仔细规划。下面为大家详细分析其逻辑:

Public Sub MoveNPC(ByVal num As Long)
    '移动单个 NPC
    With charStates(num)
        '更新移动计数 - 如果未达到移动间隔则退出
        .SpeedCount = .SpeedCount + 1
        If .SpeedCount < .SpeedDelay Then Exit Sub
        '达到移动间隔,重置移动计数器
        .SpeedCount = 0

        '根据 NPC 朝向和目标位置进行移动
        If .curpos.x < .destpos.x Then
            .curpos.x = .curpos.x + 1
            .Facing = 2 '向右
        ElseIf .curpos.x > .destpos.x Then
            .curpos.x = .curpos.x - 1
            .Facing = 6 '向左
        End If

        If .curpos.y < .destpos.y Then
            .curpos.y = .curpos.y + 1
            .Facing = 4 '向下
        ElseIf .curpos.y > .destpos.y Then
            .curpos.y = .curpos.y - 1
            .Facing = 8 '向上
        End If

        '检查是否到达目标位置
        If .curpos.x = .destpos.x And .curpos.y = .destpos.y Then
            SetRandomDestination num
        End If
    End With
End Sub

上述代码中,根据 NPC 当前位置和目标位置的比较,决定 NPC 的移动方向和移动操作。当 NPC 到达目标位置后,会调用 SetRandomDestination 子程序为其设置新的随机目标位置。

12. 设置随机目的地

设置随机目的地对于 NPC 的行为多样化很重要,可使游戏世界更加生动。以下是 SetRandomDestination 子程序的实现:

Public Sub SetRandomDestination(ByVal num As Long)
    Dim range As Integer
    range = 50 '可根据需要调整范围

    With charStates(num)
        .destpos.x = .startpos.x + Rnd() * range - range / 2
        .destpos.y = .startpos.y + Rnd() * range - range / 2
    End With
End Sub

该子程序通过随机数生成在起始位置一定范围内的新目标位置,范围大小可通过 range 变量进行调整。

13. 绘制 NPC

绘制 NPC 是将 NPC 显示在游戏屏幕上的关键步骤。以下是一个简单的绘制 NPC 的示例代码:

Public Sub DrawNPCs()
    Dim n As Long
    For n = 0 To NUMNPCS - 1
        DrawSprite d3ddev, charSprites(n), charImages(charStates(n).classindex), charStates(n).curpos.x, charStates(n).curpos.y, charStates(n).Facing
    Next n
End Sub

在这个子程序中,遍历所有 NPC,调用 DrawSprite 函数将每个 NPC 绘制到屏幕上,绘制时会根据 NPC 的当前位置和朝向进行显示。

14. 总结与展望

通过前面的一系列步骤,我们已经实现了角色类的设计、数据文件的读写、NPC 的创建、初始化、移动和绘制等功能。整个开发过程可以用以下流程图表示:

graph LR
    A[角色类设计] --> B[数据文件读写]
    B --> C[NPC 创建]
    C --> D[NPC 初始化]
    D --> E[NPC 移动]
    E --> F[设置随机目的地]
    F --> G[NPC 绘制]

在未来的开发中,我们可以进一步扩展这些功能,例如:
- 增加更多的 NPC 状态 :如前面提到的 NPC_FLEEING NPC_TALKING NPC_ATTACKING 等,丰富 NPC 的行为。
- 优化移动算法 :使 NPC 的移动更加自然,避免出现不合理的移动路径。
- 完善角色属性系统 :增加更多的角色属性,如技能、装备等,提升游戏的可玩性。

同时,我们还可以根据游戏的整体剧情和风格,设计更多不同类型的 NPC,让游戏世界更加丰富多彩。在开发过程中,要不断测试和调整,确保游戏的平衡性和趣味性。

15. 开发注意事项

在开发角色扮演游戏角色和 NPC 时,有一些注意事项需要大家牢记:
| 注意事项 | 说明 |
| ---- | ---- |
| 代码可维护性 | 随着游戏功能的增加,代码会越来越复杂,因此在编写代码时要注意代码的结构和注释,方便后续的修改和扩展。 |
| 性能优化 | 大量的 NPC 可能会影响游戏的性能,要注意对代码进行性能优化,如合理使用数组、减少不必要的计算等。 |
| 数据一致性 | 在读写数据文件时,要确保数据的一致性,避免出现数据丢失或错误的情况。 |
| 随机性控制 | 在为 NPC 添加随机性时,要控制好随机的范围和程度,避免出现过于强大或弱小的 NPC,影响游戏的平衡性。 |

通过遵循这些注意事项,可以让开发过程更加顺利,开发出更加优质的游戏。

总之,开发角色扮演游戏的角色和 NPC 是一个充满挑战和乐趣的过程。希望大家通过本文的介绍,能够掌握基本的开发方法和技巧,并根据自己的创意和需求,开发出独具特色的游戏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值