敌人没有向玩家射击。仅检测玩家何时在左侧。敌人需要向玩家射击

Posted

技术标签:

【中文标题】敌人没有向玩家射击。仅检测玩家何时在左侧。敌人需要向玩家射击【英文标题】: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;
      
      */


   


【问题讨论】:

【参考方案1】:

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

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

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

也只是几个指针:

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

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

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

【讨论】:

以上是关于敌人没有向玩家射击。仅检测玩家何时在左侧。敌人需要向玩家射击的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有敌人与它们互动的情况下产生能量提升并检测它们何时被拾取

unity检测玩家自动开火

我试图让一个敌人向我的玩家移动,但我得到一个属性错误

Unity 3D射击和摧毁敌人不起作用

Unity3D学习:实现一个简单的视觉感知

看到玩家时,敌人的音频和精灵表不会启动/更改