游戏中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在游戏中发挥重要作用,成为游戏世界中生动的一部分。
超级会员免费看
761

被折叠的 条评论
为什么被折叠?



