unity3d 与任务对话脚本无法正常工作

u91tlkcl  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(230)

我正在创建一个脚本,控制对话,并在Unity游戏中给主角任务。有一个任务列表,根据列表中变量的数量,对话可以改变。如果变量等于1主角得到了一个任务,2任务完成,3主要人物告诉NPC任务完成。当NPC碰撞器被触发时,对话图像出现,玩家看到NPC的话和2个可能的答案按钮。一个按钮关闭对话图像,另一个按钮进一步移动对话。
问题是,我找不到如何使它工作(tasks\[0\] == 3)的方式。因为它不会改变和对话循环。我试图把它放在不同的地方,但没有什么改变。
我是一个初学者,所以可能会有一些愚蠢的错误,我没有注意到。

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

public class Dialogue : MonoBehaviour
{
    [SerializeField] GameObject dialogue;
    [SerializeField] Text npcText;
    
    [SerializeField] List<Text> buttonText = new List<Text>();
    public DialogueBlock[] dialogueBlock;
    [SerializeField] public PlayerController playerController;

    int dialogueBlockPlace = 0;
    public List<int> tasks = new List<int>();
    [SerializeField] List<string> taskString = new List<string>(); 

    public void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Player")
        {
            dialogue.SetActive(true);
            dialogueBlockPlace = 0;
            Answer(0);
        }
    }
    public void OnTriggerExit(Collider other)
    {
        if(other.tag == "Player")
        {
            dialogue.SetActive(false);
        }
    }

    private void Answer(int num)
    {
        npcText.text = dialogueBlock[num].npcText;
        buttonText[0].text = dialogueBlock[num].playerAnswer[0].Text;
        buttonText[1].text = dialogueBlock[num].playerAnswer[1].Text;
    }
    
    public void AnswerButtonClicked(int buttonNum)//u=mesti ant mygtuko
    {
        if(dialogueBlock[dialogueBlockPlace].playerAnswer[buttonNum].speakEnd)
        {
            dialogue.SetActive(false);
        }
        dialogueBlockPlace = dialogueBlock[dialogueBlockPlace].playerAnswer[buttonNum].toBlock;
        TaskStarted();
        if (dialogueBlock[dialogueBlockPlace].playerAnswer[buttonNum].questInt == 1)
        {
            if (tasks[0] == 0)
            {
                tasks[0] = 1;
            }
            else if (tasks[0] > 2)
            {
                tasks[1] = 1;
            }
            else if (tasks[1] > 2 )
            {
                tasks[2] = 1;
            }
        }
        
        DialogueControl();
        
    }

    public void DialogueControl()
    {
        TaskDone();
        ChangeText();
        print(dialogueBlockPlace);
        Answer(dialogueBlockPlace);
    }

    private void TaskStarted()
    {
        if (tasks[0] == 1 || tasks[1] == 1 || tasks[2] == 1)
        {
            
            dialogueBlockPlace = 4;
        }
    }
    

    private void TaskDone()
    {
        if (tasks[0] == 2 || tasks[1] == 2 || tasks[2] == 2)
        {
            
            dialogueBlockPlace = 3;
            tasks[0] = 3;//dont work

        }
    }
    
    public void ChangeText()
    {
        if (tasks[0]==0)
        {
            dialogueBlock[2].npcText = taskString[0];
        }
        if (tasks[0] == 3)
        {
            dialogueBlock[2].npcText = taskString[1];
        }
        if (tasks[1] == 3)
        {
            dialogueBlock[2].npcText = taskString[2];
        }

    }
}
[System.Serializable]
public class DialogueBlock
{
    public string npcText;
    public PlayerAnswer[] playerAnswer;
}
[System.Serializable]
public class PlayerAnswer
{
    public string Text;
    public int toBlock;
    public bool speakEnd;
    public int questInt;
}
rsaldnfx

rsaldnfx1#

40年前,用整数编码状态是可以的,但现在是一个糟糕的做法,因为我们有所有这些讨厌的对象,编程范式和智能模式。本质上,你在这里缺少的是至少两个类和枚举来正确命名和封装它们:

class Objective
{
    bool IsCompleted {get;}
    //...
}

class Quest
{
    enum QuestState
    {
        NotStarted,
        Started,
        Completed,
        RewardCollected
    }
    //...
    QuestState State {get;}
    Objective[] Objectives {get;}
}

使用对象构建你的控制流,从代码中提取行为,将它们隔离在方法中,如果方法需要处理复杂的状态,它可以很容易地成为一个单独的对象。只是在Unity中不要把所有东西都放在自己的MonoBehavior中,你可以使用常规类,特别是对于生命周期服务:

class Unit : MonoBehaviour
{
    // use interface or base class to swap implementations easily
    protected IMovementBehaviour movementBehaviour {get;} 
    protected IAttackerBehaviour attackBehaviour {get;}
    protected IDialogueProvider dialogueProvider {get;}
    //...
}

class Villager : Unit
{
    //...
    void Awake()
    {
        movementBehaviour = new GroundMovement(); // assign 
        attackBehaviour = new MeleeAtacker();
        dialogueProvider  = new VillagerDialogue();
    }
}

当然,这只是一个粗略的说明,您更愿意使用舒适的ScriptableObjects来存储不同的行为实现,但您已经抓住了要点。

相关问题