密室逃脱——收集版修改测试

一、原版修改
1、导入资源

Unity Learn | 3D Beginner: Complete Project | URP

2、设置Scene

删除SampleScene,打开UnityTechnologies-3DBeginnerComplete下的MainScene

3、降低音量

(1) 打开Hierarchy面板上的Audio降低音量

(2) 打开Prefabs文件夹,找到Ghost,降低音量

4、给FaderCanvas添加组件

(1) Canvas Scaler

(2) Graphic Raycaster

二、编辑答题面板

(1) UI-Image,命名为Questions。

(2) 选中导入的图片,然后在Inspector面板中将Texture Type设置为Sprite (2D and UI)

(3) 更改Questions的Image,Transform

(4) 添加按钮,QuitBtn(以隐藏答题面板)

(5) 添OptionBtnA(ABCD)

(6) 新增文本:TipAnswerText、TitleText

三、建立和调用题库
1、创建Question.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Question
{
    public string titleIndex, questiont, correctOptionIndex; // 题号,问题文本, 正确答案的索引(1表示A,2表示B,依此类推)
    public string optionA, optionB, optionC, optionD;// 选项

     // 构造函数(可选),用于初始化问题
    public Questions(string titleInx, string q, string optsA, string optsB, string optsC, string optsD, string correctIndex)
    {
        titleIndex = titleInx;
        questiont = q;
        optionA = optsA;
        optionB = optsB;
        optionC = optsC;
        optionD = optsD;
        correctOptionIndex = correctIndex;
    }
    // 检查答案是否正确
    public bool CheckAnswer(string playerChoice)
    {
        return playerChoice == correctOptionIndex;
    }
}

或——建议这个

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class Question
{
    public string questionTitle, questionTitleIndex; // 问题文本、题号
    public string[] options = new string[4]; // 选项数组,假设每个问题都有4个选项
    public int correctOptionIndex; // 正确答案的索引(1表示A,2表示B,依此类推)

    // 构造函数(可选),用于初始化问题
    public Question(string questionID, string questionText, string[] options, int correctOptionIndex)
    {
        this.questionTitleIndex = questionID;
        this.questionTitle = questionText;
        this.options = options;
        this.correctOptionIndex = correctOptionIndex;
    }
}
2、加载题库并随机显示
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using TMPro;
using UnityEngine;

public class LoadQuestions : MonoBehaviour
{
    //存放问题的容器
    public TextMeshProUGUI titleText, optionTextA, optionTextB, optionTextC, optionTextD;
    private void Start()
    {
        LoadQuestionsFromFile("YW");
    }

    public void LoadQuestionsFromFile(string filePath)
    {
        //加载位于Resources文件夹中的YW文件
        TextAsset textFile = Resources.Load<TextAsset>("YW");

        //若文件加载成功
        if (textFile != null)
        {
            Debug.Log("YW文件加载成功");
            //将textFile中储存的文本按行拆分成一个字符串数组,每个数组元素都表示一行文本("\n":换行符)
            //string[] lines = textFile.text.Split("new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None");
            //不同系统或编辑器可能使用的不同换行符格式
            string[] lines = textFile.text.Split("\n");

            // 获取一个随机的索引
            int randomIndex = UnityEngine.Random.Range(0, lines.Length);

            //从lines中获取一个随机元素,将之赋值给line
            string line = lines[randomIndex];

            //解析line中的字段
            string[] fields = line.Split(":");

            // 创建问题对象
            Questions question = new(fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6]);

            titleText.text = question.questiont;
            optionTextA.text = question.optionA;
            optionTextB.text = question.optionB;
            optionTextC.text = question.optionC;
            optionTextD.text = question.optionD;
        }
        else { Debug.Log("YW文件加载失败"); }
    }
}

或 ——建议下面这个(需要在Unity编辑器中设置选项按钮的On Click

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LoadQuestions : MonoBehaviour
{
    public Text titleText;
    public Button[] optionButtons;

    private string[] lines; // 保存所有问题的数组
    private List<Question> questions = new List<Question>(); // 问题列表
    private Question currentQuestion;

    private void Start()
    {
        LoadQuestionsFromFile();
        UpdateQuestionUI();
    }
    //加载题库
    public void LoadQuestionsFromFile()
    {
        TextAsset textFile = Resources.Load<TextAsset>("test_01");
        if (textFile != null)
        {
            lines = textFile.text.Split("\n");
            for (int i = 0; i < lines.Length; i++)
            {
                string[] fields = lines[i].Split(":");
                if (fields.Length >= 7)
                {
                    string questionID = fields[0];
                    string questionTitle = fields[1];
                    string[] options = new string[] { fields[2], fields[3], fields[4], fields[5] };
                    //int correctOptionIndex = int.Parse(fields[6]); // 将正确答案的索引作为整数类型存储

                    int correctOptionIndex;
                    if (int.TryParse(fields[6], out correctOptionIndex)) // 使用 TryParse 避免异常
                    {
                        questions.Add(new Question(questionID, questionTitle, options, correctOptionIndex));
                    }
                    else
                    {
                        Debug.LogError("文件格式错误:第 " + (i + 1) + " 行中的正确答案索引不是有效的整数");
                    }
                }
                else
                {
                    Debug.LogError("文件格式错误:第 " + (Array.IndexOf(lines, lines) + 1) + " 行没有足够的字段");
                }
            }
        }
    }
    //随机显示
    public void UpdateQuestionUI()
    {
        int randomIndex = UnityEngine.Random.Range(0, questions.Count - 1);
        currentQuestion = questions[randomIndex];

        string question = currentQuestion.questionTitle;
        string[] options = currentQuestion.options; // 获取选项数组
        int correctIndex = currentQuestion.correctOptionIndex; // 获取正确选项的索引

        titleText.text = question;
        for (int i = 0; i < optionButtons.Length; i++)
        {
            optionButtons[i].onClick.RemoveAllListeners();

            int index = i; // 创建局部变量保存索引值

            optionButtons[i].GetComponentInChildren<Text>().text = options[i];
        }
    }
}
3、判断正误
    public void CheckAnswer(int optionIndex)
    {
        if (optionIndex == currentQuestion.correctOptionIndex)
        {
            Debug.Log("回答正确!" + optionIndex + currentQuestion.correctOptionIndex);
        }
        else
        {
            Debug.Log("回答错误!" + optionIndex + currentQuestion.correctOptionIndex);
        }
    }
4、禁用按钮
public void UpdateQuestionUI()
{
    int randomIndex = UnityEngine.Random.Range(0, questions.Count - 1);
    currentQuestion = questions[randomIndex];

    string question = currentQuestion.questionTitle;
    string[] options = currentQuestion.options; // 获取选项数组
    int correctIndex = currentQuestion.correctOptionIndex; // 获取正确选项的索引

    titleText.text = question;
    for (int i = 0; i < optionButtons.Length; i++)
    {
        optionButtons[i].onClick.RemoveAllListeners();

        int index = i; // 创建局部变量保存索引值

        optionButtons[i].GetComponentInChildren<Text>().text = options[i];

        optionButtons[i].interactable = true; // 启用按钮
    }
}
 
public void CheckAnswer(int optionIndex)
{
    for (int i = 0; i < optionButtons.Length; i++)
    {
        optionButtons[i].interactable = false; // 禁用按钮
    }

    if (optionIndex == currentQuestion.correctOptionIndex)
    {
        Debug.Log("回答正确!" + optionIndex + currentQuestion.correctOptionIndex);
    }
    else
    {
        Debug.Log("回答错误!" + optionIndex + currentQuestion.correctOptionIndex);
    }
}
 
5、记录答过的题目,并从题库中清除
public void LoadQuestionsFromFile()
{
    TextAsset textFile = Resources.Load<TextAsset>("test_01");
    if (textFile != null)
    {
        //确保跨平台兼容性拆分文本
        string[] lines = textFile.text.Split(new string[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries);
        for (int i = 0; i < lines.Length; i++)
        {
            string[] fields = lines[i].Split(':');

            if (questions.Count > 0)
            {
                usedQuestions.Clear();
            }

            if (fields.Length >= 7)
            {
                string questionID = fields[0];
                string questionTitle = fields[1];
                string[] options = new string[] { fields[2], fields[3], fields[4], fields[5] };

                int correctOptionIndex;
                if (int.TryParse(fields[6], out correctOptionIndex))
                {
                    questions.Add(new Question(questionID, questionTitle, options, correctOptionIndex));
                }
                else
                {
                    Debug.LogErrorFormat("文件格式错误:第 {0} 行中的正确答案索引不是有效的整数", i + 1);
                }
            }
            else
            {
                Debug.LogErrorFormat("文件格式错误:第 {0} 行没有足够的字段", i + 1);
            }
        }
    }
    else
    {
        Debug.LogError("找不到文本文件 test_01");
    }
}
 

 完整脚本

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class LoadQuestions : MonoBehaviour
{
    public Text titleText;
    public Button[] optionButtons;

    private string[] lines; // 保存所有问题的数组
    private List<Question> questions = new List<Question>(); // 问题列表
    private Question currentQuestion;

    private void Start()
    {
        LoadQuestionsFromFile();
        UpdateQuestionUI();
    }

    public void LoadQuestionsFromFile()
    {
        TextAsset textFile = Resources.Load<TextAsset>("test_01");
        if (textFile != null)
        {
            lines = textFile.text.Split("\n");
            for (int i = 0; i < lines.Length; i++)
            {
                string[] fields = lines[i].Split(":");
                if (fields.Length >= 7)
                {
                    string questionID = fields[0];
                    string questionTitle = fields[1];
                    string[] options = new string[] { fields[2], fields[3], fields[4], fields[5] };
                    //int correctOptionIndex = int.Parse(fields[6]); // 将正确答案的索引作为整数类型存储

                    int correctOptionIndex;
                    if (int.TryParse(fields[6], out correctOptionIndex)) // 使用 TryParse 避免异常
                    {
                        questions.Add(new Question(questionID, questionTitle, options, correctOptionIndex));
                    }
                    else
                    {
                        Debug.LogError("文件格式错误:第 " + (i + 1) + " 行中的正确答案索引不是有效的整数");
                    }
                }
                else
                {
                    Debug.LogError("文件格式错误:第 " + (Array.IndexOf(lines, lines) + 1) + " 行没有足够的字段");
                }
            }
        }
    }

    public void UpdateQuestionUI()
    {
        int randomIndex = UnityEngine.Random.Range(0, questions.Count - 1);
        currentQuestion = questions[randomIndex];

        string question = currentQuestion.questionTitle;
        string[] options = currentQuestion.options; // 获取选项数组
        int correctIndex = currentQuestion.correctOptionIndex; // 获取正确选项的索引

        titleText.text = question;
        for (int i = 0; i < optionButtons.Length; i++)
        {
            optionButtons[i].onClick.RemoveAllListeners();

            int index = i; // 创建局部变量保存索引值

            optionButtons[i].GetComponentInChildren<Text>().text = options[i];
            optionButtons[i].interactable = true; // 启用按钮
        }
    }

    public void CheckAnswer(int optionIndex)
    {
        for (int i = 0; i < optionButtons.Length; i++)
        {
            optionButtons[i].interactable = false; // 禁用按钮
        }
        if (optionIndex == currentQuestion.correctOptionIndex)
        {
            Debug.Log("回答正确!" + optionIndex + currentQuestion.correctOptionIndex);
        }
        else
        {
            Debug.Log("回答错误!" + optionIndex + currentQuestion.correctOptionIndex);
        }
    }
}
四、收集事件
1、新增文本

(1) 新增文本:ItemsText, TipText(可设置有透明度的黑色背景)

(2) 给JohnLemon添加标签Player

2、更改Enemies下的子物体

(1) 复制PointOfView预制体,重命名为ExitEventTriggers

(2) 删除Ghost (3)的PointOfView子物体,在该位置添加ExitEventTriggers子物体

(3) 编辑PointOfView预制体,删除Observer.cs组件,添加CollectedItems.cs组件

3、新建CollectedItems.cs

(1) 设置隐藏答题面板按钮,同时调用新题目

public GameObject questionsPanel;
public Button quitBtn;
public LoadQuestions LoadQuestions;

void Start()
{
    questionsPanel.SetActive(false);
}

public void HideQuestionPanel()
{
    if (questionsPanel != null)
    {
        questionsPanel.SetActive(false); // 隐藏物体
        LoadQuestions.UpdateQuestionUI();
    }
}

(2) 增加显示背包物品

public Text itemsText;
static int nucleus = 0, mitochondria = 0, GolgiApparatus = 0, endoplasmicReticulum = 0, ribosome = 0;

void Start()
{
    ItemsUpdate();
}

void ItemsUpdate()
{
    itemsText.text = "当前持有:……" + nucleus + ";……" + mitochondria + ";……" + GolgiApparatus + ";……" + endoplasmicReticulum + ";……" + ribosome;
}

(3) 增加冷却事件

bool canTriggerEffect = true;

void RandomEvent()
{
  if (canTriggerEffect)
    {
         //执行接触事件……

         else
         {
            tipText.text = "你什么都没有发现……";
            StartCoroutine(ClearTextRoutine(2f));//2秒后文本消失
         } 
      canTriggerEffect = false;
      StartCoroutine(CooldownRoutine());
    }
}

IEnumerator CooldownRoutine()//接触事件有1分钟的冷却时间
{
    yield return new WaitForSeconds(60f); // 等待1分钟
    canTriggerEffect = true; // 冷却结束,可以再次触发效果
}
IEnumerator ClearTextRoutine(float delay)//提示文本显示后消失
{
    yield return new WaitForSeconds(delay);
    tipText.text = "";
}

(4) 增加收集事件

    void Start()
    {
        if (itemsText == null || tipText == null)
        {
            Debug.LogError("ItemsText 或 TipText 未被正确分配!");
        }
        questionsPanel.SetActive(false);
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            RandomEvent();
        }
    }
    void RandomEvent()
    {
        int numericValue = Random.Range(0, 100);
        if (numericValue < 5 && nucleus == 0)
        {
            nucleus = 1;
            tipText.text = "你发现了nucleus!";
        }
        else if (numericValue < 26)
        {
            mitochondria++;
            tipText.text = "你得到了mitochondria!";
        }
        else if (numericValue < 41)
        {
            endoplasmicReticulum++;
            tipText.text = "你得到了endoplasmicReticulum*1!";
        }
        else if (numericValue < 56)
        {
            GolgiApparatus++;
            tipText.text = "你得到了GolgiApparatus*1!";
        }
        else if (numericValue < 76)
        {
            ribosome++;
            tipText.text = "你得到了ribosome*1!";
        }
        else if (numericValue < 86)
        {
            questionsPanel.SetActive(true);
        }
        else
        {
            tipText.text = "你什么都没有发现……";
        }
        ItemsUpdate();
    }
    void ItemsUpdate()
    {
        itemsText.text = "当前持有:nucleus" + nucleus + ";……" + mitochondria + ";……" + GolgiApparatus + ";……" + endoplasmicReticulum + ";……" + ribosome;
    }
}

