Farming Patches

Hey everyone, and hello @Brian_Trotter (if you’d like to join us. This is NOT a coding question, but me requiring some suggestions on what to do next)

OK so, I’m currently developing a Farming System, and I’m currently stuck on what to do next. My Farming System is a hybrid system of @bixarrio 's Crafting System, and the Unity Asset Store’s Easy Build System (the idea came to me when my old digging attempt was a disaster, xD), which will probably be later tuned to allow patches to only be “built” in restricted building areas (I need to read the documentation about this one)

but this question comes from lack of experience of gaming rather than a programming challenge. So, my question is, how do modern, or your favorite games of all time, handle farming? I’d like to know what makes them fun for you, just for me to get an idea of what to do

Currently I have a Patch, which can instantiate food that’s being farmed (and will need tuning), but I don’t know how to handle quantities.

I’m thinking of making the plants pickup-able, and to disable the entire Farming patch access until all vegetables are picked up off the ground, which also means adding a quantity counter to my Crafting UI (which will be a brand new challenge in and of itself, but essentially I want to keep the quantity counter only open for either farming items (up to 15 items, per farming dirt patch, that is), or stackable items). Anything else will not be allowed to use that quantity counter)

If anyone has any better ideas, now is a good time to introduce them :slight_smile:

Oh wait, I have a 3-script tight couple :sweat_smile: (that’s no good. Now I need a way out of this)

I have sent you observer pattern code in DMs

Yup, going through it, and trying to understand what’s going on (there’s a lot of complicated stuff there :sweat_smile:)

Complicated for me, that is

