How can I do a simple effect system with inheritance? - c#

I'm trying to practice with inheritance and just in general having scripts interact with each other and I thought doing a simple effect system could be fun, but I'm a bit stuck on how to structure things.
I keep wanting to do this
public abstract class BaseEffect : ScriptableObject
{
//not sure if this is a good use of enum
public enum EffectType
{
harm, //can be applied to enemies
help, //can be applied to allies
self //can be applied to yourself
}
public string name;
public string description;
public float duration;
public bool canStack; //can the effect be applied multiple times
public EffectType type;
//I'd probably also write my apply and remove effect methods here
}
And then a bunch of derived classes like this
public class TestEffect : BaseEffect
{
//maybe include some variables specific to this effect
//when the effect gets applied have this run every frame to od whatever the effect does
public void DoEffect()
{
}
}
I have a feeling though that this isn't a good way to go about doing this or at least the way I've written it isn't good so looking for some advice to get on the right track

This arrangement may benefit from an abstract method or usage of an Interface consumed by an abstract class to enforce derived classes to respond to events. Speaking of events, you could also wire the derived calls up through events. In simple terms, introduce an abstract method in the base class, which must be implemented in derived classes. Then call the method in the base classes "plumbing" when everything special about the event is ready.
public abstract class BaseEffect : ScriptableObject
{
protected abstract void DoEffect();
private SomeMethod()
{
if(canDoEffect)
DoEffect();
}
}

Related

Unity 3D: Should I make an extensive script or multiple smaller ones for in game items?

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.

Open-Close principle about new features

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.

Where should properties reside when modeling OOP? Small example included

