I am working on a game like space invaders were all the enemys are lined up and bounce back and forth just like space invaders I have the code below on each one of my enemys. I got this code from an online tutorial so I do not want to take credit for it. The issue I found is that when the enemy hits the wall all of the enemys in the row is triggering it. I just want one to trigger it. The reason is that Move() is called multiple times when it hits the left wall and not just one.
void OnTriggerEnter2D(Collider2D col){
GameObject[] enemies = GameObject.FindGameObjectsWithTag ("Enemy");
if (col.gameObject.name == "Left_Wall") {
go_left = false;
Move ();
} else if (col.gameObject.name == "Right_Wall") {
go_left = true;
Move ();
} else if (col.gameObject.name == "Player") {
GameObject.Find ("GM").GetComponent<Score> ().LostLife ();
}
}
Sorry, I do not fully understand your question. If that is the full method, though⌠I have a few suggestions for you, sort of unrelated to your real question.
the enemies array seems to be doing absolutely nothing. I would get rid of that. Itâs also using a âFindâ which is slow and can be improved (provided it was actually used).
-
GameObject.Find is used again if you find the player tag. This is unnecessary, and you can link + cache this value from the inspector to a variable and not look it up each time.
-
Using : if (col.CompareTag("Left_Wall")) { // etc }
is preferred to â==â for tag comparisons (performance/no garbage).
This is a pretty simple script (at least the part you posted). If itâs confusing, Iâd suggest that you try some learning tutorials that guide you through making scripts/small games in Unity, where you can follow along + copy + learn as you go. Youâll then be more comfortable to modify and add to them, etcâŚ
1 Like
Hello Methos, Thank you very much for your reply. Nice catch on the array in this your right Im not sure why I had that in there. I will also implement the compare tag instead of the == . I have this alot of places in my game and will replace them all. As for the main request attached is a picture.
https://ibb.co/hYj4ca
The green box represents the collider so as the enemies move to one side they hit the wall and all 5 of them trigger the move function. I just want one to trigger it. Also here is all the code so you can see more of what is going on. Hope this helps explain what I am trying to do.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
static bool go_left;
static public float enemySpeed = .7f;
int randomNum;
public GameObject enemyBullet;
public int enemyBulletSpeed = -10;
int moveCounter = 0;
bool moveDown = true;
bool canMove = false;
bool canFire = false;
Vector3 initialPos;
void Start(){
initialPos = gameObject.transform.position;
}
void Update () {
if (canMove == true) {
if (go_left == true) {
transform.position -= new Vector3 (enemySpeed * Time.deltaTime, 0, 0);
} else {
transform.position -= new Vector3 (-enemySpeed * Time.deltaTime, 0, 0);
}
}
}
void OnTriggerEnter2D(Collider2D col){
GameObject[] enemies = GameObject.FindGameObjectsWithTag ("Enemy");
if (col.gameObject.name == "Left_Wall") {
go_left = false;
Move ();
} else if (col.gameObject.name == "Right_Wall") {
go_left = true;
Move ();
} else if (col.gameObject.name == "Player") {
GameObject.Find ("GM").GetComponent<Score> ().LostLife ();
}
}
void Move(){
GameObject[] enemies = GameObject.FindGameObjectsWithTag ("Enemy");
for (int i = 0; i < enemies.Length; i++) {
enemies [i].transform.position -= new Vector3 (0, 0.05f, 0);
}
}
public void EnemyFire(GameObject tennisBall, int tennisBallSpeed){
if (canFire == true) {
GameObject spawnEnemyBullet = Instantiate (tennisBall, transform.position, Quaternion.identity);
spawnEnemyBullet.GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, tennisBallSpeed);
}
}
public void ResetPosition(){
moveDown = true;
moveCounter = 0;
gameObject.transform.position = initialPos;
}
public void SetEnemyActive(bool CM, bool CF){
canMove = CM;
canFire = CF;
}
}
Okay, so I think I kinda get it. If all of the enemies (groups of 5) always move together you could simply remove 4 of the 5 colliders. Thatâs only if you donât need the colliders for something else. If you do need them for something else, you could solve this in a few ways, trying to think of which is the simplest to tell you. So, I donât know how the game works. Do you shoot these things down or something to avoid them hitting the wall?
Tell me a bit how it works when you play, so I donât guess 
Can you show me your âGMâ script so I can offer a suggestion (maybe) on a way to fix your âGMâ find call?
ok so
is a link of what i am trying to recreate. I guess when I look at the example the enemy row moves one row at a time so then there would be only one collision. Right now my all the rows shift at once giving me the multiple collisions with the side wall. But I think that is just a work around and not the right way to do it. Thank you for your help let me know if there is anything else.
Here is the GM Script It is still a work in progress.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;
public class GameManager : MonoBehaviour {
int randomNum;
public GameObject tennisBall;
public int tennisBallSpeed = 5;
static public bool readyToFire = true;
List<GameObject> enemiesList = new List<GameObject>();
public float enemyStartspeed;
public float enemyStep1speed;
public float enemyStep2speed;
public float enemyStep3speed;
public float enemyStep4speed;
GameObject player;
public GameObject tryAgain;
public GameObject GameOverGraphic;
public int finalScore;
PlayerMovement pMovement;
bool enemyResteting=false;
void Start(){
player = GameObject.Find ("Player");
pMovement = player.GetComponent<PlayerMovement> ();
StartCoroutine (StartGame ());
}
IEnumerator StartGame(){
foreach(GameObject en in GameObject.FindGameObjectsWithTag("Enemy")){
enemiesList.Add(en);
}
Enemy.enemySpeed = enemyStartspeed;
readyToFire = false;
pMovement.SetPlayerActive(false);
yield return new WaitForSeconds (5);
StartEnemies ();
pMovement.SetPlayerActive(true);
yield return new WaitForSeconds (1);
EnemiesCanFire ();
readyToFire = true;
}
public IEnumerator RestRound(){
tryAgain.SetActive (true);
pMovement.SetPlayerActive(false);
GMResetEnemies ();
yield return new WaitForSeconds (5);
tryAgain.SetActive (false);
yield return new WaitForSeconds (1);
StartEnemies ();
pMovement.SetPlayerActive(true);
yield return new WaitForSeconds (0.5f);
EnemiesCanFire ();
readyToFire = true;
}
public IEnumerator GameOver(){
GMResetEnemies ();
GameOverGraphic.SetActive (true);
finalScore = gameObject.GetComponent<Score> ().ReturnScore();
PlayerPrefs.SetInt("finalScore", finalScore);
yield return new WaitForSeconds (1);
readyToFire = true;
Score.playerLifes = 3;
SceneManager.LoadScene("MainMenu");
}
void Update () {
if(readyToFire == true){
EnemyFire ();
}
}
public void GMResetEnemies(){
foreach(GameObject bull in GameObject.FindGameObjectsWithTag("EnemyBullet")){
Destroy (bull);
}
foreach(GameObject en in GameObject.FindGameObjectsWithTag("Enemy")){
en.GetComponent<Enemy> ().ResetPosition ();
en.GetComponent<Enemy> ().SetEnemyActive(false,false);
}
}
public void StartEnemies(){
foreach(GameObject en in GameObject.FindGameObjectsWithTag("Enemy")){
en.GetComponent<Enemy> ().SetEnemyActive (true, false);
}
}
public void EnemiesCanFire(){
foreach(GameObject en in GameObject.FindGameObjectsWithTag("Enemy")){
en.GetComponent<Enemy> ().SetEnemyActive (true, true);
}
}
public void removePlayer(GameObject en){
enemiesList.Remove (en);
if (enemiesList.Count == 25) {
Enemy.enemySpeed = enemyStep1speed;
}
else if (enemiesList.Count == 10) {
Enemy.enemySpeed = enemyStep2speed;
}
else if (enemiesList.Count == 5) {
Enemy.enemySpeed = enemyStep3speed;
}
else if (enemiesList.Count == 1) {
Enemy.enemySpeed = enemyStep4speed;
}
}
public void EnemyFire(){
readyToFire = false;
randomNum = Random.Range (0, enemiesList.Count);
enemiesList [randomNum].GetComponent<Enemy> ().EnemyFire (tennisBall, tennisBallSpeed);
}
}
Alright, for sake of brevity here, Iâd say make a variable for the Score script inside your enemy script. In Start(), assign the âGMâ script to it. Then use that variable when you want to call LostLife() in the trigger. Then, hopefully we can solve your moving issue, and then we can talk about ways you can improve that variable more, too
So,I think you could do this:
if (go_left && col.gameObject.CompareTag("Left_Wall")) {
go_left = false;
Move ();
Do the same for right, with :
if(!go_left && col.gameObject.CompareTag("Right_Wall")) {
go_left = true;
Move();
}
That should allow only 1 Move() call.
There are a number of other improvements that you could make to avoid using GameObject.Find (and its variations). Those will be good to know going forward (good habits/practice). For now, so youâre not swamped, Iâll leave this & see how it works for ya.
1 Like
Awesome. All I had to do was tag the walls also because before it was just looking for the name. Now there is only 1 call when they all hit the wall. I was thinking this would be the right way to go but mine would have been much more complex.
Cool, well enjoy your game making 
Thank you very much was there any other really big DO NOT DOES that you saw?
For now, Iâd say organizing your scripts to avoid âFindâ would be the best knowledge going forward. 
Youâll always improve as you go, but things look pretty good besides that.
Remember to change to CompareTag (you did say you would, so thatâs good).
Besides that, youâre welcome⌠Have fun 
Yep already made the Change to CompareTag Thank you very much for your help.
Awesome. No problem
Take care.