本节完整脚本

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class CollectedItems : MonoBehaviour
{
    public Text itemsText;
    public Text tipText;
    static int nucleus = 0, mitochondria = 0, GolgiApparatus = 0, endoplasmicReticulum = 0, ribosome = 0;

    public GameObject questionsPanel;
    public Button quitBtn;
    public LoadQuestions LoadQuestions;

    bool canTriggerEffect = true;
    void Start()
    {
        if (itemsText == null || tipText == null)
        {
            Debug.LogError("ItemsText 或 TipText 未被正确分配!");
        }
        questionsPanel.SetActive(false);
        ItemsUpdate();
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            RandomEvent();
        }
    }
    void RandomEvent()
    {
        if (canTriggerEffect)
        {
            int numericValue = Random.Range(0, 100);
            if (numericValue < 5 && nucleus == 0)
            {
                nucleus = 1;
                tipText.text = "你发现了nucleus!";
                StartCoroutine(ClearTextRoutine(2f));
            }
            else if (numericValue < 26)
            {
                mitochondria++;
                tipText.text = "你得到了mitochondria!";
                StartCoroutine(ClearTextRoutine(2f));
            }
            else if (numericValue < 41)
            {
                endoplasmicReticulum++;
                tipText.text = "你得到了endoplasmicReticulum*1!";
                StartCoroutine(ClearTextRoutine(2f));
            }
            else if (numericValue < 56)
            {
                GolgiApparatus++;
                tipText.text = "你得到了GolgiApparatus*1!";
                StartCoroutine(ClearTextRoutine(2f));
            }
            else if (numericValue < 76)
            {
                ribosome++;
                tipText.text = "你得到了ribosome*1!";
                StartCoroutine(ClearTextRoutine(2f));
            }
            else if (numericValue < 86)
            {
                questionsPanel.SetActive(true);
            }
            else
            {
                tipText.text = "你什么都没有发现……";
                StartCoroutine(ClearTextRoutine(2f));
            }
            ItemsUpdate();
            canTriggerEffect = false;
            StartCoroutine(CooldownRoutine());
        }
    }
    void ItemsUpdate()
    {
        itemsText.text = "当前持有:nucleus" + nucleus + ";mitochondria" + mitochondria + ";GolgiApparatus" + GolgiApparatus + ";endoplasmicReticulum" + endoplasmicReticulum + ";ribosome" + ribosome;
    }
    IEnumerator CooldownRoutine()
    {
        yield return new WaitForSeconds(60f); // 等待1分钟
        canTriggerEffect = true; // 冷却结束,可以再次触发效果
    }
    IEnumerator ClearTextRoutine(float delay)
    {
        yield return new WaitForSeconds(delay);
        tipText.text = "";
    }
    public void HideQuestionPanel()
    {
        if (questionsPanel != null)
        {
            questionsPanel.SetActive(false); // 隐藏物体
            LoadQuestions.UpdateQuestionUI();//调用新题目
        }
    }
}
五、增加生命系统
1、新建PlayerHealth.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerHealth : MonoBehaviour
{
    public int maxHealth = 3;
    private int currentHealth;
    public Text life;
    public GameEnding gameEndings;

    private void Start()
    {
        currentHealth = maxHealth; // 先设置currentHealth的值
        UpdateHealthText();
    }
    public void AddHealth()
    {
        if (currentHealth < maxHealth)
        {
            currentHealth++;
            UpdateHealthText();
        }
    }
    public void RemoveHealth()
    {
        if (currentHealth > 0)
        {
            currentHealth--;
            UpdateHealthText();

            if (currentHealth == 0)
            {
                gameEndings.CaughtPlayer(); // 玩家死亡
            }
        }
    }
    private void UpdateHealthText()
    {
        life.text = "当前生命" + currentHealth.ToString();
    }
}
2、增加文本显示生命值

(1) 增加显示当前生命值文本

(2) 增加减少生命值提醒图片

3、处理加减生命的方法
public class LoadQuestions : MonoBehaviour

public PlayerHealth PlayerHealth;

public void CheckAnswer(int optionIndex)
{
if (optionIndex == currentQuestion.correctOptionIndex)
{
    Debug.Log("回答正确!" + optionIndex + currentQuestion.correctOptionIndex);
    PlayerHealth.AddHealth();
    TipAnswerText.text = "回答正确!生命值+1!退出按Quit";
}
else
{
    Debug.Log("回答错误!" + optionIndex + currentQuestion.correctOptionIndex);
    PlayerHealth.RemoveHealth();
    TipAnswerText.text = "回答错误!生命值-1!\n+退出按Quit";
}
}
六、 更改死亡事件
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameEnding : MonoBehaviour
{
    public float fadeDuration = 1f;
    public float displayImageDuration = 1f;
    public GameObject player;
    public CanvasGroup exitBackgroundImageCanvasGroup;
    public AudioSource exitAudio;
    public CanvasGroup caughtBackgroundImageCanvasGroup;
    public AudioSource caughtAudio;

    bool m_IsPlayerAtExit;
    bool m_IsPlayerCaught;
    float m_Timer;
    bool m_HasAudioPlayed;
    
    void OnTriggerEnter (Collider other)
    {
        if (other.gameObject == player)
        {
            m_IsPlayerAtExit = true;
        }
    }

    public void CaughtPlayer ()
    {
        m_IsPlayerCaught = true;
    }

    void Update ()
    {
        if (m_IsPlayerAtExit)
        {
            EndLevel (exitBackgroundImageCanvasGroup, false, exitAudio);
        }
        else if (m_IsPlayerCaught)
        {
            EndLevel (caughtBackgroundImageCanvasGroup, true, caughtAudio);
        }
    }

    void EndLevel (CanvasGroup imageCanvasGroup, bool doRestart, AudioSource audioSource)
    {
        if (!m_HasAudioPlayed)
        {
            audioSource.Play();
            m_HasAudioPlayed = true;
        }
        m_Timer += Time.deltaTime;
        imageCanvasGroup.alpha = m_Timer / fadeDuration;

        if (m_Timer > fadeDuration + displayImageDuration)
        {
            if (doRestart)
            {
                //SceneManager.LoadScene ("MainScene1");
                Application.Quit();//退出游戏
            }
            else
            {
                Application.Quit ();
            }
        }
    }
}
七、增加敌人,增加随机死亡事件
八、添加手柄

(1) 下载并导入  资源包 

(2) 打开Prefabs 文件夹,将 Fixed Joystick 拖放到Hierarchy面板的Canvas下,调整大小和位置

(3) 调整脚本

public FixedJoystick fixedJoystick;
public float moveSpeed = 1f;

void Start()
{
   ……
  fixedJoystick = GameObject.FindObjectOfType<FixedJoystick>();
}

private void FixedUpdate()
{
  // 手柄控制代码
if (fixedJoystick != null)
{
    float joystickHorizontal = fixedJoystick.Horizontal;
    float joystickVertical = fixedJoystick.Vertical;

    if (!Mathf.Approximately(joystickHorizontal, 0f) || !Mathf.Approximately(joystickVertical, 0f))
    {
        horizontal = joystickHorizontal;
        vertical = joystickVertical;

        m_Movement.Set(horizontal, 0f, vertical);
        m_Movement.Normalize();
    }
}
}

完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{
    public FixedJoystick fixedJoystick;

    public InputAction MoveAction;
    
    public float turnSpeed = 20f;
    public float moveSpeed = 1f;

    Animator m_Animator;
    Rigidbody m_Rigidbody;
    AudioSource m_AudioSource;
    Vector3 m_Movement;
    Quaternion m_Rotation = Quaternion.identity;

    void Start ()
    {
        m_Animator = GetComponent<Animator> ();
        m_Rigidbody = GetComponent<Rigidbody> ();
        m_AudioSource = GetComponent<AudioSource> ();
        
        MoveAction.Enable();

        fixedJoystick = GameObject.FindObjectOfType<FixedJoystick>();
    }

    void FixedUpdate()
    {
        // 原有的键盘控制代码
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        m_Movement.Set(horizontal, 0f, vertical);
        m_Movement.Normalize();

        // 手柄控制代码
        if (fixedJoystick != null)
        {
            float joystickHorizontal = fixedJoystick.Horizontal;
            float joystickVertical = fixedJoystick.Vertical;

            if (!Mathf.Approximately(joystickHorizontal, 0f) || !Mathf.Approximately(joystickVertical, 0f))
            {
                horizontal = joystickHorizontal;
                vertical = joystickVertical;

                m_Movement.Set(horizontal, 0f, vertical);
                m_Movement.Normalize();
            }
        }

        bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);
        bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);
        bool isWalking = hasHorizontalInput || hasVerticalInput;
        m_Animator.SetBool("IsWalking", isWalking);

        if (isWalking)
        {
            if (!m_AudioSource.isPlaying)
            {
                m_AudioSource.Play();
            }
        }
        else
        {
            m_AudioSource.Stop();
        }

        Vector3 desiredForward = Vector3.RotateTowards(transform.forward, m_Movement, turnSpeed * Time.deltaTime, 0f);
        m_Rotation = Quaternion.LookRotation(desiredForward);

        // 移动角色
        m_Rigidbody.MovePosition(m_Rigidbody.position + m_Movement * moveSpeed * Time.fixedDeltaTime);
    }
    void OnAnimatorMove ()
    {
        m_Rigidbody.MovePosition (m_Rigidbody.position + m_Movement * m_Animator.deltaPosition.magnitude);
        m_Rigidbody.MoveRotation (m_Rotation);
    }
}
九、发布