I'm looking to learn how to use interfaces and base classes effectively. I'm not exactly sure where to put common properties? Do only behaviors belong in an interface? If properties such as: Color and MinSpeed shouldn't go in the interface, where should they live? In an abstract class?
public interface IVehicle
{
void Speed();
void Clean();
void Stop();
}
public class Bmw : IVehicle
{
// Because these pertain to every vehicle no matter of maker,
// should these propertes go in the interface? Or in an abstract class?
public string Color { get; set; }
public int MinSpeed { get; set; }
#region IVehicle Members
public void Speed()
{
}
public void Clean()
{
}
public void Stop()
{
}
#endregion
}
Interfaces can be thought of as a contract that must be satisfied by any implementing class. Use it if you want to guarentee that all classes do the same thing—satisfy the same API—but you don't care how they do it. If properties are a part of that API, then by all means include them in your interface.
From your example above, if you want all cars to be guaranteed to have a color and minSpeed, then those properties belong in the interface. If those properties are specific to BMWs alone, then they belong in the BMW class. If those properties belong to some classes but not others, you could create a new interface extending the original one:
public interface IVehicleWithColorAndMinSpeed : IVehicle
{
string Color { get; set; }
int MinSpeed { get; set; }
}
(just don't get carried away with this)
Abstract classes are similar, but allow you to provide a default implementation for your sub classes.
Abstract classes tend to be easier to version, since you can add something new to your API, and provide a default implementation that your existing subclasses will automatically pick up; adding something to an interface immediately breaks all existing classes which implement that interface.
The 'right' answer is entirely dependent on your domain model. What is the problem you're trying to solve? There is no 'right' answer other than the one which solves the particular problem at hand with the greatest:
understandability
maintainability
brevity
isolation
performance
You can probably consider most of those properties to be in order of importance, but they mean different things to different people and there's probably a lot of debate implied there too.
Can you tell us any more about the particular application you imagine these classes to serve?

Empty methods on base class vs explicit type checking

Let's say you have two types of object, one that derives from the other but adds a single piece of extra functionality. The two ways I can think to deal with this extra functionality are adding an empty method on the base class that is always called (the derived class can then override this method) or explicit type checking to see if you have an instance of the derived class and then calling the extra method.
Both of these seem like hacks, is there a better way? If not is one preferred over the other? Both ways would work but neither seems particularly clean, one way you are polluting the base class with useless method stubs, the other way you are using explicit type checking which is usually considered a bad idea.
Here's an example to make it clear what I mean:
public class Weapon
{
// Should there be an empty StartCharging() here?
public virtual void Fire()
{
// Do something
}
}
public class ChargedWeapon : Weapon
{
public void StartCharging()
{
// Do something
}
public override void Fire()
{
// Do something
base.Fire();
}
}
public class Game
{
private Weapon weapon;
public void HandleUserInput()
{
if (MouseButton.WasPressed())
{
// Or should there be an if (weapon is ChargedWeapon) here
weapon.StartCharging();
}
else if (MouseButton.WasReleased())
{
weapon.Fire();
}
}
}
It's better to add the method to base class instead of doing a type check. What will happen if you do a typecheck and then decide to implement a new type of weapon which also needs charging? Will you add another test condition?
Edit: In your code, I see a start for an implementation of Strategy Pattern. I guess that your use case will benefit greatly from it and from State Pattern. If you need more details on these, leave a comment (as they are a little offtopic from the initial question's point of view)
Definitely don't do Type Checking here.
The big question is why you are dealing with a type Weapon and then calling StartCharging on it in your Game class? The implication in this code is that all Weapons implement StartCharging - if they do not, then you have already diverged from good OO practices.
Instead of this I would create an abstract method such as Initialise on Weapon. - In your Concrete Weapon classes implement this in different ways - e.g. for ChargedWeapon you would use:
public override void Initialise()
{
StartCharging();
}
for different weapons, the implementation would differ, e.g. For a HolsteredWeapon it might be:
public override void Initialise()
{
DrawWeapon();
}
In these example, only ChargedWeapon classes need to contain a StartCharging() method, and only HolsteredWeapon classes need to contain a DrawWeapon() method. However, every weapon needs an Initialise method.
Now the base type only contains methods which apply to ALL concrete implementations, so we are once again following good OO principles.
IMHO it is better to let the weapon(class) handle its own logic without exposing to much of its internal designs.
So simply add two methods like with the pattern startAction()/stopAction() in this case startFiring()/stopFiring() and the weapons decides if it needs to charge first/fire a single shot/fire burst/continuous fire...
Better way is to do:
public interface IChargable
{
void StartCharging();
}
public interface IWeapon
{
void Fire();
}
public class Weapon : IWeapon
{
public void Fire()
{ }
}
public class ChargedWeapon : Weapon, IChargable
{
public void StartCharging ()
{ }
}
private Weapon weapon;
public void HandleUserInput()
{
if (MouseButton.WasPressed() && weapon is IChargable)
{
((IChargable)weapon).StartCharging();
}
else if (MouseButton.WasReleased())
{
weapon.Fire();
}
}
Edit: Suppose you need to add a new weapons that is not chargeable too like "ExtraWeapon, SupperWeapon" , then you can see that using that empty method "StartCharging" for all the weapons that is not support it is useless and a bad design, furthermore you may have other methods or properties to set in that new types when MouseButton... so checking the type and only use its prepare methods/properties is a better choice.

Any real example of using interface related to multiple inheritance

I m trying to understand Interfaces so that I can implement them in my programs but I m not able to imagine how should i use them.
Also give me some eg of using them with multiple inheritance in C#
A good example for an interface is a repository pattern. Your interface will define methods like Get, GetAll, Update, Delete, etc. No implementation, just function signatures.
Then, you can write a 'concrete' implementation of that class to work with, say, MySQL. Your UI should only refer to the interface, though.
Later, if you decide to change to Microsoft SQL, you write another concrete implementation, but your UI code doesn't have to change (much).
Multiple inheritance doesn't exist in C#, in the sense that you can only inherit from one 'concrete' class; though you can inherit (or 'implement') as many interfaces as you want.
I am writing a video game. In this video game I apply different forces to objects in the game. Thrust forces, impact forces, gravitational forces. While they are calculated differently, they all have the same basic elements. I need to call an update function that will evaluate the force and add the force to the object it's attached to.
So, what I've done is create an IForce interface that has an update function for its signature. All of my forces implement this interface:
public interface IForce
{
void Update(Particle particle, GameTime gameTime);
}
Here is a sample implementation.
public class Spring : IForce
{
private Particle ThisParticle;
private Particle ThatParticle;
private float K;
public Spring(Particle thisParticle, Particle thatParticle, float k)
{
ThisParticle = thisParticle;
ThatParticle = thatParticle;
}
public void Update(Particle particle, GameTime gameTime)
{
float X = Vector3.Length(ThisParticle - ThatParticle);
ThisParticle.Forces.Add(K * X);
}
}
The update function has a simplified spring force update to make it easier to understand.
This helps in a few ways.
I can completely change the way a force is calculated without effecting other parts of my code. I do this all the time. Along the same lines, it is rediculously easy for me to add new forces. As long as it implements the IForce interface I know it will mesh well with my existing code.
Another way it helps is with handling a large number of forces. I have a force registry that has a List of IForce. Since all forces implement that interface and have an Update function it's very easy to update all the forces in my game. When I create the force I add it to the list. Then, I loop through the list and call each elements update function without worrying about what type of force it is and all my forces update.
I use interfaces every day in a lot of different situations. They are fantastic!
Note :Interface is used to restrict and access the methods or events etc from differents classes at any cost, It means we can defined many more methods inside any class but when we are calling methods through Interface means we want only other than restricted methods. In the program below User1 can use Read & Write both but User2 can Write and Execute. See this Program below.........
namespace ExplConsole
{
class Program
{
static void Main ()
{
System.Console.WriteLine("Permission for User1");
User1 usr1 = new Test(); // Create instance.
usr1.Read(); // Call method on interface.
usr1.Write();
System.Console.WriteLine("Permission for User2");
User2 usr2 = new Test();
usr2.Write();
usr2.Execute();
System.Console.ReadKey();
}
}
interface User1
{
void Read();
void Write();
}
interface User2
{
void Write();
void Execute();
}
class Test : NewTest,User1, User2
{
public void Read()
{
Console.WriteLine("Read");
}
public void Write()
{
Console.WriteLine("Write");
}
}
class NewTest
{
public void Execute()
{
Console.WriteLine("Execute");
}
}
}
Output:
Permission for User1
Read
Write
Permission for User2
Write
Execute
Interfaces simply define a contract of the public elements (e.g. properties, methods, events) for your object, not behavior.
interface IDog
{
void WagTail(); //notice no implementation
ISound Speak(); //notice no implementation
}
class Spaniel : IDog
{
public void WagTail()
{
Console.WriteLine("Shook my long, hairy tail");
}
public ISound Speak()
{
return new BarkSound("yip");
}
}
class Terrier : IDog
{
public void WagTail()
{
Console.WriteLine("Shook my short tail");
}
public ISound Speak()
{
return new BarkSound("woof");
}
}
UPDATE
In "real examples" I use interfaces with:
- Unit Testing
- GENERICS (e.g. Repository, Gateway, Settings)
interface Repository<T>{
T Find(Predicate<T>);
List<T> ListAll();
}
interface Gateway<T>{
T GetFrom(IQuery query);
void AddToDatabase(IEntity entityItem);
}
interface Settings<T>{
string Name { get; set; }
T Value { get; set; }
T Default { get; }
}
Here is one (in Java, but this is not important since they're similiar):
In my project I've created simple interface:
public interface Identifiable<T> {
public T getId();
}
Which is simple replacement to some sorts of annotations. The next step: I've made all entity classes implement this interface.
The third step is to write some syntax-sugar-like methods:
public <T> List<T> ids(List<? extends Identifiable<T> entities) { ... }
This was just an example.
The more complex example is something like validation rules: you have some validation engine (probably written by you) and a simple interface for rule:
public interface ValidationRule {
public boolean isValid(...);
}
So, this engine requires the rules to be implemented by you. And of course there will be multiple inheritance since you'll certainly wish more then a single rule.
Multiple inheritance is about having a class be usable in multiple situations: [pseudo code]
interface Shape {
// shape methods like draw, move, getboundingrect, whatever.
}
interface Serializable {
// methods like read and write
}
class Circle : public Shape, public Serializable {
// TODO: implement Shape methods
// TODO: implement Serializable methods
}
// somewhere later
{
Circle circle;
// ...
deserializer.deserialize(circle);
// ...
graphicsurface.draw(circle);
// ...
serializer.serialize(circle);
}
The idea is that your Circle class implements two different interfaces that are used in very different situations.
Sometimes being too abstract just gets in the way and referring to implementation details actually clarifies things. Therefore, I'll provide the close to the metal explanation of interfaces that made me finally grok them.
An interface is just a way of declaring that a class implements some virtual functions and how these virtual functions should be laid out in the class's vtable. When you declare an interface, you're essentially giving a high-level description of a virtual function table to the compiler. When you implement an interface, you're telling the compiler that you want to include the vtable referred to by that interface in your class.
The purpose of interfaces is that you can implicitly cast a class that implements interface I to an instance of interface I:
interface I {
void doStuff();
}
class Foo : I {
void doStuff() {}
void useAnI(I i) {}
}
var foo = new Foo();
I i = foo; // i is now a reference to the vtable pointer for I in foo.
foo.useAnI(i); // Works. You've passed useAnI a Foo, which can be used as an I.
The simple answer, in my opinion, and being somewhat new to interfaces myself is that implementing an interface in a class essentially means: "This class MUST define the functions (and parameters) in the interface".
From that, follows that whenever a certain class implements the interface, you can be sure you are able to call those functions.
If multiple classes which are otherwise different implement the same interface, you can 'cast' them all to the interface and call all the interface functions on them, which might have different effects, since each class could have a different implementation of the functions.
For example, I've been creating a program which allows a user to generate 4 different kinds of maps. For that, I've created 4 different kind of generator classes. They all implement the 'IGenerator' interface though:
public interface IGenerator {
public void generateNow(int period);
}
Which tells them to define at least a "public generateNow(int period)" function.
Whatever generator I originally had, after I cast it to a "IGenerator" I can call "generateNow(4)" on it. I won't have to be sure what type of generator I returned, which essentially means, no more "variable instanceof Class1", "variable instanceof Class2" etc. in a gigantic if statement anymore.
Take a look at something you are familiar with - ie a List collection in C#. Lists define the IList interface, and generic lists define the IList interface. IList exposes functions such as Add, Remove, and the List implements these functions. There are also BindingLists which implement IList in a slightly different way.
I would also recommend Head First Design Patterns. The code examples are in Java but are easily translated into C#, plus they will introduce you to the real power of interfaces and design patterns.

Categories

Resources