【问题标题】:Enemy not shooting at player. only detects when player is on left. Enemy needs to shoot at player敌人没有向玩家射击。仅检测玩家何时在左侧。敌人需要向玩家射击
【发布时间】:2021-04-11 03:01:16
【问题描述】:

到目前为止,我的敌人仅在玩家位于玩家左侧时才开枪,但如果敌人从左到右巡逻,则意味着当它从右到左移动且玩家仍在左侧时,它会向与玩家相反的方向射击代码工作正常。如果玩家在右边,而敌人从右往左走,它就不会射击,这很好,因为玩家在敌人身后。

如何让敌人只在玩家在前面时才射击,尤其是在开始时? 有什么办法可以简化这个吗?

这是我的代码

巡逻代码:

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

public class Patrol : MonoBehaviour
{
   public float speed;
   public float distance;
   

   private bool movingRight = true;

   public Transform groundDetection;
   

   private void Update()
   {
       transform.Translate(Vector2.right * speed * Time.deltaTime);
       int layer_mask = LayerMask.GetMask("Ground");
      
       RaycastHit2D groundinfo = Physics2D.Raycast(groundDetection.position, Vector2.down, distance, layer_mask); //origin, direction, distance
      

       if (groundinfo.collider == false)
       {
           if(movingRight == true)
           {
               transform.eulerAngles = new Vector3(0, -180, 0); //turn 180 degrees
               movingRight = false;
           }
           else
           {
               transform.eulerAngles = new Vector3(0, 0, 0);
               movingRight = true;
           }
       }
   }


}

火球代码(附在火球预制件上)

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

public class Fireball : MonoBehaviour
{
   public float speed;
   public int damage;
   public float lifeTime;
   private GameObject player;

   // Start is called before the first frame update
   void Start()
   {
       
       //delay , basically to define, after how many seconds would we like to destroy game object
       Destroy(gameObject, lifeTime); 
   }

   // Update is called once per frame
   void Update()
   {
       transform.Translate(Vector2.left * speed * Time.deltaTime);
   }

   private void OnTriggerEnter2D(Collider2D collision)
   {
       if (collision.tag == "Player")
       {
           collision.GetComponent<Player>().TakeDamage(damage);
       }
       Destroy(gameObject);
   }
}

射手脚本:

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

public class ShootingPlayer : MonoBehaviour
{

   //Cached component references
   Animator enemyAnimator;

   //State
   [SerializeField] GameObject enemy;
   [SerializeField] GameObject fireBall;
   [SerializeField] Transform shotSpawnPoint;

   [SerializeField] float timeBetweenShots ;
   [SerializeField] float attackAnimationDuration;

   [SerializeField] float playerRange ;
   [SerializeField] Transform player;

   private float nextShotTime;
   private float endAttackAnimationTime;

   private void Awake()
   {
       enemy = GameObject.Find("Enemy");
       enemyAnimator = enemy.GetComponent<Animator>();
   }

   private void Start()
   {
       player = GameObject.FindGameObjectWithTag("Player").transform;
   }

   // Update is called once per frame
   void Update()
   {
       // draws line to detect player at a distance at the start and end of givem range, in this case behind and ahead of enemy
       Debug.DrawLine( new Vector3(transform.position.x + playerRange, transform.position.y, transform.position.z), new Vector3(transform.position.x - playerRange, transform.position.y, transform.position.z));

       
       if (player != null)
       {
           ShootAtPlayer();
       }

      
       if (enemyAnimator.GetCurrentAnimatorStateInfo(0).IsTag("Attacking") && Time.time > endAttackAnimationTime)
       {
           enemyAnimator.SetBool("Attacking", false);
       }
   }

   public void ShootAtPlayer()
   { 

       if (transform.localScale.x > 0 && player.transform.position.x < transform.position.x && player.transform.position.x > transform.position.x - playerRange && Time.time > nextShotTime)
       {
           Debug.Log("fireball going right");
           Instantiate(fireBall, shotSpawnPoint.position, shotSpawnPoint.rotation);
           enemyAnimator.SetBool("Attacking", true);
           nextShotTime = Time.time + timeBetweenShots;
           endAttackAnimationTime = Time.time + attackAnimationDuration;
       }

       // somehow never enters this loop

       if (transform.localScale.x < 0 && player.transform.position.x > transform.position.x && player.transform.position.x < transform.position.x + playerRange && Time.time > nextShotTime)
       {
           Debug.Log("fireball going left");
           Instantiate(fireBall, shotSpawnPoint.position, shotSpawnPoint.rotation);
           enemyAnimator.SetBool("Attacking", true);
           nextShotTime = Time.time + timeBetweenShots;
           endAttackAnimationTime = Time.time + attackAnimationDuration;
       }

       /* Continuous attacking

      if (Time.time > nextShotTime)
      {
          Instantiate(fireBall, shotSpawnPoint.position, shotSpawnPoint.rotation);
          enemyAnimator.SetBool("Attacking", true);
          nextShotTime = Time.time + timeBetweenShots;
          endAttackAnimationTime = Time.time + attackAnimationDuration;
      }
      */


   }
}

【问题讨论】:

    标签: c# unity3d raycasting


    【解决方案1】:

    您最好选择一个更简单的选项,该选项不需要那么多繁琐的代码,并且可以重复使用和更改每个预制件。

    我会在 Enemy 预制件的前面放置一个碰撞器,并在 OnTriggerStay2D 方法中运行一个脚本来运行您的拍摄代码。

    这样,您可以控制敌人的“视距”,而无需更改和重新编译任何代码,这也意味着您可以通过增加尺寸来拥有不同的敌人,它们的视锥更短或更大对撞机。

    也只是几个指针:

    • 您应该避免使用GameObject.Find("Enemy"),除非您只打算在场景中使用一个名为Enemy 的游戏对象,因为它会选择找到的第一个。

      相反,更好的选择是简单地将ShootPlayer 脚本放在你的敌人游戏对象上,并通过gameObject 引用它

    • 您可能希望避免使用LayerMask.GetMask,因为这可能是一项昂贵的操作,并且还会将您的代码与编辑器中的掩码紧密耦合。相反,如果您在该类上定义公共 LayerMask layerMask 字段,您将能够改为通过编辑器选择地面遮罩(以及任何其他应打磨的遮罩),并且遮罩名称的更改不会破坏你的代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多