Construction System

LOL… I was about to tell you that this thing ain’t working, until I realized the automatic action button was the left mouse button (I dropped an item and was still able to construct the foundation, and a little later… I find it in my inventory, and I was wondering why is disappearing stuff spawning into my inventory. Low and behold, it hits me that, well, my action button is the left mouse key (gotta set that to ‘E’ and delete the other buttons soon lel))

Anyway, I apologize man. I’ll be quiet xD

Here’s what you can do;

Open UICircularBuildingMenu.cs and find the CircularButtonSettings class inside it. Add this

[SerializeField] BuildingRecipe m_Recipe;
public BuildingRecipe Recipe { get { return m_Recipe; } set { m_Recipe = value; } }

In the circular menu, you need to set the recipe now

Open UICircularBuildingMenuButton.cs and add this

[SerializeField] BuildingRecipe m_Recipe;
public BuildingRecipe Recipe { get { return m_Recipe; } set { m_Recipe = value; } }

Find the SetButton(...) method and add this at the bottom

m_Recipe = circularButton.Recipe;

Your button now knows what the recipe is that it is meant to build. You can now use that recipe to change the color of the text if the player doesn’t have the required ingredients.


Simple ingredient check in SetButton(...) to make the text red if the ingredients aren’t available
(Edit Just found out this last part doesn’t work. The buttons are set at startup, so it only knows what’s in the inventory at startup. Will look into it)

Back in UICircularBuildingMenu.cs find the SelectBuildingPart(...) and add this to the top

BuildingRecipe recipe = m_SelectedButtonSettings.Recipe;
if (recipe != null && !HasAllRequiredItems(recipe.GetIngredients())) return;

The button will now do nothing if the player doesn’t have the ingredients.

As for the consumption of resources, this is a little more complicated. The menu goes away and the BuildPlacer goes into a placing state. I’m still trying to figure out how to do this. It may be more beneficial to ask the author where to do this. He has a far better understanding of the code and will know.

Hey man, I’ll give this a go in the morning and keep you updated

Trust me, I did. He didn’t even answer my message 6 days ago, let alone the new one (he’s purposely ignoring me since I asked him for help regarding the saving system)

For the build placer to swap to building the item, it’s under “BuildingManager.PlaceBuildingPart()”

Hey man, OK I’m done placing your code in (not sure how you changed the color, but I’m guessing it’s something you placed in as well, because mine isn’t). A few errors here and there forced me to uncomment some of my other code, but all is good for now I suppose… any updates about resource consumption from the inventory? :slight_smile:

Changing this discussion to a “Talk” topic before it overwhelms our “Ask” section.

1 Like

It was just an example, I didn’t send the code. As I mentioned, it doesn’t work because the buttons are created at startup when you may not have the ingredients, yet.

Nope, took a break after a while because I needed to get rest. I still have to work during the day. Will look at it again tonight

No worries fam, will wait to hear from you :slight_smile:

hey @bixarrio - Andrew responded, and this is what he told me about consuming resources from the inventory, in the way I want it to do so (which is right before an item is placed in the game world):

“Hi, sorry for the late response, and I hope you’re managing. To answer your question, you can scroll up in the conversation. I had sent you the methods for that.
The idea is to use: BuildingManager.Instance.OnPlacingBuildingPartEvent.AddListener((BuildingPart part) => { });
This event is triggered ‘after’ you have placed your building part. In this way, resources are not consumed when you switch to preview mode but only when you validate the placement.”

I myself am a bit confused on exactly how we can use that to consume inventory products, but I hope it helps in anyway (I am yet to investigate it)

You may want to have a look at ‘UICircularMenu.Start()’ and ‘UICircularBuildingMenuForRPGBuilder.Start()’

The main problem I have now is, how do we feed this event with data about our recipe so it consumes the right recipe resources?

Not sure if this will work or not, neither do I know how I’ll do it, but this is my plan in ‘BuildingManager.PlaceBuildingPart()’, to use the event Andrew mentioned:

            Instance.OnPlacingBuildingPartEvent.AddListener((BuildingPart part) => 
            {
                // It's all happening in 'BuildingManager.cs', so I assume the 'buildingPart' scripts are right under it:
                foreach (BuildingPart buildingPart in GetComponents<BuildingPart>()) 
                {
                    // 1. Get the building part identifier
                    // 2. if they match, get the 'RequiredIngredientsBuildingCondition.cs' script attached to that object
                    // 3. Loop over the ingredients in 'BuildingRecipe.cs' attached to that script
                    // 4. Consume the resources in that loop
                }
            });

Edit 2: Here’s what I managed to create so far, but it’s not working for some reason…:

Instance.OnPlacingBuildingPartEvent.AddListener((BuildingPart part) => 
            {
                Debug.Log("listener for placing building part event");
                var playerInventory = Inventory.GetPlayerInventory();
                
                foreach (BuildingPart buildingPart in GetComponents<BuildingPart>()) 
                {
                    // 1. Get the building part identifier
                    string identifier = buildingPart.GetGeneralSettings.Identifier;
                    Debug.Log($"identifier: {identifier}\n part Identifier: {part.GetGeneralSettings.Identifier}");
                    // 2. if they match, get the 'RequiredIngredientsBuildingCondition.cs' script attached to that object
                    if (identifier == part.GetGeneralSettings.Identifier) 
                    {
                        RequiredIngredientsBuildingCondition buildingCondition = GetComponent<RequiredIngredientsBuildingCondition>();
                        // 3. Get the recipe for that building
                        BuildingRecipe recipe = buildingCondition.GetBuildingRecipe();
                        // 4. Loop over the ingredients in 'BuildingRecipe.cs', attached to that script
                        foreach (var craftingItem in recipe.GetIngredients()) 
                        {
                            // 5. Consume the resources in that loop
                            playerInventory.RemoveItem(craftingItem.Item, craftingItem.Amount);
                        }

                    }

                }
            });


What I’m trying to do above, is scan through the ‘BuildingManager.cs’ children, and find the ID of the parts inside that GameObject… (the ‘Building Manager’ script has a list of GameObjects attached to it), and compare it to the ID of what we currently have. If they match, get their building conditions, and from there we can get the building recipe. Using that recipe, we can consume the resources needed from the inventory

I know for a fact that the listener is indeed being called the moment the player constructs the part, because the first line of debugging works. However, after that, whatever is in the loop is not working for some reason… (6 hours later, I figure it’s because the GetComponent gets nothing, literally, so the loop doesn’t even start to begin with, and I have no idea why). Do you think you or @Brian_Trotter (sorry Brian for luring you into this again… :sweat_smile: ) can please have a look at it?

I placed this event-listening script in ‘BuildingManager.PlaceBuildingPart()’

Ah, this is good news. I will check it out.

1 Like

Well, you didn’t want to use the conditions, so the RequiredIngredientsBuildingCondition does not exist for you. You won’t find a condition that doesn’t exist.

Now, for consumption;
You can create a component called PlayerBuildResourceConsumer that will just sit and wait for the BuildingManager to tell it that a building was placed and then remove the ingredients. But, to do that we kinda need something like the above condition to hold the recipe. This then also means that some of the other code you did way earlier can use this, too. Each building part prefab will now need this recipe class

public class BuildingPartRecipe : MonoBehaviour
{
    [field: SerializeField] public BuildingRecipe BuildingRecipe { get; private set; }
}

It’s really just metadata. It will hold the recipe for that specific BuildingPart (naming is up to you. It’s already getting pretty confusing)

Next, you will create the PlayerBuildResourceConsumer that will wait for a building to be placed and consume the resources. It goes on the player object

public class PlayerBuildResourceConsumer : MonoBehaviour
{
    private Inventory inventory;

    private void Awake()
    {
        // cache the player inventory
        inventory = GetComponent<Inventory>();
    }

    private void OnEnable()
    {
        // Bind to the building manager
        BuildingManager.Instance.OnPlacingBuildingPartEvent.AddListener(OnBuildingPartPlaced);
    }

    private void OnDisable()
    {
        // release the building manager
        BuildingManager.Instance.OnPlacingBuildingPartEvent.RemoveListener(OnBuildingPartPlaced);
    }

    public void OnBuildingPartPlaced(BuildingPart buildingPart)
    {
        // a building was placed, consume the resources
        // 1. get the recipe from the BuildingPartRecipe
        var buildingPartRecipe = buildingPart.GetComponent<BuildingPartRecipe>();
        // 2. Consume each ingredient
        foreach(var item in buildingPartRecipe.BuildingRecipe.GetIngredients())
            inventory.RemoveItem(item.Item, item.Amount);
    }
}

Now it works, but you have an issue because you didn’t want to use the conditions. We got to this point because the player had the ingredients, but now they’ve used some ingredients and may not have enough anymore. The building system doesn’t go back to the menu, it allows you to place more of that part, and the check has already been passed, so no more checking. It’s time to re-introduce the condition

public class RequiredIngredientsBuildingCondition : BuildingCondition
{
    public override bool CheckPlacingCondition()
    {
        var buildingRecipe = GetComponent<BuildingPartRecipe>().BuildingRecipe;

        // Check if we have the required items in our inventory
        var inventory = Inventory.GetPlayerInventory();

        foreach (var craftingItem in buildingRecipe.GetIngredients())
        {
            if (!inventory.HasItem(craftingItem.Item, out int amount)) return false;
            if (craftingItem.Amount < amount) return false;
        }

        return true;
    }
}

It’s a little smaller now, because it, too, needs to be on each BuildingPart and it can now get the recipe from the BuildingPartRecipe script.

A building part should now have these

With this in place, everything works like you want except for the text on the circular menu. I haven’t looked into that further. Maybe tomorrow

wait, which part was that again…? :sweat_smile:

I’ll go through all this and update you when I’m done testing it :slight_smile:

and… that worked marvelously, thank you @bixarrio

The next step I took was to naturally integrate my skilling system into this one. It took a little bit of thinking and re-reading the scripts we integrated and created (my main issue was, how to get the skill level for the specific part, and a line of code in “UICircularBuildingMenu.SelectBuildingPart()”, specifically the line defining the recipe, accidentally gave it away, so I knew that integrating it in ‘BuildingRecipe.cs’ was ideal, and it worked (against all odds for me lel). You can check my previous edit for more details about what my issue was), but in the end it was possible for me to make it :slight_smile: - anyway, here is how I want the text to go, if possible:

Basically, split the description text to two: one for the ingredients, one for the level. The level text will always be red, and always visible if the player highlights an item that his construction level is not up to just yet. If it’s equal to that level at the very least, then it’ll go away, and it will vanish when he reaches the level. The ingredients will toggle between red and white. Red when you’re short on stuff, white when you got the resources (I’m guessing a foreach loop), and it’ll never vanish (unlike the skill level requirement one)) - I’ll give this a go after work or something :slight_smile:

OK so, I gave the text thing a shot. I did not go through coloring it yet, but I managed to get it to work as expected within the engine itself. Here is what I managed to code so far:

in ‘BuildingRecipe.cs’:

private string description;

public string GetDescription()
        {
            SkillStore skillStore;
            skillStore = GameObject.FindWithTag("Player").GetComponent<SkillStore>();

            string level = "Requires level " + GetRequiredLevel() + " Construction";
            string recipe = "";

            foreach (var craftingItem in GetIngredients())
            {
                recipe += "Requires " + craftingItem.Item.GetDisplayName() + " x" + craftingItem.Amount.ToString() + "\n";
            }

            if (description == null) return null;
            else description = skillStore.GetSkillLevel(Skill.Construction) < GetRequiredLevel() ? level + "\n" + recipe : recipe;
            return description;
        }

in ‘UICircularBuildingMenu.cs’, around line 360, I coded this:

// The line I replaced:
// m_UICircularSelectionDescription.text = selectedButton.UIDescriptionText;

            // Test (NEW CODE):
            BuildingRecipe recipe = m_SelectedButtonSettings.Recipe;
            
            if (recipe == null) {
            m_UICircularSelectionDescription.text = selectedButton.UIDescriptionText;
            }
            else 
            {
                m_UICircularSelectionDescription.text = recipe.GetDescription();
            }

It works well in the game engine itself, but for some unknown reason, when I build the game, it does not show up… like at all (the description over there is basically gone, only for the items that can get their recipes from the ‘BuildingRecipe.cs’ script. Other items with direct descriptions aren’t suffering with this problem). What might be the cause of this? @bixarrio

Your GetDescription() is returning null. Always. I don’t have any idea how it can work in the editor. You never set description so when it gets to the end it checks if (description == null). It is, so it returns null

half of my Unity life, in one sentence :stuck_out_tongue_winking_eye:

and… yup, that was the issue (lol I was about to start an investigation on ‘OnValidate()’, because once it caused a similar issue for me with the Dialogue next button). Thank you @bixarrio :slight_smile: - I’ll work on figuring out how to color them in a while (when I get a break from work), should be simple (hopefully)

The only reason I had that line, was because earlier it was complaining about NREs for some reason

You can use tags (I do) to color text

textField.text = "This text is <color=red>RED</color>";
// or
textField.text = "This text is <color=#ff0000>RED</color>";

that goes in the ‘UICircularBuildingMenu.cs’, right? OR… GetDescription()?

Whereever you want it

lol I’m really confused on how to use these two lines, or where… NGL (if this comment isn’t deleted, then I haven’t figured it out…)

All I did was show you how to make text have color. You put it where you want it.

Privacy & Terms