23、游戏中NPC的行为实现与交互系统搭建

游戏中NPC的行为实现与交互系统搭建

1. NPC移动与目的地设定

1.1 检查是否到达目的地

在游戏中,NPC的移动是一个关键部分。首先,需要检查NPC是否到达了设定的目的地。以下是实现该功能的代码:

'check to see if destination reached
If .curpos.x = .destpos.x And .curpos.y = .destpos.y Then
    'yes! set a new destination then exit
    .state = NPC_STOPPED
    SetRandomDestination num
    Exit Sub
Else
    .state = NPC_WALKING
End If

上述代码逻辑如下:
- 如果当前位置( .curpos )的x和y坐标与目标位置( .destpos )的x和y坐标都相等,说明NPC已经到达目的地。此时,将NPC的状态设置为 NPC_STOPPED ,并调用 SetRandomDestination 函数为其设置一个新的随机目的地,然后退出该子程序。
- 如果未到达目的地,则将NPC的状态设置为 NPC_WALKING ,表示NPC正在移动。

1.2 设置NPC的“朝向”方向并更新位置

确定NPC是否到达目的地后,需要根据当前位置和目标位置的关系,设置NPC的“朝向”方向,并更新其X、Y坐标。以下是实现该功能的代码:

'time to set the NPC’s “facing” direction
'and update the X,Y position
If .curpos.x < .destpos.x Then
    'needs to walk westward
    .curpos.x = .curpos.x + 1
    If .curpos.y < .destpos.y Then
        'facing SE
        .curpos.y = .curpos.y + 1
        .Facing = 3
    ElseIf .curpos.y > .destpos.y Then
        'facing NE
        .curpos.y = .curpos.y - 1
        .Facing = 1
    Else
        'facing EAST
        .Facing = 2
    End If
ElseIf .curpos.x > .destpos.x Then
    'needs to walk eastward
    .curpos.x = .curpos.x - 1
    If .curpos.y < .destpos.y Then
        'facing SW
        .curpos.y = .curpos.y + 1
        .Facing = 5
    ElseIf .curpos.y > .destpos.y Then
        'facing NW
        .curpos.y = .curpos.y - 1
        .Facing = 7
    Else
        'facing WEST
        .Facing = 6
    End If
Else 'must be facing due NORTH or SOUTH
    If .curpos.y < .destpos.y Then
        'facing SOUTH
        .curpos.y = .curpos.y + 1
        .Facing = 4
    ElseIf .curpos.y > .destpos.y Then
        'facint NORTH
        .curpos.y = .curpos.y - 1
        .Facing = 0
    End If
End If

该代码根据当前位置和目标位置的关系,分为以下几种情况进行处理:
- 当当前位置的x坐标小于目标位置的x坐标时,NPC需要向西移动,x坐标加1。然后根据y坐标的关系,进一步确定NPC的朝向和y坐标的更新。
- 当当前位置的x坐标大于目标位置的x坐标时,NPC需要向东移动,x坐标减1。同样根据y坐标的关系,确定NPC的朝向和y坐标的更新。
- 当当前位置的x坐标等于目标位置的x坐标时,NPC只能向北或向南移动,根据y坐标的大小关系,确定NPC的朝向和y坐标的更新。

1.3 设置随机目的地

为了让NPC在游戏世界中有更自然的移动,需要为其设置随机目的地。以下是实现该功能的代码:

Public Sub SetRandomDestination(ByVal num As Long)
    With charStates(num)
        'set random X near the starting position
        '(the NPC will never wander away from his “home”)
        .destpos.x = .startpos.x + Random(600)
        If .destpos.x > GAMEWORLDWIDTH Then
            .destpos.x = GAMEWORLDWIDTH - 1
        End If
        'set random Y near the starting position
        .destpos.y = .startpos.y + Random(600)
        If .destpos.y > GAMEWORLDHEIGHT Then
            .destpos.y = GAMEWORLDHEIGHT - 1
        End If
    End With
End Sub

上述代码逻辑如下:
- 首先,根据NPC的起始位置( .startpos ),为其目标位置的x坐标( .destpos.x )加上一个0到600之间的随机数。
- 如果目标位置的x坐标超过了游戏世界的宽度( GAMEWORLDWIDTH ),则将其设置为游戏世界宽度减1,以确保NPC不会超出游戏世界范围。
- 同样,为目标位置的y坐标( .destpos.y )加上一个0到600之间的随机数,并检查是否超出游戏世界的高度( GAMEWORLDHEIGHT ),若超出则进行相应调整。

1.4 NPC移动流程总结

下面是NPC移动的整体流程,使用mermaid流程图表示:

graph TD;
    A[开始] --> B{是否到达目的地};
    B -- 是 --> C[设置状态为NPC_STOPPED];
    C --> D[设置新的随机目的地];
    D --> E[结束];
    B -- 否 --> F[设置状态为NPC_WALKING];
    F --> G{确定移动方向};
    G -- 西 --> H[更新x坐标,确定朝向];
    G -- 东 --> I[更新x坐标,确定朝向];
    G -- 北/南 --> J[更新y坐标,确定朝向];
    H --> K[结束];
    I --> K;
    J --> K;

2. NPC行为与状态管理

2.1 行为多样性设想

为了让NPC在游戏中更具真实感,可以为其赋予多种不同的行为。例如,可以参考游戏《模拟人生》,根据游戏中的条件,为NPC编程实现不同的行为。比如,当玩家攻击一个农民村民时,NPC不应只是站在那里,而应该有相应的反应,如逃跑或反击。

2.2 行为修改的实现方法

可以通过TNPC结构中的状态属性来实现NPC行为的修改。通过在 NPCSTATES 枚举列表中添加额外的状态,可以让NPC对玩家做出更真实的反应。以下是新的 NPCSTATES 枚举:

'keeps track of NPC state
Public Enum NPCSTATES
    NPC_STOPPED = 0
    NPC_WALKING = 1
    NPC_PAUSED = 2
    NPC_TALKING = 3
End Enum

通过设置不同的状态值,可以在游戏循环的更合适的点处理事件。例如,当玩家与NPC接近时,可以将NPC的状态设置为 NPC_TALKING ,表示NPC正在与玩家进行交互。

2.3 NPC状态说明

状态名称 状态值 说明
NPC_STOPPED 0 NPC停止移动
NPC_WALKING 1 NPC正在移动
NPC_PAUSED 2 NPC暂停移动
NPC_TALKING 3 NPC正在与玩家进行交互

3. NPC的绘制

3.1 绘制所有NPC

在游戏主循环中,会调用 DrawNPCs 子程序来绘制游戏世界中的所有NPC。以下是该子程序的代码:

Public Sub DrawNPCs()
    Dim n As Long
    'loop through all of the NPCs and draw them
    For n = 0 To NUMNPCS - 1
        DrawNPC n
    Next n
End Sub

上述代码通过一个循环,依次调用 DrawNPC 子程序来绘制每个NPC。

3.2 绘制单个NPC

DrawNPC 子程序负责绘制单个NPC。其主要功能是根据 ScrollX ScrollY 变量,判断NPC的精灵是否应该显示在屏幕上,如果显示,则更新其动画帧并绘制。以下是该子程序的代码:

Public Sub DrawNPC(ByVal num As Long)
    Dim r As RECT
    Dim classindex As Long
    'grab a shortcut to these long variable names
    r.Left = charStates(num).curpos.x
    r.Top = charStates(num).curpos.y
    r.Right = r.Left + charSprites(num).width
    r.Bottom = r.Top + charSprites(num).height
    'remember, images/data are referred to using the NPC’s classindex!
    'the sprite and state arrays are for every single unique NPC,
    'but the bitmap image and class data are shared by all NPCs
    classindex = charStates(num).classindex
    'now check to see if the sprite is within the scrolling viewport
    'sprite’s position is actually global, so this determines if it’s visible
    If r.Left > ScrollX - 1 And r.Right < ScrollX + SCREENWIDTH + 1 And _
       r.Top > ScrollY - 1 And r.Bottom < ScrollY + SCREENHEIGHT + 1 Then
        'update animation frame if walking
        If charStates(num).state = NPC_WALKING Then
            AnimateSprite charSprites(num)
        End If
        'draw the sprite—remember, it’s using the shared image (texture)
        charSprites(num).x = charStates(num).curpos.x - ScrollX
        charSprites(num).y = charStates(num).curpos.y - ScrollY
        charSprites(num).AnimSeq = charStates(num).Facing
        DrawSprite charImages(classindex), charSprites(num), C_WHITE
    End If
