问题
The full warning msg:
You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
Im trying to make an inventory to my game i followed the code from BLACKTHORNPROD but there is no stack item so i'm trying to modify the code. This is the Inventory script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public int[] items;
public List<Pickup> itemList;
public GameObject[] slots;
void start(){
}
void Update(){
// Debug.Log(itemList);
}
public Inventory(){
itemList = new List<Pickup>();
}
public List<Pickup> GetItemList(){
return itemList;
}
public void AddItem(Pickup item, int i, GameObject itemButton){
if (item.IsStackable()){
bool itemAlreadyInInventory = false;
foreach (Pickup InventoryItem in itemList){
if(InventoryItem.itemType == item.itemType){
InventoryItem.amount += item.amount;
itemAlreadyInInventory= true;
}
}
if(!itemAlreadyInInventory){
itemList.Add(item);
items[i] = 1;
Instantiate(itemButton, slots[i].transform, false);
}
}else{
itemList.Add(item);
items[i] = 1;
Instantiate(itemButton, slots[i].transform, false);
}
}
}
The pickup Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pickup : MonoBehaviour
{
public ItemType itemType;
public int amount;
// public ItemType[] itemTypes;
private Inventory inventory;
private GameObject slots;
public GameObject itemButton;
// Start is called before the first frame update
private void Start()
{
slots = GameObject.FindGameObjectWithTag("Player");
inventory = GameObject.FindGameObjectWithTag("Player").GetComponent<Inventory>();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
for (int i = 0; i < inventory.items.Length; i++)
{
if (inventory.items[i] == 0)
{
inventory.AddItem(new Pickup { itemType = itemType, amount = 1 }, i, itemButton);
Destroy(gameObject);
break;
}
}
}
}
public bool IsStackable()
{
switch (itemType)
{
default:
case ItemType.Arrow:
return true;
case ItemType.Bow:
case ItemType.Sword:
return false;
}
}
public enum ItemType
{
Bow,
Arrow,
Sword,
}
}
回答1:
As I see it the problem is this line:
itemList = new List<Pickup>();
You need to understand that if you add MonoBehaviour to a class then you cannot create them using "new" (As the warning message tells you). It helps to think of the PickUp-class as an UI-Element.
回答2:
The error is obviously coming from
inventory.AddItem(new Pickup { itemType = itemType, amount = 1 }, i, itemButton);
and probably also from
public Inventory()
{
itemList = new List<Pickup>();
}
it tells you exactly what is wrong so I guess that is not in question here. MonoBehaviour
may not be instantiate via new
nor have any constructor! The only way to create instances is by either using AddComponent
, Instantiate
or via the GameObject
constructor.
To solve this you should simply not use a List<Pickup>
but rather separate the data from the behavior e.g.:
public enum ItemType
{
Bow,
Arrow,
Sword,
}
// This will be the data type you pass on and store in your inventory
[Serializable]
public struct PickUpData
{
public ItemType itemType;
public int amount;
}
Then in the inventory
public class Inventory : MonoBehaviour
{
public int[] items;
public List<PickUpData> itemList = new List<PickUpData>();
public GameObject[] slots;
// Note: Remove empty Unity message methods they are just overhead
// Note: Inventory is a MonoBehaviour and therefore may not have any constructor!
// Do you need this? itemList is public anyway ...
public List<PickupData> GetItemList()
{
return itemList;
}
public void AddItem(PickUpData item, int i, GameObject itemButton)
{
if (item.IsStackable())
{
var itemAlreadyInInventory = false;
foreach (Pickup InventoryItem in itemList)
{
if(InventoryItem.itemType == item.itemType)
{
InventoryItem.amount += item.amount;
itemAlreadyInInventory= true;
}
}
if(!itemAlreadyInInventory)
{
itemList.Add(item);
items[i] = 1;
Instantiate(itemButton, slots[i].transform, false);
}
}
else
{
itemList.Add(item);
items[i] = 1;
Instantiate(itemButton, slots[i].transform, false);
}
}
}
and then in the Pickup instead have a field of PickUpData
which you can configrue just the same as the direct fields before and then pass it on
public class Pickup : MonoBehaviour
{
// This will hold the data you pass on and store in the inventory
// Since the struct is serializable and public this will be initialized with a valid
// reference by default
public PickUpData data;
private Inventory inventory;
private GameObject slots;
public GameObject itemButton;
// Start is called before the first frame update
private void Start()
{
slots = GameObject.FindGameObjectWithTag("Player");
inventory = GameObject.FindGameObjectWithTag("Player").GetComponent<Inventory>();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
for (int i = 0; i < inventory.items.Length; i++)
{
if (inventory.items[i] == 0)
{
inventory.AddItem(data, i, itemButton);
Destroy(gameObject);
break;
}
}
}
}
public bool IsStackable()
{
switch (itemType)
{
case ItemType.Bow:
case ItemType.Sword:
return false;
// default should always be on the bottom
case ItemType.Arrow:
default:
return true;
}
}
}
来源:https://stackoverflow.com/questions/62015651/im-getting-the-warning-you-are-trying-to-create-a-monobehaviour-using-the-new