【问题标题】:Enemy AI Stop enemy in certain distance敌人 AI 在一定距离内阻止敌人
【发布时间】:2019-09-13 20:41:47
【问题描述】:

你好,我试图用if(Vector2.Distance(transform.position, player.position) > minDistance)让我的敌人停在玩家面前

但这并没有按我的预期工作。敌人应该开始在一定范围内跟随玩家,而不是停在他面前。这与if(Vector2.Distance(transform.position, player.position) <= range) 工作得很好

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

public class Enemy : MonoBehaviour
{
    public int Health;
    public Transform player;
    public float range;
    public float speed;
    public Animator anim;
    public Transform goblinRange;
    public float attackRangeGoblin;
    public LayerMask whatIsPlayer;
    public int damage;
    private float timeBtwAttack;
    public float startTimeBtwAttack;

    // Update is called once per frame
    void Update()
    {
        if (Vector2.Distance(transform.position, player.position) <= range)          
        {
            anim.SetBool("GWalking", true);
            transform.position = Vector2.MoveTowards(transform.position, player.position, speed * 
  Time.deltaTime);

            Collider2D[] playerToDamage = Physics2D.OverlapCircleAll(goblinRange.position, 
  attackRangeGoblin, whatIsPlayer);
            for (int i = 0; i < playerToDamage.Length; i++)
            {
                playerToDamage[i].GetComponent<PlayerMovement>().TakeDamage(damage);               
            } 
        }
        else
        {
            Idle();
        } 
    } 

    private void FixedUpdate()
    {
        if (Health <= 0)
        {
            Destroy(gameObject);
        }
    }

    private void Idle()
    {
        anim.SetBool("GWalking", false);        
    }

    public void TakeDamage(int Damage)
    {
        Health -= Damage;
        Debug.Log("Damage Taken");
    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(goblinRange.position, attackRangeGoblin);
    }

    private void Attack()
    {
        anim.SetTrigger("goblinAttack");        
    }     
}

所以我需要敌人停在我的玩家面前并开始攻击动画,但我不知道如何在不删除“if(Vector2.Distance(transform.position, player.position) > minDistance)。任何帮助将不胜感激。

【问题讨论】:

  • 我不确定我是否理解您的问题。 if(Vector2.Distance(transform.position, player.position) &gt; minDistance) 的意思是“如果对手距离玩家的距离超过 minDistance ,你确定这就是你想要的吗?你是说只有在这种情况下才跑?

标签: c# unity3d artificial-intelligence


【解决方案1】:

您可以将minDistance 支票嵌套在您的range 支票内,如下所示:

if (Vector2.Distance(transform.position, player.position) <= range)
{
    if (Vector2.Distance(transform.position, player.position) <= minDistance)
    {
        //Attack
    }
    else
    {
        //Chase
    }
}

这样,只要玩家在追赶范围内,敌人就会追赶玩家,但距离还不够近而无法攻击。一旦进入攻击范围,它就会停止追击并开始攻击。

【讨论】:

  • 小问题,但这与问题代码中的行为并不完全一致。在那里,攻击将发生在位置变为minDistance 的同一帧中。然而,这只会触发下一帧的攻击。 --- My answer 涵盖了真正等同于问题的伪代码,但由于我还涵盖了所有(?)其他问题,所以需要更长的时间来编写。 ---除此之外,答案通常是正确的。 +1
【解决方案2】:

rangeminDistance 检查不是互斥的(“一个或另一个”)。它们既可以存在也可以共存:

//Avoid redundancy, write less, and make things more readable
var distance = Vector2.Distance(transform.position, player.position);

//If within range..
if (distance <= range) {
    //If not within minDistance..
    if(!(distance <= minDistance)) {
        //Move
    }

    //If within minDistance (incl. after moving, above)..
    if (distance <= minDistance) {
        //Attack
    }
}
//If not within range..
else {
    //Idle
}

代码还有其他几个问题:

  1. 您应该遵循命名约定:

    • 如果你的变量和参数是驼峰式,那么Health应该是healthGWalking应该是gWalkingDamage应该是damage
  2. 名称应该是描述性的:

    为了打字而跳过几个字符不值得让您或其他人(例如我们)不得不解密您的代码。

    • 避免歧义。 anim 可以引用 animatoranimation。使用animator
    • 避免使用首字母缩略词。在GWalking 中,G 代表什么? --- Goblin。我知道。问题是:我从其余代码的推断中知道;不是来自名字本身。请改用goblinWalking
    • 避免使用类似首字母缩略词的缩写形式,例如 Btw 而不是 Between。它们不好的原因与“G”的原因相同。
  3. 保持一致:

    • 对相似的东西使用相同的命名结构。决定一个计划,并遵循它。不要将GWalking 放在一个位置,而将goblinAttack 放在另一个位置。如果结构为“subjectAction”,则使用goblinWalkinggoblinAttack等。
    • 在名称中使用相同的结构顺序。如果您的主题要放在开头,如goblinRange,那么不要将它放在其他地方的末尾,如attackRangeGoblin。使用goblinAttackRange
    • 如果类是“敌人”,则不应出现“地精”的东西。所有地精可能都是敌人,但并非所有敌人都可能是地精。你的职业可能对所有敌人都是通用的,或者是地精特有的;不是都。将其命名为Goblin;或从它的元素中删除“妖精”的东西。
  4. 为变量命名,而不是根据它们的作用:

    • whatIsPlayerplayerLayerMask
  5. 在命名时要足智多谋(又名:“描述性并不意味着冗长!”):

    • timeBtwAttacksattackInterval
  6. 尝试对相关内容进行分组。

修复后应该是这样的:

//External(?) dependencies
public Transform player;
public LayerMask playerLayerMask; //From: whatIsPlayer

//Internal dependencies
public Animator animator; //From: anim

//Settings
public int health; //From: Health
public float range;
public float speed;
public int damage;
public float attackInterval; //From: timeBtwAttack

//Gobling stuff (probably redundant/unnecessary)
public Transform goblin; //From: goblinRange
public float goblinAttackRange; //From: attackRangeGoblin

//Used in the answer, as infered from the question
public float minDistance; //Probably what 'goblinAttackRange' is.

其他修复:

  • FixedUpdate 用于物理内容。如果要遵循当前结构,if (health &lt;= 0) { Destroy(gameObject); } 应该在Update 中(加上return)。如果不是,那么它应该对健康状况的变化做出反应,因此在 TakeDamage 中。
  • 在代码中保持一致。不要在一个地方使用anim.SetBool("GWalking", true),然后在另一个地方使用Idle()。两者都应该是方法(Idle() Walk())或者两者都应该是SetBool 调用。
  • Transform goblin 是单独的转换吗?如果不是,请像在 Vector2.Distance 中一样使用 transform

【讨论】:

    【解决方案3】:

    尝试使用

    if((transform.position, player.position).magnitude <range)
    

    而不是

    if(Vector2.Distance(transform.position, player.position) <= range)
    

    【讨论】:

    • 您的意思是(transform.position - player.position).magnitude? --- 不管怎样,这并没有什么不同,因为Vector2.Distance 的作用相同,and has equivalent code
    猜你喜欢
    • 1970-01-01
    • 2015-01-17
    • 2020-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多