1、安装 WebGL Build Support

2、更改Color Space(other……)下

3、在File下进行打包

4、在publish中上传

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/780123.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

推荐3款【王炸级别】的效率软件,免费无广告,你一定要收藏

Temp Cleaner Temp Cleaner 是一款专为 Windows 操作系统设计的临时文件清理工具。它的主要功能是安全且快速地清理磁盘上的临时文件和系统缓存&#xff0c;从而释放磁盘空间。该软件体积小巧&#xff08;仅有826KB&#xff09;&#xff0c;并且是无广告的绿色软件&#xff0c;…

智能交通(3)——Learning Phase Competition for Traffic Signal Control

论文分享 https://dl.acm.org/doi/pdf/10.1145/3357384.3357900https://dl.acm.org/doi/pdf/10.1145/3357384.3357900 论文代码 https://github.com/gjzheng93/frap-pubhttps://github.com/gjzheng93/frap-pub 摘要 越来越多可用的城市数据和先进的学习技术使人们能够提…

初学Spring之 AOP 面向切面编程

AOP&#xff08;Aspect Oriented Programming&#xff09;面向切面编程 通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术 是面向对象&#xff08;OOP&#xff09;的延续 AOP 在 Spring 中的作用&#xff1a; 1.提供声明式事务 2.允许用户自定义切面 导…

Java 基础--File - IO流(2)

I/O流 定义 数据从硬盘流向内存为输入流&#xff0c;数据从内存流向硬盘为输出流。输入也叫读取数据&#xff0c;输出也叫写出数据。 IO分类 1.按照数据的流向分为&#xff1a;输入流和输出流 ①输入流&#xff1a;把数据从其他设备上读取到内存中的流 ②输出流&#xff1…

pdf怎么转换成图片格式文件,pdf文档怎么转换成图片格式

在数字化时代&#xff0c;pdf文件转换成图片格式是一种常见的操作&#xff0c;无论是在工作还是日常生活中&#xff0c;我们总会遇到需要将pdf文件转换为图片的需求。这可能是因为图片格式更易于分享、展示或编辑。那么&#xff0c;如何高效地将pdf转换成图片呢&#xff1f;本文…

240705_昇思学习打卡-Day17-基于 MindSpore 实现 BERT 对话情绪识别

240705_昇思学习打卡-Day17-基于 MindSpore 实现 BERT对话情绪识别 近期确实太忙&#xff0c;此处仅作简单记录&#xff1a; 模型简介 BERT全称是来自变换器的双向编码器表征量&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;&#xff0c…

#数据结构 顺序表

线性表 顺序表 每种结构都有它存在意义 线性表的顺序存储实现指的是用一组连续的存储单元存储线性表的数据元素。 概念 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性表&#xff0c;一般情况下采用数组存储。在数组上完成数据的增查改删。 逻辑结构&#…

阶段三:项目开发---大数据开发运行环境搭建:任务8:安装配置Redis

任务描述 知识点&#xff1a;安装配置Redis 重 点&#xff1a; 安装配置Redis 难 点&#xff1a;无 内 容&#xff1a; Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可…

