@xiaoyixy
2020-04-02T15:43:43.000000Z
字数 2209
阅读 799
文档
选择向 RPG 游戏往往通过不同的多个选择(这里称为路线)最终导向不同的结局。
当路线的数目和结局数目比较少的时候可以通过设定数值,最后数值统计的方式来推出下一步的方向和结局。
比如:
graph LR;
A[选择卡1] --> B[选择子项1-1分]
A[选择卡1] --> C[选择子项2-2分]
A[选择卡1] --> D[选择子项3-3分]
B --> E[剧情1]
C --> O[结局1]
D --> F[剧情2]
E[剧情1] --> G[选择卡2]
G --> H[选择子项1-1分]
G --> I[选择子项2-2分]
G --> J[选择子项3-3分]
F[剧情2] --> K[选择卡3]
K --> L[选择子项1-1分]
K --> M[选择子项2-2分]
H --> O[结局1-累计2分]
I --> P[结局2-累计3分]
J --> Q[结局3-累计4分]
L --> Q[结局3-累计4分]
M --> R[结局4-累计5分]
但是,一旦路线数和结局过多,中途出现选项合并,比如出现不同分数可以导向同一下一步/结局,或者分数相同时可导向不同的下一步/结局的情况,那么逻辑就会显得相当混乱,管理非常麻烦且容易出错。
graph LR;
A[选择卡1] --> B[选择子项1-1分]
A[选择卡1] --> C[选择子项2-2分]
A[选择卡1] --> D[选择子项3-3分]
B --> E[剧情1]
C -.2分.-> O[结局1]
D --> F[剧情2]
E[剧情1] --> G[选择卡2]
G --> H[选择子项1-1分]
G --> I[选择子项2-2分]
G --> J[选择子项3-3分]
F[剧情2] --> K[选择卡3]
K --> L[选择子项1-1分]
K --> M[选择子项2-2分]
H -.2分.-> P[结局2]
I --3分--> P[结局2]
J --4分--> Q[结局3]
L --4分--> Q[结局3]
M -.5分.-> Q[结局3]
如上图这种情况,多个不同的分数得到了同一个结局。
上面设计存在的问题在于分数导向结局的过程,当分数出现相同时难以管理。
以上的问题可以通过合理设定分数来避免重复冲突,但是很明显这项工作不仅设计工作量巨大且不利于管理和程序设计,一旦有一点小改动,那么后果是灾难性的。
一个不那么好的优化措施是使用穷举法,通过步伐记录(每一个选择选择了什么)来区分每一种不同的情况,事先保存一系列可能的路线。但是带来的是出现大量重复的问题。
另一个比较好的思路是运用动态规划(线性规划)的思想,不用关注之前的所有选择和结果,而只关注当前的问题和选择。
跳出积分导向思路,而把某些变量的数值当成动态判断方向的依据,结合面向切面编程思想,目标是实现每一个步骤可插拔,可替换,这样可以实现每一步的操作不会影响之前或者之后的发展。因此选用双向链表的数据结构显然非常合适。
graph LR
A[剧情片段1] -->|数值变动| B{选择1}
B -->|数值变动| D[剧情片段2]
B -->|数值变动| E[剧情片段3]
B -->|数值变动| E[剧情片段3]
D -->|数值变动| F{选择2}
F -->|数值变动| G[剧情片段4]
F -->|数值变动| H[剧情片段5]
E -->|数值变动| I{数值达到一定值}
I -->|满足条件1| H[剧情片段5]
I -->|满足条件2| J[剧情片段6]
G -.->|后续剧情| K[结局1]
H -.->|后续剧情| L[结局2]
J -.->|后续剧情| M[结局3]
定义一个组件超类 Component
,子类:台词类 Line
,选择器类 Selector
,条件触发器类 Judgement
,数值类 GameValues
。
类 | 名称 | 解释 |
---|---|---|
Action | 场景类 | 代表一个场景/回合 |
Component | 组件超类 | |
Line | 台词类 | 台词组件,角色台词 |
Selector | 剧情选择器类 | 提供剧情选择器组件,用于提供不同选择从而导向后续分支剧情 |
Judgement | 数值裁决组件 | 裁决器组件,某些数值达到一定的阈值则触发相关事件或者导向后续分支剧情 |
GameValues | 数值类 | 在此处代表数值变动,在本场景被演出之后相关数值应该如何变动 |
classDiagram
class Action{
// 当前场景的ID
+int id
// 前一个场景的ID
+int previous_action_id
// 下一个场景的ID
+int next_action_id
// 场景背景
+Sprite bg
// 场景音乐
+AudioSource bgm
Line line
Selector selector
Judgement judgement
GameValues gamevalues
}
class Component{
int id
int action_id
}
class Line{
// 角色台词
+String text
// 台词样式
+Style style
// 角色语音
+AudioSource voice
}
class Selector{
// 已选择的值
object selected_value
// 子选项列表
List<Option> options
}
class Judgement{
// 达成触发条件的数值组合
List<GameValues> meetGameValues
}
class GameValues{
// ...
int HP
int MP
int EXP
}
Action <|-- Component
Component <|-- Line
Component <|-- Selector
Component <|-- Judgement
Component <|-- GameValues