Other
Script function being applied to everything it's attached to logic error
Hello,
I have a script that is attached to produce stands within my game. Whenever a produce stand is out of stock via customers picking from them; I have the player able to walk up to it, hold down a button and restock it. My problem seems to be that if one produce stand is out of stock, and I go to refill it, every produce stand that is currently out of stock is refilled. I have an indicator on the UI show up when the player is next to a produce stand that needs stocked, but it doesn't show up near any but one even though it's detecting all of them. You are still able to hold the button down on the ones not showing the UI to restock and it will restock all of them as well. I would appreciate help on finding this logic bug, as I am not able to find it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Restock_Logic_UI : MonoBehaviour
{
// UI elements
public Image Progress_Bar;
public GameObject Holder;
// Quicktime numbers
public float Amount_Held;
[HideInInspector] public float Max_Held = 1;
//References
public Restock_Logic Restock_Logic_Ref;
void Update()
{
Logic();
Check_Progress();
}
void Logic()
{
if (!Input.GetKey(KeyCode.E) && Progress_Bar.fillAmount < 1 && Progress_Bar.fillAmount > 0)
Degrade();
if (Progress_Bar.fillAmount >= 1)
Remove_UI();
}
public void Check_Progress()
{
if (Amount_Held < 0)
Amount_Held = 0;
}
public void Display_Progress()
{
Progress_Bar.fillAmount = (Amount_Held / Max_Held);
}
public void Quicktime()
{
Amount_Held += Time.deltaTime;
}
void Degrade()
{
Amount_Held -= Time.deltaTime;
}
public void Remove_UI()
{
Holder.SetActive(false);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Restock_Logic : MonoBehaviour
{
GameObject Player, Clone;
public GameObject Restock_Indicator;
public int Amount_Stocked;
[HideInInspector] public int Max_Stock = 15;
public bool Out = false, Allow_Send_Indicator = true;
// References
public Restock_Logic_UI UI_Ref;
public Player_Logic Player_Logic_Ref;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
Amount_Stocked = 0;// Random.Range(0, 15);
}
void Update()
{
Stand_Status();
if (Input.GetKeyDown(KeyCode.Space))
Amount_Stocked--;
}
void Call_For_Restock()
{
Vector3 New_Position = transform.position + new Vector3(0, 2, 0);
Clone = Instantiate(Restock_Indicator, New_Position, Quaternion.identity);
Clone.transform.rotation = Quaternion.LookRotation(transform.position - Player.transform.position);
Allow_Send_Indicator = false;
}
void Stand_Status()
{
if (Amount_Stocked <= 0)
Out = true;
if (Out && Allow_Send_Indicator)
Call_For_Restock();
if (Out)
{
if (UI_Ref.Amount_Held >= UI_Ref.Max_Held)
{
this.Amount_Stocked = this.Max_Stock;
Destroy(Clone);
Player_Logic_Ref.Customer_Content_Bonus++;
Player_Logic_Ref.Gain_Points(200);
UI_Ref.Remove_UI();
Out = false;
Allow_Send_Indicator = true;
}
if (Vector3.Distance(transform.position, Player.transform.position) <= 3 && this.Amount_Stocked < this.Max_Stock)
{
UI_Ref.Holder.SetActive(true);
UI_Ref.Restock_Logic_Ref = this.transform.GetComponent<Restock_Logic>();
UI_Ref.Display_Progress();
UI_Ref.Check_Progress();
if (Input.GetKey(KeyCode.E))
UI_Ref.Quicktime();
}
else if (Vector3.Distance(this.transform.position, Player.transform.position) >= 3)
UI_Ref.Remove_UI();
}
}
}
Answer by WeirdBeardDev · Aug 19, 2020 at 07:19 PM
What's the distance between the player and all the stands? On line 106, your if statement checks if the distance is 3 or less. Every stand in a 3 unity radius will be affected.
Perhaps you could use a trigger collider on the stand so it sets a variable to true when the player is near and false when the player moves away. Then update your if statement to check that this variable is true and only then restock.
EDIT: Update the if (Out)
statement to include a check against the variable.
Checking the position from the player to the stands should yield the UI showing up whenever I'm next to one of the stands, but it seems to be the case that the UI does in fact not pop up like it's supposed to, yet retains all functionality otherwise.
Yes but what's the actual distance between the player and the stands. According to the logic you currently have every stand within 3 units will be affected.
I did a check to see if multiple stands were being picked up at once and only one is being picked up at a time.
Stands = GameObject.FindGameObjectsWithTag("Produce_Stand");
foreach (GameObject st in Stands)
{
if (Vector3.Distance(transform.position, st.transform.position) <= 3 && !Nearby_Stands.Contains(st))
Nearby_Stands.Add(st);
else
Nearby_Stands.Remove(st);
}
Answer by Sneakyshot4012 · Aug 19, 2020 at 08:02 PM
It is set to the restock_logic_ui script that is attached to the player. I have not tried using the debugger. I will try that now.
Okay, so I used the debugger, and I figured this was the issue in the first place, but from what I'm seeing the "this" keyword keeps changing rapidly, as in every time I click the continue button in the debugger, "this" references a different produce stand which means that the script is confused on what it's referencing possibly?
Ahh, this script is attached to every stand and on every update it is called. You have to account for that in your logic. In my game I have a similar situation where I have multiple ExplorationZone
objects, and each zone has an enum ExplorationZoneType
associated with it, so I can use logic like if (ZoneType == ExplorationZoneType.Plains)
. I don't think this will work for you. You need a better way to detect exactly which stand the player is near and only then do the refill check. You could add a collider set to trigger to the stand and when the player collides with it set playerNearby = true
then update your refill check to include that item. It should only be true in a single stand at a time, assu$$anonymous$$g the colliders aren't overlapping.
On line 109 you have UI_Ref.Restock_Logic_Ref = this.transform.GetComponent<Restock_Logic>();
- if I'm reading it correctly you are making the UI_Ref.Restock_Logic_Ref equal to the current script. Why not just use this
which in this context would be the same as this.transform.GetComponent<Restock_Logic>()
. It probably has nothing to do with your issue, my brain just keeps getting locked on it. :)
After implementing your suggestions, I am still having the issue where only one stand seems to allow the UI to show up when you're next to it. Every other stand's UI doesn't show up, yet can still be stocked.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Restock_Logic : $$anonymous$$onoBehaviour
{
GameObject Player, Clone;
public GameObject Restock_Indicator;
public int Amount_Stocked;
[HideInInspector] public int $$anonymous$$ax_Stock = 15;
public bool Out = false, Allow_Send_Indicator = true, Player_Near_$$anonymous$$e = false;
// References
public Restock_Logic_UI UI_Ref;
public Player_Logic Player_Logic_Ref;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
Amount_Stocked = 0;// Random.Range(0, 15);
}
void Update()
{
Stand_Status();
if (Input.GetKeyDown(KeyCode.Space))
Amount_Stocked--;
}
void Call_For_Restock()
{
Vector3 New_Position = transform.position + new Vector3(0, 2, 0);
Clone = Instantiate(Restock_Indicator, New_Position, Quaternion.identity);
Clone.transform.rotation = Quaternion.LookRotation(transform.position - Player.transform.position);
Allow_Send_Indicator = false;
}
void Stand_Status()
{
if (Amount_Stocked <= 0)
Out = true;
if (Out && Allow_Send_Indicator)
Call_For_Restock();
if (!Player_Near_$$anonymous$$e)
UI_Ref.Remove_UI();
if (Out)
{
if (UI_Ref.Amount_Held >= UI_Ref.$$anonymous$$ax_Held)
{
this.Amount_Stocked = this.$$anonymous$$ax_Stock;
Destroy(Clone);
Player_Logic_Ref.Customer_Content_Bonus++;
Player_Logic_Ref.Gain_Points(200);
UI_Ref.Remove_UI();
Out = false;
Allow_Send_Indicator = true;
}
if (Player_Near_$$anonymous$$e && this.Amount_Stocked < this.$$anonymous$$ax_Stock)
{
UI_Ref.Holder.SetActive(true);
UI_Ref.Restock_Logic_Ref = this;
UI_Ref.Display_Progress();
UI_Ref.Check_Progress();
if (Input.GetKey(KeyCode.E))
UI_Ref.Quicktime();
}
}
}
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
this.Player_Near_$$anonymous$$e = true;
}
void OnTriggerExit(Collider other)
{
if (!other.transform.Equals(Player))
this.Player_Near_$$anonymous$$e = false;
}
}