Reputation: 43
I am learning C# and made a simple "Player" class. But I struggle having multiple overload. Here's my best solution but I feel like it could be done simpler/better.
class Player : Entity
{
public Player() {
Name = "Player";
XP = 0;
LVL = 1;
XPToLvlUp = 10;
XpRank = 10;
}
public Player(string name) : this() {
Name = name;
}
public Player(string name, int _Hp, int _Mp) : this(name) {
HP = _Hp;
MP = _Mp;
}
public Player(string name, int _Hp, int _Mp, int _Xp, int _Lvl) : this(name, _Hp, _Mp) {
XP = _Xp;
LVL = _Lvl;
}
public Player(string name, int _Hp, int _Mp, int _Xp, int _Lvl, int XpByRank) : this(name, _Hp, _Mp, _Xp, _Lvl) {
XpRank = XpByRank;
}
//deleted code for better reading
private int XPToLvlUp;
private int XpRank;
public int XP;
public int LVL;
public string Name;
}
Is it good and if not please tell me why. Thanks for your responses!
Upvotes: 2
Views: 1987
Reputation: 4824
Your class is almost good and acceptable.
Short story: use Properties.
Long story:
First of all make or follow the naming rules, it will make your code more friendly to read. It's up to you, just a suggestion. For complex names consisting of multiple words you may use CamelCasedNames
. And avoid shorten names for all types of data where it maybe useful. For example you may expand Lvl
to Level
but Xp
to Experience
will look as something odd. It's up to you too.
string name; // local Variable, first character lower cased
private string _name; // private Field, first character is lower cased with leading "_"
public string Name { get; set; } // public Property, first character is upper cased
I'll show you alternatives to overriden constructors and will follow the naming rules.
1) Default values for constructor (with a part of your class to keep it simple)
class Player
{
public Player(string name = "Player", int xp = 0, int level = 1)
{
Name = name;
Xp = xp;
Level = level;
}
// Properties instead of Fields
public int Xp { get; private set; } // restrict modification of the property outside of a class but reading is available
public int Level { get; private set; }
public string Name { get; set; }
}
2) Properties without constructor with default values
First Property purpose is restrict access to data to keep internal object data consistent. Even you make mistakes in the code. Good way to avoid some bugs.
Second property purpose is executing code while you're getting or setting one. For example, making properties dependent on each other to store less and only unique data.
class Player
{
public int Xp { get; private set; } = 0;
public int Level { get; private set; } = 1;
public string Name { get; set; } = "Player";
}
Usage
Player player = new Player() { Name = "KillerPWNZ", Level = 100, Xp = 999999 };
Bonus: Another Property feature
You can execute any code in get
or set
clause.
Let's assume that each next player's level require doubled amount of xp from previous but 2nd level requre 100 XP. And you decided to invoice to the 1st leveled player 1000 XP. Obviously you'll need to bump the Level
few times. Assuming that Xp
contains relative to Level
value.
The invoice
player.Xp += 1000;
The Property with code
private int _xp = 0;
public int Level { get; private set; } = 1;
public int Xp
{
get => _xp; // same as: get { return _xp; }
set
{
_xp = value; // here value is keyword containing data you want to set
while (_xp >= GetXpPerLevel(Level))
{
_xp -= GetXpPerLevel(Level);
Level++;
}
while (_xp < 0 && Level > 1)
{
_xp += GetXpPerLevel(Level - 1);
Level--;
}
}
}
// helper method
private int GetXpPerLevel(int level)
{
if (level < 1) return 0;
// int result = 100;
// for (int i = 1; i < level; i++) result *= 2;
// return result;
// or the same with some binary shift magic :)
return 100 << (level - 1);
}
Upvotes: 4
Reputation: 4395
I think it's fine as is. One question to ask yourself: Are each of those methods actually likely to be called?
One option is to just let the programmer set those values after they've instantiated the class:
var myPlayer = new Player();
myPlayer.XP = 5;
However, there are situations where you really want all the info up front, so that may not be suitable.
Another option could be an options class that is passed to the ctor:
public class PlayerSettings
{
public Name = "Player";
public XP = 0;
public LVL = 1;
public XPToLvlUp = 10;
public XpRank = 10;
}
Then your ctors looks like this:
public Player() : this(new PlayerSettings())
{
}
public Player(PlayerSettings settings)
{
//Fill in appropriate variables here
}
That option would be called in this way:
var playerSettings = new PlayerSettings() { XP = 5 };
var myPlayer = new Player(playerSettings());
In the end, I'm not sure one is "better" than the other, it largely depends on your needs.
Upvotes: 5