C# 中的视觉小说决策结构
Visual Novel Decision Structure in C#
一段时间以来,我一直在努力解决这个问题。多次搜索结果很少,所以我希望得到帮助。我对 C# 有很好的掌握,但我对结构或如何以最好的方式处理事情不太有经验。我目前正作为首席程序员与一个团队一起开发我的第一款独立游戏,因为我即将获得游戏编程学位,并且取得了良好的进步。我们正在 Unity 中制作一部视觉小说(我主要想为 art/sound 资产使用 if 并为我处理场景),在我需要开始实施决策结构之前,我将尽可能地使用代码对于玩家。
现在我发现的大多数教程或指南都说一个简单的开关或 if/then 语句就可以了。问题在于,在具有多个时间线的较长游戏中,我不确定这会有多高效。例如,某些决策可能不会被击中,或者在不同的时间被击中。这给需要不止一个决定才能达成的对话线带来了问题。如果玩家选择向左走,然后打开一扇门 vs 向右走,踢翻一个水桶,我是否必须为其设置 4 个单独的变量?
这很难解释,因为我不太确定这些决策结构通常是如何设置的,而且我读到的所有内容要么显示了对 1 个问题的简单陈述和结果场景,要么只是说使用视觉小说引擎.我希望在未来的某个时候扩展到点和点击游戏。
所以我的主要问题是,我将如何在存储和处理方面构建决策树?到目前为止,我最好的猜测是存储一个结构或对象列表,每个对象都是一个决定,其中存储了以前的需求。这也意味着为了选择对话框,程序将从第一个连接(对象链接到对象)开始跳到树下。
我可以设置一种以某种方式存储特定选择的方法吗?树越复杂,它就越难。例如,如果你走下一条让你做出 100 多个决定的道路,它会使对话选项越来越长。我在这里错过了什么?
我想我可以存储包含 A、B、C 或 D 的枚举器的每个决定。可以说,左右类问题只会使用 A 和 B。但是,如果您有一个带有枚举器的对话框选项,它最终会看起来像这样。
凯尔:choiceHallway:1:choiceDoor2:"Welcome to the left hallway's door!";
我想除非你无论如何都要走第一个走廊,否则无法到达门,但我觉得当你假设除非你这样做就无法到达某些东西时,这可能会在路上造成问题,并且会产生错误因为它在选择选择。有没有更好的方法来解决这个问题?
我应该注意,我现在正在使用 mysql 数据库来存储对话。我已经有 import/export 工作,只是没有处理它。
听起来您正在寻找 finite state machine。我不会尝试在单个状态机中表示整个游戏,而是将每个都有自己的状态机的东西分解(例如分成 "chapters" 或类似的东西),而 "chapters" 的集合会本身就是一个状态机(例如,如果你已经完成了第 2 章和第 3 章,你只能过渡到第 4 章,但你可以在完成第 1 章后过渡到第 2 章或第 3 章,等等)。
这是我在 "normal" C# 项目中使用过的(即不是 Unity),但它应该 与 Unity 一起使用,而且它很容易获得设置:https://github.com/MassTransit/Automatonymous。另外,查看文档中的 "sagas" 。虽然不能直接应用,但它们将为您提供编排多个状态机的一些指导。
只是一点点 answer.Hope 这将对您有所帮助。据我所知,您需要一个抽象的解决方案,而不是在每个语句中使用 if else 。制作对象图,例如 (https://i.stack.imgur.com/nVpih.jpg) ,制作路径并设置像 isInRoomVariable =true 和你的对象,它会告诉你你来自哪里,甚至功能 当你在左边的房间或右边的房间时你能做什么
从游戏开发的角度来看,我想轻松地操纵变量/条件要求,例如任务或关卡等
我建议收集由可编写脚本的对象组成的需求。您可以将它们存储在可以从检查器中轻松操作的对象中。
您可以创建一个名为 "Kick the bucket" 的决定。
[CreateAssetMenuAttribute(menuName = "Decision")]
public Decision : ScriptableObject
{
public string Name;
public DecisionState State; // Use an Enum with states "Inactive" "Completed", "Failed", "Unavailable" etc.
// Other variables that may be relevant, like score or whatever
}
您可以在游戏开始时将状态设置为默认状态。然后,当您 select 结束时,将其标记为您想要的任何状态。
然后您可以提出要求,接受决定和期望的状态。
[CreateAssetMenuAttribute(menuName = "Requirement")]
public Requirement : ScriptableObject
{
public Decision Decision;
public DecisionState State;
}
现在,在您的房间、章节或任何脚本中,您可以附上执行您想要的任何逻辑所需的要求列表。您可以 运行 CheckRequirements 方法来查看是否满足所有要求。
public Room : MonoBehaviour
{
public List<Requirement> Requirements;
public bool CheckRequirements()
{
foreach (var requirement in Requirements)
{
if (requirement.Decision.State != requirement.State)
{
return false;
}
}
return true;
}
}
我喜欢这种方法的原因是您可以轻松创建新的决定和要求,然后将它们拖放到检查器槽中。因此,当您的游戏流程发生变化时,您可以简单地添加或删除一个决定/要求。
编辑:
有一些时间,做了一些思考...
为了使其设计更加友好,您还可以集成在进入房间并为您设置某些决定时触发的 UnityEvents。
public Room : MonoBehaviour
{
UnityEvent OnRoomEnter;
public void OnEnable() // Or whatever function you call when instantiating a room
{
OnRoomEnter();
}
}
然后考虑以下
public GameManager : MonoBehaviour
{
public void SetDecisionToActive(Decision decision)
{
decision.State = DecisionState.Active;
}
public void SetDecisionToInactive(Decision decision)
{
decision.State = DecisionState.Inactive;
}
// etc...
}
您现在可以将您的游戏管理器拖放到 Unity 中 'room' 单一行为对象的事件槽中,select 一个方法,然后将您创建的一个决策拖放到它的参数槽中。
一段时间以来,我一直在努力解决这个问题。多次搜索结果很少,所以我希望得到帮助。我对 C# 有很好的掌握,但我对结构或如何以最好的方式处理事情不太有经验。我目前正作为首席程序员与一个团队一起开发我的第一款独立游戏,因为我即将获得游戏编程学位,并且取得了良好的进步。我们正在 Unity 中制作一部视觉小说(我主要想为 art/sound 资产使用 if 并为我处理场景),在我需要开始实施决策结构之前,我将尽可能地使用代码对于玩家。
现在我发现的大多数教程或指南都说一个简单的开关或 if/then 语句就可以了。问题在于,在具有多个时间线的较长游戏中,我不确定这会有多高效。例如,某些决策可能不会被击中,或者在不同的时间被击中。这给需要不止一个决定才能达成的对话线带来了问题。如果玩家选择向左走,然后打开一扇门 vs 向右走,踢翻一个水桶,我是否必须为其设置 4 个单独的变量?
这很难解释,因为我不太确定这些决策结构通常是如何设置的,而且我读到的所有内容要么显示了对 1 个问题的简单陈述和结果场景,要么只是说使用视觉小说引擎.我希望在未来的某个时候扩展到点和点击游戏。 所以我的主要问题是,我将如何在存储和处理方面构建决策树?到目前为止,我最好的猜测是存储一个结构或对象列表,每个对象都是一个决定,其中存储了以前的需求。这也意味着为了选择对话框,程序将从第一个连接(对象链接到对象)开始跳到树下。
我可以设置一种以某种方式存储特定选择的方法吗?树越复杂,它就越难。例如,如果你走下一条让你做出 100 多个决定的道路,它会使对话选项越来越长。我在这里错过了什么?
我想我可以存储包含 A、B、C 或 D 的枚举器的每个决定。可以说,左右类问题只会使用 A 和 B。但是,如果您有一个带有枚举器的对话框选项,它最终会看起来像这样。
凯尔:choiceHallway:1:choiceDoor2:"Welcome to the left hallway's door!";
我想除非你无论如何都要走第一个走廊,否则无法到达门,但我觉得当你假设除非你这样做就无法到达某些东西时,这可能会在路上造成问题,并且会产生错误因为它在选择选择。有没有更好的方法来解决这个问题?
我应该注意,我现在正在使用 mysql 数据库来存储对话。我已经有 import/export 工作,只是没有处理它。
听起来您正在寻找 finite state machine。我不会尝试在单个状态机中表示整个游戏,而是将每个都有自己的状态机的东西分解(例如分成 "chapters" 或类似的东西),而 "chapters" 的集合会本身就是一个状态机(例如,如果你已经完成了第 2 章和第 3 章,你只能过渡到第 4 章,但你可以在完成第 1 章后过渡到第 2 章或第 3 章,等等)。
这是我在 "normal" C# 项目中使用过的(即不是 Unity),但它应该 与 Unity 一起使用,而且它很容易获得设置:https://github.com/MassTransit/Automatonymous。另外,查看文档中的 "sagas" 。虽然不能直接应用,但它们将为您提供编排多个状态机的一些指导。
只是一点点 answer.Hope 这将对您有所帮助。据我所知,您需要一个抽象的解决方案,而不是在每个语句中使用 if else 。制作对象图,例如 (https://i.stack.imgur.com/nVpih.jpg) ,制作路径并设置像 isInRoomVariable =true 和你的对象,它会告诉你你来自哪里,甚至功能 当你在左边的房间或右边的房间时你能做什么
从游戏开发的角度来看,我想轻松地操纵变量/条件要求,例如任务或关卡等
我建议收集由可编写脚本的对象组成的需求。您可以将它们存储在可以从检查器中轻松操作的对象中。
您可以创建一个名为 "Kick the bucket" 的决定。
[CreateAssetMenuAttribute(menuName = "Decision")]
public Decision : ScriptableObject
{
public string Name;
public DecisionState State; // Use an Enum with states "Inactive" "Completed", "Failed", "Unavailable" etc.
// Other variables that may be relevant, like score or whatever
}
您可以在游戏开始时将状态设置为默认状态。然后,当您 select 结束时,将其标记为您想要的任何状态。
然后您可以提出要求,接受决定和期望的状态。
[CreateAssetMenuAttribute(menuName = "Requirement")]
public Requirement : ScriptableObject
{
public Decision Decision;
public DecisionState State;
}
现在,在您的房间、章节或任何脚本中,您可以附上执行您想要的任何逻辑所需的要求列表。您可以 运行 CheckRequirements 方法来查看是否满足所有要求。
public Room : MonoBehaviour
{
public List<Requirement> Requirements;
public bool CheckRequirements()
{
foreach (var requirement in Requirements)
{
if (requirement.Decision.State != requirement.State)
{
return false;
}
}
return true;
}
}
我喜欢这种方法的原因是您可以轻松创建新的决定和要求,然后将它们拖放到检查器槽中。因此,当您的游戏流程发生变化时,您可以简单地添加或删除一个决定/要求。
编辑:
有一些时间,做了一些思考...
为了使其设计更加友好,您还可以集成在进入房间并为您设置某些决定时触发的 UnityEvents。
public Room : MonoBehaviour
{
UnityEvent OnRoomEnter;
public void OnEnable() // Or whatever function you call when instantiating a room
{
OnRoomEnter();
}
}
然后考虑以下
public GameManager : MonoBehaviour
{
public void SetDecisionToActive(Decision decision)
{
decision.State = DecisionState.Active;
}
public void SetDecisionToInactive(Decision decision)
{
decision.State = DecisionState.Inactive;
}
// etc...
}
您现在可以将您的游戏管理器拖放到 Unity 中 'room' 单一行为对象的事件槽中,select 一个方法,然后将您创建的一个决策拖放到它的参数槽中。