Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

enemy projectile shooting at diff positions

Discussion in 'Scripting' started by tepozki, Mar 24, 2020.

  1. tepozki

    tepozki

    Joined:
    Mar 22, 2020
    Posts:
    8
    I'm making a musical platformer game with few of my friends and in every map we are going to have it's own boss. rn i want one of the bosses to shoot 2 different projectiles at random at random positions(4 diff destinations) How should i approach this?


    Code (CSharp):
    1. public class JazzBossScript : MonoBehaviour
    2. {
    3.     private float timeBtwShots;
    4.     public float startTimeBtwShots;
    5.     public GameObject projectile;
    6.     public GameObject projectile2;
    7.     public GameObject[] projectileDest;
    8.     //public Transform target;
    9.     public GameObject projectileStartingPos;
    10.     //public GameObject ProjectileDestination;
    11.     void Start()
    12.     {
    13.         timeBtwShots = startTimeBtwShots;
    14.         Debug.Log("SHOOT");
    15.     }
    16.  
    17.     void Update()
    18.     {
    19.    
    20.         if (timeBtwShots <= 0)
    21.         {
    22.  
    23.             Instantiate(projectile, projectileStartingPos.transform.position, transform.rotation);
    24.             timeBtwShots = startTimeBtwShots;
    25.         }
    26.         else
    27.         {
    28.             timeBtwShots -= Time.deltaTime;
    29.         }
    30.    
    31.     }
    32. }
    this script is rn attached to the boss itself

    Code (CSharp):
    1. public class JazzBossProjectile : MonoBehaviour
    2. {
    3.     public float speed;
    4.  
    5.     private Transform player;
    6.     //private Transform player2;
    7.     //private Transform player3;
    8.  
    9.  
    10.     private Vector3 target;
    11.     private Vector3 target2;
    12.     private Vector3 target3;
    13.     public GameObject projectileDestination;
    14.     //public GameObject projectileDestination2;
    15.     //public GameObject projectileDestination3;
    16.     float dirX, dirY;
    17.     public Rigidbody rb;
    18.     public float shootForce;
    19.     private int destPoint;
    20.  
    21.  
    22.  
    23.  
    24.  
    25.     private void Start()
    26.     {
    27.    
    28.         rb = GetComponent<Rigidbody>();
    29.         player = GameObject.FindGameObjectWithTag("ProjectileDestination").transform;
    30.         //player2 = GameObject.FindGameObjectWithTag("ProjectileDestination2").transform;
    31.         //player3 = GameObject.FindGameObjectWithTag("ProjectileDestination3").transform;
    32.         target = new Vector3(player.position.x, player.position.y, player.position.z);
    33.  
    34.         direction = (player.position - transform.position).normalized;
    35.     }
    36.  
    37.  
    38.     private Vector3 direction;
    39.     private void FixedUpdate()
    40.     {
    41.    
    42.         //transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.fixedDeltaTime);
    43.         transform.position += direction * speed;
    44.  
    45.  
    46.         if (transform.position.x == target.x && transform.position.y == target.y && transform.position.z == target.z)
    47.         {
    48.             DestroyProjectile();
    49.         }
    50.  
    51.  
    52.  
    53.  
    54.     }
    55.  
    56.     private void OnCollisionEnter(Collision collision)
    57.     {
    58.         DestroyProjectile();
    59.     }
    60.  
    61.     private void OnTriggerEnter(Collider other)
    62.     {
    63.         if (other.CompareTag("Player"))
    64.         {
    65.             DestroyProjectile();
    66.         }
    67.     }
    68.  
    69.     void DestroyProjectile()
    70.     {
    71.         Destroy(gameObject);
    72.     }
    73. }
    And this script is on the projectile prefab
     
    Last edited: Mar 25, 2020
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    Hi and welcome.
    Please use code tags to post code examples, otherwise they are hardly readable.

    As for the problem, if you want the boss to shoot in 4 different directions, either save the directions, or the targets in an array. Then chose one of them at random and make the projectile go in that direction (in case you save targets, the direction is target-ownPosition).
     
  3. tepozki

    tepozki

    Joined:
    Mar 22, 2020
    Posts:
    8
    Ive tried using the array and random.range. I just dont know how to execute that properly. I feel like im so close to solving my problem.

    PS. Thanks for the tup about the code tag. Im new to the forums and that information really helps me out.
     
  4. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    You may wanna change some things around, but the general idea would be as follows:
    Code (CSharp):
    1. // Inspector visible class attribute
    2. [SerializeField] private List<Vector3> targets; // or alternatively directions
    3.  
    4. // Inside Start() initialize targets to = new List<Vector3>();
    5.  
    6. // Call this function when you need a random target
    7. public Vector3 GetRandomTarget(){
    8.     int randomIndex = Random.Range(0, targets.Count -1); // -1 since min and max are both inclusive
    9.     return targets[randomIndex];
    10. }
    That's about it. You just fill the 'targets' List with positions you want to shoot at, through the inspector.
    To get the direction to those:
    Code (CSharp):
    1. Vector3 attackDirection = (GetRandomTarget() - transform.position); // vec pointing from us (boss) to target, thus direction
    2. attackDirection.Normalize(); // for most intents and purposes, we want the vector to be 1 unit long
    If you save directions instead of targets in the list, you obviously skip this step.

    You would now instantiate a projectile and set its velocity to the calculated normalized direction, potentially multiplied with some speed value.

    If your projectile handles 'flying forward' itself or you dont want to set the velocity for other reasons, you could also skip the direction-calculation and instead just make the projectile LookAt(target) after instantiating it. For this, 'targets' would need to be a List<Transform>, but the idea stays the same.
     
  5. tepozki

    tepozki

    Joined:
    Mar 22, 2020
    Posts:
    8
    I edited my original post and put the code tag in there. Maybe now you can actually read it lol. Also i tried your solution to it but i couldnt get it to work properly. Like i said i'm new to coding and i believe your solution works. Its just that idk where to put the lines really..
     
  6. tepozki

    tepozki

    Joined:
    Mar 22, 2020
    Posts:
    8
    Now it gives me error "index was out of range. Must be non-negative and less than the size of the collection". This is the code rn


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class JazzBossProjectile : MonoBehaviour
    6. {
    7.     public float speed;
    8.  
    9.     private Transform player;
    10.     //private Transform player2;
    11.     //private Transform player3;
    12.  
    13.  
    14.     private Vector3 target;
    15.     private Vector3 target2;
    16.     private Vector3 target3;
    17.     public GameObject projectileDestination;
    18.     //public GameObject projectileDestination2;
    19.     //public GameObject projectileDestination3;
    20.     float dirX, dirY;
    21.     public Rigidbody rb;
    22.     public float shootForce;
    23.     private int destPoint;
    24.     [SerializeField] private List<Vector3> targets;
    25.  
    26.  
    27.  
    28.  
    29.  
    30.  
    31.  
    32.     private void Start()
    33.     {
    34.          targets = new List<Vector3>();
    35.         rb = GetComponent<Rigidbody>();
    36.         player = GameObject.FindGameObjectWithTag("DrumProjectileDestination").transform;
    37.         //player2 = GameObject.FindGameObjectWithTag("ProjectileDestination2").transform;
    38.         //player3 = GameObject.FindGameObjectWithTag("ProjectileDestination3").transform;
    39.         target = new Vector3(player.position.x, player.position.y, player.position.z);
    40.  
    41.         direction = (player.position - transform.position).normalized;
    42.     }
    43.     public Vector3 GetRandomTarget()
    44.     {
    45.  
    46.         int randomIndex = Random.Range(0, targets.Count - 1); // -1 since min and max are both inclusive
    47.         return targets[randomIndex];
    48.  
    49.     }
    50.  
    51.  
    52.  
    53.  
    54.  
    55.     private Vector3 direction;
    56.     private void FixedUpdate()
    57.     {
    58.  
    59.         //transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.fixedDeltaTime);
    60.  
    61.         //transform.position += direction * speed;
    62.         Vector3 attackDirection = (GetRandomTarget() - transform.position); // vec pointing from us (boss) to target, thus direction
    63.         attackDirection.Normalize();
    64.  
    65.         if (transform.position.x == target.x && transform.position.y == target.y && transform.position.z == target.z)
    66.         {
    67.             DestroyProjectile();
    68.         }
    69.        
    70.  
    71.  
    72.  
    73.     }
    74.  
    75.     private void OnCollisionEnter(Collision collision)
    76.     {
    77.         DestroyProjectile();
    78.     }
    79.  
    80.     private void OnTriggerEnter(Collider other)
    81.     {
    82.         if (other.CompareTag("Player"))
    83.         {
    84.             DestroyProjectile();
    85.         }
    86.     }
    87.  
    88.     void DestroyProjectile()
    89.     {
    90.         Destroy(gameObject);
    91.     }
    92. }
     
    Last edited: Mar 25, 2020
  7. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    Hi again,
    when posting errors, it is generally preferable to post the entire error message. It usually contains useful information, like for example the line at which the problem occurs. For now i'll assume it occurs in the code i posted, ie line 47.

    An IndexOutOfBoundsException is caused if you try to access an array at an index that does not exist. So for example, if we had an array with 4 entries, these would be stored at the locations array[0], ..., array[3]. The maximum index we can get in line 46 is Count-1, which makes sure that no index we calculate could be outside the bounds of the array. The only way for it to still be outside the bounds, would be if you did not put any entries into the list. If the list was empty, the only indices we could calculate would be 0 and -1, both of which do not exist (since the list is empty), one of which doesnt even make any sense (since having items in a list at negative indices is not possible).

    So i gotta ask; did you put entries into the list in the inspector? Click on the gameobject which has the posted script attached. There you will see a 'Targets' which you can expand. Put its size to 4 and enter a couple Vectors. These Vectors are your target positions, ie where you shoot at.

    The above is written unser the assumption that the error is indeed thrown by line 47.
    If that's not the case, please post the entire error message. Also thanks for adding code tags :)
     
  8. tepozki

    tepozki

    Joined:
    Mar 22, 2020
    Posts:
    8
    Code (CSharp):
    1. //System.ThrowHelper.ThrowArgumentOutOfRangeException //(System.ExceptionArgument argument, //System.ExceptionResource resource) (at //<437ba245d8404784b9fbab9b439ac908>:0)
    2. //System.ThrowHelper.ThrowArgumentOutOfRangeException //() (at <437ba245d8404784b9fbab9b439ac908>:0)
    3. //System.Collections.Generic.List`1[T].get_Item (System.Int32 //index) (at <437ba245d8404784b9fbab9b439ac908>:0)
    4. //JazzBossProjectile.GetRandomTarget () (at //Assets/Scripts/JazzBossScripts/JazzBossProjectile.cs:47)
    5. //JazzBossProjectile.FixedUpdate () (at //Assets/Scripts/JazzBossScripts/JazzBossProjectile.cs:62)
    So apparently its line 47 and 62. Thats the error it gives me. rn the boss instantiates the fireball projectile normally but it doesnt add any force to it, it stays still. (i dont know if theres an error tag somewhere i could use so i used code tag for it) :)

    PS. i did that entries in the inspector and still it didnt work. Also wouldn't using Transform instead of vector3 be more efficient? I wouldn't have to put those vector3 values manually there. All i have to do is drag gameobjects into that list?
     
    Last edited: Mar 26, 2020
  9. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    Yes, if you want to place some gameobjects as potential targets in the scene, i would make it type Transform - as i mentioned in my first such post. The thing is, i have little knowledge about how your system is built so far, so i tried to offer as many / flexible solutions as possible. Not everyone is a fan of having target gameobjects. Some may prefer dynamically setting target positions through a script, others may randomly generate directions and so on.

    The error says line 62, since that is where we call GetRandomTarget,
    which is where the error is caused at line 47.

    The cause of the error is as i said, because the list is empty. But that's my fault :oops:
    I forgot that we dont need to instantiate a variable if we fill it through the inspector. So the targets = new List<Vector3>(); actually just resets the list when you launch the game. You can test this. Look at the inspector at your 'Targets' entries, then press play. The list will get emptied, since we replace it with a new List in Start(). Again, my bad. Just remove that line (line 34) and it should work nearly as intended.

    One other mistake that slipped into my example is that Random.Range with integers actually excludes the last value (while for floats, it includes it), so we also have to remove the -1 in line 46, otherwise it cannot return the last target index.
    https://docs.unity3d.com/ScriptReference/Random.Range.html

    With that i hope all mistakes should be fixed. Sorry for the cofusion :)
     
  10. tepozki

    tepozki

    Joined:
    Mar 22, 2020
    Posts:
    8
    Well now the error went away so your solution worked for that. Thank you. It still doesn't apply any force to the projectile. Boss just instantiates it and when he spawns another projectile it disappears ( probably destroys both projectiles when they collde with each other) The problem lies on my script and not your fix i think?
    Code (CSharp):
    1. Vector3 attackDirection = (GetRandomTarget() - transform.position); // vec pointing from us (boss) to target, thus direction
    2.         attackDirection.Normalize();
    This should add force to the projectile if i'm not mistaken :eek:
     
  11. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,590
    No it doesnt. It just calculates the direction you need to apply the force into.
    You still need to apply the force after spawning the projectile.