第十一章 地图动作与地图事件(Map Action and Map Event)
我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制。
我们这一章来完成地图上的操作,地图的操作将全部由MapAction
控制。
文章目录
二 地图剧情(Map Plot)
地图中的剧情和普通的剧情在操作上区别不大。
区别:
-
命令执行器不同;
-
返回上一层不同。
1 返回上一个行动(Back Game Action)
在GameDirector
中,我们缺少了返回上一个动作的方法。
-
它在剧本中是返回上一个剧本动作;
-
而在触发地图剧情结束后,我们同样需要返回上一层的
MapAction
,且我们的MapScenarioAction
并不是由GameDirector
控制,而是由MapAction
控制的。
基于以上,先在GameDirector
中创建返回上一层的方法:
/// <summary>
/// 返回上一个action
/// </summary>
public void BackGameAction()
{
IGameAction old = currentAction;
currentAction = currentAction.previous;
old.Dispose();
if (currentAction == null)
{
// TODO 返回游戏的开始场景
}
}
在ActionStatus
中,我们添加两个状态:
namespace DR.Book.SRPG_Dev.ScriptManagement
{
public enum ActionStatus : int
{
// 省略其它
/// <summary>
/// 返回上一个Action
/// </summary>
BackAction,
/// <summary>
/// 在地图中等待剧情
/// </summary>
WaitScenarioDone
}
}
MapAction
不同于ScenarioAction
。实际上在MapAction
中,ActionStatus
只使用了WaitScenarioDone
、WaitInput
与Error
。而其它方面全部由MapStatus
控制。
在ScenarioAction
中,我们为新的状态添加控制,让它可以返回上一层:
/// <summary>
/// 每帧运行
/// </summary>
/// <returns></returns>
public override bool Update()
{
if (status == ActionStatus.Continue)
{
// 执行每一条命令,直到状态不为Continue
do
{
status = Step();
} while (status == ActionStatus.Continue);
}
// 如果出错了,就中断
if (status == ActionStatus.Error)
{
Abort();
return false;
}
// 等待下一帧
else if (status == ActionStatus.NextFrame)
{
status = ActionStatus.Continue;
}
// 返回上一个Action
else if (status == ActionStatus.BackAction)
{
BackAction();
status = ActionStatus.NextFrame;
}
return true;
}
protected virtual void BackAction()
{
GameDirector.instance.BackGameAction();
}
而在新的MapScenarioAction
中,我们来重写它:
namespace DR.Book.SRPG_Dev.ScriptManagement
{
public class MapScenarioAction : ScenarioAction
{
public MapScenarioAction(MapAction previous) : base(previous)
{
}
protected override void BackAction()
{
MapAction action = previous as MapAction;
action.ScenarioDone();
}
}
}
ScenarioDone
是表示地图剧本运行结束,在MapAction
完成ScenarioDone()
:
/// <summary>
/// 剧本运行结束
/// </summary>
public void ScenarioDone()
{
if (status == ActionStatus.WaitScenarioDone)
{
status = ActionStatus.WaitInput;
GameDirector.instance.StopGameAction();
}
}
2 运行地图剧本(Run Map Scenario)
在上一节,我们可以结束剧情了,先还缺少开始剧情。
在地图中,某些事件会触发剧情,这需要跳转到我们需要的剧情,而这就用到了剧情标识符。
/// <summary>
/// 开始地图剧情
/// </summary>
/// <param name="flag"></param>
/// <returns></returns>
public bool ScenarioCommand(string flag)
{
if (scenarioAction == null)
{
error = "MapAction -> No scenario.";
return false;
}
ActionStatus s = scenarioAction.GotoCommand(flag, out m_Error);
if (s == ActionStatus.Error)
{
status = ActionStatus.Error;
return false;
}
status = ActionStatus.WaitScenarioDone;
GameDirector.instance.RunGameAction();
return true;
}
3 地图剧情的输入(Map Scenario Input)
由于我们的地图剧情由MapAction
控制,所以我们的输入操作都应被它代理。
建立方法(以左键为例):
/// <summary>
/// 左键
/// </summary>
/// <param name="mousePosition"></param>
public override void OnMouseLButtonDown(Vector3 mousePosition)
{
if (status == ActionStatus.WaitScenarioDone)
{
scenarioAction.OnMouseLButtonDown(mousePosition);
return;
}
// TODO
}
如“左键例子”所示,在执行剧情时,所有在地图中用到的输入,都应被剧本拦截。
在输入方法最开始的地方,都应添加如下格式:
if (status == ActionStatus.WaitScenarioDone)
{
scenarioAction.输入操作(mousePosition);
return;
}
4 每帧执行(Update)
同样的,在每帧执行方法Update()
中,我们也应被剧情拦截:
/// <summary>
/// 每帧刷新
/// </summary>
/// <returns></returns>
public override bool Update()
{
// 如果是剧本,就运行剧本
if (status == ActionStatus.WaitScenarioDone)
{
if(!scenarioAction.Update())
{
if (scenarioAction.status == ActionStatus.Error)
{
status = ActionStatus.Error;
error = scenarioAction.error;
Abort();
}
return false;
}
return true;
}
// TODO
}