Transparency based on energy, not on mouse down

I managed to get the code to work as Rick has done. All good there.

I want to try something different, but I’m struggling with how to do it. Thought I’d mention it here in case anyone has any feedback.

Instead of having the unit transparency change to white for the unit you click on, I want to have the unit’s transparency change to white once you have enough energy to summon that unit.

As this would have multiple units fully shown at once, this mode would also need to add a selection box around the unit in the quad, that has the mouse down on - so you know which one is currently selected.

I have managed to get the selection box working, using the approach Rick has done - in this case, I used a separate sprite that overlays on top.

The challenge I’m having is getting the game to know when to make the unit transparency show once enough energy has been reached.

I imagine it would need an ‘if statement’ comparing the starText variable from the StarDisplay script with the starCost variable from within the Defender script? Struggling with how to piece that together.

Anyways, if anyone has any thoughts it would be appreciated. One of the games I want to make down the road will also lean on this kind of code, so I’d really like to figure it out.

Many thanks in advance.

Hi Matt,

These are a lot of ideas. I would suggest to focus on one first. The easiest one is probably the selection box.

For simplicity, I would add such a box or frame to each of the buttons as a child game object. Disable the game object.

In your Button component, you probably have an OnMouseDown method. There are other built-in methods such as OnMouseOver, which could be helpful for you. In that method, you could enable the “frame” game object. You know how to reference another game object in your component, so you’ll certainly be able to make this work.

For more helpful methods, check the API. Scroll down to the list of public methods to see what is available.

The challenge I’m having is getting the game to know when to make the unit transparency show once enough energy has been reached.

Do you have a ButtonHandler or ResourceHandler class or something like that? If not, create one. Wire up the logic there. Your game already “knows” when you are allowed to spawn a defender, thus you know where you could gather the relevant information.

The trophy (or whatever) spawns the stars/currency/whatever. In that moment, your current solution adds the spawned things to some variable. You could simply check if enough “money” is available to potentially spawn a defender. And if the condition is true, you could make that defender white.

The best would be if you made a diagram of your concept/logic without thinking too much about the actual implementation. Then break your concept down into single tasks and maybe even subtasks. That’ll make everything way easier for you because you know how to write the required code even if you currently aren’t aware of it.

If Rick’s current solution makes it difficult for you to realise your idea, don’t hesitate to write your own class and, if necessary, to replace his solution.

Thank you Nina, you have been very helpful :slight_smile:

I took your advice earlier too, and watched Bob Tabor’s videos. They were great and helped me understand some key basics that I was lacking.

I am now at the stage where I can (for the most part) understand the code when I see it on the screen. However, I really struggle when I have to do things from scratch. I get the Unity engine stuff fine, but the coding is a bit tricky for me. I just need to keep at it and practice big-time.

I have managed to get the selection box to work, but I’m still stumped on getting the units to become visible (from transparency) once there is enough energy to summon them.

I used Rick’s ButtonHandler logic, and created a new script called DefenderButton. I figured instead of using OnMouseDown(), I would put the code within the Update method so it checks every frame.

This is my code:

public class DefenderButton : MonoBehaviour
{
[SerializeField] Defender defenderPrefab;

private void Update()
{
    var StarDisplay = FindObjectOfType<StarDisplay>();
    int defenderCost = FindObjectOfType<Defender>().GetStarCost();
    var buttons = FindObjectsOfType<DefenderButton>();


    foreach (DefenderButton button in buttons)
    {
        button.GetComponent<SpriteRenderer>().color = new Color32(41, 41, 41, 255);
    }
    if (StarDisplay.HaveEnoughStars(defenderCost))
    {
        GetComponent<SpriteRenderer>().color = Color.white;
        
        FindObjectOfType<DefenderSpawner>().SetSelectedDefender(defenderPrefab);
    }
    
}

}

I am not getting any errors within Visual Studio, but when I run within Unity it gives a NullReferenceException: Object reference not set to an instance of an object. And the line it snags on is:

int defenderCost = FindObjectOfType().GetStarCost();

I have the defender prefab dragged onto the serialized field.

Not sure how close I am to the solution. I’m still struggling a bit with the logic, but I’ll continue to play with it. Thought I’d post my progress. If anyone has any feedback with code samples that may fix it up, it would be super helpful.

That’s normal. I’ve been using Unity for quite a few years, and, for me, the first steps in a project are usually difficult. Once I started a project and made something work, it’s not that difficult anymore.

int defenderCost = FindObjectOfType<Defender>().GetStarCost(); returns “some” Defender object. If you need a specific Defender object, don’t call FindObjectOfType.

Have you already tried to add Debug.Logs to your code to see what is going on during runtime?

I’ve read your code, and I think you are on the right track. However, if I didn’t know anything about your idea, I would have a difficult time to understand the concept.

  1. Where do you want to implement the logic regarding the colour of the button? Inside the DefenderButton class? (You can do that but I would suggest to create a new method with a self-explanatory name.)
  2. if (StarDisplay.HaveEnoughStars(defenderCost)) looks as if the StarDisplay is supposed to determine the colour of the DefenderButton. I, personally, would just check the amount of stars stored in the StarDisplay object because “star” and “button” are two different concepts. By passing on information to the StarDisplay and receive data from the StarDisplay, you are creating a tight dependency. You can do that, it’s not wrong by any means but, in my personal opinion, it would be better if your concept became more obvious.

Furthermore, I would not mix the colour logic with the “select defender” logic. This is a pure matter of personal preference but the more complex your ideas become mixing concepts can make it difficult to enhance parts of the code.

For example:

StarDisplay starDisplay;

// Button
SpriteRenderer spriteRenderer;
int defenderCost;

// Colours
Color disabledColor = new Color32(41, 41, 41, 255);
Color enabledColor = Color.white;

void Start()
{
    // get the data for the instance variables
}

public void UpdateButtonColour()
{
    Color color = enabledColor;

    int starsAmount = StarDisplay.GetStars();
    if (starsAmount < defenderCost)  { color = disabledColor; }
    
    spriteRenderer.color = color;
}

This is just an example. It probably won’t work this way in your case because the code you posted appears to set the color of multiple DefenderButton SpriteRenderers inside one DefenderButton object. For a simple idea like Rick’s his approach is fine but your idea is a bit more complex, thus I’d rather recommend to define some kind of a ButtonHandler which, for example, calls the UpdateButtonColour of each DefenderButton whenever something is supposed to happen.

One could even remove the reference to the StarDisplay instance from the DefenderButton and move it to the ButtonHandler.

For example:

// Button
[SerializeField] GameObject defenderPrefab;
[SerializeField] int defenderCost;

// Colors
SpriteRenderer spriteRenderer;
Color disabledColor = new Color32(41, 41, 41, 255);
Color enabledColor = Color.white;

ButtonHandler buttonManager;

void Start()
{
    // get the data for the instance variables
}

public void SetColor (bool isActive)
{
    spriteRenderer.color = isActive ? enabledColor : disabledColor;
}

void OnMouseDown()
{
    buttonHandler.SetSelectedDefender(defenderPrefab);
}

The ButtonHandler object could pass the reference to the prefab on to the DefenderSpawner object.

There are multiple ways to make your idea work. My two examples are supposed to show you how to express your logic and a “task” in a (hopefully) self-explanatory way. If you organise your code in a similar way, it’ll also be easier for you to identify flaws in the logic and to debug.

Please do share your progress. I’m curious. :slight_smile:

Thanks Nina. I really appreciate your help.

I’ve looked at the code examples you have provided but am having some troubles getting them to work. I assume I need to integrate them with my existing code somehow, as opposed to them being self-contained solutions.

I’m heading up north this weekend, but I look forward to jumping back into this on Monday. Would love to get this feature to work, but regardless of outcomes I’m learning a lot along the way.

Taking a break is a good idea. You often come up with new approaches when doing something else for a while.

