美文网首页Unity游戏开发学习记录
Unity练习2 - 《John Lemon's Haunted

Unity练习2 - 《John Lemon's Haunted

作者: 我阿郑 | 来源:发表于2023-12-25 13:19 被阅读0次

    在本教程中,您将:

    • 创建一个静态的石像鬼 (Gargoyle) 敌人
    • 编写自定义脚本,使石像鬼可以找到 JohnLemon
    • 将游戏设置为在抓到 JohnLemon 时重新开始

    ✅ 创建石像鬼 (Gargoyle) 预制体

    现在您的游戏正在成形:JohnLemon 可以在环境中移动,摄像机跟随着他,当他离开鬼屋时,游戏结束。不过,这里还缺少用于增加游戏难度的敌人!

    image.png

    ✅ 给Gargoyle添加动画

    石像鬼只一段可以播放的动画,因此其 Animation Controller 将非常简单。

    新的 Animation Controller 命名为“Gargoyle”:

    image.png

    双击 Gargoyle 以打开 Animator 窗口。

    展开 Gargoyle@Idle 模型资源,拖入 Idle 动画

    image.png

    石像鬼 (Gargoyle) 的 Animation Controller 已完成,拖到 Animator 组件的Controller上:


    image.png

    保存场景,运行看看效果。

    ✅ 石像鬼添加碰撞体

    添加Capsule Collider。

    • 将 Capsule Collider 的 Center 属性设置为 (0, 0.9, 0)
    • 将 Radius 属性更改为 0.3
    • 将 Height 属性更改为 1.8
    image.png

    ✅ 创建触发器以模拟石像鬼的视线

    编写一个自定义脚本,以确保石像鬼无法透过墙壁看到玩家,但是首先需要创建一个触发器。

    为了方便定位,Create Empty 游戏对象,命名为“PointOfView” 。作为 Gargoyle 的子项,并将触发器置于其上
    此游戏对象将充当石像鬼 (Gargoyle) 对于世界的视角。

    image.png

    石像鬼的动画显示其视线是朝正前方并略微向下,调整 PointOfView 的 Transform :

    • 将 Position 改为 (0, 1.4, 0.4)
    • 将 Rotation 改为 (20, 0, 0)
    image.png

    注意:如果 Scene 窗口中的 Transform 控制柄不是稍微向下,则可能是因为它们设置为 Global 而不是 Local。

    现在,已经设置了石像鬼的视角对象 PointOfView,接下来给PointOfView 添加和配置触发器。

    添加一个 Capsule Collider ,启用 Is Trigger。

    • 将 Capsule Collider 的 Center 属性设置为 (0, 0, 0.95)
    • 将 Radius 属性更改为 0.7
    • 将 Height 属性更改为 2
    • 将 Direction 属性从 Y-Axis 更改为 Z-Axis
    image.png

    ➡️ 编写一个脚本来处理 JohnLemon 进入触发器时发生的情况。

    创建脚本Observer挂载到PointOfView 游戏对象上。

    该脚本将检查玩家角色的 Transform,而不是其游戏对象。这样可以更轻松地了解 JohnLemon 的位置并确定是否可以清楚看到他。

    public class Observer : MonoBehaviour
    {
        public GameEnding gameEnding;
        public Transform player; // 玩家
        bool m_IsPlayerInRange;
    
        void OnTriggerEnter(Collider other)
        {
            if (other.transform == player)
            {
                m_IsPlayerInRange = true;
            }
        }
    
        // 进入此触发器的玩家角色可能并不自动表示游戏结束,
        // 例如,路径中可能有墙壁阻挡,保护了玩家。这意味着检测 JohnLemon 何时离开触发器也很重要。
        void OnTriggerExit(Collider other)
        {
            if (other.transform == player)
            {
                m_IsPlayerInRange = false;
            }
        }
    }
    

    ✅ 检查敌人的视线是否清晰

    在此游戏中,检查敌人对于 JohnLemon 的视线是否清晰很重要。否则,当实际上在路径中遇到的是墙壁时,也可能会触发游戏结束。由于玩家角色的位置随时可能发生变化,因此该检查需要在每一帧中进行。

    仅当玩家角色实际在范围内时检查视线才有意义。但是如何实际检查视线呢?射线检测

    射线需要一个原点和一个方向。原点就是 PointOfView 游戏对象的位置,但是确定方向要稍微复杂一些。

    void Update ()
        {
            if (m_IsPlayerInRange)
            {
                Vector3 direction = player.position - transform.position + Vector3.up;
                Ray ray = new Ray(transform.position, direction);
                RaycastHit raycastHit;
    
                if(Physics.Raycast(ray, out raycastHit))
                {
                    if (raycastHit.collider.transform == player)
                    {
                        
                    }
                }
            }
        }
    

    ✅ 修改 GameEnding 脚本

    此游戏需要两种不同的方式来结束关卡:一种是 JohnLemon 逃脱,另一种是他被抓住

    被敌人抓住的玩家能够重新开始该关卡,而不是退出游戏。

    创建两种结束关卡的方式:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class GameEnding : MonoBehaviour
    {
    
        public float fadeDuration = 1f;  // 淡入淡出的默认值为1秒
        public float displayImageDuration = 1f;
    
        public GameObject player; // 玩家
        public CanvasGroup exitBackgroundImageCanvasGroup;
        // 此代码将为新图像创建另一个 CanvasGroup,如果抓住 JohnLemon,将显示这些图像。
        public CanvasGroup caughtBackgroundImageCanvasGroup;
    
        bool m_IsPlayerAtExit;
        bool m_IsPlayerCaught; // 玩家是否被抓
        float m_Timer; // 需要一个计时器来确保游戏在淡入淡出之前不会结束
    
    
        void OnTriggerEnter(Collider other)
        {// 监听触发器callback
            if (other.gameObject == player)
            {
                m_IsPlayerAtExit = true; // 发生触发
            }
        }
    
        public void CaughtPlayer()
        {
            m_IsPlayerCaught = true;
        }
    
        void Update()
        {
            if (m_IsPlayerAtExit)
            {
                EndLevel(exitBackgroundImageCanvasGroup,false);
            }
            else if (m_IsPlayerCaught)
            {
                EndLevel(caughtBackgroundImageCanvasGroup,true);
            }
        }
    
        void EndLevel(CanvasGroup imageCanvasGroup, bool doRestart)
        {
            m_Timer += Time.deltaTime;
    
            imageCanvasGroup.alpha = m_Timer / fadeDuration;
    
            if (m_Timer > fadeDuration + displayImageDuration)
            {
                if (doRestart)
                {
                    // 只有一个场景,因此索引为 0。
                    SceneManager.LoadScene(0);
                }
                else
                {
                    Application.Quit();
                }
            }
        }
    
        //void EndLevel()
        //{
        //    //获取从上一帧以来经过的时间的方式:使用 Time.deltaTime
        //    m_Timer += Time.deltaTime;
        //    // 设置 Canvas Group 的 Alpha
        //    exitBackgroundImageCanvasGroup.alpha = m_Timer / fadeDuration;
        //    if (m_Timer > fadeDuration + displayImageDuration)
        //    {
        //        // 当计时器值大于持续时间时,淡入淡出将结束
        //        // 该方法确实可以退出游戏,但仅适用于完全构建的应用程序
        //        // 目前在Unity Editor中没有效果
        //        Application.Quit();
    
        //    }
    
        //}
    }
    

    ✅ 完善您的石像鬼 (Gargoyle) 预制件

    您的 Observer 脚本已经可以:

    • 识别玩家角色进入触发器
    • 使用射线投射 (Raycast) 并知道它是否击中碰撞体
    • 识别该碰撞体是否为玩家角色
    image.png

    您可以稍后添加更多的石像鬼 (Gargoyle) 预制件实例,但让我们将当前已有的这个实例放在起始房间中的一角

    • 将其 Position 属性更改为 (-15.2, 0, 0.8)
    • 将其 Rotation 属性更改为 (0, 135, 0)

    接着,设置 Observer 脚本所需的两个引用:


    image.png

    接下来,您需要创建 UI 来处理由于已经抓到玩家而结束关卡的情况。在 Hierarchy 窗口展开 FaderCanvas 游戏对象。

    image.png

    选中 ExitImageBackground 游戏对象,Ctrl + D (Windows) 或 CMD + D (macOS)复制一份,新的副本重命名为 CaughtImageBackground,展开其子项,将 ExitImage 游戏对象重命名为 CaughtImage,将Source修改为 Caught精灵。

    image.png

    选择 GameEnding 游戏对象,将 CaughtImageBackground 游戏对象拖到 Game Ending 的 Caught Background Image Canvas Group 字段上:

    image.png

    保存场景。

    相关文章

      网友评论

        本文标题:Unity练习2 - 《John Lemon's Haunted

        本文链接:https://www.haomeiwen.com/subject/ugtxndtx.html