You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity模拟人生AI需求值异常求助:值同时增减/满值骤降

模拟人生AI需求系统问题排查与修复

需求目标

开发Unity模拟人生项目的AI需求系统,核心逻辑:

  • AI靠近对应需求的目标点时,需求值(如饥饿值)从0增长至100
  • 需求值满100后,逐渐下降至0
  • 下降到0后触发下一个需求

初始代码问题

初始代码中,需求值到0后无法上升,还出现同时增减的异常。代码如下:

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

public class PlayerMove : MonoBehaviour { 
public GameObject targetFood; 
public GameObject targetSleep; 
public GameObject targetDance; 
public GameObject targetRead;

private NavMeshAgent agent;
private Animator animator;

[Header("Needs")]
public float hunger = 10f;
public float sleepiness = 50f;
public float dance = 80f;
public float reading = 100f;
[Header("Parameters")]
public float hungerRate = 4f;
public float sleepinessRate = 4f;
public float danceRate = 4f;
public float readingRate = 4f;

void Start()
{
    agent = GetComponent<NavMeshAgent>();
    animator = GetComponent<Animator>();
}

void Update()
{
    bool isIncreasing = false;

    if (hunger <= 0 && Vector3.Distance(agent.transform.position, targetFood.transform.position) <= 1f)
    {
        hunger += hungerRate * 10 * Time.deltaTime;
        if (hunger > 100)
        {
            hunger = 100;
            isIncreasing = false;
        }
        else
        {
            isIncreasing = true;
        }
    }
    else if (hunger >= 100)
    {
        hunger -= hungerRate * Time.deltaTime;
        if (hunger < 0)
        {
            hunger = 0;
            isIncreasing = true;
        }
        else
        {
            isIncreasing = false;
        }
    }
    else
    {
        if (isIncreasing)
        {
            hunger += hungerRate * 10 * Time.deltaTime;
            if (hunger > 100)
            {
                hunger = 100;
                isIncreasing = false;
            }
        }
        else
        {
            hunger -= hungerRate * Time.deltaTime;
            if (hunger < 0)
            {
                hunger = 0;
                isIncreasing = true;
            }
        }
    }
    CheckNeeds();
}

void CheckNeeds()
{
    if (hunger <= 0)
    {
        animator.SetBool("isEating", true);
        MoveToTarget(targetFood.transform.position);
    }
    else
    {
        animator.SetBool("isEating", false);
    }

    if (sleepiness <= 0)
    {
        animator.SetBool("isSleeping", true);
        MoveToTarget(targetSleep.transform.position);
    }
    else
    {
        animator.SetBool("isSleeping", false);
    }

    if (dance <= 0)
    {
        animator.SetBool("isDancing", true);
        MoveToTarget(targetDance.transform.position);
    }
    else
    {
        animator.SetBool("isDancing", false);
    }

    if (reading <= 0)
    {
        animator.SetBool("isReading", true);
        MoveToTarget(targetRead.transform.position);
    }
    else
    {
        animator.SetBool("isReading", false);
    }
}

void MoveToTarget(Vector3 targetPosition)
{
    agent.SetDestination(targetPosition);
}

}

修改后新问题

将isIncreasing变量移至类成员变量后,解决了无法上升的问题,但出现新异常:需求值从100开始,还没到达指定位置就直接骤降到0。修改后的代码如下:

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

public class PlayerMove : MonoBehaviour
{
    public GameObject targetFood;
    public GameObject targetSleep;
    public GameObject targetDance;
    public GameObject targetRead;

    private NavMeshAgent agent;
    private Animator animator;

    private bool isIncreasing;

    [Header("Needs")]
    public float hunger = 10f;
    public float sleepiness = 50f;
    public float dance = 80f;
    public float reading = 100f;
    [Header("Parameters")]
    public float hungerRate = 4f;
    public float sleepinessRate = 4f;
    public float danceRate = 4f;
    public float readingRate = 4f;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
    }

    void Update()
    {
        if (hunger <= 0 && Vector3.Distance(agent.transform.position, targetFood.transform.position) <= 1f)
        {
            hunger += hungerRate * 10 * Time.deltaTime;
            if (hunger > 100)
            {
                hunger = 100;
                isIncreasing = false;
            }
            else
            {
                isIncreasing = true;
            }
        }
        else if (hunger >= 100 )
        {
            hunger -= hungerRate * Time.deltaTime;
            if (hunger < 0)
            {
                hunger = 0;
                isIncreasing = true;
            }
            else
            {
                isIncreasing = false;
            }
        }
        else
        {
            if (isIncreasing)
            {
                hunger += hungerRate * 10 * Time.deltaTime;
                if (hunger > 100)
                {
                    hunger = 100;
                    isIncreasing = false;
                }
            }
            else
            {
                hunger -= hungerRate * Time.deltaTime;
                if (hunger < 0)
                {
                    hunger = 0;
                    isIncreasing = true;
                }
            }
        }

        CheckNeeds();

    }

    void CheckNeeds()
    {
        if (hunger <= 0)
        {
            animator.SetBool("isEating", true);
            MoveToTarget(targetFood.transform.position);
        }
        else
        {
            animator.SetBool("isEating", false);
        }

        if (sleepiness <= 0)
        {
            animator.SetBool("isSleeping", true);
            MoveToTarget(targetSleep.transform.position);
        }
        else
        {
            animator.SetBool("isSleeping", false);
        }

        if (dance <= 0)
        {
            animator.SetBool("isDancing", true);
            MoveToTarget(targetDance.transform.position);
        }
        else
        {
            animator.SetBool("isDancing", false);
        }

        if (reading <= 0)
        {
            animator.SetBool("isReading", true);
            MoveToTarget(targetRead.transform.position);
        }
        else
        {
            animator.SetBool("isReading", false);
        }
    }

    void MoveToTarget(Vector3 targetPosition)
    {
        agent.SetDestination(targetPosition);
    }
}

