点击对话时停止玩家的移动 - Unity

问题描述 投票:0回答:3

我有一个问题,当我在穿过 NPC 或移动时单击对话时,角色将继续朝操纵杆的方向移动,然后再将其设置为活动为 false。

我尝试将水平和垂直输入设置为零,甚至将计算的水平和垂直输入的移动方向设置为零,但角色仍然沿上次移动的方向移动。我不确定我创建的 if 语句是否正确,但这就是我想到的想法。

这是玩家移动的脚本:

using UnityEngine;
using UnityEngine.EventSystems;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] private GameObject interactButton;
    public float speed, rotationSpeed, ySpeed, originalStepOffset;
    public Joystick joystick;

    private Animator animator;
    private CharacterController characterController;

    void Start()
    {
        animator = GetComponent<Animator>();
        characterController = GetComponent<CharacterController>();
        originalStepOffset = characterController.stepOffset;
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        float horizontalInput = joystick.Horizontal;
        float verticalInput = joystick.Vertical;

        Vector3 movementDirection = new Vector3(horizontalInput, 0, verticalInput);
        movementDirection = Quaternion.Euler(0, 45f, 0) * movementDirection;
        float magnitude = Mathf.Clamp01(movementDirection.magnitude) * speed;
        movementDirection.Normalize();

        ySpeed += Physics.gravity.y * Time.deltaTime;

        if(characterController.isGrounded)
        {
            characterController.stepOffset = originalStepOffset;
            ySpeed = -0.5f;
        }
        else
        {
            characterController.stepOffset = 0;
        }

        Vector3 velocity = movementDirection * magnitude;
        velocity = AdjustVelocityToSlope(velocity);
        velocity.y += ySpeed;
        //transform.Translate(movementDirection * speed * Time.deltaTime, Space.World);
        characterController.Move(velocity * Time.deltaTime);

        if (movementDirection != Vector3.zero)
        {
            if(EventSystem.current.currentSelectedGameObject != null)
            {
                if (EventSystem.current.currentSelectedGameObject.name == "InteractButton")
                {
                    horizontalInput = 0f;
                    verticalInput = 0f;
                    movementDirection = Vector3.zero;
                    animator.SetBool("IsMoving", false);
                }
                else
                {
                    //transform.forward = movementDirection;
                    animator.SetBool("IsMoving", true);
                    Quaternion toRotation = Quaternion.LookRotation(movementDirection, Vector3.up);
                    transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
                }
            }else
            {
                animator.SetBool("IsMoving", true);
                Quaternion toRotation = Quaternion.LookRotation(movementDirection, Vector3.up);
                transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
            }
        } else
        {
            animator.SetBool("IsMoving", false);
        }
    }

    private Vector3 AdjustVelocityToSlope(Vector3 velocity)
    {
        var ray = new Ray(transform.position, Vector3.down);

        if(Physics.Raycast(ray, out RaycastHit hitInfo, 0.2f))
        {
            var slopeRotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);
            var adjustedVelocity = slopeRotation * velocity;

            if(adjustedVelocity.y < 0)
            {
                return adjustedVelocity;
            }
        }

        return velocity;
    }
}

将按钮设置为 active 为 true 并添加其 onclick 侦听器的函数是一个触发器进入函数和一个触发器退出函数,用于将其设置为 active 为 false 并删除 onclick 侦听器。它附着在多个 NPC 上,每当我靠近它们时,按钮就会出现。如果有人需要在此处查看按钮的脚本,但我只会粘贴到相关部分:

using System;
using System.Collections;
using System.Drawing;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[System.Serializable]
public class DialogueManager : MonoBehaviour
{
    /*
    // NPC INTERACTION
    private static DialogueManager buttonOwner;
    private Camera mainCamera;
    */

    // NPC DATA
    private Character characterJson;

    // FOR DIALOG FLOW
    private int multiDialogCycle;
    public static int dialogId;
    // GAME OBJECTS REFERENCE
    [SerializeField] private GameObject dialogBox, addPanel, m1, id, darkPanel;
    [SerializeField] private Button nameBtn, choiceOneBtn, choiceTwoBtn;
    [SerializeField] private TextMeshProUGUI npcName, choiceOne, choiceTwo, dialogName, dialogMessage, addedText;
    [SerializeField] private TextAsset characterData;

