Delegate Using "this" - c#

I'd like to create a class that has overrideable methods in the form of delegates.
I basically would like to create an interface, but not have to create a new class every time I want to make it slightly different.
Further, I would like to bundle the delegate with a number of other variables in a struct.
Now here are some more specifics.
class Gun
{
public delegate void ShootDelegate;
// There are more variables, I'm just using this one as an example
public double fireRate;
public Gun(GunStats stats)
{
this.Shoot = stats.Shoot;
this.fireRate = stats.fireRate;
}
public ShootDelegate Shoot;
}
struct GunStats
{
public ShootDelegate Shoot;
public double fireRate;
}
then, what I'd like to be able to do is make a gun like this
GunStats stats;
stats.fireRate = 3;
stats.Shoot = new delegate() { this.fireRate++; /* stupid example */ };
new Gun(stats);
however, when I create the delegate, it obviously can't interact with the inner class variables.
What's the best way to handle this?

You can pass a reference to a Gun object in the delegate.
Change delegate to:
public delegate void ShootDelegate(Gun g);
Then you can do this:
GunStats stats;
Gun g = new Gun(stats);
stats.fireRate = 3;
stats.Shoot = new delegate(g) { g.fireRate++; };

Related

How to change a class variable?

I have a class in a very basic C# console game (text adventure) that I would like to modify a variable elsewhere in the code. I understand that C# does not allow global variables, but that is essentially what I am looking for.
I am a beginner at programming. I am stumped and I've been unable to find an answer to this question. It's really a question of scope that I'm after; what variables can "talk" to each other. I'll include a simple example below.
All of these fields in the class will
be modified elsewhere within various methods.
class Player
{
public int health = 100;
public string armor = "none";
public string gun = "none";
public int money = 1000;
}
public static void AddMoney()
{
var NewPlayer = new Player();
NewPlayer.money += 1500;
}
So I want to basically know what is expected of me to do if global variables aren't a thing in C#.
There's a few ways of updating instance variables in C#: Using properties or setters like in Java or instance methods. Following code shows you a few of those.
Ultimately, what you want to do is pass a reference to the instance of the player to different methods and let them use the properties/methods to update the instance variables:
namespace Test
{
class Program
{
static void Main(string[] args)
{
var p1 = new Player();
p1.Health = 5000;
p1.Armor = "Helmet";
p1.AddMoney(200);
Console.WriteLine($"Health: { p1.Health }");
var enemy = new Enemy();
enemy.Shoot(p1);
Console.WriteLine($"Health after being shot: {p1.Health}");
}
}
class Player
{
private string armor;
private int money;
public int Health { get; set; }
public string Armor
{
get => armor;
set
{
Console.WriteLine("Updating armor.");
armor = value;
}
}
public int Money { get; private set; }
public void AddMoney(int money)
{
// More complex logic here, example: synchronization.
this.money = money;
}
}
class Enemy
{
public void Shoot(Player p)
{
p.Health -= 500;
}
}
}
This is the object-oriented way of doing things. As for global variables in the sense of application-wide variables, you can refer to this.
You can also make the Player a singleton. This is more a design choice than actual C# stuff. I'm not going to go into singleton pattern here. If you search singletons and their pros and cons, you will get an earful of that :)
Disclaimer: you could make Player a static class, which would probably behave how you want, but doing so is ill-advised as it limits you to a single player object and can't easily be unit tested, amongst other problems. See When to use static classes in C#.
You have to understand that you Player is a class. Think of it as a blueprint for how a Player object should look. I usually go to a car analogy for this: you buy two Toyota Priuses. Identical in every way. You take one to a spray shop and have a design painted on it. Has the other Prius changed? No. It's the same with var player1 = new Player(); var player2 = new Player(); - they are both of type "Player", but they are not the same player.
Now consider your AddMoney method:
public static void AddMoney()
{
var NewPlayer = new Player();
NewPlayer.money += 1500;
}
You're creating a player that only exists within the AddMoney method. Once outside, it effectively doesn't exist anymore (stuff isn't deleted from memory immediately, but garbage collection isn't a topic you should be concerned with just yet).
Since Player is a class, it's a reference type, which means that passing it to a method will pass a reference to the same object in memory. This means that we can change the object in AddMoney and it will be reflected in the caller. Note that we can't replace the object - for that you would need the ref keyword (but that's another topic too).
public static void AddMoney(Player player)
{
player.money += 1500;
}
Example:
var player = new Player();
player.money = 8500;
Console.WriteLine(player.money); // 8 500
AddMoney(player);
Console.WriteLine(player.money); // 10 000
Try it online
Alternatively, if you want to create a player, you could create a factory method:
public static Player CreatePlayer()
{
return new Player
{
money = 1500
};
}

using a delegate function in a dictionary, code optimization public vs protected

Hi there I'm currently trying to optimize some code. As I'm still new to coding I try to use this opportunity to learn new "complicated" features. So now I'm stuck with delegate functions and lambda operators and don't know how to use them properly. My goal is to have a class which has one static Dictionary in which all values for different types of enemies I want for my game are stored. My current code probably works(didn't test it yet) but I don't fully understand it.
public class EnemyTypes
{
private class TypeValues
{
public delegate void Func(Transform Entity);//just used for handing over values on initialization, somehow has to be public
private string Name; //the Name of an EnemyType, NOT the name of a specific entity
private float BaseSpeed; //actual speed of each enemy is randomly set within (BaseSpeed +/- SpeedTolerance) everytime it respawns
private float SpeedTolerance;
private Func Animate;
public TypeValues(string Name, float BaseSpeed, float SpeedTolerance, Func Animate) //constructor apparently needs to be public too?
{
this.Name = Name;
this.BaseSpeed = BaseSpeed;
this.SpeedTolerance = SpeedTolerance;
this.Animate = Animate;
}
}
[SerializeField]
private static Dictionary<int, TypeValues> Types = new Dictionary<int, TypeValues>
{
{1, new TypeValues("Standard", 1f, 0.5f, Entity => Entity.Rotate(new Vector3(0, 5, 0)))}
};
}
As you can read from the comments I don't understand why the delegate and the constructor have to have the same access modifier. And why can't it be protected? Also is there a way to get rid of Func and define the delegate directly when creating the ANimate variable?
TypeValues(...) constructor can't be private or protected because you need to call it outside of the TypeValues class.
Constructor's parameters contain Func delegate, so it should be at least as visible as the constructor is. So, if constructor has to be public, then this delegate has to be public too.
You don't really need to declare your own delegate, but you can use standard System.Action<T> (documentation here). Declare your field as private Action<Transform> Animate;

Getting adjacent objects to interact [C#]

I'm doing a basic game in C#, and I'm running up on a problem I can't solve. Here's the (relevant) code:
public class GameManager
{
public GameMap MainMap;
public EntityManager GameWorld;
public SystemManager GameSystems;
public GameManager()
{
EntityManager GameWorld = new EntityManager();
SystemManager GameSystems = new SystemManager();
GameMap MainMap = new GameMap(61, 41);
}
public void InputHandler(string Trigger)
{
switch (Trigger)
{
case "north":
GameSystems.Move(GameWorld, MainMap, 0, 8);
break;
//etc
}
}
}
public class SystemManager
{
public rkcPosition _position;
public SystemManager()
{
}
public bool Move(EntityManager TargetWorld, GameMap TargetMap, int TargetID, int TargetDirection)
{
rkcPosition _position = TargetWorld.GetPosition(TargetID);
// here, GetPosition returns an instance of rkcPosition
// pulled from a List<rkcPosition> - this seems to be the problem point
}
}
The problem I'm getting is with the part where I try to call GameSystems.Move - it jumps to highlight the last line of the code I included (w/rkcPosition) and gives a null ref exception. (rkcPosition is a class I've not included in this code snippet)
I'm trying to have the Move function perform some changes to values within the GameWorld and MainMap objects. I'm beginning to think I'm doing this all wrong, so...
If I want to run a method on my existing instances "GameWorld" and "GameSystems" from the InputHandler function, how would I do this properly?
Like Sami Kuhmonen said, the problem in your code is that you are constantly passing around and reassigning your objects that are essentially supposed to be global. Not only does this require that you pass them as parameters to anything that would need them, it is also incredibly error-prone (as you have discovered).
Instead of having these objects behave like instance objects, utilize the Singleton design.
What this means is that instead of instance members, these objects are static members that represent a single global object for everything else to access.
public class GameManager
{
public static GameMap MainMap;
public static EntityManager GameWorld;
public static SystemManager GameSystems;
static GameManager()
{
GameWorld = new EntityManager();
GameSystems = new SystemManager();
MainMap = new GameMap(61, 41);
}
//...
}
Now in your other classes, instead of having to worry if you are passing around the correct object, simply reference these singletons from the GameManager.
public class SystemManager
{
public rkcPosition _position;
//...
public bool Move(int TargetID, int TargetDirection)
{
rkcPosition _position = GameManager.MainMap.GetPosition(TargetID);
}
}
You are constantly redefining variables inside methods that override the member variables. As your debugger shows the GameWorld, MainMap etc are null and you're trying to use them. I don't know how it even goes to Move() since the member variable GameSystems will also be null.
Remove the definitions of the variables inside the methods, that way you're actually storing the objects somewhere and not throwing them away immediately after the method is over. For example:
public GameManager()
{
GameWorld = new EntityManager();
GameSystems = new SystemManager();
MainMap = new GameMap(61, 41);
}

C# Cross-Class object

I'm working on very simple Roguelike game (just for myself) and get a question:
As it is not possible to create a cross-class struct-object (entity in the game case) that could be accessible from any class of my program, what to use to create a cross-class object? I was thinking of something like storing all newly created object (enities) in a static object array, but I guess there is more simple solution on this problem.
Question itself: How to create a cross-class accessible object(s) with your own properties?
Thanks everybody, I found what I was searching for.
It seems like you tried passing around a value type (a struct) between different classes and you noticed that when you update the value in one place it doesn't change the value in another place.
That's the basic difference between value types and reference types.
If you are creating the struct yourself you may want to instead define it as a class.
If not, you could wrap all your structs in a class and pass the class around as your state object.
If all you have is simply a list of the same type of struct (like Points), just pass the List itself around. C# collections are implemented as classes.
public class GameState
{
public Point PlayerLocation { get; set; }
public List<Point> BulletPoints { get; set; }
public double Health { get; set; }
}
Now you can create a GameState and pass it around to different classes:
public class Game
{
private GameState _state = new GameState();
private BulletUpdater _bulletUpdater = new BulletUpdater();
public void Update()
{
_bulletUpdater.UpdatePoints(_state);
// Points have now been modified by another class, even though a Point is a struct.
}
}
public class BulletUpdater
{
public void UpdatePoints(GameState state)
{
for (int i = 0; i < state.BulletPoints.Count; i++)
{
Point p = state.BulletPoints[i];
state.BulletPoints[i] = new Point(p.X + 1, p.Y + 1);
}
}
}
Just remember in the above code if I were to write:
Point p = state.BulletPoints[i];
p.X += 1;
p.Y += 1;
That wouldn't affect the original point! When you read a value type from a list or from a class into only copies the value into a local variable. So in order to reflect your changes in the original object stored inside the reference type you need to overwrite it like so:
state.BulletPoints[i] = p;
This same principal is why the following also will not work:
state.PlayerLocation.X += 5; // Doesn't do anything
state.PlayerLocation.Y += 5; // Also doesn't do anything
The compiler would tell you in this case that you are doing something wrong. You are only modifying the returned value of the property, not the backing field itself. You have to write it like so:
state.PlayerLocation = new Point(state.PlayerLocation.X + 5, state.PlayerLocation.Y + 5); // This works!
You can do the following:
Using IoC Framework, like Ninject. You can setup Ninject to create single instance for all usages.
The other option is to use Singleton pattern design pattern
And the third one is to use static property
It sounds like you want to use the Singleton pattern:
http://en.wikipedia.org/wiki/Singleton_pattern
Here is an example of what this would look like in C#:
public class Singleton
{
static Singleton()
{
Instance = new Singleton();
}
public static Singleton Instance { get; private set; }
}
It's possible. What about public and static class?
public static class CrossClassObject
{
public static object MyProperty { get; set; }
public static void MyMethod() {}
}
Of course this class should be placed in the same namespace that other ones.
How to use it?
class OtherClassInTheSameNamespace
{
private void SomeMethod()
{
var localVariable = CrossClassObject.MyProperty; // get 'cross-class' property MyProperty
CrossClassObject.MyMethod(); // execute 'cross-class' method MyMethod()
}
}
No idea what you are trying to achieve... but if you want a list of objects accessible 'cross-class', just make a static class with a list of objects and then when you reference your class from any other class, you will have access to its list of objects. Here is something like that:
public static class ObjectController
{
private static IList<object> existingObjects;
public static IList<object> ExistingObjects
{
get
{
if (existingObjects == null)
{
existingObjects = new List<object>();
}
}
}
}
public class MyObject
{
public MyObject()
{
ObjectController.ExistingObjects.Add(this);
}
public void Delete()
{
ObjectController.ExistingObjects.Remove(this);
}
}
Then you can add stuff like
MyObject newObj = new MyObject();
//// other stuff... This object should now be visible to whatever other class references ObjectController
newObj.Delete();

C# value/reference passing?

I have a declared entity of a class, and want to assign different pre-made templates to it without the templates ever changing. Using a const doesn't seem to do the trick.
Example:
Weapon w1;
w1 = Sword; // premade weapon.
w1.reducedamage(1); // for example a debuff
In this case the premade weapon's damage would be decreased, and it would no longer be available as a template. This problem becomes more profound with enemies.
Example:
Enemy enemy;
enemy = enemies[r] // r being a randomly generated integer and enemies a list of enemy templates
Fight(player,enemy); // this method would resolve a fight between the two entities of the type Character.
This problem would not be visible in the player class, since player is a single reference being passed along all the game methods - because there is only one player. Every time the player fights, an enemy template would be "corrupted".
How would I create templates or classes/structs in general that always pass by value, meaning that the properties of a first class would have the same values as a second, without any relationship between the two classes?
The only success I've gotten with this is to create a method that manually copies each attribute of every class that has a template onto another entity of the same class; but this is extremely unpractical since it needs constant upgrading whenever a new class is added, or an old one changed.
I must be missing something. This seems like a reasonably simple issue that is easily solved by inheritance, perhaps in conjunction with some sort of Factory. First, you don't want to use a reference to a single instance, you want to create a new instance each time so it is a unique object. I prefer classes over structs, but you could easily create a new struct as well. You could use a Factory to create various pre-configured instances of the objects that have pre-defined values. For example, the Sword of Damocles or the Sword of Destiny.
public static class WeaponFactory
{
public static Weapon CreateSword(SwordType type)
{
var sword = new Sword(); // plain, old default sword
// override properties based on type
switch (type)
{
case SwordType.SwordOfDamocles:
sword.FallTime = GetRandomFutureTime();
break;
case SwordType.SwordOfDestiny:
sword.Invincible = true;
break;
...
}
return sword;
}
...
}
Alternative using Actions
public static class WeaponFactory
{
public static Weapon Create<T>(Action<T> decorator) where T : IWeapon, new()
{
var weapon = new T();
decorator(weapon);
return weapon;
}
public static void SwordOfDamocles(Sword sword)
{
sword.FallTime = GetRandomFallTime();
}
public static void SwordOfDestiny(Sword sword)
{
sword.Invincible = true;
}
}
var weapon = WeaponFactory.Create(WeaponFactory.SwordOfDamocles);
What you want is object cloning. You can implement it via the ICloneable interface[1]. That requires that you implement your own cloning mechanism though--you have to do the heavy lifting.
However, what you probably should do instead is just have the constructor take a parameter that represents the template you want, and then fill the properties of the object in question based on that template. That's the direction I go when I want to make duplicate things with a base set of values.
You could do actual copying (e.g. provide a copy constructor as in http://msdn.microsoft.com/en-us/library/ms173116(v=vs.80).aspx ), but what I've seen most often in such cases is a factory pattern, e.g. Weapon w1 = Weapon.CreateSword(); or Enemy e=Enemy.CreateEnemyOfType(r);
you could build a method to return multiple enemies in either a generic collection or array into your enemy class. Something like:
public shared function getEnemies(num as integer, type as string) as list(of clsEnemy)
dim enemyGroup as list(of clsEnemy)
for i = 0 to num - 1
dim thisEnemy as new clsEnemy(type)
enemyGroup.add(thisEnemy)
next
return enemyGroup
end function
Contrary to copying objects to implement some kind of "applied object" pattern, it's good to keep in mind it's not the sword "base item" that is being altered, but the item your player is carrying.
For example, a given sword, say "rusty old sword", will always have a base damage of 50. Now if someone applies "old stuff gets better magic" to it, it's not the "rusty old sword" that gets more damage: if some other player that hasn't got that kind of magic picks up the item, it's back to its base damage of 50.
So if you implement some kind of EquippedWeapon (or even EquippedItem) class, you can let your player equip weapons and give it extended properties. Something like this to declare a Sword:
interface IWeapon
{
int Damage { get; }
}
class Sword : IWeapon
{
public int Damage { get; private set; }
public Sword()
{
this.Damage = 50;
}
}
Now we have a sword with a base damage of 50. Now to let the player carry this sword:
interface IDamageModifier
{
int Damage { get; set; }
}
class EquippedWeapon : IWeapon
{
public int Damage
{
get
{
return CalculateActualDamage();
}
}
public List<IDamageModifier> DamageModifiers { get; set; }
private IWeapon _baseWeapon = null;
public EquippedWeapon(IWeapon weapon)
{
_baseWeapon = weapon;
}
private int CalulcateActualDamage()
{
int baseDamage = _baseWeapon.Damage;
foreach (var modifier in this.DamageModifiers)
{
baseDamage += modifier.Damage;
}
return baseDamage;
}
}
A weapon contains a list of active modifiers, that affect the damage of the carried item, but not the base item. This way you can share one Sword instance with many (non-)playable characters.
Now if the player gets attacked and that attack has a damage effect, you simply apply that to the item(s) the player is carrying, so each successive attack from that player will have those effects applied:
class Player
{
public EquippedWeapon PrimaryWeapon { get; set; }
public Player()
{
this.PrimaryWeapon = new EquippedWeapon(new Sword());
}
public void UnderAttack(Attack attack)
{
// TODO: implement
if (attack.Buffs...)
{
this.EquippedWeapon.DamageModifiers.Add(attack.Buffs);
}
}
}
I wrote an answer answering your question directly. But now I see that all you want is to create items that are the same but not linked.
That's what happens anyway when you create an instance. You don’t have to do anything.
If you have:
class Class1
{
public int i;
}
Then:
Class1 c1 = new Class1() { i = 1 };
Class1 c2 = new Class1() { i = 2 };
Text = c1.i.ToString();
Prints "1", not "2".
And if you mean you want a "Player" class with sub-classes "Friend" and "Foe" - That's what inheritance is for:
class Player
{
}
class Friend : Player
{
}
class Foe : Player
{
}
EDIT:
Perhaps this will make the task easier: (The "Duplicate" method)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Class1 c1 = new Class1() { i = 1, j = 2 };
Class1 c2 = Duplicate(c1);
c1.i = 3;
Text = c2.i.ToString();//Prints "1";
}
public Class1 Duplicate(Class1 c)//Duplicates all public properties.
{
Class1 result = new Class1();
PropertyInfo[] infos = typeof(Class1).GetProperties();
foreach (PropertyInfo info in infos)
info.SetValue(result, info.GetValue(c, null), null);
return result;
}
}
public class Class1
{
public int i { get; set; }
public int j { get; set; }
}

Categories