So, I have a list (using System.Collections.Generic) of a class ‘Item’. Four classes inherit from Item: MeleeWeapon, RangedWeapon, MagicWeapon, and Armor. I use upcasting (or downcasting, not sure which one it technically is) to get the information I need fairly regularly. I’m going to do my best to explain everything so no one will need to dive into the scripts below because they are quite lengthy. I have an ID based inventory system, and each item is ‘logged’ with the Item class, or classes that inherit from Item. All of the items are kept within a class ‘Database’. I have an custom editor script for database so I can add items a bit easier. I find myself having to keep a ‘reference’ variable of the type of inherited class (MeleeWeapon, RangedWeapon, MagicWeapon, and Armor) to later up/downcsat to the right type of class because all of the items are kept in a list of ‘Item’. This list is known as ‘visibleItems’ that I modify with the editor script. In the start method of the Database class, I transfer all of the visibleItems to a Dictionary for a better numerical order. Seems more suiting for an ID based inventory system. Is there a better way to work with this? I thought that keeping this list of ‘Item’ that consists of Item and its child classes would be the best approach, but I just don’t know anymore. And, my main issue is the fact that when I transfer everything over from visibleItems to the dictionaly of Items, everything seems to become just ‘Item’ and if it was supposed to be one of the child classes it appears to forget that data.
I currently only have two items in visibleItems, and both are ‘MeleeWeapon’, but they become Item when I start the game. They forget the variables that are declared within Melee.
Hopefully no one has to dig though this too much, but Ill list the scripts I mentioned. I want to note, though, that I will not include MagicWeapon, RangedWepaon, and Armor as they are blank. I also want to note that whenever I have switch statements that go through the different sub classes, MeleeWeapon is the only one you should worry about because I have not yet begun to implement the other weapons, so those statements are blank for the most part. You can also probably ignore most of the ditor script, but maybe note how I keep track of that reference variable I mentioned and what I do with it.
I will take any tips anyone has for me as well. The editor script isnt too unorganized, but I’m a bit more lax to organization in that compared to script that actually go in the game itself.
//Item.cs
using UnityEngine;
using System.Collections.Generic;
using Inventory;
[System.Serializable]
public class Item {
//DataBase Preference
public int id;
public string name;
public int maxStack;
public string icon;//Path to icon
public bool handEquippable = false;//NOT ARMOR, Weapon Only
public bool matchHandRotation = true;//Does the object always point a certain way (according to the player look direction)
public bool lockToHand = true;//Does the object lock itself to the players hand even if the animation attempts to take it far away
public string model;
public string fps_equipAnimation;//Path to animation
public string world_equipAnimation;//Path to animation
//Reference Variables
public ItemType type = ItemType.Generic;
//Constructor
public Item( ItemType iType = ItemType.Generic ) {
type = iType;
}
public Item( int iId, string iName, int iMaxStack ) {
id = iId;
name = iName;
maxStack = iMaxStack;
}
public Item( int iId, string iName, int iMaxStack, bool iHandEquippable, bool iMatchHandRotation, bool iLockToHand, ItemType iType = ItemType.Generic ) {
id = iId;
name = iName;
maxStack = iMaxStack;
handEquippable = iHandEquippable;
matchHandRotation = iMatchHandRotation;
lockToHand = iLockToHand;
type = iType;
}
}
//MeleeWeapon.cs
using UnityEngine;
using System.Collections.Generic;
using Inventory;
public class MeleeWeapon : Item {
//Preference Variables
public float damage;
public float range;
//Constructor
public MeleeWeapon() : base( ItemType.MeleeWeapon ) {
}
}
//Database.cs
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using Inventory;
public class Database : MonoBehaviour {
//Static Variables
public static Database database;
public static Dictionary<int, Item> items = new Dictionary<int, Item>();
//Preference Variables
public Item[] visibleItems;
void Start() {
if ( database == null ) {
database = this;
SetupDatabase();
} else {
Destroy( this );
}
}
private void SetupDatabase() {
for ( int i = 0; i < visibleItems.Length; i++ ) {
switch ( visibleItems*.type ) {*
-
case ItemType.Armor:*
_ items.Add( i, visibleItems as Armor );_
* break;*
* case ItemType.MeleeWeapon:*
_ items.Add( i, visibleItems as MeleeWeapon );
* break;
case ItemType.RangedWeapon:
items.Add( i, visibleItems as RangedWeapon );
break;
case ItemType.MagicWeapon:
items.Add( i, visibleItems as MagicWeapon );
break;
case ItemType.Generic:
items.Add( i, visibleItems );
break;
}
}
}
public static int FindItemIdByName( string name ) {
foreach ( KeyValuePair<int, Item> i in items ) {
if ( i.Value.name == name ) {
return i.Key;
}
}
return -1;
}
}
namespace Inventory {
public enum ItemType {
Generic,//Item base-class (non-eqippable)
Armor,
MeleeWeapon,
RangedWeapon,
MagicWeapon*
* }
public enum DualHandType {
SingleHandEquip,
BothHands,
LeftHandOnly,
RightHandOnly*
* }
}
//DatabaseEditor.cs*
* using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using Inventory;
[CustomEditor( typeof( Database) )]
public class DatabaseEditor : Editor {
Database db;
void OnEnable() {
db = (Database)target;
for ( int i = 0; i < db.visibleItems.Length; i++ ) {
Reininialize( i );
}
}
public override void OnInspectorGUI() {
int toRemove = -1;
for ( int i = 0; i < db.visibleItems.Length; i++ ) {
GUILayout.BeginVertical( “box” );
GUILayout.BeginVertical( “box” );
//Start:Intro*
Item item = db.visibleItems as Item;
* GUILayout.BeginHorizontal();
GUILayout.Label( "ID: " + ( i <= 9 ? “0” : “” ) + ( i <= 99 ? “0” : “” ) + i );
GUILayout.FlexibleSpace();
if ( GUILayout.Button( “Up”, GUILayout.Width( 50 ) ) )
MoveUp( i );
if ( GUILayout.Button( “Down”, GUILayout.Width( 50 ) ) )
MoveDown( i );
if ( GUILayout.Button( “Remove”, GUILayout.Width( 80 ) ) )
toRemove = i;
if ( GUILayout.Button( “Add At”, GUILayout.Width( 60 ) ) )
AddItem( i );
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label( “Name:” );
item.name = EditorGUILayout.TextField( item.name );
GUILayout.FlexibleSpace();
ItemType was = item.type;
item.type = (ItemType)EditorGUILayout.EnumPopup( “as”, item.type );
if ( was != item.type ) {
Reininialize( i );
}
GUILayout.EndHorizontal();
//End*
* GUILayout.EndVertical();
GUILayout.BeginVertical( “box” );
//Start:Generic*
* if ( item.type == ItemType.Generic ) {
GUILayout.BeginHorizontal();
GUILayout.Label( “Max stack:” );
GUILayout.FlexibleSpace();
item.maxStack = EditorGUILayout.IntField( item.maxStack );
GUILayout.EndHorizontal();
} else {
item.maxStack = 1;
}
GUILayout.BeginHorizontal();
GUILayout.Label( “Icon path:” );
GUILayout.FlexibleSpace();
item.icon = EditorGUILayout.TextField( item.icon );
GUILayout.EndHorizontal();
if ( item.type == ItemType.Generic ) {
GUILayout.BeginHorizontal();
GUILayout.Label( “Hand equippable:” );
GUILayout.FlexibleSpace();
item.handEquippable = EditorGUILayout.Toggle( item.handEquippable );
GUILayout.EndHorizontal();
} else {
item.handEquippable = true;
}
if ( item.handEquippable ) {
//item.dualHandType = (DualHandType)EditorGUILayout.EnumPopup( “Dual Hand Type:”, item.dualHandType );
GUILayout.BeginHorizontal();
GUILayout.Label( “Match hand rotation:” );
GUILayout.FlexibleSpace();
item.matchHandRotation = EditorGUILayout.Toggle( item.matchHandRotation );
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label( “Lock to hand:” );
GUILayout.FlexibleSpace();
item.lockToHand = EditorGUILayout.Toggle( item.lockToHand );
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label( “Model path:” );
GUILayout.FlexibleSpace();
item.model = EditorGUILayout.TextField( item.model );
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label( “Equip anim. path (FPS):” );
GUILayout.FlexibleSpace();_
item.fps_equipAnimation = EditorGUILayout.TextField( item.fps_equipAnimation );
_ GUILayout.EndHorizontal();
/
* GUILayout.BeginVertical( “box” );
GUILayout.Label( “FPS Animations” );_
for ( int j = 0; j < item.fps_animations.Count; j++ ) {
_ GUILayout.BeginHorizontal();
GUILayout.Label( “Anim. path (FPS):” );
GUILayout.FlexibleSpace();_
item.fps_animations[j] = EditorGUILayout.TextField( item.fps_animations[j] );
_ if ( GUILayout.Button( “X”, GUILayout.Width( 35 ) ) )_
item.fps_animations.RemoveAt( j );
_ GUILayout.EndHorizontal();
}
if ( GUILayout.Button( “Add FPS Animation” ) )_
item.fps_animations.Add( “null” );
_ GUILayout.EndVertical();
/
}
* //End*
* GUILayout.EndVertical();
if ( item.type != ItemType.Generic ) {
GUILayout.BeginVertical( “box” );
//Start:Specific*
* switch ( item.type ) {
case ItemType.Armor:
Armor armor = db.visibleItems as Armor;
GUILayout.BeginHorizontal();
GUILayout.Label( “Protection:” );
GUILayout.FlexibleSpace();
armor.protection = EditorGUILayout.IntField( armor.protection );
GUILayout.EndHorizontal();
break;
case ItemType.MeleeWeapon:
MeleeWeapon meleeWeapon = db.visibleItems as MeleeWeapon;
GUILayout.BeginHorizontal();
GUILayout.Label( “Damage:” );
GUILayout.FlexibleSpace();
meleeWeapon.damage = EditorGUILayout.FloatField( meleeWeapon.damage );
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label( “Range:” );
GUILayout.FlexibleSpace();
meleeWeapon.range = EditorGUILayout.FloatField( meleeWeapon.range );
GUILayout.EndHorizontal();
break;
case ItemType.RangedWeapon:
RangedWeapon rangedWeapon = db.visibleItems as RangedWeapon;
break;
case ItemType.MagicWeapon:
MagicWeapon magicWeapon = db.visibleItems as MagicWeapon;
break;
}
//
GUILayout.EndVertical();
}
GUILayout.EndVertical();
}
GUILayout.Space( 20 );
if ( GUILayout.Button( “Add Item” ) )
AddItem( -1 );
if ( toRemove != -1 )
Remove( toRemove );
//base.OnInspectorGUI();
}
void AddItem( int location ) {
if ( location == -1 ) {
Item newArray;
if ( db.visibleItems == null ) {
newArray = new Item[1];
} else {
newArray = new Item[db.visibleItems.Length + 1];
for ( int i = 0; i < db.visibleItems.Length; i++ ) {_
newArray _= db.visibleItems;
}
}
db.visibleItems = newArray;
} else {
Item newArray = new Item[db.visibleItems.Length + 1];
for ( int i = 0; i < location + 1; i++ ) {_
newArray _= db.visibleItems;
}
newArray[location + 1] = new Item();
for ( int i = location + 1; i < newArray.Length - 1; i++ ) {
newArray[i + 1] = db.visibleItems;
}
db.visibleItems = new Item[newArray.Length];
for ( int i = 0; i < newArray.Length; i++ ) {_
db.visibleItems _= newArray;
}
}
}
void MoveUp( int index ) {
if ( index == 0 )
return;
Item temp = db.visibleItems[index - 1];
db.visibleItems[index - 1] = db.visibleItems[index];
db.visibleItems[index] = temp;
}
void MoveDown( int index ) {
if ( index == db.visibleItems.Length - 1 )
return;
Item temp = db.visibleItems[index + 1];
db.visibleItems[index + 1] = db.visibleItems[index];
db.visibleItems[index] = temp;
}
void Reininialize( int index ) {
Item old = db.visibleItems[index];
switch ( db.visibleItems[index].type ) {
case ItemType.Armor:
db.visibleItems[index] = new Armor();
break;
case ItemType.MeleeWeapon:
db.visibleItems[index] = new MeleeWeapon();
break;
case ItemType.RangedWeapon:
db.visibleItems[index] = new RangedWeapon();
break;
case ItemType.MagicWeapon:
db.visibleItems[index] = new MagicWeapon();
break;
case ItemType.Generic:
db.visibleItems[index] = new Item();
break;
}
db.visibleItems[index].id = old.id;
db.visibleItems[index].name = old.name;
db.visibleItems[index].maxStack = old.maxStack;
db.visibleItems[index].icon = old.icon;
db.visibleItems[index].handEquippable = old.handEquippable;
db.visibleItems[index].matchHandRotation = old.matchHandRotation;
db.visibleItems[index].lockToHand = old.lockToHand;
db.visibleItems[index].model = old.model;_
db.visibleItems[index].fps_equipAnimation = old.fps_equipAnimation;
_ }
void Remove( int index ) {
Item newArray = new Item[db.visibleItems.Length - 1];
for ( int i = 0; i < index; i++ ) {_
newArray _= db.visibleItems;
}
for ( int i = index; i < db.visibleItems.Length - 1; i++ ) {
newArray = db.visibleItems[i + 1];
}
db.visibleItems = new Item[newArray.Length];
for ( int i = 0; i < newArray.Length; i++ ) {_
db.visibleItems _= newArray;
}
}
}
I couldnt get it to format correctly in seperate areas, so its all together with like 10 spaces between each. It consists of Item.cs, MeleeWeapon.cs, Database.cs and DatabaseEditor.cs. The namespace ‘Inventory’ is part of the database script, located at the bottom of it. FYI.
I also want to thank anyone who looks into this. I know it a lot of code to go through. I appreciate it a whole lot, as this is the foundation of a game I am working on and I care about it very dearly.
Thanks
-Michael*
PS: Going to bed, very late. I plan on checking back here early tomorrow! ~9-10hr_