2017-09-25 89 views
0

我正在为一个Unity平台游戏的敌人AI运动系统工作,这将允许敌人在一个固定的基础上作出三个决定之一:空闲,向右移动,或移动到剩下。我希望敌人能够选择任何这些决策,即使它刚刚挑选出的决策将与其下一个决策相同(即它可以连续选择“向右移动”两次,也可以选择多次希望)。下面的脚本没有错误,但是当我测试游戏时,它会导致我的敌人口吃。有时候,它会立即向右移动,然后向左移动等等。我觉得我的代码的内在逻辑有点正确,但实现它的方式需要一些工作。我很感激你能给我的任何帮助。顺便说一句,如果我将“MakeMovementDecision”功能放在“开始”功能中,敌人会向左或向右移动.07,或者静止不动,并且从不执​​行另一个移动功能。敌方人工智能运动决策

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

public class AIMovement : MonoBehaviour { 

// References the enemy's Rigidbody2D component 
private Rigidbody2D enemyRigidbody; 

// Sets the enemy's movement speed 
[SerializeField] 
private int movementSpeed; 

// Checks if the enemy is moving (to be used with animations) 
private bool isMoving; 

// The direction in which the enemy will move 
private Vector2 directionToMove; 

// The random decision (0, 1 or 2) that represents which movement function the enemy will perform 
private int decisionValue; 

// The time remaining before the enemy chooses which movement function to perform again 
private float timeTilNextDecision; 

// The random float that will be used to determine for how long the enemy remains idle 
private float idleTime; 

// The random float that will be used to determine for how long the enemy moves left or right 
private float moveTime; 

// Use this for initialization 
void Start() { 

    // Accesses the enemy's Rigidbody2D component 
    enemyRigidbody = GetComponent<Rigidbody2D>(); 
} 

void FixedUpdate() { 

    MakeMovementDecision(); 
} 

/// <summary> 
/// Generates the decision for which type of movement the enemy will perform 
/// </summary> 
private void MakeMovementDecision() 
{ 
    // Chooses a value upon which the movement decision will be based 
    decisionValue = Random.Range(0, 3); 

    switch (decisionValue) 
    { 
     // Keeps the enemy standing still 
     case 0: 
      Idle(); 
      break; 

     // Moves the enemy to the right 
     case 1: 
      MoveRight(); 
      break; 

     // Moves the enemy to the left 
     case 2: 
      MoveLeft(); 
      break; 
    } 
} 

/// <summary> 
/// Causes the enemy to stand still with idle animations 
/// </summary> 
private void Idle() 
{ 
    // Sets the idle stance duration 
    idleTime = Random.Range(5.0f, 10.0f); 

    // Calculates the time until the enemy may decide to change its movement 
    timeTilNextDecision = idleTime - Time.deltaTime; 

    // Sets the movement bool to false to play the idle animations 
    isMoving = false; 

    // Stops the enemy's movement 
    enemyRigidbody.velocity = Vector2.zero; 

    // Checks if the enemy should make a decision on its next movement 
    if (timeTilNextDecision < 0) 
    { 
     MakeMovementDecision(); 
    } 

} 

private void MoveRight() 
{ 
    moveTime = Random.Range(2.0f, 5.01f); 
    timeTilNextDecision = moveTime - Time.deltaTime; 
    isMoving = true; 
    directionToMove = Vector2.right; 
    transform.Translate(directionToMove * (movementSpeed * Time.deltaTime)); 

    if (timeTilNextDecision < 0) 
    { 
     MakeMovementDecision(); 
    } 

} 

private void MoveLeft() 
{ 
    moveTime = Random.Range(2.0f, 5.01f); 
    timeTilNextDecision = moveTime - Time.deltaTime; 
    isMoving = true; 
    directionToMove = Vector2.left; 
    transform.Translate(directionToMove * (movementSpeed * Time.deltaTime)); 

    if (timeTilNextDecision < 0) 
    { 
     MakeMovementDecision(); 
    } 

} 

}

+0

你为什么调用FixedUpdate(您MakeMovementDecision),并在自己的决定?尝试删除'FixedUpdate()'并将'MakeMovementDecision()'函数放在'Start()'里面...... – 0014

+0

是的,我试过了(我编辑了我的原始文章以包含关于此的注释)。它只是向左或向右移动敌人0.07个单位,或者选择“空闲”变体,但是敌人再也不会移动。在检查员看不到x值的情况下,根本无法察觉到敌人正在移动。 – Dalsia

回答

0

你需要计算内部FixedUpdate()的时间。你的代码假设看起来像这样;

void FixedUpdate() { 
    // Calculates the time until the enemy may decide to change its movement 
    moveTime += Time.deltaTime; 
    timeTilNextDecision = idleTime - moveTime; 

    if (timeTilNextDecision < 0) 
    { 
     MakeMovementDecision(); 
    } 
} 

/// <summary> 
/// Generates the decision for which type of movement the enemy will perform 
/// </summary> 
private void MakeMovementDecision() 
{ 
    // Chooses a value upon which the movement decision will be based 
    decisionValue = Random.Range(0, 3); 

    switch (decisionValue) 
    { 
     // Keeps the enemy standing still 
     case 0: 
      Idle(); 
      break; 

     // Moves the enemy to the right 
     case 1: 
      MoveRight(); 
      break; 

     // Moves the enemy to the left 
     case 2: 
      MoveLeft(); 
      break; 
    } 
} 

/// <summary> 
/// Causes the enemy to stand still with idle animations 
/// </summary> 
private void Idle() 
{ 

    // Sets the idle stance duration 
    idleTime = Random.Range(5.0f, 10.0f); 
    // Sets the movement bool to false to play the idle animations 
    isMoving = false; 

    // Stops the enemy's movement 
    enemyRigidbody.velocity = Vector2.zero; 

    // Checks if the enemy should make a decision on its next movement 


} 

private void MoveRight() 
{ 
    moveTime = Random.Range(2.0f, 5.01f); 
    isMoving = true; 
    directionToMove = Vector2.right; 
    transform.Translate(directionToMove * (movementSpeed * Time.deltaTime)); 
} 

private void MoveLeft() 
{ 
    moveTime = Random.Range(2.0f, 5.01f); 
    isMoving = true; 
    directionToMove = Vector2.left; 
    transform.Translate(directionToMove * (movementSpeed * Time.deltaTime)); 
} 

编辑:我发现你是在计算错误的时间。 Time.deltaTime是一个固定的参数,它不会返回经过的时间。

+0

谢谢你在这方面与我一起工作,但是这个解决方案也导致了我最初提到的在Start()函数中放置MakeMovementDecision()。 – Dalsia

+0

@Dalsia是的,我意识到你也在计算错误的时间,尝试编辑'FixedUpdate()'函数 – 0014

+0

嗯,似乎是导致原来的问题再次(它结结巴巴地来回暴跳)。我不明白为什么这不起作用,这似乎是有道理的,我忘了你需要为Time.deltaTime设置一个变量。我尝试了几次不同的安排,但没有成功。 – Dalsia

2

我想通了。我是重写的受害者。这非常简单,而且完全符合我的要求。关键是timeTilNextMovement变量是决定下一次移动何时发生的唯一变量。我在其他脚本中使用了太多的变量来完成这个简单的任务。

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

public class EnemyMovement : MonoBehaviour { 

private Rigidbody2D enemyRigidbody; 

private int movementValue; 

private float timeTilNextMovement; 

private bool isMoving; 

[SerializeField] 
private float movementSpeed; 

private Vector2 moveRight; 
private Vector2 moveLeft; 

// Use this for initialization 
void Start() { 

    enemyRigidbody = GetComponent<Rigidbody2D>(); 
    moveRight = Vector2.right; 
    moveLeft = Vector2.left; 

    MakeMovementDecision(); 
} 

// Update is called once per frame 
void FixedUpdate() { 

    timeTilNextMovement -= Time.fixedDeltaTime; 

    switch (movementValue) 
    { 
     case 0: 
      Debug.Log("IDLE"); 
      isMoving = false; 
      enemyRigidbody.velocity = Vector2.zero; 
      break; 
     case 1: 
      Debug.Log("RIGHT"); 
      isMoving = true; 
      transform.Translate(moveRight * (movementSpeed * Time.fixedDeltaTime)); 
      break; 
     case 2: 
      Debug.Log("LEFT"); 
      isMoving = true; 
      transform.Translate(moveLeft * (movementSpeed * Time.fixedDeltaTime)); 
      break; 
    } 

    if (timeTilNextMovement < 0) 
    { 
     MakeMovementDecision(); 
    } 

} 

private void MakeMovementDecision() 
{ 
    movementValue = Random.Range(0, 3); 
    timeTilNextMovement = Random.Range(2.0f, 5.0f); 
} 

}