End Sub

该代码的逻辑如下:
- 首先,获取NPC的当前位置和大小信息,存储在 RECT 结构体 r 中。
- 然后,根据NPC的类索引( classindex )获取其对应的图像数据。
- 接着,检查NPC的精灵是否在滚动视口内,如果在,则进行下一步操作。
- 如果NPC的状态为 NPC_WALKING ,则调用 AnimateSprite 子程序更新其动画帧。
- 最后,更新精灵的位置和动画序列,并调用 DrawSprite 子程序绘制精灵。

3.3 NPC绘制流程总结

下面是NPC绘制的整体流程,使用mermaid流程图表示:

graph TD;
    A[开始] --> B[循环遍历所有NPC];
    B --> C[调用DrawNPC绘制单个NPC];
    C --> D{精灵是否在视口内};
    D -- 是 --> E{NPC是否在移动};
    E -- 是 --> F[更新动画帧];
    E -- 否 --> G[不更新动画帧];
    F --> H[更新精灵位置和动画序列];
    G --> H;
    H --> I[绘制精灵];
    I --> J[结束本次绘制];
    D -- 否 --> J;
    J --> K{是否遍历完所有NPC};
    K -- 否 --> B;
    K -- 是 --> L[结束];

4. 新游戏版本与精灵制作

4.1 新游戏版本

新的游戏版本可以在CD-ROM的 \sources\chapter16\CelticCrusader1 中找到。建议加载该项目并运行,以便更好地理解游戏的工作原理,并对其进行修改。

4.2 精灵制作流程

在深入研究新的游戏源代码之前,需要为游戏中的每个新角色创建自定义精灵图稿。以下是精灵制作的步骤:
1. 从 http://www.reinerstilesets.de 获取3D建模和渲染的精灵。
2. 将维京精灵加载到Pro Motion中,导出为一系列八个动画条带,每个条带包含八个动画帧,对应一个移动方向。
3. 将动画条带保存为八个单独的位图文件。
4. 使用图形编辑器(如Paint Shop Pro)将这些位图文件合并为一个大的位图。注意,背景的透明像素应为粉色,RGB值为(255, 0, 255)。

5. NPC与玩家的交互

5.1 遇到玩家

当玩家接近NPC时,NPC会做出相应的反应。通过新开发的代码,当玩家与NPC发生碰撞(即接近)时,会将NPC的状态设置为 NPC_TALKING 。例如,在某些截图中可以看到,NPC会减慢速度并面向玩家,仿佛正在与玩家进行对话。

5.2 与玩家交谈

让NPC对玩家做出反应后,下一步是让他们参与对话。可以通过按下空格键来与附近的NPC进行交互,此时NPC会在屏幕上显示“Hello”消息。为了创建更强大和功能丰富的对话系统,可以参考以下建议:
- 让NPC从可能的引语列表中显示随机引语。
- 允许玩家从列表中选择要说的话,例如使用鼠标或箭头键。
- 暂停屏幕上的所有动画,并在屏幕上弹出一个包含对话选项的窗口。
- 为每个角色类创建标准对话,根据NPC的类型设置不同的反应,如维京角色可能对玩家表现出敌意。

5.3 NPC与玩家交互流程总结

下面是NPC与玩家交互的整体流程,使用mermaid流程图表示:

graph TD;
    A[开始] --> B{玩家是否接近NPC};
    B -- 是 --> C[设置NPC状态为NPC_TALKING];
    B -- 否 --> D[NPC继续正常移动];
    C --> E{玩家是否按下空格键};
    E -- 是 --> F[显示对话消息];
    E -- 否 --> D;
    F --> G{是否继续对话};
    G -- 是 --> H[显示对话选项,处理交互];
    G -- 否 --> D;
    H --> I[结束对话,NPC恢复正常状态];
    I --> D;
    D --> J[结束];