Sadly I prototyped something similiar to yours and used a patch of land(farmable) with 3 states(planted,growing, hungry(where it needed water) then used a raycast to see if i can plant then I created scriptable recipes basically that set up each seed witht he type and quanity it produces over time, I did set it so it all picksup at once then added to the Inventory and just reset the farmingland back to the default farmable state.

I mean this worked very simply and could have been expaneded apon using this method, but since you want to incorporate the building system, and crafting system into it. I personally don’t know how you could approach that but this is the simple approach I took. :laughing:

you’ll need an asset store asset called the “Easy Build System” for this, and I also opened a topic about it once. It’s quite a long topic tbh. Just search up “Construction System” on this website and I believe you’ll find it

As for the Crafting, ask bixarrio. He invented the system :slight_smile:

But this topic is quite challenging for me, mainly because I’m trying to break a tight couple in my code, combined with trying to do other things

I wouldn’t use Raycasts if I were you though. They will be computationally expensive if your land positions are dynamic and can be placed around a lot. I personally would just assign a prefab when crafting starts, and destroy it when the item is picked up

well me and @bixarrio successfully decoupled our notification system from our crafting table. It was an insanely long topic, but we solved it. All it took was an entire day :sweat_smile: (this guy is honestly a genius, and I’m honoured to be able to seek help from two brilliant people, him and @Brian_Trotter (and ChatGPT from time to time :stuck_out_tongue:)).

Tomorrow is a brand new challenge, adding and removing quantities from crafting. It’s high time this system gets introduced and limited for our needs (i.e: Disable it for non-stackable items, and when it comes to farming, make sure you can’t go beyond the count of slots available per patch)

and I need to fix a bug, by making sure no saving is allowed when the player is on the back of an animal. I know how to do this, just don’t know where to write it

I’m not a huge fan of farming games… but I’ll share one of the best implementations… in World of Warcraft.

Now WoW is a MMORPG, which you would think would complicate farming (because others might come along and steal your crops, right?) But what they did, and this was in the Mists of Pandaria expansion, is that they gave every player (once they discovered the area) a very small plot of land to farm with… They took advantage of instancing so that if you were in the plot of land’s boundaries, you were in your own tiny microuniverse. I couldn’t touch your crops because if I tried, I’d just find myself in my own tiny microverse.

So WoW handled this by giving players a set number of nodes within the plot… I think it was like 4x5 by the time you finished clearing all the weeds and rocks from the plot, which happened over time. Each node could get it’s own seed. You then needed to water the plant, and often you needed to weed the node or fight off a gopher.

Because these plants took often a day or two to mature, it wasn’t a complete time suck. Maybe 5-10 minutes a day and you would get ingredients that could be used to create interesting dishes in WoW’s cooking system.

Unlike games like FarmVille that are 100% time sucks with no redeeming value whatsoever.

OK that doesn’t sound too bad. I want to allow it to happen anywhere (BUT… I might enable building areas from the EBS system just to prevent insanity), and you potentially need to cover it up with some guard rails or something from wandering NPCs (they can’t jump), and maybe a water tower nearby can acceletate growth by 10% or something

I wanted to start with dirt patches that get prepared for farming, and then smoothed to dirt rows, etc etc, but… I can’t figure out a way to get that done if my construction system doesn’t have an Upgrade system to my knowledge, so I went straight to the dirt rows (i.e: finalized soil for farming) from the get go. I’m still convinced I can talk the EBS Developer into helping me develop an Upgrade System

but… I’m currently stuck at the step of "OK I only want to activate a ‘Quantity’ counter for my Farming System only, and deactivate it in all other systems, and it should only count up to how many more fruits this patch can handle. Essentially, deactivate it in one script, and reactivate it in another (I’m stuck with “I can’t find it in the other script for some NRE reason” to reactivate it. I haven’t got to the counter yet)

For the moment, we tuned the crafting system so it doesn’t have an output. The product will be a pickup that can be picked up off the ground (since food is non-stackable in the game, and it didn’t make sense with the current Crafting System to be given an output, especially with large farming patches), and the experience is, unlike the rest, given to you once you get the notification that your plant is fully grown, instead of once you come to collect your item from the Crafting Table (which, I might make destroyable down the line, not sure if I want to go that harsh path yet tbh). I already had something setup for that, so it didn’t take a lot to figure it out (just a little bit, to avoid tight coupling)

We wrote an entire ‘PlantGrowthHandler’ script just for that growth process

But you can’t eat it just yet. The output is a simple, empty ‘Food.cs’ script, which is waiting for a command to play an eating animation, and increase health (up to max health, that is), once clicked

hello again @Brian_Trotter - I need a little bit of help :slight_smile: - OK so here’s the problem:

I’m trying to activate and deactivate a quantity counter for my crafting system, so that it only works if, and only if, you’re using a farming patch (remember when I told you I mixed my Construction and Crafting Systems to come up with a farming system?), and here’s the (somewhat minor) problem:

The system works based on an ‘OnEnable()’ and ‘OnDisable()’ function, and through countless try and errors, this is as clean as it will ever get:

    void OnEnable() 
    {
        // Happens for a millisecond when the game scene starts, and then disabled 
        // by 'OnDisable', unless commanded by the 'Crafting UI' to open up
        Debug.Log($"Quantity Controller has been enabled");
        // Initialize the Quantity to the minimum value
        currentQuantity = minQuantity;
        UpdateQuantityText();

        // Add listeners to the buttons
        plusButton.onClick.AddListener(AddQuantity);
        minusButton.onClick.AddListener(SubtractQuantity);

        // Buttons' Image Components
        plusButtonImage = plusButton.GetComponent<Image>();
        minusButtonImage = minusButton.GetComponent<Image>();

        // Update button transparency
        UpdateButtonState();

        // The Crafting Table is opened by finding the nearest Crafting Table, so this approach just fits perfectly
        currentCraftingTable = craftingFinder.GetNearestTable();

        // Only activate the Quantity Controller if, and only if, the table near you is 
        // a farming table (i.e: it has a 'PlantGrowthHandler' as a child gameObject):
        plantGrowthHandler = currentCraftingTable?.GetComponentInChildren<PlantGrowthHandler>();
        if (plantGrowthHandler == null) 
        {
            Debug.Log($"Current Crafting Table has no Plant Growth Handler. Disabling QuantityController");
            this.gameObject.SetActive(false); // will go to 'OnDisable()'
            return;
        }
    }

    void OnDisable() 
    {
        // Quickly disables 'OnEnable' when the game scene starts, 
        // and also called when 'Crafting UI' Quit Button commands a shut down
        Debug.Log($"Quantity Controller has been disabled");
        plusButton.onClick.RemoveListener(AddQuantity);
        plusButton.onClick.RemoveListener(SubtractQuantity);

        if (!this.gameObject.activeSelf)
        {
            this.gameObject.SetActive(true);
        }
    }

(I don’t mind sharing the full script, but I didn’t want to overwhelm anyone)

This script is called ‘QuantityController.cs’, and it goes right on top of the Parent that controls the UI of the quantities we are controlling

The problem I have is, is that Unity each time I open a non-farming patch (i.e: ‘PlantGrowthHandler’ is not null), it’ll complain that the code is going to ‘OnDisable()’ really quickly, and it kinda makes sense tbh. Here’s what the error looks like:

GameObject is already being activated or deactivated.
UnityEngine.StackTraceUtility:ExtractStackTrace ()
QuantityController:OnDisable () (at Assets/Asset Packs/bixarrio/RPG Crafting System/Scripts/UI/QuantityController.cs:73)
QuantityController:OnEnable () (at Assets/Asset Packs/bixarrio/RPG Crafting System/Scripts/UI/QuantityController.cs:61)
RPG.Crafting.CraftingSystem:OnCraftingInteraction (RPG.Crafting.ICraftingTable) (at Assets/Asset Packs/bixarrio/RPG Crafting System/Scripts/CraftingSystem.cs:170)
RPG.Crafting.CraftingMediator:NotifyInteraction (RPG.Crafting.ICraftingTable) (at Assets/Asset Packs/bixarrio/RPG Crafting System/Scripts/CraftingMediator.cs:17)
RPG.Crafting.CraftingTable:NotifyCrafting () (at Assets/Asset Packs/bixarrio/RPG Crafting System/Scripts/CraftingTable.cs:90)
RPG.States.Player.PlayerCraftingState:Enter () (at Assets/Asset Packs/bixarrio/RPG Crafting System/Scripts/PlayerCraftingState.cs:29)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:13)
RPG.States.Player.PlayerFacingState:Tick (single) (at Assets/Project Backup/Scripts/State Machines/Player/PlayerFacingState.cs:35)
RPG.States.StateMachine:Update () (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:18)

Do you know of an alternative solution to go around this? (I tried modifying it from bixarrio’s CraftingSystem.cs script, which looks exactly like the copy he gave you, but it needed that ‘extra step’ of opening and shutting it down once, before it worked again. So, this is the most accurate, but troublesome solution, I can get so far)

Any idea how to fix this? (I didn’t get to the point of making this actually work just yet)

Does that not create a nasty stack overflow… In OnEnable you are disabling the object - which will let OnDisable execute, and then in OnDisable you enable it again - which will let OnEnable execute, cue stack overflow.

Also, I don’t think your CraftingSystem script looks like the one @Brian_Trotter has because we made changes. I also need to revisit mine because I noticed there are things in there that we did for your version and it shouldn’t be there.

compiler doesn’t say so :sweat_smile: - the if statement in OnDisable seems to be limiting it to once only, and that ‘once only’ only happens each time I open a non-farming patch Crafting UI. I tried disabling it in ‘CraftingSystem.CloseCrafting’, but it needed that ‘one extra step’ (i.e: when it comes to farming, shut it down once, and then re-enable it before it works again), so I eliminated that approach and went with this one, straight in ‘QuantityController.cs’. I even built the game, and that problem seems to be ignored there

Any better ideas? (You may want to have a look at your DMs for that one. It’s a whole-lot more detailed there) - I just don’t like seeing errors in the debugger :sweat_smile:

On a second quick glimpse, kinda true. I just noticed I even got stuff I added on my own in there at some point, to classify the systems apart

The CraftingSystem was made for crafting, not farming in the way you want to do it.

I don’t know what your UI setup looks like but you can probably have a ‘holder’ for the quantity UI and have it control that.

