第十一章 地图动作与地图事件(Map Action and Map Event)
我们已经有了剧本,而且可以运行剧本,但我们还缺少对地图的操作控制。
我们这一章来完成地图上的操作,地图的操作将全部由MapAction
控制。
文章目录
十一 摄像机(Camera)
这一章,我们来处理摄像机的跟随移动,并测试整章。
1 添加Cinemachine(Add “Cinemachine” Plugin)
在游戏中,我们的摄像机在以下情况需要移动:
-
观察地图(光标移到地图边缘);
-
角色移动到地图边缘;
-
其它情况(某些特殊技能或攻击方式等)。
这并不需要我们自己来写跟随方法,Unity官方提供的Cinemachine已经解决了它们。
我们只需要在Asset Store中搜索Cinemachine并添加到项目中,然后进行相应的设置即可。
在我们的项目中,我们只需要在地图场景中让摄像机跟随鼠标光标(MouseCursor)。
而在需要移动摄像机时,只需要让鼠标光标移动即可。
同时Cinemachine配合Timeline
也可以进行复杂的过场动画处理,这暂时不在我们的讨论范围。
在MapAction
中加入它们:
using Cinemachine;
在MapAction
中添加摄像机字段:
private CinemachineVirtualCamera m_VirtualCamera = null;
而在初始化方法中,寻找场景中的摄像机,并设置它:
/// <summary>
/// 读取地图
/// </summary>
/// <param name="scriptName"></param>
/// <returns></returns>
public bool Load(string scriptName)
{
// 省略部分代码
// 寻找摄像机
virtualCamera = GameObject.FindObjectOfType<CinemachineVirtualCamera>();
if (virtualCamera == null)
{
error = "MapAction -> CinemachineVirtualCamera was not found.";
return false;
}
// 设置摄像机跟随MouseCurosr
virtualCamera.Follow = map.mouseCursor.transform;
// 设置状态
status = ActionStatus.WaitInput;
return true;
}
2 移动摄像机(Move Camera)
移动摄像机就相当于移动MouseCursor
。
在平时,我们的MouseCursor
在OnMouseMove
中已经跟随了鼠标指针。
而在角色移动时,就停止了。这需要我们自己控制,并且每帧进行操作。
每帧操作的方法Update
中进行移动控制:
/// <summary>
/// 每帧刷新
/// </summary>
/// <returns></returns>
public override bool Update()
{
// 省略 MapScenarioAction 操作
// 摄像机跟随职业
if (selectedUnit != null && (mapStatus == MapStatus.Animation || mapStatus == MapStatus.Event))
{
map.mouseCursor.transform.position = selectedUnit.transform.position;
return true;
}
if (turn != AttitudeTowards.Player)
{
// 省略NPC操作
return true;
}
return false;
}
2.1 玩家(Player)
而在职业移动时,也需要修改:
/// <summary>
/// 移动
/// </summary>
/// <param name="mapClass"></param>
/// <param name="moveTo"></param>
protected void MoveMapClass(MapClass mapClass, CellData moveTo)
{
// 省略部分代码
// 如果是玩家,打开Update,
// 在Update中,光标会跟随角色移动(由于摄像机是跟随光标的)。
if (turn == AttitudeTowards.Player)
{
GameDirector.instance.RunGameAction();
}
}
在移动后,我们还需要关闭它:
/// <summary>
/// 移动结束回调
/// </summary>
/// <param name="mapClass"></param>
/// <param name="endCell"></param>
private void MapClass_OnMovingEnd(MapClass mapClass, CellData endCell)
{
// 省略部分代码
// 如果是玩家
if (turn == AttitudeTowards.Player)
{
GameDirector.instance.StopGameAction();
mapClass.role.OnMoveEnd(endCell.g); // 减去移动消耗
ShowMapMenu(true);
}
// npc
else
{
// 省略npc代码
}
}
2.2 NPC
我们在每次进行NPC控制时,应该先将摄像机移动到NPC身上。
/// <summary>
/// 每帧刷新
/// </summary>
/// <returns></returns>
public override bool Update()
{
// 省略部分代码
if (turn != AttitudeTowards.Player)
{
if (mapStatus == MapStatus.Animation
|| mapStatus == MapStatus.Event
|| mapStatus == MapStatus.Menu || mapStatus == MapStatus.SubMenu)
{
return true;
}
// 获取npc
List<MapClass> units;
if (!m_UnitDict.TryGetValue(turn, out units) || npcIndex >= units.Count)
{
NextTurn();
return true;
}
MapClass unit = units[npcIndex];
// 如果摄像机不在npc上,则移动摄像机
if (map.mouseCursor.cellPosition != unit.cellPosition)
{
MoveCursorCommand(unit.cellPosition, 0.5f);
return true;
}
// npc移动
if (mapStatus != MapStatus.AttackCursor)
{
NpcMove(unit);
}
// npc攻击
else
{
NpcAttack(unit);
}
return true;
}
return false;
}
3 Cinemachine的设置(Cinemachine Setting)
Cinemachine的摄像机(CinemachineVirtualCamera
)是要在关卡场景中添加的,
这相当于我们的每个存在地图的场景都应存在:
-
一个主摄像机(
Main Camera
) -
一个Cinemachine摄像机(
CinemachineVirtualCamera
) -
一个地图(
MapGraph
)
在这里,我们直接建立两个新的场景:
-
过场场景
InterludeScene
,过场动画,对话等等; -
游戏序章关卡场景
Stage0Scene
,战斗地图。
创建好场景后,进入Stage0Scene
中:
-
其一,点击菜单
Cinemachine/Create 2D Camera
,会自动建立CinemachineVirtualCamera
,如 图 11.4 所示。- 图 11.4 CinemachineVirtualCamera
-
其二,从预制体中,拖入
MapGraph
,此时场景中物体如 图 11.5 所示。- 图 11.5 Hierarchy
-
其三,我们的
2D Camera
是依赖于Collider2D
的,它的范围将不能超过Collider2D
的范围。-
首先,为"TilemapBackground"与"Terrain"添加
TilemapCollider2D
组件,并设置Used By Composite
为true
,如 图 11.6 所示;- 图 11.6 TilemapCollider2D
-
其次,为"MapGraph"添加
Rigidbody2D
与CompositeCollider2D
组件,并设置Body Type
为Static
,Geometry Type
为Polygons
如图 11.7 所示;- 图 11.7 CompositeCollider2D
-
最后,不要忘记保存预制体,这样就限定了摄像机的移动范围。
-
-
其四,点击
CinemachineVirtualCamera
的物体"CM vcam1"。-
首先,设置
Body
为Framing Transposer
,如 图 11.8 所示;- 图 11.8 CinemachineVirtualCamera Component
-
其次,点击
Add Extension
,选择CinemachinCollider
,会自动添加CinemachineConfiner
组件,如 图 11.9 所示;- 图 11.9 Add Extension “CinemachineConfiner”
-
最后,在
CinemachineConfiner
组件中,设置Bounding shape 2D
为"MapGraph",如 图 11.10 所示。- 图 11.10 CinemachineConfiner
-
-
其五,创建一个空的
GameObject
,将CinemachineVirtualCamera
的Follow
设置成他; -
其六,在Game面板中,设置摄像机的范围,它将改变第四部中
Framing Transposer
的参数,如 图 11.11 所示。- 图 11.11 Game
其中摄像机存在三个区域,被两条方框区分:
-
外层线:对应软区域;
-
内层线:如果
MouseCurosr
超过了它,摄像机将开始移动。
具体摄像机将如何移动,请多做尝试。
除以上在Game面板中调整外,比较重要的参数为:
-
X Damping:x轴,摄像机阻尼(即,摄像机移动时的摩擦力,让摄像机做减速运动更平滑的移动)
-
Y Damping:y轴,摄像机阻尼。
-
其七,删除第五步中创建的
GameObject
。 -
其八,保存场景。
这个场景可以作为模板场景,以后再创建关卡时,只需要复制这个场景并改名字即可。不用再次调整参数,只需修改地图的Tile。
这样,我们的摄像机就设置好了,同时也有了关卡场景。我们可以开始进行整章的整合测试了。