问题根源与修复方案

核心问题分析

  1. 初始代码问题:isIncreasing是Update内的局部变量,每帧都会重置为false,导致需求值上升逻辑无法持续执行,出现无法上升或异常增减的情况。
  2. 修改后新问题:单例isIncreasing变量被所有需求共享,某一需求状态切换时会影响其他需求的增减逻辑;同时需求值下降无场景限制——只要满100就开始下降,不管AI是否在执行其他需求,导致未到目标点就直接掉至0。

修复步骤

1. 为每个需求单独维护状态

创建封装类,将每个需求的属性和状态独立管理:

[System.Serializable]
public class Need
{
    public string needName;
    public GameObject target;
    public float currentValue;
    public float increaseRate;
    public float decreaseRate;
    public bool isIncreasing;
    public AnimatorBool animatorSetting;
}

[System.Serializable]
public class AnimatorBool
{
    public string parameterName;
    public bool isActive;
}

2. 重构需求逻辑

使用列表统一管理所有需求,确保状态独立、逻辑清晰:

public class PlayerMove : MonoBehaviour
{
    private NavMeshAgent agent;
    private Animator animator;

    public List<Need> needs = new List<Need>();
    private Need currentActiveNeed;

    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        foreach (var need in needs)
        {
            need.isIncreasing = false;
            animator.SetBool(need.animatorSetting.parameterName, false);
        }
    }

    void Update()
    {
        UpdateNeeds();
        CheckAndProcessNeeds();
    }

    void UpdateNeeds()
    {
        foreach (var need in needs)
        {
            if (need.currentValue <= 0 && IsNearTarget(need.target))
            {
                need.currentValue += need.increaseRate * Time.deltaTime;
                need.isIncreasing = true;
                need.animatorSetting.isActive = true;
                if (need.currentValue >= 100)
                {
                    need.currentValue = 100;
                    need.isIncreasing = false;
                    need.animatorSetting.isActive = false;
                    currentActiveNeed = null;
                }
            }
            else if (need.currentValue >= 100)
            {
                need.currentValue -= need.decreaseRate * Time.deltaTime;
                need.isIncreasing = false;
                need.animatorSetting.isActive = false;
                if (need.currentValue <= 0)
                {
                    need.currentValue = 0;
                    need.isIncreasing = true;
                }
            }
            else
            {
                if (need.isIncreasing && IsNearTarget(need.target))
                {
                    need.currentValue += need.increaseRate * Time.deltaTime;
                    if (need.currentValue >= 100)
                    {
                        need.currentValue = 100;
                        need.isIncreasing = false;
                        need.animatorSetting.isActive = false;
                        currentActiveNeed = null;
                    }
                }
                else if (!need.isIncreasing)
                {
                    need.currentValue -= need.decreaseRate * Time.deltaTime;
                    if (need.currentValue <= 0)
                    {
                        need.currentValue = 0;
                        need.isIncreasing = true;
                    }
                }
            }
            animator.SetBool(need.animatorSetting.parameterName, need.animatorSetting.isActive);
        }
    }

    void CheckAndProcessNeeds()
    {
        if (currentActiveNeed != null) return;
        var needToProcess = needs.Find(n => n.currentValue <= 0);
        if (needToProcess != null)
        {
            currentActiveNeed = needToProcess;
            MoveToTarget(currentActiveNeed.target.transform.position);
            currentActiveNeed.animatorSetting.isActive = true;
        }
    }

    bool IsNearTarget(GameObject target)
    {
        return Vector3.Distance(transform.position, target.transform.position) <= 1f;
    }

    void MoveToTarget(Vector3 targetPosition)
    {
        agent.SetDestination(targetPosition);
    }
}

3. 关键优化点

  • 每个需求独立维护isIncreasing状态,避免跨需求的状态冲突
  • 仅当AI靠近目标点时才允许需求值增长,防止未到达目标就触发下降逻辑
  • 增加currentActiveNeed变量,确保同一时间只处理一个需求,避免多需求同时触发移动
  • 使用序列化类封装需求属性,便于在Unity Inspector面板中直观配置

内容的提问来源于stack exchange,提问作者kizofan193

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:54:58