Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
218 views
in Technique[技术] by (71.8m points)

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


   }
}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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.

    Instead, a better option would be to simply place the ShootPlayer script on your enemy game object, and reference it via 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. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...