How to use method(s) to add multiple, changing values - c#

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.

Related

C# How to to indicate relationship between properties to the user of a class?

I have a class that looks like this:
public class House
{
public string Address {get; set;}
private int _numberOfBedrooms;
public int NumberOfBedrooms
{
get { return _numberOfBedrooms; }
set
{
_numberOfBedrooms = value;
_groundPlanIsObsolete |= true;
}
}
private int _numberOfBathrooms;
public int NumberOfBathrooms
{
get { return _numberOfBathrooms; }
set
{
_numberOfBathrooms = value;
_groundPlanIsObsolete |= true;
}
}
private bool _groundPlanIsObsolete;
private myFloorPlan _groundPlan;
public myFloorPlan GroundPlan
{ get
{
if(_groundPlanIsObsolete)
_groundPlan = new myFloorPlan(NumberOfBedrooms, NumberOfBathrooms);
_groundPlanIsObsolete &= false;
return _groundPlan;
}
}
}
new myFloorPlan(NumberOfBedrooms, NumberOfBathrooms) is a very lengthy function.
I want to call it as rarely as possible.
Is this bad design?
I don't like my current design, because from a user point of view, it is not clear, which properties will have an effect on GroundPlan.
This has two disadvantages:
If one of them is not set, and the user tries to get the GroundPlan I could throw an exception, but is there a "nicer" way to let him know before he makes the mistake?
I would like to encourage the user to make up his mind about the number of rooms before calling the GroundPlan, to prevent frequent computationally heavy updates.
Should I indicate this?
Or is this something that should be documented in the comment section of the properties?
And:
How could I indicate this?
Make House immutable and use proper encapsulation.
You can combine immutability with fluent syntax easily in C# to build your object:
House house = new House();
house = house.AddBedrooms(2);
Code for House:
class House
{
int _numberOfBedrooms;
public House()
{
}
public House AddBedrooms(int numberOfBedroomsToAdd)
{
House house = new House();
house._numberOfBedrooms = _numberOfBedrooms + numberOfBedroomsToAdd;
return house;
}
//etc...
}
It's a bit more work, but it provides proper encapsulation. Putting getters/setters on domain objects is nasty. There are more advanced patterns which split the building of the object into a builder but the principle is the same. You could then use fluent syntax on your builder.
I would like to encourage the user to make up his mind about the number of rooms before calling the GroundPlan, to prevent frequent computationally heavy updates.
I would recommend passing NumberOfBathrooms and NumberOfBedrooms through as parameters on the method, that way it's clear to the user what the dependencies are. Or, if you want to keep them as properties perhaps pass them through on the constructor and make the properties read only.

Basic Inventory System Using Arrays

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.

Base Class Distribution Issue

So I'm currently writing an API, but I've hit a road block in construction. The issue is a series of values will constantly be called throughout, which requires a lot of parameters to be constantly pushed into series of classes and methods throughout the API.
Which is not very elegant nor practical. As it will induce a large amount of extra code.
My thought was originally was this:
public class CustomerProfile
{
public string ParentSite { get; private set; }
public string DynamicSite { get; private set; }
public string SiteDb { get; private set; }
public CustomerProfile(string parentSite, string dynamicSite, string siteDb)
{
if (string.IsEmptyOrNull(parentSite) &&
string.IsEmptyOrNull(dynamicSite) &&
string.IsEmptyOrNull(siteDb))
{
throw new Exception("Error Message: + "\n"
+ "Null value exception...");
}
else
{
ParentSite = parentSite;
DynamicSite = dynamicSite;
SiteDb = siteDb;
}
}
}
So my thought was to have a nice class that will set the properties, will act like a container for these repeatable values.
However, my issue seems to come from the next class.
public class Configuration
{
public CustomerProfile profile;
public Configuration(string parentSite, string dynamicSite, string siteDb)
{
CustomerProfile profile = new CustomerProfile(parentSite, dynamicSIte, siteDb);
}
}
This now works throughout the class I would just use profile.SiteDb or another property that resides within it.
But is this really the best approach?
I could use simple inheritance, but I'm not really sure that is cleaner or more efficient. Any thoughts on the matter would be terrific?
Is this approach the more ideal to pass property values from one class to another, as it will be used throughout several and several methods as well. I was looking for the cleanest way to invoke.
So my question is:
Out of all the ways to pass properties, what way is the best and why?
I thought this approach would be best but as I begin to use it
throughout it seems like it may not be the most ideal.
Thank you.

How do I refer to properties of object array inside jagged array in c#?

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();

A Game Design Solution for mapping large property data sets with many mutations that can be applied.

I'm having some trouble coming up with a sound design for what to me is a fairly tricky module. The actual business logic got me in a terrible mess, so I rephrased it into a more readily understandable form. I'm coding in C#, although I guess the actual design is language agnostic.
Imagine you're coding a simple fantasy roleplaying game. You have a player, who has some basic attributes. The player can equip some items, which may impact his attributes in some way. Items have one or more properties, which define which attributes are modified.
public Character
{
public string charName;
public int charStrength;
public int charHitPoints;
...
public List<Item> equippedItems;
}
public Item
{
public string itemName;
public List<ItemProperty> itemProperties;
}
public ItemProperty
{
public int propertyValue;
public virtual void applyPropertyModification(Character charStatsToBeModified){}
}
Character data is in XML format:
<Character>
<Name>John Doe</Name>
<BaseStrength>10</BaseStrength>
<BaseHitPoints>100</BaseHitPoints>
<Items>
<Item>
<Name>Short Sword</Name>
<Properties>
<Strength>10</Strength>
<HitPoints>200</HitPoints>
</Properties>
</Item>
</Items>
<Character>
I'm looking for a way to load a character data from XML which allows me to easily add X generic new character attributes (imagine 50 or so) and/or Y generic item Properties (imagine 100-150 or so).
My design thoughts:
Each possible character attribute gets added to the Character class as a new property. May get unwieldy as number of attributes grows large. Each possible Item Property is added as its own subclass of ItemProperty, with an appropriate applyPropertyModification method.
public Strength : ItemProperty
{
public override void applyPropertyModification(Character charStatsToBeModified)
{
charStatsToBeModified.charStrength += this.propertyValue
}
}
This does seem like a large amount of excessive code, especially since all the overwridden method is doing is determining which character attribute should be modified.
The ItemProperty is to be created using reflection, with the element XML tags corresponding to appropriate ItemProperty subclasses (alternative would be a 100 condition switch I think?).
Is my general design sound, or am I approaching this is the wrong direction? I'm not knowledgeable enough to figure this out by myself, but I'm convinced there is a neater way to do this. Also, if this question is unclear at all, or rambling, please let me know and I will try to clarify/rephrase. Thanks.
Ok a few people here were on the right path... but nobody hit the nail on the head so here it goes. It seems like you started on the right path but need to take it a bit further. I wrote this with comments in the code to let it do a bit of the explanation for me.
Here goes:
//So you have a character...
public class Character
{
//You know you ALWAYS need Raw Attribs in a game
private Dictionary<string, Attrib> _rawAttributes;
//You know you will always need a record of modified attribs
private Dictionary<string, Attrib> _modifiedAttributes;
//And while your at it, take a light optimization to not have to recalculate everytime
private bool _areModifiedAttribsCurrent { get; set; }
//A character has gear! This is what makes the world go around
public List<Equipment> Equipment { get; private set; }
//You don't want to give public access to setting gear, this should be controlled.
//You'll want to do more as far as remove / change... but this'll get you started
public void AddEquipment(Equipment e)
{
Equipment.Add(e);
_areModifiedAttribsCurrent = false;
}
//And a way to add attribs and set base values..
//once again, you will want more but this will get you started
public void AddAttribute(Attrib x)
{
_rawAttributes.Add(x.Name, x);
}
//Finally you want a way to fetch the modified attribs
//Keep in mind you need to do the copy dance in the apply to not upset your
//base stats.
public Dictionary<string, Attrib> FetchModifiedAttributes()
{
if (!_areModifiedAttribsCurrent)
{
var traceAttribs = _rawAttributes;
foreach (var e in Equipment.OrderBy(x => x.ApplyOrder))
{
traceAttribs = e.ApplyModifiers(traceAttribs);
}
_modifiedAttributes = traceAttribs;
}
return _modifiedAttributes;
}
}
//Attrib, pretty simple.. Could go away but we all know attribs have effects so don't even start down that path
//You WILL need this class later on... but right now it looks pretty meaningless.
public class Attrib
{
public string Name { get; set; }
public decimal Value { get; set; }
}
//GEAR... yes, this is what all RPG lovers love...
//Grind for that awesome gear!
public class Equipment
{
//Ok so I put in some stuff unrelated to your problem but you need a name right?!
public string Name { get; set; }
//What order does gear effect stats... this is important if you do more than flat modifiers.
public int ApplyOrder { get; set; }
//What modifiers does this gear have?!
public List<Modifier> ItemModifiers { get; set; }
//Aha.... let the gear apply its modifiers to an attrib dictionary... I knew I loved OO for some reason
public Dictionary<string, Attrib> ApplyModifiers(Dictionary<string, Attrib> inParams)
{
//Copy / Clone... Whatever you want to call it this is important as to not
//unintentionally screw up yoru base collection.
var response = new Dictionary<string, Attrib>();
foreach (var m in ItemModifiers)
{
//If we have this attrib, keep going
if (inParams.ContainsKey(m.TargetName))
{
//If this is the first time the response ran into it, add it
if (!response.ContainsKey(m.TargetName))
{
response.Add(m.TargetName, inParams[m.TargetName]);
}
//And wait what's this... let the Modifier apply it!?
//yes... pass it down again... you'll see why in a second.
m.Apply(response[m.TargetName]);
}
}
return response;
}
}
//A modifier... what the!?
//Yep... abstraction is key to maintainable and expandable code
public class Modifier
{
public string TargetName { get; set; }
public decimal ModifierValue { get; set; }
//The other stuff is kind of pointless... but this is where the magic happens... All in a modifier type.
public ModifierType ModifierType { get; set; }
//Let the modifier apply it's own values... off the type... yea
//I did that on purpose ;-)
public void Apply(Attrib a)
{
a.Value = ModifierType.ApplyModifier(this, a.Value);
}
}
//Decoration... Wonderful
//This base class gives you a interface to work with... Hell, it could be an interface but I decided
//to type abstract today.
public abstract class ModifierType
{
public abstract string ModifierName { get; }
public abstract decimal ApplyModifier(Modifier m, decimal InitialValue);
}
//A concrete type of ModifierType... This is what determines how the modifier value is applied.
//This gives you more flexibility than hard coding modifier types. If you really wanted to you could
//serialize these and store lambda expressions in the DB so you not only have type driven logic, you could have
//data driven behavior.
public class FlatModifier : ModifierType
{
//The names can be really handy if you want to expose calculations to players.
public override string ModifierName { get { return "Flat Effect"; } }
//And finally... let the calculation happen! Time to bubble back up!
public override decimal ApplyModifier(Modifier m, decimal InitialValue)
{
return InitialValue + m.ModifierValue;
}
}
Let your objects do the work for you. I know it's coming from XML but let them deserialize into your objects and call a few choice methods to handle it. This keeps a few of the nagging issues at bay like C# is by reference and all that annoying stuff. Also it keeps from redundant processing passes from jacking up your object graph.
Let me know if you have any questions... I'm bored tonight.
So you Character type has hundreds of properties / fields, and you want to simply set the value of those fields based on the XML element name?
The easiest solution would be to simply read the XML element and construct a Dictionary<string, string> that contains your values. Then, for each element of your dictionary, if your Character type exposes a matching property / field from your dictionary key, attempt to set the value of the property via reflection with that value. AKA:
Character someCharacter = // Create your character
Dictionary<string, string> myDictionary = // Load XML and transform
var properties = someCharacter.GetType().GetProperties();
foreach(KeyValuePair<string, string> kvp in myDictionary)
{
var matchingProperty = properties.FirstOrDefault(x => x.PropertyName.ToLower() == kvp.Key.ToLower());
if(matchingProperty != null)
{
matchingProperty.SetValue(character, kvp.Value, null); // make sure to type convert if necesary here, since kvp.Value is a string, etc
}
}
You write the code once, and thus you can add properties to your XML / Object and be able to override as you please.
Instead of using refection. Change the xml to match something like this
<Items>
<Item name="Short Sword">
<Properties>
<Property name="Strength" type="int">10<Property>
<Propery name="HitPoints" type="int">200</HitPoints>
</Properties>
</Item>
</Items>
Parse it based on the attributes into a Dictionary<String,Dynamic>, implement the indexer
e.g.
private Dictionary<String, Dynamic> _properties = new Dictionary<String,Dynamic>();
public dynamic this[Strng argIndex]
{
get {return _properties[argIndex];}
}
Carry this forward in to characters and such and you can do fun stuff like
characters["Fred"].Hitpoints = characters["Fred"].Items["Short Sword"].Hitpoints * characters["Fred"].Experience["Blades"]
Once you've defined the propertybag class (Dictionary<String,Dynamic> thingy) a property can be a propertybag.
NB it will be a bit slower, as basically this is using .net's version of Ducktyping, it uses late binding but it's extremely flexible, if you want to pay the price, for sirry ellors at run time.

Categories

Resources