数据结构1:C++实现变长数组

数组作为线性表的一种&#xff0c;具有内存连续这一特点&#xff0c;可以通过下标访问元素&#xff0c;并且下标访问的时间复杂的是O(1)&#xff0c;在数组的末尾插入和删除元素的时间复杂度同样是O(1)&#xff0c;我们使用C实现一个简单的边长数组。 数据结构定义 class Arr…

【手写数据库内核组件】01 解析树的结构,不同类型的数据结构组多层的链表树,抽象类型统一引用格式

不同类型的链表 ​专栏内容&#xff1a; postgresql使用入门基础手写数据库toadb并发编程 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 文章目录 不同类型…

图像基础知识

图像卷积 卷积(convolution)是通过两个函数f和g生成第三个函数的一种数学算子,表征函数f与g经过翻转和平移的重叠部分的面积。 卷积概念是两个变量在某范围内相乘后求和的结果。图像处理中的卷积概念:数字图像是一个二维的离散信号,对数字图像做卷积操作其实就是利用卷积…

【帧中继实验-ensp】

实验要求 在R1上开启一个点对点子接口&#xff0c;用于连接 R1–R2&#xff0c;两端IP地址为12.1.1.x 。开启一个多点子接口 &#xff0c;用于连接R1–R3&#xff0c;R4&#xff0c;两段IP地址为134.1.1.x。 具体DLCI分配和映射关系如下&#xff1a; R1 102 R2 201—动态映射…

华为OD机试 - 来自异国的客人(Java 2024 D卷 100分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

使用Github Actions自建Docker镜像仓库

使用Github Actions自建Docker镜像仓库 背景使用Github Actions自建Docker镜像仓库fork项目[docker_image_sync](https://github.com/xqxyxchy/docker_image_sync)获取云厂商容器镜像服务信息配置github secrets运行github action配置需要同步的镜像同步后效果华为云配置 背景 …

机器学习简介--NLP(二)

机器学习简介 机器学习简介机器学习例子机器学习分类有监督学习有监督学习的应用 无监督学习 机器学习常见概念数据集k折交叉验证过拟合欠拟合评价指标 机器学习简介 机器学习例子 问题&#xff1a; 2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;&#xff1f;&#…

深入理解JS逆向代理与环境监测

博客文章&#xff1a;深入理解JS逆向代理与环境监测 1. 引言 首先要明确JavaScript&#xff08;JS&#xff09;在真实网页浏览器环境和Node.js环境中有很多使用特性的区别。尤其是在环境监测和对象原型链的检测方面。本文将探讨如何使用JS的代理&#xff08;Proxy&#xff09…

2024亚太杯中文赛数学建模B题word+PDF+代码

2024年第十四届亚太地区大学生数学建模竞赛&#xff08;中文赛项&#xff09;B题洪水灾害的数据分析与预测&#xff1a;建立指标相关性与多重共线性分析模型、洪水风险分层与预警评价模型、洪水发生概率的非线性预测优化模型&#xff0c;以及大规模样本预测与分布特征分析模型 …

算法011:最大连续的1的个数

最大连续的1的个数. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/max-consecutive-ones-iii/ 乍一看&#xff0c;这道题很奇怪&#xff0c;什么叫最多翻转k个0&a…

自动控制:反馈控制

自动控制&#xff1a;反馈控制 反馈控制&#xff08;Feedback Control&#xff09;是一种在控制系统中通过测量输出信号&#xff0c;并将其与期望信号进行比较&#xff0c;产生误差信号&#xff0c;再根据误差信号调整输入来达到控制目标的方法。反馈控制是自动控制系统中最常…

揭秘Conda:Python开发者必备的包管理神器

conda 简介 Conda 是一个开源的包管理系统和环境管理系统&#xff0c;用于安装和管理软件包以及创建和维护不同的软件环境。 它最初是为 Python 语言设计的&#xff0c;但现在已经支持多种编程语言&#xff0c;包括 R、Ruby、Lua、Scala 等。 1、Anaconda&#xff1a;是一个…