    // FOR MULTIPLE DIALOGUES WITHOUT CHOICES
    private bool clickEnable;
    private string[] multiDialog;

    // CHOICES STORAGE
    private static Choice[] choices = new Choice[2];

    //private TryInstantiate tryInstantiate = new TryInstantiate();
    private GameData gameData;

    private void Start()
    {

        // LOAD NPC DATA
        characterJson = JsonUtility.FromJson<Character>(characterData.text);
        
        // SET DEFAULT VALUE
        //dialogId = 0;
        multiDialogCycle = 0;
        clickEnable = false;

        // SET SCRIPTABLE OBJECT FOR DATA STORAGE
        gameData = Resources.Load<GameData>("GameData/GameData");
    }

    private void Update()
    {
        if(nameBtn.gameObject.activeInHierarchy)
        {
            if(Input.GetKey(KeyCode.Space))
            {
                EventSystem.current.SetSelectedGameObject(nameBtn.gameObject);
            }
        }

        // FOR ENDING DIALOGUES WITHOUT CHOICES
        if (Input.GetMouseButtonDown(0) && clickEnable == true)
        {
            if (multiDialog.Length > 1 )
            {
                if(getDialog(dialogId).choices.Length == 0 && multiDialogCycle == multiDialog.Length - 1)
                {
                    addArticles();
                    addObjectives();
                    addClues();
                    closeDialog();
                    Debug.Log(getDialog(dialogId).minigame);
                }
                else
                {
                    if(getDialog(dialogId).minigame != "" && multiDialogCycle < multiDialog.Length - 1)
                    {
                        if(!gameData.idShown)
                        {
                            darkPanel.SetActive(true);
                            id.SetActive(true);
                        }
                    }else
                    {
                        multiDialogCycle++;
                        loadCharacterData();
                    }
                }
            }
            else
            {
                if (getDialog(dialogId).minigame != "")
                {
                    if(getDialog(dialogId).minigame == "spot_object")
                    {
                        m1.SetActive(true);
                    }
                    dialogBox.SetActive(false);
                    gameData.dialogActive  = false;
                }
                else
                {
                    addArticles();
                    addObjectives();
                    addClues();
                    closeDialog();
                }
            }
        }

        if(gameData.idShown)
        {
            multiDialogCycle++;
            loadCharacterData();
            gameData.idShown = false;
        }

        if (gameData.dialogActive && dialogId != 0 && getDialog(dialogId).minigame != "" && !gameData.loadedData)
        {
            updateID();
            loadCharacterData();
        }
        
        // FOR NPC NAMES
        /*
        if (buttonOwner != this) return;

        if (!mainCamera) mainCamera = Camera.main;
        var position = mainCamera.WorldToScreenPoint(head.position + offset);

        //uiUse.transform.position = position;
        nameBtn.transform.position = position;
        */
    }

    private void OnTriggerEnter(Collider collisionInfo)
    {
        if (collisionInfo.CompareTag("Player"))
        {
            nameBtn.gameObject.SetActive(true);
            nameBtn.GetComponent<Image>().sprite = Resources.Load<Sprite>("InteractionAsset/DIALOGUE");
            nameBtn.transform.GetChild(0).GetComponent<TextMeshProUGUI>().color = new Color32(75,75,75,255);

            //buttonOwner = this;

            nameBtn.onClick.RemoveListener(onNameClick);
            nameBtn.onClick.AddListener(onNameClick);

            choiceOneBtn.onClick.RemoveListener(onChoiceClick);
            choiceOneBtn.onClick.AddListener(onChoiceClick);

            choiceTwoBtn.onClick.RemoveListener(onChoiceClick);
            choiceTwoBtn.onClick.AddListener(onChoiceClick);

            npcName.text = characterJson.name;
        }
    }

    private void OnTriggerExit(Collider collisionInfo)
    {
        if (collisionInfo.CompareTag("Player"))
        {
            nameBtn.onClick.RemoveListener(onNameClick);

            choiceOneBtn.onClick.RemoveListener(onChoiceClick);
            choiceTwoBtn.onClick.RemoveListener(onChoiceClick);

            nameBtn.gameObject.SetActive(false);

            //buttonOwner = null;
        }
    }

    // DIALOGUE SYSTEM
    public void onNameClick()
    {
        nameBtn.gameObject.SetActive(false);
        dialogBox.SetActive(true);
        gameData.dialogActive  = true;
        FindObjectOfType<AudioManager>().Play("ButtonSound");
        if (dialogBox.activeInHierarchy)
        {
            if (dialogMessage != null && dialogName != null)
            {
                loadCharacterData();
                interactedNPC();
            }
            else
            {
                // Debug.Log("null dialog message");
            }
        }
    }
    public void updateID()
    {
        if (gameData.win && !gameData.loadedData)
        {
            dialogId = gameData.targetId_1;
            gameData.loadedData = true;
        }
        else if (!gameData.win && !gameData.loadedData)
        {
            dialogId = gameData.targetId_2;
            gameData.loadedData = true;
        }
    }

我怎样才能至少重置操纵杆的位置。我目前正在使用 Unity Asset Store 中的操纵杆包。

c# unity-game-engine triggers collision
3个回答
1
投票

我将从对话步骤开始对话流程。对话启动后,您可以设置一个布尔值或任何其他类型的属性(甚至是引用的对象,例如对话本身或与之聊天的 NPC,但布尔值更简单)作为标记。简单来说:

public bool IsTalking;
。这可能位于 PlayerMovement 或主要的类似 Player 的组件(或 SO)中,您可以通过 GameObject 或不同的公共变量从 PlayerMovement 访问它们。

接下来,一旦对话机制启动,您可以将Player-like组件或PlayerMovement中的标记(例如bool或NPC ref)设置为true,当聊天停止时为false。

然后在 PlayerMovement.FixedUpdate() 中你可以停止代码执行:

// Update is called once per frame
void FixedUpdate()
{
    // or if (Player.IsTalking == true) if you want the marker there, 
    // but you can have it inside PlayerMovement if you wish as long as   
    // you can reference it without overhead - meaning don't do crazy 
    // stuff like searching all game objects/components for PlayerMovement)
    if (IsTalking == true)
    {
         if (characterController != null)
             characterController.Move(Vector3.zero);
         if (animator != null)
             animator.SetBool("IsMoving", false);
         return;
    }

    // everything starts executing once the player stops talking to NPCs
    float horizontalInput = joystick.Horizontal;
    float verticalInput = joystick.Vertical;

    Vector3 movementDirection = new Vector3(horizontalInput, 0, verticalInput);
    movementDirection = Quaternion.Euler(0, 45f, 0) * movementDirection;
    float magnitude = Mathf.Clamp01(movementDirection.

0
投票

据我了解,对话窗口是模态的。根据您的需要,您可以使用

停止时间进程的内部增量
Time.timeScale = 0f;

但这会停止,例如(UI)动画和事件系统的正确功能,所以有些人使用

Time.timeScale = 0.0001f;

这有一个缺点,即游戏玩法继续缓慢,当用户在暂停屏幕中休息时,我们的玩家英雄可能会被非常慢的火箭击中。


0
投票

我想补充一点,您只需调用 Player 脚本上的一个方法来确定该布尔值设置为 true 还是 false,而不是公开内部变量。像这样的东西:

private bool canMove = true;

[YarnCommand("canMove")] // you don't need this if not using YarnSpinner
public void CanMove(bool permission) {
    canMove = permission;
}

然后,无论采用哪种方法处理您的运动,请务必输入以下内容:

private void MoveCharacter(Vector2 direction) {
    if (!canMove) {
        return;
    }
//... rest of move code

这样做的原因是您不希望其他脚本能够直接修改您的属性。最好公开一个只做单一事情的公共方法。

稍后,如果您决定需要更多逻辑,那么唯一需要更改的是

CanMove
方法,其他一切保持不变。

请注意,时髦的

[YarnCommand()]
条目仅适用于 YarnSpinner,如果您不使用 YarnSpinner,则不需要它。这只是 Yarn 脚本能够从对话中调用 C# 方法的一种方式。

奖金: 为了从另一个脚本中调用此方法,您需要首先访问它,使用

FindObjectOfType<>
:

private Move moveScript; // Move is the script's class name
private void Start() {
    moveScript = FindObjectOfType<Move>();
}

然后当你想在对话开始后调用该方法时:

moveScript.CanMove(false);

当你的对话结束时:

moveScript.CanMove(true);
© www.soinside.com 2019 - 2024. All rights reserved.