[关闭]
@xiaoyixy 2020-04-02T15:43:43.000000Z 字数 2209 阅读 799

设计策略/模型

文档


问题描述

选择向 RPG 游戏往往通过不同的多个选择(这里称为路线)最终导向不同的结局。
当路线的数目和结局数目比较少的时候可以通过设定数值,最后数值统计的方式来推出下一步的方向和结局。
比如:

  1. graph LR;
  2. A[选择卡1] --> B[选择子项1-1分]
  3. A[选择卡1] --> C[选择子项2-2分]
  4. A[选择卡1] --> D[选择子项3-3分]
  5. B --> E[剧情1]
  6. C --> O[结局1]
  7. D --> F[剧情2]
  8. E[剧情1] --> G[选择卡2]
  9. G --> H[选择子项1-1分]
  10. G --> I[选择子项2-2分]
  11. G --> J[选择子项3-3分]
  12. F[剧情2] --> K[选择卡3]
  13. K --> L[选择子项1-1分]
  14. K --> M[选择子项2-2分]
  15. H --> O[结局1-累计2分]
  16. I --> P[结局2-累计3分]
  17. J --> Q[结局3-累计4分]
  18. L --> Q[结局3-累计4分]
  19. M --> R[结局4-累计5分]

但是,一旦路线数和结局过多,中途出现选项合并,比如出现不同分数可以导向同一下一步/结局,或者分数相同时可导向不同的下一步/结局的情况,那么逻辑就会显得相当混乱,管理非常麻烦且容易出错

  1. graph LR;
  2. A[选择卡1] --> B[选择子项1-1分]
  3. A[选择卡1] --> C[选择子项2-2分]
  4. A[选择卡1] --> D[选择子项3-3分]
  5. B --> E[剧情1]
  6. C -.2分.-> O[结局1]
  7. D --> F[剧情2]
  8. E[剧情1] --> G[选择卡2]
  9. G --> H[选择子项1-1分]
  10. G --> I[选择子项2-2分]
  11. G --> J[选择子项3-3分]
  12. F[剧情2] --> K[选择卡3]
  13. K --> L[选择子项1-1分]
  14. K --> M[选择子项2-2分]
  15. H -.2分.-> P[结局2]
  16. I --3分--> P[结局2]
  17. J --4分--> Q[结局3]
  18. L --4分--> Q[结局3]
  19. M -.5分.-> Q[结局3]

如上图这种情况,多个不同的分数得到了同一个结局。

问题分析

上面设计存在的问题在于分数导向结局的过程,当分数出现相同时难以管理。

以上的问题可以通过合理设定分数来避免重复冲突,但是很明显这项工作不仅设计工作量巨大且不利于管理和程序设计,一旦有一点小改动,那么后果是灾难性的。

一个不那么好的优化措施是使用穷举法,通过步伐记录(每一个选择选择了什么)来区分每一种不同的情况,事先保存一系列可能的路线。但是带来的是出现大量重复的问题。

另一个比较好的思路是运用动态规划(线性规划)的思想,不用关注之前的所有选择和结果,而只关注当前的问题和选择。

动态规划

建模思路

跳出积分导向思路,而把某些变量的数值当成动态判断方向的依据,结合面向切面编程思想,目标是实现每一个步骤可插拔,可替换,这样可以实现每一步的操作不会影响之前或者之后的发展。因此选用双向链表的数据结构显然非常合适。

  1. graph LR
  2. A[剧情片段1] -->|数值变动| B{选择1}
  3. B -->|数值变动| D[剧情片段2]
  4. B -->|数值变动| E[剧情片段3]
  5. B -->|数值变动| E[剧情片段3]
  6. D -->|数值变动| F{选择2}
  7. F -->|数值变动| G[剧情片段4]
  8. F -->|数值变动| H[剧情片段5]
  9. E -->|数值变动| I{数值达到一定值}
  10. I -->|满足条件1| H[剧情片段5]
  11. I -->|满足条件2| J[剧情片段6]
  12. G -.->|后续剧情| K[结局1]
  13. H -.->|后续剧情| L[结局2]
  14. J -.->|后续剧情| M[结局3]

基础类设计

定义一个组件超类 Component,子类:台词类 Line,选择器类 Selector,条件触发器类 Judgement,数值类 GameValues

名称 解释
Action 场景类 代表一个场景/回合
Component 组件超类
Line 台词类 台词组件,角色台词
Selector 剧情选择器类 提供剧情选择器组件,用于提供不同选择从而导向后续分支剧情
Judgement 数值裁决组件 裁决器组件,某些数值达到一定的阈值则触发相关事件或者导向后续分支剧情
GameValues 数值类 在此处代表数值变动,在本场景被演出之后相关数值应该如何变动
  1. classDiagram
  2. class Action{
  3. // 当前场景的ID
  4. +int id
  5. // 前一个场景的ID
  6. +int previous_action_id
  7. // 下一个场景的ID
  8. +int next_action_id
  9. // 场景背景
  10. +Sprite bg
  11. // 场景音乐
  12. +AudioSource bgm
  13. Line line
  14. Selector selector
  15. Judgement judgement
  16. GameValues gamevalues
  17. }
  18. class Component{
  19. int id
  20. int action_id
  21. }
  22. class Line{
  23. // 角色台词
  24. +String text
  25. // 台词样式
  26. +Style style
  27. // 角色语音
  28. +AudioSource voice
  29. }
  30. class Selector{
  31. // 已选择的值
  32. object selected_value
  33. // 子选项列表
  34. List<Option> options
  35. }
  36. class Judgement{
  37. // 达成触发条件的数值组合
  38. List<GameValues> meetGameValues
  39. }
  40. class GameValues{
  41. // ...
  42. int HP
  43. int MP
  44. int EXP
  45. }
  46. Action <|-- Component
  47. Component <|-- Line
  48. Component <|-- Selector
  49. Component <|-- Judgement
  50. Component <|-- GameValues

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注