If you grasped what I did in my code and what is going on in your code, you can certainly combine both or even develop a completely different solution. Have I already mentioned Debug.Logs? If not, definitely use them to see if the flow of the program follows your logic/concept. Sometimes it’s just a little detail hidden in a single line of code that prevents things from working as expected.

If I get stuck and if it becomes too complicated/complex to add my idea to existing code, I sometimes discard the current solution and write the stuff from scratch. That’s often faster than trying to cram my code somewhere. Do the same if necessary. You’ll learn a lot from that experience.

Thanks Nina.

Yeah, I have a feeling there is a small hiccup in the code somewhere that is preventing things from working. I’ll continue to look into it, but will move on if I can’t get things to flow. I can always come back later.

I really appreciate the help you have provided. Have a good one :slight_smile:

I managed to get the units to only appear once the player has enough energy to summon them, using the following script:

public class EnergyCheck : MonoBehaviour
{
public StarDisplay energyTotal;
[SerializeField] int defenderCost;

public void UpdateButtonColour()
{

    if (energyTotal.stars < defenderCost)
    {
        GetComponent<SpriteRenderer>().color = new Color32(41, 41, 41, 255);
    }
    else
    {
        GetComponent<SpriteRenderer>().color = Color.white;
    }
}


private void Update()
{
    UpdateButtonColour();
}

}

This script is added to each defender unit.

Need to drag the Star Text from the canvas into the Energy Total field.

Need to enter the energy cost of each unit into the Defender Cost field.

Need to adjust Rick’s StarDisplay script by changing the line from:

[SerializeField] private int stars = 100;

to:

[SerializeField] public int stars = 100;

Also keep Rick’s Defender Button script, but remove the lines that change unit transparency. So what is kept is:

public class DefenderButton : MonoBehaviour
{
[SerializeField] Defender defenderPrefab;

private void OnMouseDown()
{
    var buttons = FindObjectsOfType<DefenderButton>();
    foreach(DefenderButton button in buttons)
    {
        FindObjectOfType<DefenderSpawner>().SetSelectedDefender(defenderPrefab);
    
}

This will make defender units visible only when enough energy is available to summon them. It continues to select the unit when you click on them but no longer makes them visibly selected by doing so.

What is needed now is to create a selection box when units are clicked on - so you know which unit is selected.

I’m close to figuring this out, but I can’t quite get it to work properly.

What I have done so far, is created a game object with a sprite renderer component (I guess that’s a sprite? lol), and attached a sprite image of a box outline to it. I created one for each location on the quad, so there is a selection box positioned for each unit. I then deactivated each of them so they start disabled.

I then created a script called EnableSquare.cs:

{
public GameObject square;

private void OnMouseDown()
{
    square.SetActive(true);
}

I attached this script to each of the defender units in the quad, and dragged each unit’s respective selection box sprite to the Square field.

This works when you click on a unit - the selection box appears on the unit and the script that makes the units visible based on energy continue to work.

However, as you can tell from the code - once you click on the unit the graphic of the selection box stays there forever.

I am trying to figure out how to get the selection box to remove when a new unit is clicked on.

I have checked the Unity API, and tried the isActiveAndEnabled property, but cannot seem to get it to work. Was wondering if there are any other options I could check out.

What is needed now is to create a selection box when units are clicked on - so you know which unit is selected.

Do you know what an enum is? If not, look it up on DotNetPerls. You could define states for your buttons. Since you access all your buttons anyway, you could give the buttons colours or outlines or whatever depending on their current state. If you don’t know enums, check the examples on DotNetPerls, then you’ll probably understand what I mean by “depending on their current state”.

Well, if you make the outline visible by calling SetActive(true), you need the corresponding line to make the outline invisible again. Same method to call, you’ll just have to pass on false. And that value could depend on the “state” (see above).

From what I see what you posted, you have almost everything you need to make your idea work. What’s missing are one or two conditions, so Unity knows when to enable/disable stuff.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms