SRPG游戏开发(六十二)第十一章 地图动作与地图事件 - 十一 摄像机(Camera)

版权声明:本文为博主原创文章,未经允许不得转载。 https://blog.csdn.net/darkrabbit/article/details/88121839

返回《SRPG游戏开发》导航

第十一章 地图动作与地图事件(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

在平时,我们的MouseCursorOnMouseMove中已经跟随了鼠标指针。

而在角色移动时,就停止了。这需要我们自己控制,并且每帧进行操作。

每帧操作的方法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 所示。

    CinemachineVirtualCamera

    • 图 11.4 CinemachineVirtualCamera
  • 其二,从预制体中,拖入MapGraph,此时场景中物体如 图 11.5 所示。

    Hierarchy

    • 图 11.5 Hierarchy
  • 其三,我们的2D Camera是依赖于Collider2D的,它的范围将不能超过Collider2D的范围。

    • 首先,为"TilemapBackground"与"Terrain"添加TilemapCollider2D组件,并设置Used By Compositetrue,如 图 11.6 所示;

      TilemapCollider2D

      • 图 11.6 TilemapCollider2D
    • 其次,为"MapGraph"添加Rigidbody2DCompositeCollider2D组件,并设置Body TypeStaticGeometry TypePolygons 如图 11.7 所示;

      CompositeCollider2D

      • 图 11.7 CompositeCollider2D
    • 最后,不要忘记保存预制体,这样就限定了摄像机的移动范围。

  • 其四,点击CinemachineVirtualCamera的物体"CM vcam1"。

    • 首先,设置BodyFraming Transposer,如 图 11.8 所示;

      CinemachineVirtualCamera Component

      • 图 11.8 CinemachineVirtualCamera Component
    • 其次,点击Add Extension,选择CinemachinCollider,会自动添加CinemachineConfiner组件,如 图 11.9 所示;

      Add_CinemachineConfiner

      • 图 11.9 Add Extension “CinemachineConfiner”
    • 最后,在CinemachineConfiner组件中,设置Bounding shape 2D为"MapGraph",如 图 11.10 所示。

      CinemachineConfiner

      • 图 11.10 CinemachineConfiner
  • 其五,创建一个空的GameObject,将CinemachineVirtualCameraFollow设置成他;

  • 其六,在Game面板中,设置摄像机的范围,它将改变第四部中Framing Transposer的参数,如 图 11.11 所示。

    Game

    • 图 11.11 Game

    其中摄像机存在三个区域,被两条方框区分:

    • 外层线:对应软区域;

    • 内层线:如果MouseCurosr超过了它,摄像机将开始移动。

    具体摄像机将如何移动,请多做尝试。

    除以上在Game面板中调整外,比较重要的参数为:

    • X Damping:x轴,摄像机阻尼(即,摄像机移动时的摩擦力,让摄像机做减速运动更平滑的移动)

    • Y Damping:y轴,摄像机阻尼。

  • 其七,删除第五步中创建的GameObject

  • 其八,保存场景。

这个场景可以作为模板场景,以后再创建关卡时,只需要复制这个场景并改名字即可。不用再次调整参数,只需修改地图的Tile。


这样,我们的摄像机就设置好了,同时也有了关卡场景。我们可以开始进行整章的整合测试了。


猜你喜欢

转载自blog.csdn.net/darkrabbit/article/details/88121839