- Home /
The question is answered, right answer was accepted
Affecting one instantiated object instead of all of them
Hi all. I'm working on a tower defense game, and I want to be able to upgrade towers. When I upgrade one tower, all instances of that tower are getting upgraded as well. To fix this, I added a "selected" boolean. Debugging shows me that the bool is working properly, but my upgrade does not work if I try to check that "selected" is true. Another intriguing thought that may or may not help is that the cyan color change works properly. I'm sure there's something obvious that I'm missing, but I have been staring at this code all day and just can't see it. Does anyone see why this wouldn't work? I only included the code where the bool is used for simplicity sake, but if you need the entire script, let me know! Thanks in advance!
Edit: As it turns out, this won't even work the way I need it to, as all clones will still be affected. The selected bool will still apply to all clones and all of them will get upgraded. Thank you for the replies, but I'll have to try to find a whole different solution to this problem.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HumanScript : MonoBehaviour
{
[SerializeField]
GameObject myUpgrade1;
[SerializeField]
GameObject myUpgrade2;
[SerializeField]
GameObject daggerUpgrade;
[SerializeField]
GameObject shieldUpgrade;
RaycastHit2D humanUpgrade;
bool canOpenUpgrade = true;
public UpgradeSystem closeUpgrade;
bool selected = false;
void Update()
{
Debug.Log(selected);
Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition);
humanUpgrade = Physics2D.Raycast(ray2.origin, ray2.direction, Mathf.Infinity);
if (Input.GetButtonDown("Fire1") && (closeUpgrade.mouseOnButtons == false) && (canOpenUpgrade == false))
{
selected = false;
StartCoroutine(WhiteColorOpenUpgrade());
}
if (Input.GetMouseButtonUp(0))
{
if(humanUpgrade.collider.gameObject.name == "UP_Dagger(Clone)")
{
if (ClayCountScript.clayCount > 5 && selected)
{
Instantiate(daggerUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
else if (humanUpgrade.collider.gameObject.name == "UP_Shield(Clone)")
{
if (ClayCountScript.clayCount > 5)
{
Instantiate(shieldUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
}
}
private void OnMouseUp()
{
if (canOpenUpgrade == true)
{
selected = true;
GetComponent<SpriteRenderer>().color = Color.cyan;
Instantiate(myUpgrade1, new Vector2(7.3f, 5), Quaternion.identity);
Instantiate(myUpgrade2, new Vector2(7.3f, 2.6f), Quaternion.identity);
canOpenUpgrade = false;
}
}
IEnumerator WhiteColorOpenUpgrade()
{
Debug.Log(selected);
GetComponent<SpriteRenderer>().color = Color.white;
yield return new WaitForSeconds(0.25f);
canOpenUpgrade = true;
}
}
Can you post the rest of the code? Can't really see where the issue is since this snippet doesn't show when closeUpgrade.mouseOnButtons toggles between true and false, and when canOpenUpgrade is set to true initially.
The mouseOnButtons toggle is actually in an entirely different script that doesn't affect or check for the selected variable. It's attached to the buttons so they can check where the cursor is and if it's placement should affect them. Here's that script, and I'll also edit the original post with the rest of that script. Thanks!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class UpgradeSystem : $$anonymous$$onoBehaviour
{
RaycastHit2D whereClicked;
public bool mouseOnButtons = false;
bool canClose;
void Update()
{
Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition);
whereClicked = Physics2D.Raycast(ray2.origin, ray2.direction, $$anonymous$$athf.Infinity);
if (Input.GetButtonDown("Fire1") && !mouseOnButtons)
{
Destroy(gameObject);
}
}
void On$$anonymous$$ouseEnter()
{
mouseOnButtons = true;
GetComponent<SpriteRenderer>().color = Color.grey;
}
void On$$anonymous$$ouseExit()
{
mouseOnButtons = false;
GetComponent<SpriteRenderer>().color = Color.white;
}
}
Answer by Vallyrie · May 20, 2020 at 07:33 PM
Hey everyone! I made a lot of changes to this script in the last few days. I'm not sure if simply making the "selected" variable public would help because I switched a lot of the code over to raycasting and checking colliders, but I'm going to attach the working version in case anyone ever needs to look through it. Just in case anyone tries something similar, don't make the "selected" variable static because that will make it static across all clones. Thanks for all the answers!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HumanScript : MonoBehaviour
{
public int towerStartHealth;
bool hit = false;
bool canTakeDamage = true;
[SerializeField]
GameObject myUpgradeButton1;
[SerializeField]
GameObject myUpgradeButton2;
[SerializeField]
GameObject daggerUpgrade;
[SerializeField]
GameObject shieldUpgrade;
RaycastHit2D humanUpgrade;
public HumanUpgradeSystem closeUpgrade;
bool canOpenUpgrade = true;
public bool selected = false;
public bool upgraded = false;
private void Start()
{
upgraded = false;
}
private void OnMouseUp()
{
if (canOpenUpgrade == true)
{
selected = true;
GetComponent<SpriteRenderer>().color = Color.cyan;
GameObject upgradeButton1 = Instantiate(myUpgradeButton1, new Vector2(7.3f, 5), Quaternion.identity);
HumanUpgradeSystem sys1 = upgradeButton1.GetComponent<HumanUpgradeSystem>();
sys1.selectedHuman = this;
GameObject upgradeButton2 = Instantiate(myUpgradeButton2, new Vector2(7.3f, 2.6f), Quaternion.identity);
HumanUpgradeSystem sys2 = upgradeButton2.GetComponent<HumanUpgradeSystem>();
sys2.selectedHuman = this;
canOpenUpgrade = false;
}
}
void Update()
{
if (hit == true)
{
GetComponent<SpriteRenderer>().color = Color.red;
if (selected == false)
{
StartCoroutine(WhiteColorAfterDamage());
}
else StartCoroutine(CyanColorAfterDamage());
}
if (towerStartHealth < 1)
{
Destroy(gameObject);
}
Debug.Log(selected);
Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition);
humanUpgrade = Physics2D.Raycast(ray2.origin, ray2.direction, Mathf.Infinity);
if (Input.GetButtonDown("Fire1") && (canOpenUpgrade == false)) {
if(humanUpgrade.collider.gameObject.tag != "Upgrade Human")
{
if (humanUpgrade.collider.gameObject.name == "Human(Clone)")
{
selected = false;
StartCoroutine(WhiteColorOpenUpgrade());
}
}
}
if (Input.GetMouseButtonUp(0))
{
if(humanUpgrade.collider.gameObject.name == "UP_Dagger(Clone)" && selected)
{
if (ClayCountScript.clayCount >= 5)
{
upgraded = true;
Instantiate(daggerUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
else if (humanUpgrade.collider.gameObject.name == "UP_Shield(Clone)" && selected)
{
if (ClayCountScript.clayCount >= 5)
{
upgraded = true;
Instantiate(shieldUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
}
}
Answer by icehex · May 16, 2020 at 05:59 PM
Hi, I think your selected bool won't be necessary if you use OnMouseUpAsButton(); which will only activate if released above the collider that mouse down was given:
// bool selected = false;
void Update()
{
//Debug.Log(selected);
if (Input.GetButtonDown("Fire1") && (closeUpgrade.mouseOnButtons == false) && (canOpenUpgrade == false))
{
//selected = false;
StartCoroutine(WhiteColorOpenUpgrade());
}
if (Input.GetMouseButtonUp(0))
{
if(humanUpgrade.collider.gameObject.name == "UP_Dagger(Clone)")
{
if (ClayCountScript.clayCount > 5 )
{
Instantiate(daggerUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
}
}
private void OnMouseUpAsButton()
{
if (canOpenUpgrade == true)
{
//selected = true;
GetComponent<SpriteRenderer>().color = Color.cyan;
canOpenUpgrade = false;
}
}
IEnumerator WhiteColorOpenUpgrade()
{
//Debug.Log(selected);
}
}
Hey thanks for the answer! On$$anonymous$$ouseUpAsButton() actually wouldn't work in this scenario if it needs to be above the same object, as I need to click somewhere else to buy the upgrade.
Answer by AlirezaSH2004 · May 17, 2020 at 03:24 AM
Hello there. Have you tried:
else if (Input.GetMouseButtonUp(0))...
Sometimes Unity doesn’t work properly with these statements.
I'm not sure where you're referring to. If you meant at line 36, that change didn't have any noticeable effect. Thanks for the reply though!
Have you attached your code to Unity and debugged it?
I don't know what you mean by attaching it to unity, but debug lines are showing the bool working
If you’re using Visual Studio, in the top bar, you can see “Attach to Unity” or you can hit F5 on your keyboard. You can debug your code and by putting breakpoints you can fully understand whether something is missing or not.
Doesn’t this work for you?
if (Input.GetButtonUp(“Fire1”))
{
if(humanUpgrade.collider.gameObject.name == "UP_Dagger(Clone)")
{
if (ClayCountScript.clayCount > 5 && selected)
{
Instantiate(daggerUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
else if (humanUpgrade.collider.gameObject.name == "UP_Shield(Clone)")
{
if (ClayCountScript.clayCount > 5)
{
Instantiate(shieldUpgrade, transform.position, Quaternion.identity);
ClayCountScript.clayCount -= 5;
Destroy(gameObject);
}
}
}
}
No, that gives me the same results. Debugging also doesn't show any problems.
Follow this Question
Related Questions
Instantiating Objects 1 Answer
Checking if object intersects? 1 Answer
Have gameObjects destroy themselves from external script 4 Answers
Referencing a variable in another script possibly not working? 0 Answers
IndexOutOfRangeException: Array index is out of range when using an Array and instantiating 2 Answers