- Home /
How can define item type in my item pickup system
Hi,
First let me explain what is a item: An item is a prefab that player can get it in the game and then some value add to his/her health, score,... .
Here is my interface and class (that is an item) that implemented interface:
Interface:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ArcadeCar
{
public interface IItem
{
bool isMoney
{
get;
}
bool isHealth
{
get;
}
void OnPickup();
}
public class ItemEventArgs : EventArgs
{
public ItemEventArgs(IItem item)
{
Item = item;
}
public IItem Item;
}
}
Class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ArcadeCar
{
public class AC_Item_Money : MonoBehaviour, IItem
{
public bool _isMoney;
public bool isMoney
{
get
{
return _isMoney;
}
}
public bool _isHealth;
public bool isHealth
{
get
{
return _isHealth;
}
}
public Transform _pickupEffect;
public void OnPickup()
{
//e.g we instantiate the pickupEffect and then destroy this gameobject
}
}
}
Now my question is how can i define item type (e.g health potion or money) and then in "gameController" script based on item type change player values?!
To answer you: your OnPickup
could take a Player
as parameter, so your gameController won't have to do anything. Your item would have the responsibility to increase the health / add itself to the inventory / add money ....
Thank you, I'll check this out. Now please exit my question from under moderation mode.
Answer by Hellium · May 03, 2020 at 10:23 AM
Here is how I would do it:
using UnityEngine;
namespace ArcadeCar
{
public abstract class AC_Item : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
Player player = other.GetComponent<Player>();
if(player != null)
OnCollectedByPlayer(player);
}
protected abstract void OnCollectedByPlayer(Player player);
}
}
namespace ArcadeCar
{
public class AC_Item_Money : AC_Item
{
[SerializeField] private int amount = 1;
protected override void OnCollectedByPlayer(Player player)
{
player.AddMoney(amount);
}
}
}
namespace ArcadeCar
{
public class AC_Item_Health : AC_Item
{
[SerializeField] private int amount = 1;
protected override void OnCollectedByPlayer(Player player)
{
player.Heal(amount);
}
}
}
namespace ArcadeCar
{
public enum PotionType { Health, Mana, Rage }
public class AC_Item_Potion : AC_Item
{
[SerializeField] private PotionType potionType;
protected override void OnCollectedByPlayer(Player player)
{
player.AddToInventory(potionType);
}
}
}
namespace ArcadeCar
{
// Facade design pattern
public class Player : MonoBehaviour
{
// Drag & drop the other components
[SerializeField] private Health health;
[SerializeField] private Inventory inventory;
[SerializeField] private Purse purse;
public void AddMoney(int amount)
{
purse.AddMoney(amount);
}
public void Heal(int amount)
{
health.Value += amount;
}
public void AddToInventory(PotionType potionType)
{
inventory.AddPotion(potionType);
}
}
}
I don't know what your "GameController" is supposed to do, but the less it does, the better.
If you want an entity to display the health or the money, then create specific entities. For instance:
using UnityEngine;
using UnityEngine.UI;
namespace ArcadeCar
{
public class PursePresenter : MonoBehaviour
{
// Drag & drop the other components
[SerializeField] private Purse purse;
[SerializeField] private Text;
private void Start()
{
// OnMoneyAmountChanged is an `public event Action<int>`
// invoked each time the amount of money in the purse is changed
purse.OnMoneyAmountChanged += UpdateUI;
}
private void UpdateUI(int moneyAmount)
{
Text.text = "Money: " + moneyAmount;
}
}
}
I just say Wow! This is very helpful, not for me but for everyone that want to know more about unity program$$anonymous$$g. So a question, my gameController has a method called ChangeHealth that changes player health, now it's better that i move ChangeHealth method to the Player script or it's place is okay?!
I would definitely advise you to have a dedicated component to manage the health, or at least, move the method in your Player script indeed.
OK, thank you so much for sharing your knowladge. How can i contact with you later?
Another thing that is wrong, is that abstract method can't be private, so i should public them. $$anonymous$$ake these method public isn't illegal?!
$$anonymous$$y bad, I fixed my answer. The method should be protected
Answer by Eh3an · May 02, 2020 at 10:55 PM
I checked Hellium answer, but if i use his method i can't control game from gameController script, this is very important that gameController controls all of game, and this is illegal that i access the player from Item script.
Now i use this way:
New interface:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ArcadeCar
{
public interface IItem
{
bool isMoney
{
get;
}
bool isHealth
{
get;
}
void OnPickup();
}
public class ItemEventArgs : EventArgs
{
public ItemEventArgs(IItem item)
{
Item = item;
}
public IItem Item;
}
}
New Class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ArcadeCar
{
public class AC_Item_Money : MonoBehaviour, IItem
{
public bool _isMoney;
public bool isMoney
{
get
{
return _isMoney;
}
}
public bool _isHealth;
public bool isHealth
{
get
{
return _isHealth;
}
}
public Transform _pickupEffect;
public void OnPickup()
{
//e.g we instantiate the pickupEffect and then destroy this gameobject
}
}
}
So now what is your idea about this way, do you have any suggestion?
this is very important that gameController controls all of game
This is a very, very bad idea. Your gameController will become a "God object" with hundreds or maybe thousands lines. Debugging such class will be a nightmare.
$$anonymous$$oreover, having the isHealth
and is$$anonymous$$oney
is also a very bad idea. What if you want other types of pickups? Will you add new getters to your interface (and thus, to all your classes implementing the interface)?
Okay, so what is your idea about this way:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace ArcadeCar
{
public class AC_Item : $$anonymous$$onoBehaviour
{
static AC_GameController gameController;
public bool is$$anonymous$$oney;
public bool isHealth;
//We can have more boolean (e.g isShield,...) and we can select multiple
void OnTriggerEnter(Collider other)
{
//Now here we can change health or score from gameController variable
}
}
}
Your answer
Follow this Question
Related Questions
How to add item to my inventory when I pick them up? 1 Answer
Item/Buff Selection UI 2 Answers
Picking up flashlight? 0 Answers
How to make sure score can't be increased by picking up same item multipe times--new idea 2 Answers
Best Way to do Regular Items and Weapons/Intractable/Special Items. 1 Answer