CraftingSystem UI
   |
   +- Holder
         |
         +- Quantity UI

On the holder I’d put a script that Enables/Disables the Quantity UI

public class QuantityHolder : MonoBehaviour
{
    [SerializeField] GameObject quantityUI;
    public void ActivateQuantityUI(bool isActive)
    {
        quantityUI.SetActive(isActive);
    }
}

Then just call that when the CraftingSystem opens (you’ll need a reference to the holder

private void OnCraftingInteraction(ICraftingTable craftingTable)
{
    // somewhere between the other code that makes sense
    var plantGrowthHolder = craftingTable.GetComponentInChildren<PlantGrowthHolder>();
    quantityHolder.ActivateQuantityUI(plantGrowthHolder != null);
}

This is terrible, really, because the CraftingSystem now needs to know about PlantGrowthHolders and stuff.

I guess the better way would’ve been to have the crafting table supply its own UI to the crafting system (as a prefab) and then the crafting system could just instantiate it and hook into events and stuff it needs to know about. That way, each crafting table can specialise in whatever it wants to without polluting the crafting system. When (if) I revisit the crafting system I’d look into that. I want to create ‘workstation’ based crafting like Enshrouded and Conan at some point where you dump resources into its little inventory, choose a recipe and it will craft for as long as there are resources available, dropping the result into the same little inventory. We’ll see.

There you go:

OK based on reading what you said, isn’t that exactly what I’m doing…?! I placed the ‘QuantityController.cs’ script on the parent of the entire Quantity Controller, and I tried making the changes in ‘CraftingSystem.OnCraftingInteraction’ and ‘CraftingSystem.CloseCrafting()’ before, but again, it needed an extra step, so there was an obvious glitch

and here’s the full ‘QuantityController.cs’ script, for your convenience, if you need it:

using RPG.Crafting;
using RPG.Farming;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class QuantityController : MonoBehaviour
{
    public int maxQuantity = 100;
    public int minQuantity = 1;
    private int currentQuantity;

    public TextMeshProUGUI quantityText;
    public Button plusButton;
    public Button minusButton;

    private Image plusButtonImage;
    private Image minusButtonImage;

    // CraftingFinder relies on CraftingTable, so this is perfectly fine 
    // (no Circular Dependencies)
    // (i.e: 'QuantityController' -> 'CraftingFinder' -> 'CraftingTable')
    private CraftingFinder craftingFinder;
    private CraftingTable currentCraftingTable;

    // Plant Growth Handler
    private PlantGrowthHandler plantGrowthHandler;

    void Awake() 
    {
        craftingFinder = FindObjectOfType<CraftingFinder>(); // Get it off the Player
    }

    void OnEnable() 
    {
        // Happens for a millisecond when the game scene starts, and then disabled 
        // by 'OnDisable', unless commanded by the 'Crafting UI' to open up
        Debug.Log($"Quantity Controller has been enabled");
        // Initialize the Quantity to the minimum value
        currentQuantity = minQuantity;
        UpdateQuantityText();

        // Add listeners to the buttons
        plusButton.onClick.AddListener(AddQuantity);
        minusButton.onClick.AddListener(SubtractQuantity);

        // Buttons' Image Components
        plusButtonImage = plusButton.GetComponent<Image>();
        minusButtonImage = minusButton.GetComponent<Image>();

        // Update button transparency
        UpdateButtonState();

        // The Crafting Table is opened by finding the nearest Crafting Table, so this approach just fits perfectly
        currentCraftingTable = craftingFinder.GetNearestTable();

        // Only activate the Quantity Controller if, and only if, the table near you is 
        // a farming table (i.e: it has a 'PlantGrowthHandler' as a child gameObject):
        plantGrowthHandler = currentCraftingTable?.GetComponentInChildren<PlantGrowthHandler>();
        if (plantGrowthHandler == null) 
        {
            Debug.Log($"Current Crafting Table has no Plant Growth Handler. Disabling QuantityController");
            this.gameObject.SetActive(false); // will go to 'OnDisable()'
            return;
        }
    }

    void OnDisable() 
    {
        // Quickly disables 'OnEnable' when the game scene starts, 
        // and also called when 'Crafting UI' Quit Button commands a shut down
        Debug.Log($"Quantity Controller has been disabled");
        plusButton.onClick.RemoveListener(AddQuantity);
        plusButton.onClick.RemoveListener(SubtractQuantity);

        if (!this.gameObject.activeSelf)
        {
            this.gameObject.SetActive(true);
        }
    }

    void AddQuantity() 
    {
        if (currentQuantity < maxQuantity) 
        {
            currentQuantity++;
            UpdateQuantityText();
            UpdateButtonState();
        }
    }

    void SubtractQuantity() 
    {
        if (currentQuantity > minQuantity) 
        {
            currentQuantity--;
            UpdateQuantityText();
            UpdateButtonState();
        }
    }

    void UpdateQuantityText() 
    {
        quantityText.text = currentQuantity.ToString();
    }

    void UpdateButtonState() 
    {
        // Update the Plus Button state
        if (currentQuantity >= maxQuantity) 
        {
            plusButton.interactable = false;
            Color plusColor = plusButtonImage.color;
            plusColor.a = 0.5f;
            plusButtonImage.color = plusColor;
        }
        else 
        {
            plusButton.interactable = true;
            var plusColor = plusButtonImage.color;
            plusColor.a = 1f;
            plusButtonImage.color = plusColor;
        }

        // Update the Minus Button state
        if (currentQuantity <= minQuantity) 
        {
            minusButton.interactable = false;
            var minusColor = minusButtonImage.color;
            minusColor.a = 0.5f;
            minusButtonImage.color = minusColor;
        }
        else 
        {
            minusButton.interactable = true;
            var minusColor = minusButtonImage.color;
            minusColor.a = 1f;
            minusButtonImage.color = minusColor;
        }
    }
}

No, you are disabling the object. In my case the object is disabling it’s child meaning it stays active forever, but its children are being disabled. No issues with OnEnable and OnDisable

You also have a whole lot of FindCraftingTable stuff which is completely unnecessary because the crafting system knows which crafting table it’s working with. You just need to pass it down to it

OK so just to be clear, because I’m a tad bit confused, I will go to ‘OnCraftingInteraction’ and add this code, based on my script naming?:

// initialize the QuantityController in 'OnEnable()' of 'CraftingSystem.cs'

private void OnCraftingInteraction(ICraftingTable craftingTable)
{
    // somewhere between the other code that makes sense
    var plantGrowthHolder = craftingTable.GetComponentInChildren<PlantGrowthHolder>();
    quantityHolder.ActivateQuantityUI(plantGrowthHolder != null);
}

and activate it from there? Man is a little confused right now because of the difference of names of the script

I didn’t change any of your script names. I don’t know what you’re saying here.

  1. You create the QuantityHolder.cs like I said
  2. Create a serialized reference to it in the CraftingSystem
  3. Move the Crafting Quantity into a parent object
  4. Put the QuantityHolder script on the parent object
  5. Drag it into the crafting system field you created in 2.
  6. Add the code I provided to OnCraftingInteraction

OK let me just get this straight. Based on this map:

and this diagram:

what is ‘QuantityController.cs’ called? I just want to get rid of the confusion for this part

Crafting Quantity

Based on your image

Crafting UI
 |
 +- Crafting Window
     |
     +- Crafting Controls
         |
         +- Quantity Holder <- Mine with QuantityHolder.cs
             |
             +- Crafting Quantity <- Yours with QuantityController.cs

there’s no ‘GetComponentInChildren’ in ‘craftingTable’, since it’s an interface :sweat_smile: (I still don’t know how you got an interface to work with all of this instead of a normal script, but for now I’m just following along)

no hate, but I personally prefer the classic approach of ‘choose how much you want to craft’. I find it more intuitive for everyone, but that’s just me :smiley:

I renamed it to ‘CraftingQuantity.cs’, so I can keep up with your commands

Privacy & Terms