Skip to content

选择向问题分析&策略方案 #1

Description

@RyougiChan

问题描述

选择向 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分]
Loading

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

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]

Loading

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

问题分析

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

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

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

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

动态规划

建模思路

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

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]
Loading

基础类设计

定义一个组件超类 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
Loading

Metadata

Metadata

Assignees

No one assigned

    Labels

    analysisOrganize your thoughts

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions