Note: I am somewhat of a beginner to C#.
I'm working on a little game that will have a bunch of different levels. Each level has its own class that contains variables (and other irrelevant code). Since I need to pass these values to the main class (my form) I have made them all into methods that returns the value I want (since I can't come up with a better solution). example:
class Level01
{
public int Boxes() { return 3; }
public int MaxPoints() { return 46; }
public int Health() { return 63; }
public int[,] SolidBoxes()
{
int[,] position = new int[Boxes(), Boxes()];
position[1, 1] = 1;
return position;
}
}
When I access these values from my form class I do
int boxes;
int maxPoints;
int health;
int[,] solidBoxes;
void readLevelData() //Starts each new level
{
//Reads the correct level
switch (levelNo)
{
case 1:
setValues(Lvl01.Boxes(), Lvl01.MaxPoints(), Lvl01.Health(), Lvl01.SolidBoxes());
break;
//The same case 2:, 3: for Level02,03..
}
}
void setValues(int getBoxes, int getMaxPoints, int getHealth, int[,] getSolidBoxes)
{
boxes = getBoxes;
maxPoints = getMaxPoints;
health = getHealth;
solidBoxes = getSolidBoxes;
}
I am aware that there's probably a million things in my code here that can be done better and I gladly listen if you have any suggestions, but the thing I wish to ask is:
How can I get all the values from each class using maybe just one name? Ex. Instead doing as I do now, is there a way so I can do something similar to this:
case 1:
setValues(Lvl01.Values);
break;
The problem here is in the setValues method, some of the levels has quite a lot of settings that I wish to use, but I doubt the method would want to take like 15 parameters, and I'm not sure what to do when some levels are not using settings that other levels use.
How should I change my code so I do not have to use every single value as a parameter?
You could use a Dictionary<int, Level> to lookup the object representing each level. Instead of the switch/case, you would do something like
Level level = myLevelDictionary[currentLevel];
That requires you change your classes from having one class per level, to one class that represents any level, e.g.:
class Level
{
public int Boxes { get; set; }
public int MaxPoints { get; set; }
public int Health { get; set; }
public int[,] SolidBoxes()
{
int[,] position = new int[boardSize, boardSize];
position[1, 1] = 1;
return position;
}
}
You would then populate your dictionary like
Dictionary<int, Level> myLevelDictionary = new Dictionary<int, Level>()
{
{ 1, new Level() { Boxes = 3, MaxPoints = 46, Health = 63 } },
// etc.
};
UPDATE
A note about abstract classes
You mention abstract classes in your comments. They are useful if all of your levels have some behavior in common, but some have specialized behavior too. They will often be used in games for things that can move in the game, e.g. something like
abstract class Character
{
// Something everyone has
public int HitPoints { get; set; }
// Something everyone does, but does differently
public abstract void Attack(Character target);
}
public class Fighter : Character
{
public int SwordDamage { get; set; }
public void Attack(Character target)
{
target.Damage(this.SwordDamage - target.PhysicalDamageResistance);
}
}
public class Mage : Character
{
public int MagicFireDamage { get; set; }
public int MagicColdDamage { get; set; }
public void Attack(Character target)
{
if (UseFireDamage()) // e.g. roll random chance that the mage uses a fire spell
{
target.Damage(this.SwordDamage - target.FireDamageResistance);
}
else
{
target.Damage(this.SwordDamage - target.ColdDamageResistance);
}
}
}
one way maybe to use a dictionary.
class Level01
{
Dictionary<string,int> values;
public level01()
{
values.Add("Boxes",3);
values.Add("MaxPoints",3);
values.Add("Health",3);
}
//indexer
public int this[string s] {get{return values[s];} set {values[s] = value;}}
}
and use like:
Level01 lv = new Level01();
somemethod(lv["Boxes"]); //passes 3 to some method
although really you would want to use Dictionary<string,object> and add some type checking and other things to make it work smoothly but hopefully you can get started with that
Related
I have the class Node that is manipulating instances of my Person class.
The base class with the minimum functionalities looks like this:
public class Node
{
//attributes
protected readonly int steps;
protected readonly int angleDeltaQ;
//constructor
public Node(int steps, int angleDeltaQ)
{
this.steps = steps;
this.angleDeltaQ = angleDeltaQ;
}
//methods
public virtual int UpdateMe(Person me)
{
me.angleQ = QMath.RadLimitQ(me.angleQ + angleDeltaQ);
me.xQ += QMath.CosQ(me.angleQ, me.speedRev);
me.zQ += QMath.SinQ(me.angleQ, me.speedRev);
me.steps--;
if (me.steps == 0) return (int)NodeFeedback.targetReached;
else return (int)NodeFeedback.notFinished;
}
public virtual void AssignMe(Person me)
{
me.steps = steps << me.speedRev;
}
}
I leave the Person class out of here as it is not important to describe my problem.
What is only needed to know is that Person has a Node attribute and calls the Node's Assign method once, and then Update in a regular manner.
Now there are many additional things the Node might be able to do.
For example at the Update method, it also should change the value of me.yQ. For this it needs additional attributes and needs additional code in the Update method.
For the Person instance it should not matter what exactly is going on with it's Node attribute as long it can call it's two methods.
My problem is now, I have 8 additional features for the Node class. If I would create a subclass of Node for each combination, it would become awfully large.
My question is, is there a tidy way to do this? I plan to have many many instances of Node so I only want it to contain the attributes and methods this specific Node needs.
you should use visitor pattern
public abstract class Node
{
//attributes
protected readonly int steps;
public readonly int angleDeltaQ;
private IUpdateVisitor updateVisitor;
protected Node():this(new DefaultUpdateVisitor())
{
}
protected Node(IUpdateVisitor visiter)
{
updateVisiter = visiter;
}
//constructor
public Node(int steps, int angleDeltaQ)
{
this.steps = steps;
this.angleDeltaQ = angleDeltaQ;
}
//methods
public virtual int UpdateMe(Person me)
{
updateVisitor.UpdateMe(this,me);
}
public virtual void AssignMe(Person me)
{
me.steps = steps << me.speedRev;
}
}
public interface IUpdateVisitor
{
int UpdateMe(Person me);
}
public class DefaultUpdateVisitor : IUpdateVisitor
{
public int UpdateMe(Node node, Person me)
{
me.angleQ = QMath.RadLimitQ(me.angleQ + node.angleDeltaQ);
me.xQ += QMath.CosQ(me.angleQ, me.speedRev);
me.zQ += QMath.SinQ(me.angleQ, me.speedRev);
me.steps--;
if (me.steps == 0) return (int)node.NodeFeedback.targetReached;
else return (int)node.NodeFeedback.notFinished;
}
}
public class AotherUpdateVisitor: IUpdateVisitor
{
public int UpdateMe(Node node, Person me)
{
.....
}
}
I am learning about writing constructors and properties in c# and was asked to write a console app and class to operate a beverage machine. I wrote part of the class code but ran into an issue. One of the many blocks of code asks for a constructor method that starts the SodaCanCount at 5 bottles and sets the CustBalance field to zero. I don't know what this constructor should look like. I am specifically talking about the private sodaVandorClass(), right under the two private fields.
I wrote what I could so far and I have no errors however the SodaVendorClass does not look right.
namespace VendorClass
{
public class SodaVendorClass
{
// members
// fields
//Customer balance is $0 until the customer inserts a dollar
//All customer entries are one dollar increments and a soda costs one dollar.
private int CustBalance = 0;
//a machine holds 10 cans of soda
private int SodaCanCount = 5;
//A soda costs 1 dollar
//private int sodaCost = 1;
public int _SodaCanCount
{
get
{
return SodaCanCount;
}
}
public int _CustBalance
{
get
{
return CustBalance;
}
}
public int BuySoda(int pCustBalance, int SodaCanCount)
{
return SodaCanCount;
}
public void AcceptCash(int CustBalance)
{
CustBalance++;
}
public int GiveRefund(int pCustBalance)
{
return CustBalance;
}
}
I only want to see an example of a constructor that sets default values for my private class fields. Any help will be appreciated.
You can define a public constructor like below but probably you don't need one if you enable your properties to set values too
public SodaVendorClass()
{
this.CustBalance = 0;
this.SodaCanCount = 0;
}
You can make your properties writable too. Notice below are auto properties and in such case you don't need those private backing fields explicitly.
public int SodaCanCount
{
get; set;
}
public int CustBalance
{
get; set;
}
You can instantiate your type saying (using Object Initializer construct)
SodaVendorClass sc = new SodaVendorClass
{
SodaCanCount = 10,
CustBalance = 500,
};
A constructor for this class could look like this:
public SodaVendorClass () {
}
That would be an empty constructor that does nothing.
To set the two values you want, you can add some paramters:
public SodaVendorClass (int customerBalance, int sodaCount) {
this.CustBalance = customerBalance;
this.SodaCanCount = sodaCount;
}
To create an instance of this class with 5 soda cans and a customer balance of 0, you would call the constructor in the code like this:
var vendor = new SodaVendorClass(0, 5);
namespace VendorClass
{
public class SodaVendorClass
{
private int CustBalance;
private int SodaCanCount;
//...
public SodaVendorClass() // default constuctor
{
CustBalance = 0;
SodaCanCount = 5;
}
//...
}
}
Default constructor is called when you are creating object like this:
SodaVendorClass obj = new SodaVendorClass();
So obj._SodaCanCount is 5 and obj._CustBalance is 0
Also you can define constructor with parameters.
public SodaVendorClass(int balance, int count)
{
CustBalance = balance;
SodaCanCount = count;
}
and create call this constructor.
SodaVendorClass obj = new SodaVendorClass(0, 5);
A constructor is being used while creating a object like "Class obj=new Calss()". If you don define a constructor in your class a default constructor will be provided implicitly.User defined Constructor usually used for initializing value for class properties. Unlike function constructor does not have any return type at all not even void. All the answers are good.
public class SodaVendorClass{
private int CustBalance = 0;
//a machine holds 10 cans of soda
private int SodaCanCount = 5;
//A soda costs 1 dollar
//private int sodaCost = 1;
public int _SodaCanCount
{
get
{
return SodaCanCount;
}
}
public int _CustBalance
{
get
{
return CustBalance;
}
}
public SodaVendorClass(int cancount, int sodacost){
SodaCanCount=cancount;
sodaCost=sodacost;
}
}
//creating a object of Sodavendorclass
Sodavendorclass obj=new Sodavendorclass(0,0); //Provided value for class property
Notice that at the time of object creation, provided for Property. This is one of the way you can use constructor.
I'm confused about properties in C#, espacially with inheritance:
I have a Pokemon class as an example and want the stats to be protected to modify them in the subclasses (for example at level ups) and I want to read the stats from outside.
This would be the verbose way to do it:
// base class
abstract class Pokemon
{
// stats
protected int hp;
public int Hp {
get
{
return hp;
}
protected set
{
hp = value;
}
}
// other stats...
}
My Question is: Is there a short form for this? Something like:
// base class
abstract class Pokemon
{
// stats
public int Kp { get; protected set; }
// other stats...
}
Do these 2 classes work similarly?
I'm confused, because for public getters and setters you write:
// base class
abstract class Pokemon
{
// stats
public int Kp { get; set; }
// other stats...
}
And it works like:
// base class
abstract class Pokemon
{
// stats
private int kp;
public int Kp {
get
{
return kp;
}
set
{
kp = value;
}
}
// other stats...
}
Which one should I prefer?
My Question is: Is there a short form for this?
Yes exactly as you wrote it
Do these 2 classes work similarly?
Yes, in the first example you can additionally manipulate the field hp in the derived classes directly. (personally I don't see the point, you can also make it private )
Which one should I prefer?
That is difficult to say. If you need extra logic to validate the setting of the property use the first option.
private const int maxHP = 3000;
protected int hp;
public int Hp {
get
{
return hp;
}
protected set
{
// extra validation
if(value < maxHP)
hp = value;
else
hp = maxHP;
}
}
if you don't need it, don't use it
I am working on a C# game that will have predefined levels. I am trying to have a class that will hold the predefined data of all of the levels. Here's what I'm trying to do:
public static GameLevel startLevel = new Level() {
startLevel.Actions.Add(action);
startLevel.Actions.Add(action);
}
And so on. However, it seems that C# does not want me to initialize this way. How can I achieve my desired effect without throwing it into a massive constructor?
How do you think if we change the static variable as below:
private static GameLevel _startLevel;
public static GameLevel StartLevel
{
get
{
if(_startLevel == null)
{
_startLevel = new Level();
_startLevel.Action.Add(action1);
_startLevel.Action.Add(action2);
}
return _startLevel;
}
}
Since you have predefined levels, I suggest a little different approach.
Create a Level base class, and a class for each Level. The constructor for each level class can set up the Actions and any other things the game needs to know how to display itself.
using System;
public class Program
{
public static void Main()
{
new GameState(new Level1());
Console.WriteLine("Current level is " + GameState.CurrentLevel.Name);
Console.WriteLine("User leveled up");
GameState.CurrentLevel = new Level2();
Console.WriteLine("Current level is " + GameState.CurrentLevel.Name);
}
}
public class Level
{
public string Name;
// public static IEnumerable<Action> Actions { get; set; }
}
public class Level1 : Level
{
public Level1()
{
// level 1 init
Name = "1";
// Actions = new List<Action> { ... }
}
}
public class Level2 : Level
{
public Level2()
{
// level 2 init
Name = "2";
}
}
public class GameState
{
public static Level CurrentLevel { get; set; }
public GameState(Level startLevel)
{
CurrentLevel = startLevel;
}
}
Working copy: https://dotnetfiddle.net/qMxUbw
"...C# does not want me to initialize this way..."
You can init this way. You simply don't have the right syntax. This should work
public static Level startLevel = new Level()
{
Actions = new List<Action>()
{
new Action() {...},
new Action() {...}
},
OtherProprty = "Other"
};
NOTE: this has to be done under class scope
"Massive constructor" - you usually don't init static members in constructor unless this is static constructor. Sounds like you need to use Singleton pattern for this piece. Then again, you call all the needed code in constructor, "massive" or not. Break it into methods.
I am trying to build a unit test.
The class Position is implemented in a third party library. But for my unit test I need the Size property to be set to a specific value.
public class Position
{
private double _size;
private double Size
{
get
{
return _size;
}
internal set
{
_size = value;
}
}
}
I read this post: How do you create a unit-testing stub for an interface containing a read-only member?
but could not figure out how to make it work for me.
This is the class under test (just a simplified example). The posargument in the CalcPositionMetric() method must be of type Position:
public class PositionMetrics
{
public PositionMetrics()
{}
public double CalcPositionMetric(Position pos)
{
return 2 * pos.Size;
}
}
Here is a piece of my unit test:
using NUnit.Framework;
using NMock;
[TestFixture]
public class PositionUnitTests
{
[Test]
public void TestPosition()
{
Mock<Position> tmpPosMock = mFactory.CreateMock<Position>();
tmpPosMock.Expects.One.GetProperty(v => v.Size).WillReturn(7); /* !!! Exception !!! System.ArgumentException : mock object position has a getter for property Size, but it is not virtual or abstract */
/* Execute Test with tmpPositions*/
PositionMetrics pm = new PositionMetrics();
double result = pm.CalcPositionMetric(tmpPosMock.MockObject)
Assert.AreEqual(14, result);
}
}
But as you can see I get an exception. Could somebody help me to resolve this problem? Any other solutions are also welcome!
Cheers
Konstantin
New answer for the updated question I suggest you to introduce some kind of a proxy interface for that. See the code below:
interface IPosition {
int Size { get; }
}
class Position { //in 3rd party lib
public int Size {
get { return 5; }
}
}
class RealPosition : IPosition { //use this as your real object instead of using Position directly
private Position position;
public RealPosition(Position position) {
this.position = position;
}
public int Size {
get { return position.Size; }
}
}
class MockPosition : IPosition { //use this for testing
public int Size{ get; set; }
}
public class Program {
static void Main(string[] args) {
var pos = new MockPosition { Size = 7 };
Console.WriteLine(Calc(pos)); //prints 14
Console.ReadLine();
}
static int Calc(IPosition pos) { //change your method signature to work with interface
return pos.Size * 2;
}
}
Old answer If the class is not sealed you don't need any mocking libraries. Just use the new modifier for the required properties like this:
class Position {
public int Size { get { return 5; } }
}
class MockPosition : Position {
public new int Size { get; set; }
}
....
var mock= new MockPosition();
mock.Size = 7;
To use these items in some sort of list you'll have to cast them like this:
var items = new List<Position>();
for (int i = 0; i < 5; i++) {
items.Add(new MockPosition { Size = i });
}
foreach (var item in items.Cast<MockPosition>()) {
Console.Write("{0}\t", item.Size); //prints 0 1 2 3 4
}
If it is sealed and the property is not virtual than you'll have to use some other techniques, Moq (which I guess you are using) does not allow that