i was looking at facade-like delegation in classes, for example let's suppose that you got the Equipment class ( with Equip() and UnEquip() methods), and then you have a Player class which has a reference to the Equipment.
The way i would implement the Player class is to have some public methods like EquipItem and UnEquipItem, and those methods will delegate the tasks to the Equipment class. Now if the player also has another class that does stuff, like movement, then i would put again some public methods on the Player class that delegates to the Movement class, in a facade-like way. Now one of the disadvantages of the facade pattern is the growing interface the more classes or systems it handles. And let's suppose that i know that in the future, the Player class will have alot more functionality.
I don't know if this is the correct approach, nonetheless i was thinking if it would be possible to expose the Equipment and Movement references as properties, like so:
Class Player
{
public Equipment equipment { get; set; }
public Movement movement { get; set; }
}
Now, i know that exposing the object's state is bad, but this way you have a better control of the growing interface of the class, and have more focused methods on the Player class. So instead of:
player.Equip();
you can do
player.equipment.Equip();
Sooo finally, my question would be what is the best approach in this scenario, or maybe i got something wrong ?. Thanks
PS: the example is from a game area, but the solution doesn't have to be necessarily applicable to games, i just thought it was simple to understand.
An alternate approach would be to develop a set of command actions that can be applied to the player which manipulate the state. While the command objects would have extended access to the player, the outer API would keep the implementation details as a black box.
As an example:
public abstract class Action
{
public abstract void ActOn(Player player);
}
public class EquipAction : Action
{
private Item item;
public EquipCommand(Item item) {
this.item = item;
}
public void ActOn(Player player) {
player.Equipment.Add(item);
}
}
public interface IPlayer
{
void PerformAction(Action action);
}
public class EquipmentSet
{
public List<Item> Items { get; private set;}
}
public class EquipmentManager
{
public Add(Item item) {
}
public List<Item> Items { get; }
}
public class Player : IPlayer
{
public EquipmentManager manager;
public PerformAction(Action action) {
action.ActOn(this);
}
public List<Items> Equipment {
return manager.Items;
}
}
Now obviously, there's a lot more that should be done to make this fully capable to do what you want, but the idea would be to limit your public interface to player to the structure that you want to expose (e.g. attributes, equipment, status, .etc) and delegate all the verbs to actions.
Under the covers, the actual functionality of a Player could be broken up into as many components as would make sense to limit the size of each individual components.
Related
Basically I'm trying to create a attatchment system for a 2D platform/shooter game, the weapon system is working great but I want to implement some attachments, diferent barrels, magazines even ammo types.
For the simpler ones that just modify a stat I was thinking of just creating a class or even a struct with all the possible stats (damage, recoil, spread etc) and just setting them to the appropiate values (+1, -5, 0 if it doesn't use it). However, there are some ideas that might require a separate method/function, like shooting different bullets.
My main question is would it be more effective/efficient to just make smaller scripts for the edge cases and a main one for the simple stat changers. Or should I just overload a main script/class with methods for all the possible attachments?
There aren't that many "special" attachments, but i'd like to make a system that expandable if possible.
Im not an expert programmer (I just learned about enums a couple days ago!) so any suggestions are greatly appreciated.
I would use Unity's ScriptableObject class to create an abstract class then inherit from that abstract class to create more spesific classes and abstract classes.
Then I would create my attachments etc. in unity editor and modify whatever value I want from it.
An example armor piece would inherit the following ArmorItem class and use the ApplyEffect method to make the player bigger to show that you can make any type of modification.
ItemBase class
using UnityEngine;
public abstract class ItemBase: ScriptableObject
{
public string ItemName;
public abstract void ApplyEffect();//override this method for any edge case items
}
ArmorItem
public abstract class ArmorItem: ItemBase
{
public float Armor;//use this however you want
}
EdgeCaseArmor
[CreateAssetMenu(menuName = "Items/Armor/EdgeCaseArmor")]
public class EdgeCaseArmor: ArmorItem
{
public override void ApplyEffect()
{
//find player and make it bigger
GameObject.FindGameObjectWithTag("Player").transform.localScale *= 1.5f;
}
}
Obviously you will need to load items and somehow call ApplyEffect. You can do it at the start of the game by adding this to a start method.
var item = Resources.Load("path to your scriptable object that inherits ItemBase") as ItemBase;
item.Activate();
How you load the items and call them is up to you. You will need to save your scriptable objects in Assets>Resources folder(create one if you haven't created one already).
You can also make multiple armors with different names, armor values etc. like this.
Note that if you want to have an armor with no special effect you will need to make ArmorItem a normal class or make a NormalArmor class that inherits ArmorItem. Just leave the ApplyEffect function empty if you don't want any special effects.
This is a fairly general question so keep in mind that you may get several varying opinion-related answers.
With that said, the biggest suggestion that I would give is to look into Inheritance. Using a series of interfaces and classes to more refine the base concept of "item modifications".
For instance, I would create an interface:
interface IItemModification
{
void Apply();
}
Any more refined modification class or interface would implement (in the case of a class) or inherit (in the case of another interface) this interface.
In this example we will just create a base class that implements that interface:
public class ItemModification : IItemModification
{
public void Apply()
{
// Logic to apply modifications to the item.
}
}
In the case above, you now have a very basic class that represents an item modification which contains the implementation of the interface.
Next you might want to go into further detail, perhaps by creating item type implementations:
public class WeaponItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, AttackType attackType)
{
this.Modifiers = modifiers;
this.Attack= attackType;
}
public AttackType Attack
{
get; set;
}
public StatModification Modifiers { get; set; }
}
public class ArmorItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, DefenseType defenseType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
}
public DefenseType Defense
{
get; set;
}
public StatModification Modifiers { get; set; }
}
Of course a logical progression of that would be more specific item types:
public class VestModification : ArmorItemModification
{
public VestModification(StatModification modifiers, DefenseType defenseType, AreaProtectionType areaProtectionType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
this.AreaProtection = areaProtectionType;
}
public AreaProtectionType AreaProtection
{
get; set;
}
}
These are just some basic examples to point you in the right direction. I would suggest reading up on inheritance concepts to get a better understanding of it.
There is something I do not understand about open-close principle. Let's say that you have done this code:
public abstract class Player
{
public string Name { get; set; }
public int Level { get; set; }
}
public sealed class Fighter : Player { /* ... */ }
public sealed class Warrior : Player { /* ... */ }
This code works perfectly, you've done a first release, eveyrthing is OK.
Now you want to add some features, like a player can equip a ring. Open-close principle says open to extension, close to modification. How could I implement the fact that my players can have rings if I shouldn't modify these class?
You can modify class Player by adding new methods and fields. It is open to extension. But if you already have some methods like Jump or Fight and you want to modify them - that is breaking the principle.
Imagine, your class Fighter has method Fight() and it uses only bare hands:
public Fighter() : Player
{
...
public virtual void Fight()
{
//use bare hands
}
}
If you want Fighter to fight with a stick (for example) you should not modify initial method Fight() but add another class like FighterWithStick : Fighter and override method Fight() there:
public FighterWithStick() : Fighter
{
...
public override void Fight()
{
//use stick
}
}
First think why this kind of rule might be useful. Closed to modification, open to extension. This makes sense for libraries or code that must be backwards compatible. Think of this example:
I've written "BestLibrary" library which exposes interface:
namespace BestLibrary
{
public interface GoodStuff
{
Goodies GiveMeGoodStuff();
}
}
But in the next release I want to decide what Goodies to give based on a parameter, so I change the interface to:
namespace BestLibrary
{
public interface GoodStuff
{
Goodies GiveMeGoodStuff(GoodiesType type);
}
}
public enum GoodiesType { All, Type1, Type2 }
Now everyone who uses my library has to fix their code, because their projects will stop building. This brakes Open/Closed principle. Instead I should make another method, like this:
namespace BestLibrary
{
public interface GoodStuff
{
Goodies GiveMeGoodStuff();
Goodies GiveMeGoodStuff(GoodiesType type);
}
}
Here I didn't modify anything. Old code still works. Someone wants random Goodies? They can still get it. I extended GoodStuff interface with additional method. This way everything compiles and people can use new functionality.
If you work on a project that is not a library or api, then I don't see any reason to follow this principle. Requirements change and code should follow.
I guess I've run into a design issue... which I'm not sure how to solve myself. So sorry, but I have to provide some basic design info...
A game. Players, monsters, objects, different things may be under different effects:
public interface IEffect {}
There may be different particular Effects:
public interface IResistanceBuff : IEffect
{
void modifyIncomingDamage(Damage damage);
}
public interface IDamageBuff : IEffect
{
void modifyOutgoingDamage(Damage damage);
}
Why this way? Well, the concept it to avoid duplicating code. For example, this way I can unify damage reductions from type resistances and, for example, wearing armor. Simply, I make the Type class and the Armor class implement IResistanceBuff. (Similarily, the Weapon class will implement IDamageBuff).
But some effects are temporary, not permanent. For this, we will have:
public interface ITemporaryEffect : IEffect
{
long TimeRemaining {get; set;}
}
Again, the purpose here is to avoid duplicating code. For example, the PotionOfMight class will implement IDamageBuff interface and derive from Potion abstract class, which in turn will implement ITemporaryEffect interface. Or, we will have IStun interface, which will implement ITemporaryEffect.
Now every object that can be under certain effects will store a collection (HashSet maybe?) of all effects it is under. This is to be able to more easily call these effects. For example, a character will have a property public HashSet<IResistanceBuff> ResistanceBuffs {get; private set;} and so we can make a character's TakeDamage method look like this:
void TakeDamage(Damage damage)
{
this.ResistanceBuffs.ForEach(resistanceBuff =>
resistanceBuff.modifyIncomingDamage(damage)
);
this.HP -= damage.Amount;
if(this.HP <= 0) {
this.Faint();
}
}
But here comes the problem. I want to have one piece of code to update the remaining duration of temporary effects and remove those whose duration has expired.
My (not working, by design of C#) idea for that was to make the Character class (and any other class that represents an object that can be under any sort of Effect - that means even WorldMap, because I thought I'd store weather conditions as Effects applied to the world) implement IEffectStorage interface:
public interface IEffectStorage
{
List<HashSet<IEffect>> AllEffects {get;}
}
public class Character : IEffectStorage
{
// ...
public HashSet<IResistanceBuff> ResistanceBuffs {get; private set;}
public HashSet<IDamageBuff> DamageBuffs {get; private set;}
// ...
public List<HashSet<IEffect>> AllEffects =>
new List<HashSet<IEffect>> {ResistanceBuffs, DamageBuffs, /* ... */};
}
Now dealing with temporary effect expiration would be the responsibility of the Effect static class:
public static class Effect
{
public static void ExpireTemporaryEffects(IEffectStorage effectStorage)
{
effectStorage.AllEffects.ForEach(effectSet =>
{
var effects = effectSet.ToList();
effects.ForEach(effect =>
{
if(effect is ITemporaryEffect) {
effect.TimeRemaining--;
if(effect.TimeRemaining <= 0) {
effectSet.Remove(effect);
}
}
});
});
}
}
But, of course, as I said, I cannot do this.
Now I may start looking for some hackish and/or ugly ways to make this design working. ALtervatively, I may reason that I'm likely trying to do something against the design of the C# programming language and/or OO programming paradigm because of my failure to understand this paradigm well enough... Especially since this is the first project of this size I'm doing on my own, I choose to do the latter... So I'm asking this question :) Is my design all wrong and if yes, then how to fix it?
Sorry for the length of this post, but I feel all information above is necessary.
I am not a game developer or have experience with game engines but I think most games or engines use something like frames as a meassure for time (maybe I am totally wrong on this). My Idea would be to change your ITemporaryEffect to
public interface ITemporaryEffect : IEffect
{
bool IsActive(long currentFrame)
}
And implement it as follows:
public class SilencedEffect : ITemporaryEffect
{
private long duration = 1000;
private long endFrame;
public SilencedEffect(int currentFrame)
{
endFrame = currentFrame + duration;
}
public bool IsActive(long currentFrame)
{
return endFrame > currentFrame;
}
}
This way you could iterate over it in your character or worldmap class and remove it if isn't is active anymore.
public class Character
{
private IList<ITemporaryEffect> temporaryEffect;
public void UpdateEffects(long currentFrame)
{
var outdatedTempEffects = temporaryEffect.Where(p => !p.IsActive(currentFrame));
temporaryEffects.RemoveRange(outdatedTempEffects);
}
}
Could interfaces representing each attribute of a player class be appropriate? Are there problems with this?
As attributes are added to the model, so will interfaces resulting in a long declaration.
public class Player : INamed, IEnergy, IInventory, IMana, ...
{
public string Name { get; set; }
public int Energy { get; set; }
public int Mana { get; set; }
public Inventory Backpack { get; }
...
}
To me, that would tell me that not all players have a name, energy, etc. For a basic game, all units usually have some sort of name and a series of hit points which denote how much damage can the unit take.
If all the units in your game have similar properties but different values (maybe a priest can withstand less damage than a soldier, but can move faster since it does not have armor), you could define an interface which specifies the behavior of your units, thus you could have something like so:
public interface IBaseUnit
{
int HitPoints
..
}
Then, each specific unit will have their own implementation. That being said, I would presume that the units will act in a similar fashion in most things, thus, it might be more effective to use an abstract class instead of an interface at the top of your hierarchy.
In my opinion, what you need is a class hierarchy, not a bunch of interfaces. Instead of building a large pool of "properties" that different characters can have, you'd be more well advised to model some sort of hierarchy with some base abstract classes that concrete units inherit from.
A basic idea:
abstract class Character
{
String name
int hitpoints;
IList<Item> inventory;
}
abstract class Spellcaster : Character
{
int manapoints;
IList<Spell> knownSpells;
}
class Mage : Spellcaster
{
// Mage specific stuff
}
class Necromancer : Spellcaster
{
// Necromancer specific stuff
}
And so on. Obviously the classes that you model will depend on what kind of game it is that you are making.
If I have a class that is based off another class, how do I access the properties of the first class if it can have any name? I was thinking of using generics to access the properties, but the generics are "generic" for a reason...
For example:
public class AGameInXNA : Microsoft.Xna.Framework.Game
{
int ExampleGameProperty;
}
// ... another class ... //
public class ReferenceToAGameInXNA
{
Game gameInstance;
public void SetGameInstance(Game game)
{
gameInstance = game;
}
public void SetExampleGameProperty()
{
gameInstance.ExampleGameProperty = 21; // I don't know the name of
// AGameInXNA, so I want to
// access it using a generic
// class.
}
}
I know that that does not work, so how would I use generics in this case to access the AGameInXNA's properties in another class if I don't know AGameInXNA's name?
EDIT: I am trying to make it so that I can reuse this code later on. I want to be able to have a class that is unknown, such as public class unknownclassname that extends another class, such as Microsoft.Xna.Framework.Game, and be able to access the class unknownclassname without directly calling/implementing it in the library code.
I would recommend looking into XNA Services.
So for example, you would create a service which could be as simple as an
interface IExamplePropertyService
{
int ExampleProperty { get; set; }
}
public class AGameInXNA : Microsoft.Xna.Framework.Game, IExamplePropertyService
{
int ExampleGameProperty { get; set; }
void Initialize()
{
// Do other initialization
Services.Add( typeof(IExamplePropertyService), this );
}
}
public class ReferenceToAGameInXNA
{
IExamplePropertyService propertyService;
public void GetGameInstance(Game game)
{
propertyService = (IExamplePropertyService)game.GetService( typeof(IExamplePropertyService) );
}
public void SetExampleGameProperty()
{
propertyService.ExampleGameProperty = 21;
}
}
Implement it, and register it with the Game component, then in your ReferenceToAGameInXNA, you would query for this service and store it (rather than the Game) for use later.
As a bonus benefit, The IExamplePropertyService no longer even needs to be implemented by the Game class, it could be implemented by any GameComponent.
This makes for an easy way to seperate classes from having to know about the inner workings of other classes in the Game. So long as the services exist somewhere, your ReferenceToAGameInXNA can be used.
I don't think generics are what you are actually looking for here. In your second class, just change the type of all of the gameInstance to the type of the class you created for your game, in this case AGameInXNA. There should only be a need for one subclass of the Game type in each XNA game. That will allow you to access any public members of AGameInXNA from the Reference class.
If this isn't what you are after, please give a more detailed explanation of what you are trying to accomplish and I'll try to help you.
I don't know XNA, but if you want to have several classes that inherit from Game and have the same property on all of them, you could create an abstract class that inherits from Game and let the other classes inherit from that instead.
(Also, your GetGameInstance() is badly named, because it sets the field, it doesn't get it. And it's probably better as property anyway.)
public abstract class GameBase : Microsoft.Xna.Framework.Game
{
public int ExampleGameProperty { get; set; }
}
public class AGameInXNA : GameBase
{
// code specific to AGameInXNA
}
public class ReferenceToAGameInXNA
{
public GameBase GameInstance { get; set; }
public void SetExampleGameProperty()
{
GameInstance.ExampleGameProperty = 21;
}
}
If the other classed that have ExampleGameProperty shouldn't inherit from Game, you could create an interface instead. AGameInXNA would then inherit from Game directly and it would also implement the interface. And you would work with that interface in ReferenceToAGameInXNA.
using "Game gameInstance;" you can not acess ExmpleProp. You should use "AGameInXNA gameInstance;" too access ExampleProp.