I am trying to create a basic (very, very basic) inventory system in Unity though C#, and am having trouble deciding how to use arrays. Would it be best to have a different multidimensional array for each inventory slot, with each dimension carrying the integer values of item data? Or use a jagged array , with each "jag" representing a different value of item data? Or is there a better solution that doesn't use arrays? I plan to have around 40-50 inventory slots, and each item having around 10-15 aspects, so neither option seems simple. Any help would be appreciated. Thanks in advance!
The more you divide up the objects are the better. You should normalize the objects as much as possible, being said separate a chair object to multiple parts and have chair inherit / instantiate some generalized properties. I believe the following would explain better;
class Item
{
public string Name { get; set; }
public int Quantity { get; set; }
public Properties Props { get; set; }
}
class Properties
{
public int Weight { get; set; }
public int Height { get; set; }
// All of the possible properties here...
}
The Item has a field called Props which is global for a lot of objects / items in your game, and Item is an object that can refer to many things. If you construct your objects like this, you can use them over and over again instead of creating separate objects for each feature in your game.
Then you can finally create the inventory as the following;
var Inventory = new List < Item > {
new Item {
Name = "Bullet", Quantity = 100, Props = new Properties {
Height = 10, Weight = 10
}
}
};
Edit:
Upon your request, I will try to explain the code a bit more. Lists are generic classes that holds data for you. You could create an array as well but Lists are more dynamic, and you may eventually have sizing issues with Arrays more than with lists. Please check https://msdn.microsoft.com/en-us/library/6sh2ey19%28v=vs.110%29.aspx for more information on Lists.
I believe the second part is the one you may be having a tough time with. The following pseudo code should explain it better.
Class Item { Fields, Properties }
Class Properties { Fields }
new Inventory = List of <Items> ( New Item Class(es))
As you see above, we create List of Items and the Inventory type would be List as well since it would host items.
I hope it makes better sense now.
Related
In my application, I have a desired flow to create an object.
Just for demonstration, I will say my object is a "Pokemon". So I have an interface for "Pokemon" with stats that are relevant to all of them, something like:
public interface IPokemon
{
string Type { get; set; }
public static List<SelectListItem> TypeList { get; }
int HPStat { get; set; }
int ATKStat { get; set; }
int DEFStat { get; set; }
int SPATKStat { get; set; }
int SPDEFStat { get; set; }
}
I then have an abstract Pokemon class:
public abstract class Pokemon : IPokemon
{
public static List<SelectListItem> TypeList { get; } = new List<SelectListItem>
{ new SelectListItem { Value = "Bulbasaur", Text = "Bulbasaur" },
new SelectListItem { Value = "Squirtle", Text = "Squirtle" },
new SelectListItem { Value = "Charmander", Text = "Charmander" }
};
// also implements each of the int Stats
}
In the HTML, I bind the select to the TypeList, for the string Type on the IPokemon interface. The object passed from the server is a Bulbasaur by default.
<select asp-for="Type" asp-items="IPokemon.TypeList"></select>
When I try to POST the result, there is an error because an IPokemon cannot be initialized.
I understand why the error occurs, but I'm having trouble figuring out what is the best way to structure this interaction as a whole. I assumed I want to return a different model object depending on which the user selects, but I'm also thinking I might have a wrong interpretation of how this should be structured in general.
After this step, I figured I would create the correct model Object depending on what was returned, and then continue in the creation process by allowing certain options dependent on which Pokemon class was chosen in this first step. An example; if Squirtle were chosen on this step I'd want to move to a page that allows selection of different "water type" moves.
Any clarification or pointing to resources to learn how to achieve this is welcome.
Here are a few pointers:
Firstly, I wonder if you actually wanted to make your Pokemon.TypeList static?
At the moment, the way you have it means that every object of type Pokemon (or any of its sub-classes) will have a list of all of the Pokemon types. This seems like a lot of data duplication.
Secondly, in your combo box you have asp-items="IPokemon.TypeList" but the TypeList object is currently sitting in the Pokemon class, and not in the IPokemon interface.
I expect this is a typo and that you're actually wanting to point to Pokemon.TypeList.
Furthermore, you wouldn't really have a list of types sitting withiin an interface anyway really. They'd be better sitting in the base class or even just off in their own static class somewhere else.
Thirdly, regards structure: If all of your Pokemon objects are inheriting from your abstract base class, it would seem to me to make more sense to have all of your abstract IPokemon methods sitting in your base class, as adding an extra interface only really adds complexity here.
I remember reading one thing in terms of stuff like inheritance and interfaces that's stuck with me: When inheritance trees are taught in an academic context, it's done with the premise that you're going to have a very hierarchical inheritance structure (e.g. classes A and B inherit from class C , class C and D inherit from class E) whereas in the real world your inheritance structures tend to be very flat (as in, classes A, B, C, and D all inherit from class E) Things are just a lot simpler to do this way.
Hope these pointers make sense to you! If not, hit me up with a question
New to multidimensional arrays and a bit stuck on a little project I am working on.
Getting a error when I try to store 2 arrays (student and teacher) in to a course array, when creating them as class arrays
Below is the code from my main()
Student stud1 = new Student("Alex", "Kelly", DateTime.Parse("14/07/2000"));
Student stud2 = new Student("Tom", "Smith", DateTime.Parse("16/08/198
Student stud3 = new Student("Mary", "Jones", DateTime.Parse("10/01/1998"));
//add students to an array and get the count
Student[] studentArray = new Student[3] { stud1, stud2, stud3 };
int count1 = studentArray.Length;
//add teacher objects
Teacher prof1 = new Teacher("Beckham");
Teacher prof2 = new Teacher("Pele");
Teacher prof3 = new Teacher("Maradonna");
Teacher[] teacherArray = new Teacher[3] { prof1, prof2, prof3 };
//course Object
Course course1 = new Course("Programming with C#");
Course[,] courseList = new Course[,] { {studentArray} , { teacherArray } };
I am getting the error on the last line shown, when I try to add the { studentArray, teacherArray } to the courseList array.
The error is
cannot implicitly convert type Student[] to Course
If I change the array from Course to object [,] it works fine
Do I need to add something to my class file?
It looks like you code can be refactored.
For example, why don't your Course class look like:
class Course
{
public string Name;
public List<Student> Students;
public List<Teacher> Teachers;
}
It is more natural and object-orianted way. In this case you don't need two-dimensional array, and you can use only List<Course>.
Also note - in many cases List<T> is more convinient then T[] array sincу it is resizing automatically.
The error you are experiencing is because Course array will only allow objects of Course type. You cannot place other objects or arrays with it.
To resolve your problem, it might be better to have the Student and Teacher arrays as a properties of the Course object. These can then be assigned values as needed.
See:
https://msdn.microsoft.com/en-us/library/9b9dty7d.aspx for information on arrays.
https://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx for information on properties.
Update following edit
The object[,] array will work because object is the base type for all other types. As a result of this, an object[] can have any other type assigned to it. As you indicate you are learning to program so it might be worth reading up on object oriented design - It will help you model your data better. For a starting point try https://msdn.microsoft.com/en-us/library/dd460654.aspx.
What you should try to do is use OBJECT ARRAYS . This array will store the the different objects and it will also retain their form .
Check out this link . Its quite detailed on this topic.
enter link description here
To extend on a previous answers, always think about how you separate up your data. For example, the Course itself is a very 'static' concept compared to the attendees and the tutors. The Course could even have different dates with different attendees etc but will not change whereas dates and those involved will.
So your model could be:
public class CourseSchedule
{
public CourseSchedule(Course course, Student[] students, Teacher[] teacher)
{
this.Course = course;
....
}
// Some sort of Date too
public Course Course { get; private set; }
public IEnumerable<Student> Students { get; private set; }
public IEnumerable<Teacher> Teachers { get; private set; }
}
Multi-dimensional arrays are worth understanding but are specific to certain types of programming - graphics, mathematical transforms etc. You tend to use them for low level coding but for modelling real world structures such as your course booking they are generally not appropriate.
this question is probably going to be a bit confusing, as I'm just starting c# and object-oriented coding in general, but I'll do my best to explain things clearly! For context, I'm trying to make a random dungeon generator for a game project.
I have the jagged array "Dungeon," which I've declared like this:
public Level[][,] Dungeon;
To clarify, Dungeon is a 1D array of "Levels." A level is its own object, and it has a few unique properties that I defined in its constructor.
Each level is a 2D array of "mazePieces," which are also objects.
I've figured out how to refer to the entire Dungeon array to do things such as see how many levels are in the dungeon:
Dungeon[x].Length
I also can refer to individual mazePieces in a given level:
Dungeon[i][x,y].mobAmount
However, I can't figure out how to refer to the properties of an entire Level. If I type in
Dungeon[i].numberOfRooms
"numberOfRooms" is not recognized as a property of the level. However, I've found that it will be recognized if I type
Dungeon[i][,].numberOfRooms
The issue I'm running into is that the second set of brackets are marked with a syntax error, saying that a value is expected.
What can I put into the second set of brackets so I can refer to the entire level rather than just a specific part of the level?
Hopefully this was at least somewhat understandable, please let me know and I'll do my best to clarify! Thanks!
You could use a little more composition in your design. Maybe something like this:
class Dungeon {
public Level[] Levels { get; private set; }
class Level {
public int NumberOfRooms
{ get { return Maze.GetUpperBound(0) * Maze.GetUpperBound(1); }
public MazePiece[,] Maze { get; private set; }
}
class MazePiece {
private List<Mob> _mobs = new List<Mob>();
public IEnumerable<Mob> Mobs { get { return _mobs; } }
public int MobCount { get { return _mobs.Count; } }
}
class Mob {
public string Name { get; private set; }
}
Then you can more naturally refer to things:
var mobsAtTenTenOfLevelThree = dungeon.Levels[2].Maze[9, 9].Mobs;
I would say that pieces of maze should be a part of Level class,
So you would have
public Levels[] Dungeon.
Also your Level class would have indexer:
public SomeReturnType this[int x, int y]
{
get
{
// return maze piece
}
}
In this case you would be able to access to any level property via Dungeon[i].numberOfRooms. And you still would be able to access to maze pieces like you want Dungeon[i][x,y].mobAmount
Assuming numberOfRooms is a property of MazePiece, if you want to find a total for the dungeon you can use SelectMany:
int totalRooms = dungeon.SelectMany(p=>p.numberOfRooms).Sum();
I may be missing basic knowledge here, but i ll go for it and ask it.
Lets say we have an array of strings:
ItemCode
ItemDescription
and we have a class:
public class InventoryItem
{
public string ItemCode { get; set; }
public string ItemDescription { get; set; }
}
I want to be able to reference the properties of an InventoryItem dynamically based on the values of the array.
I need to loop through the array and get the value of the property of the class by the current string member of the array.
How can i do it?
You use reflection:
foreach (var name in propertyNames)
{
// Or instance.GetType()
var property = typeof(InventoryItem).GetProperty(name);
Console.WriteLine("{0}: {1}", name, property.GetValue(instance, null));
}
See:
Type.GetProperty
Type.GetProperties (to find them all)
PropertyInfo.GetValue
Jon Skeet's answer is absolutely correct (does he have any other kind?) and works well if you'd need to dynamically access say 1000 InventoryItem objects. But if you need to dynamically access more objects, say 10 million, reflection starts to be painfully slow. I have a little helper class I made a while ago that can easily access a property about 26 times faster than reflection (at least on my computer) by creating and compiling a dynamic method to access the property. It's nowhere near as fast as accessing it statically, but since you need to access it dynamically that's not even a consideration. Here's how you use it:
var accessor = new DynamicPropertyAccessor(typeof(InventoryItem).GetProperty("ItemCode"));
foreach (var inventoryItem in warehouse13)
{
Console.WriteLine("{0}: {1}", accessor.Name, accessor[inventoryItem]);
}
You can also use it to set a value with: accessor[item] = "newValue". And you can have a collection of accessors if you need to access several properties dynamically. The performance gain will be substantial when you create a DynamicPropertyAccessor once per property and reuse to access many objects (or the same object many times).
I've posted the DynamicPropertyAccessor class here: https://gist.github.com/3059427
I'm working on a personal project for a friend and have hit a bit of a roadblock. I can continue as I am and write some really redundant code, but I feel there must be a more efficient way of doing this.
What I'm trying to do is write a method that will add three values and display the results to the text box under "Skill Modifier" header (see screenshot). I need to get the method, or a series of methods, to do that for each skill. It needs to get the Skill Modifier value for Balance, Climb, Escape Artist, etc...
The method would be something like "CalculateSM"
What I have currently:
private void btnUpdate_Click(object sender, EventArgs e)
{
//AM + R + MM =SM
//AM = Ability Modifier
//R = Rank
//MM = Misc Modifier
//SM = Skill Modifier
decimal balanceMod = balanceAM.Value + balanceR.Value + balanceMM.Value;
balanceSM.Text = balanceMod.ToString();
decimal climbMod = climbAM.Value + climbR.Value + climbMM.Value;
climbSM.Text = climbMod.ToString();
//etc...
}
Essentially the biggest issue, for me, is figuring out how to contrive a method that can deal with so many different field names and add them in the same way. I'd like to avoid copy and pasting the same two lines of code fifty times over for each and every skill.
Any ideas would be much appreciated! Thank you.
using fields like this is not very object-oriented. you're probably going to want to introduce a Skills class that implements the method to calculate the final skill score and then use some Skills objects for different skills.
public class Skill
{
int ability, rank, misc;
public Skill(int ability, int rank, int misc)
{
this.ability = ability;
this.rank = rank;
this.misc = misc;
}
public int Score { get { return ability + rank + misc; }
}
Skill balance = new Skill(10, 1, 1);
textBalance.Text = balance.Score.ToString();
Skill programming = new Skill(10, 100, 0);
textProgramming.Text = programming.Score.ToString();
also, think of a clever way to tie the skills to your user controls. you're not going to like ending up with 50 text boxes that are all alike except for a bit of a name. a first step could be to wire them all up to the same event handler, for example.
Normally, the approach would be to create a class which represents one row of your skills screen. You could then keep a list of these in some way (say, List<Skill>). You could then quite easily loop through all of them:
foreach (Skill skill in character.Skills)
{
// do something with the skill object
}
The trick would be to dynamically generate the user interface. It's not actually very hard to do this (although a bit too much code to go into here), by far the easiest approach would be to use something like a DataGridView. It should be fairly easy to google for examples, or just ask if you want specific info.
Looks like you have an object collection which you could databind to something in the UI (like a data grid or something)
Modify the values calculate things, what you could do in some example code:
class Skill
{
public string Name { get; set; }
public string KeyAbility { get; set; }
public int SkillModifier { get; set; }
public int AbilityModifier { get; set; }
public int Ranks { get; set; }
public int MiscModifier { get; set; }
void Calculate()
{
//Formula goes here
//Set the SkillModifier
}
}
Skill balance = new Skill() { Name = "Balance" }
Basically you can make a collection of skills, update through what ever UI object you bind to etc. Using fields the way you are atm is very redundant and using OO you can achieve the same with alot less work.
Basically in You'd create a collection of the Skill class, with Balance and all other skills you mentioned. Databind this collection to something in the UI, allow for updating, call different methods. You could even implement some inheritance for different type of skills. With a Skill base class.
What type are balanceAM, balanceR etc?
Can they not derive from a base type or interface that you can use to pass to a helper method?
private string GetText(IModel modelAM, IModel modelR, IModel modelMM)
{
return modelAM.Value + modelR.Value + modelMM.Value;
}
balanceSM.Text = this.GetText(balanceAM, balanceR, balanceMM);
Ok, the fact that you only have private fields for each individual control is your core problem. You're probably better off creating a list of structs to store them:
struct PickYourOwnNameHere
{
Control SM;
Control AM;
Control R;
Control MM;
}
List<PickYourOwnNameHere> skills = new List<PickYourOwnNameHere>();
Obviously, populate that list on initialization, and then you can just do:
skills.ForEach(skill =>
skill.SM.Text = (skill.AM.Value + skill.R.Value + skill.MM.Value).ToString()
);
I'm doing that syntax from memory, but hopefully you get the idea.