通过以上步骤和代码,可以实现NPC在游戏中的移动、行为管理、绘制以及与玩家的交互,为游戏增添更多的真实感和趣味性。

6. 游戏中NPC交互系统的代码实现与分析

6.1 核心代码功能概述

在实现NPC与玩家交互的系统中,有几个关键的代码部分起到了核心作用。前面已经介绍了NPC移动、绘制等相关代码,下面将详细分析与交互相关的代码逻辑。

6.2 状态管理代码分析

'keeps track of NPC state
Public Enum NPCSTATES
    NPC_STOPPED = 0
    NPC_WALKING = 1
    NPC_PAUSED = 2
    NPC_TALKING = 3
End Enum
  • 代码解释 :这段枚举代码定义了NPC的不同状态。 NPC_STOPPED 表示NPC停止移动, NPC_WALKING 表示NPC正在移动, NPC_PAUSED 可用于表示NPC暂停移动(如欣赏风景或与其他NPC聊天), NPC_TALKING 表示NPC正在与玩家进行交互。
  • 作用 :通过设置不同的状态值,可以在游戏循环的合适点处理不同的事件,实现NPC行为的灵活控制。

6.3 碰撞检测与状态设置代码

在判断玩家与NPC是否接近时,会涉及到碰撞检测相关代码(此处未详细给出,但原理是判断玩家和NPC的位置关系)。当检测到接近时,会将NPC的状态设置为 NPC_TALKING

' 伪代码示例,假设检测到玩家接近NPC
If PlayerIsNearNPC Then
    charStates(NPCIndex).state = NPC_TALKING
End If
  • 代码解释 :当检测到玩家接近某个NPC(通过 PlayerIsNearNPC 条件判断)时,将该NPC在 charStates 数组中的状态设置为 NPC_TALKING
  • 作用 :使得NPC能够对玩家的接近做出反应,进入与玩家交互的状态。

6.4 对话触发代码

' 伪代码示例,假设按下空格键触发对话
If KeyPressed(VK_SPACE) And charStates(NPCIndex).state = NPC_TALKING Then
    DisplayDialogMessage("Hello")
End If
  • 代码解释 :当玩家按下空格键(通过 KeyPressed(VK_SPACE) 判断),并且NPC的状态为 NPC_TALKING 时,调用 DisplayDialogMessage 函数显示对话消息“Hello”。
  • 作用 :实现了玩家与NPC之间简单对话的触发机制。

6.5 代码功能总结表格

代码功能 代码示例 作用
状态管理 Public Enum NPCSTATES ... 定义NPC的不同状态,方便控制NPC行为
碰撞检测与状态设置 If PlayerIsNearNPC Then ... 检测玩家与NPC的接近,设置NPC状态为交互状态
对话触发 If KeyPressed(VK_SPACE) And ... 玩家按下空格键触发与NPC的对话

7. 进一步优化与拓展思路

7.1 对话系统优化

  • 随机对话内容 :目前的对话只是简单显示“Hello”,可以进一步优化为让NPC从一个预设的对话列表中随机选择内容进行显示。
' 假设定义了一个对话列表
Dim dialogList() As String = {"Hello", "How are you?", "Nice to meet you!"}
' 随机选择一个对话内容
Dim randomIndex As Integer = Random(UBound(dialogList) + 1)
DisplayDialogMessage(dialogList(randomIndex))
  • 玩家选择对话选项 :允许玩家从列表中选择要说的话,可以使用鼠标或箭头键进行选择。可以创建一个对话选项列表,根据玩家的选择做出不同的反应。

7.2 NPC行为拓展

  • 不同性格NPC :为不同类型的NPC赋予不同的性格特点,如友好型、敌对型、中立型等。不同性格的NPC对玩家的反应会有所不同。例如,友好型NPC可能会主动打招呼并提供帮助,敌对型NPC可能会直接攻击玩家。
  • NPC之间的交互 :除了与玩家交互,还可以实现NPC之间的交互。例如,两个友好的NPC可能会互相交谈、交换物品等。

7.3 优化与拓展流程总结

下面是优化与拓展的整体流程,使用mermaid流程图表示:

graph TD;
    A[开始] --> B{是否优化对话系统};
    B -- 是 --> C[实现随机对话内容];
    C --> D[允许玩家选择对话选项];
    B -- 否 --> E{是否拓展NPC行为};
    E -- 是 --> F[设置不同性格NPC];
    F --> G[实现NPC之间的交互];
    E -- 否 --> H[结束];
    D --> H;
    G --> H;

8. 总结

8.1 关键知识点回顾

通过前面的介绍,我们了解了游戏中NPC的多个重要方面:
- NPC移动 :包括检查是否到达目的地、设置移动方向、更新位置以及设置随机目的地等功能。
- 行为与状态管理 :通过状态属性和枚举列表,实现NPC对不同事件的反应,如遇到玩家、与玩家交谈等。
- 绘制 :根据NPC的位置和状态,判断是否显示在屏幕上,并更新动画帧进行绘制。
- 交互系统 :实现了玩家与NPC的接近检测、对话触发等交互功能。

8.2 未来展望

游戏中NPC的开发是一个不断完善和拓展的过程。通过进一步优化对话系统、拓展NPC行为等,可以让游戏更加丰富和有趣。例如,实现更加复杂的AI行为,让NPC能够根据游戏中的各种情况做出更智能的决策。同时,也可以增加更多的NPC类型和交互场景,为玩家带来更好的游戏体验。

总之,通过合理的设计和代码实现,可以让NPC在游戏中发挥重要作用,成为游戏世界中生动的一部分。

内容概要:本文介绍了一种基于蒙特卡洛模拟和拉格朗日优化方法的电动汽车充电站有序充电调度策略,重点针对分时电价机制下的分散式优化问题。通过Matlab代码实现,构建了考虑用户充电需求、电网负荷平衡及电价波动的数学模【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)型,采用拉格朗日乘子法处理约束条件,结合蒙特卡洛方法模拟大量电动汽车的随机充电行为实现对充电功率和时间的优化分配,旨在降低用户充电成本、平抑电网峰谷差并提升充电站运营效率。该方法体现了智能优化算法在电力系统调度中的实际应用价值。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事新能源汽车、智能电网相关领域的工程技术人员。; 使用场景及目标:①研究电动汽车有序充电调度策略的设计仿真;②学习蒙特卡洛模拟拉格朗日优化在能源系统中的联合应用;③掌握基于分时电价的需求响应优化建模方法;④为微电网、充电站运营管理提供技术支持和决策参考。; 阅读建议:建议读者结合Matlab代码深入理解算法实现细节,重点关注目标函数构建、约束条件处理及优化求解过程,可尝试调整参数设置以观察不同场景下的调度效果,进一步拓展至多目标优化或多类型负荷协调调度的研究。
内容概要:本文围绕面向制造业的鲁棒机器学习集成计算流程展开研究,提出了一套基于Python实现的综合性计算框架,旨在应对制造过程中数据不确定性、噪声干扰面向制造业的鲁棒机器学习集成计算流程研究(Python代码实现)及模型泛化能力不足等问题。该流程集成了数据预处理、特征工程、异常检测、模型训练优化、鲁棒性增强及结果可视化等关键环节,结合集成学习方法提升预测精度稳定性,适用于质量控制、设备故障预警、工艺参数优化等典型制造场景。文中通过实际案例验证了所提方法在提升模型鲁棒性和预测性能方面的有效性。; 适合人群:具备Python编程基础和机器学习基础知识,从事智能制造、工业数据分析及相关领域研究的研发人员工程技术人员,尤其适合工作1-3年希望将机器学习应用于实际制造系统的开发者。; 使用场景及目标:①在制造环境中构建抗干扰能力强、稳定性高的预测模型;②实现对生产过程中的关键指标(如产品质量、设备状态)进行精准监控预测;③提升传统制造系统向智能化转型过程中的数据驱动决策能力。; 阅读建议:建议读者结合文中提供的Python代码实例,逐步复现整个计算流程,并针对自身业务场景进行数据适配模型调优,重点关注鲁棒性设计集成策略的应用,以充分发挥该框架在复杂工业环境下的优势。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值