简体   繁体   English

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

[英]Enemy not shooting at player. only detects when player is on left. Enemy needs to shoot at player

So far my enemy only shoots when player is to the left of the player but if enemy is patrolling from left to right it means it shoots in opposite direction to player when it moves from right to left and player is still on the left code works fine.到目前为止,我的敌人只在玩家在玩家左侧时射击,但如果敌人从左到右巡逻,这意味着当它从右到左移动并且玩家仍然在左侧时,它会向玩家相反的方向射击代码工作正常. if player is to the right and enemy is going right to left it doesn't shoot which is fine since player is behind enemy.如果玩家在右边,而敌人从右到左,则它不会射击,这很好,因为玩家在敌人身后。

How do I get enemy to shoot only when player is in front especially at the start?我如何让敌人只有在玩家在前面时才射击,尤其是在开始时? Is there any way I could simplify this?有什么办法可以简化这个吗?

Here are my codes这是我的代码

Patrol code:巡逻代码:

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;
           }
       }
   }


}

Fireball code (attached to the prefab of fireball)火球代码(附在火球的预制件上)

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);
   }
}

Shooting player script:射击播放器脚本:

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;
      }
      */


   }
}

You could be better off going with a simpler option that won't require as much fiddly code, and can be reused and changed per prefab.您最好选择一个更简单的选项,该选项不需要那么多繁琐的代码,并且可以在每个预制件中重复使用和更改。

I'd place a collider at the front of the Enemy prefab, and have a script that runs your shoot code inside of an OnTriggerStay2D method.我会在Enemy预制件的前面放置一个对撞机,并有一个脚本在OnTriggerStay2D方法中运行你的射击代码。

That way, you can control the "seeing distance" of your enemy without having to change and recompile any code, and it also means that you can have different enemies that have a shorter or larger cone of vision just by increasing the size of the collider.这样,您可以控制敌人的“视距”,而无需更改和重新编译任何代码,这也意味着您可以通过增加对撞机的大小来拥有更短或更大视锥的不同敌人.

Also just a couple pointers:也只是几个指针:

  • You'll want to avoid using GameObject.Find("Enemy") unless you only plan on having one game object titled Enemy in your scene, as it'll pick the first one it finds.您将要避免使用GameObject.Find("Enemy") ,除非您只计划在场景中拥有一款名为Enemy的游戏 object,因为它会选择找到的第一个游戏。

    Instead, a better option would be to simply place the ShootPlayer script on your enemy game object, and reference it via gameObject相反,更好的选择是简单地将ShootPlayer脚本放在你的敌人游戏 object 上,并通过gameObject引用它

  • You might want to avoid using LayerMask.GetMask as it could be an expensive operation, and also tightly couples your code with the masks in the editor.您可能希望避免使用LayerMask.GetMask ,因为它可能是一项昂贵的操作,并且还会将您的代码与编辑器中的掩码紧密耦合。 Instead, if you define a public LayerMask layerMask field on that class, you'll be able to choose the ground mask (and also any other mask that should be ground) via the editor instead, and changes to the masks name won't break your code.相反,如果您在 class 上定义公共LayerMask layerMask字段,您将能够通过编辑器选择地面遮罩(以及任何其他应该打磨的遮罩),并且遮罩名称的更改不会中断你的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM