How to use abstract methods in inherited classes? - c#

I'm currently working on a school project that's due to friday & I've got a whole lot to do.
The assignment is to make a video game with XNA framework using Monogame. I'm currently working with collisions.
The structure for gameobjects looks somewhat like this:
For collisions, I have a simple collision class
class Collision{
public GameObject Other;
public GameObject Obj1;
public Collision(GameObject obj1, GameObject other)
{
Other = other;
Obj1 = obj1;
}}
The collisions are handled in a static method in the GameObject class:
public static void UpdateCollisions()
{
//Empty the list
AllCollisions.Clear();
for (int a = 0; a < AllGameObjectsWithCollision.Count; a++)
{
GameObject obja = AllGameObjectsWithCollision[a];
for (int b = 0; b < AllGameObjectsWithCollision.Count; b++)
{
GameObject objb = AllGameObjectsWithCollision[b];
if (obja.Mask != null & objb.Mask!= null && obja != objb)
{
if (obja.Mask.CollisionRectangle.Intersects(objb.Mask.CollisionRectangle))
AllCollisions.Add(new Collision(obja, objb));
}
}
}
}
This far it's working, the game is finding all collisions like it should. However now I need to let my objects know that they're colliding, and tell them what to do.
For this, I made the entity class abstract to be able to declare an abstract method called "OnCollision(Collision collision)"
abstract class Entity : GameObject
{
public float Health;
public float MaxHealth;
public bool Alive;
public float OriginalDmg;
public float Dmg;
public abstract void OnCollision(Collision collision);
}
Then I'm overriding the method in the classes that inherit the Entity class
Ex. Projectile
class Projectile : Entity
{
Entity Owner;
ProjectileType pType;
public Projectile(Texture2D image, float maxSpeed, Entity owner, float dmg, ProjectileType type)
{
Image = image;
MaxSpeed = maxSpeed;
AccelerationSpeed = MaxSpeed;
Owner = owner;
Dmg = dmg;
pType = type;
}
public override void OnCollision(Collision collision)
{
#region If this projectile friendly
if (pType == ProjectileType.Friendly)
{
//If colliding with an enemy
if (collision.Other.GetType() == typeof(Enemy))
{
var enemy = (Enemy)collision.Other;
enemy.Health -= Dmg;
Destroy(this);
}
}
#endregion
#region If this projectile is hostile
if (pType == ProjectileType.Hostile)
{
}
#endregion
}
}
Then I'm trying to call the OnCollision method from my Update in the GameObject class.
This is how I try to inform my objects if they are collding and who they're colliding with:
if (GetType().IsAssignableFrom(typeof(Entity)))
{
Entity entity = (Entity)this;
if (GetType() == typeof(Player))
entity = (Player)this;
if (GetType() == typeof(Enemy))
entity = (Enemy)this;
if (GetType() == typeof(Projectile))
entity = (Projectile)this;
var entityCol = FindCollision(entity);
if (entityCol != null)
entity.OnCollision(entityCol);
}
I'm new to abstract classes & overriding, so I might have gotten the whole idea wrong.
But it seems the OnCollision method isn't reached as I've tried to Debug.WriteLine stuff but nothing shows up in the output window.
Thanks for reading & perhaps trying to help me out :)
Mediafire link to download the project in case you want to see all the code.

You should read up on interfaces. An interface provides a contract (a bunch of methods and properties) that deriving classes must implement. Abstract classes are more concrete than interfaces in that they can also provide a base implementation for deriving classes. You can only derive from one abstract class whereas you can derive from multiple interfaces. From the code in your post it looks like you are using an abstract class like an interface.
You are using reflection to do type checking. There's the is keyword for testing type compatibility. For example:
if(entity is Player)
{
var player = (Player)entity;
// player specific code
}
Finally; from what I can gather from your post it looks like you aren't quite using inheritance correctly. It looks like you are correctly using inheritance to build a type hierarchy but then putting all the logic in a base class.
Inheritance is meant to let you put the specialized logic in the appropriate class.
public interface IGameObject
{
void OnCollision(IGameObject target);
}
public class Player : IGameObject
{
public void OnCollision(IGameObject target)
{
Console.WriteLine("Player collision");
}
}
public class Projectile : IGameObject
{
public void OnCollision(IGameObject target)
{
Console.WriteLine("Projectile collision");
}
}
When we then have a reference to a IGameObject and call OnCollision the appropriate OnCollision function will automatically be called. For example:
IGameObject player = new Player();
IGameObject projectile = new Projectile();
player.OnCollision(projectile);
projectile.OnCollision(player);
Output:
Player collision
Projectile collision

Eh, wrong if statement...
Using
if (GetType().IsSubclassOf(typeof(Entity)))
fixed it.
Silly mistake, my bad.

Related

Is it possible to set a method of a class from another script in Unity C#?

I'm working on a weapon system that for my fps game. The player class contains it's own methods that might need to change when a weapon is used. The problem is I want to define the methods that will be replaced with player class' methods on the weapon class.
For example I have a shooting coroutine which uses private members of Player class, I want to change the corouitine using delegates but a coroutine defined in the Weapon class won't be able to access those members.
I know that I can define the coroutine that will come with given Weapon at the Player class and change it according to the attached item, but for clarity of the code, I want to define the shooting corouitines on the Weapon classes. Is there any approach to overcome this issue? Thanks in advance.
If I understand you correctly, something like this should work?
public interface IWeapon
{
void Shoot();
}
// -------------------------------------
public class WaterGun : IWeapon
{
void Shoot()
{
// Shoot water?
}
}
// -------------------------------------
public class LaserPistol : IWeapon
{
void Shoot()
{
// Shoot laser?
}
}
// -------------------------------------
public class Player {
IWeapon weapon;
void Start()
{
this.weapon = new WaterGun();
// later
this.weapon = new LaserPistol();
}
IEnumerator Shoot()
{
// player shoot logic here then weapon-specific logic ->
this.weapon.Shoot();
}
}
But if you simply want to keep a function in a variable, there are ways to do that too, for example:
Action shootFunction;
var waterGun = new WaterGun();
shootFunction = waterGun.Shoot; // assigning a reference to the function without executing the method
shootFunction(); // calls waterGun's Shoot() method
I think you need to detail what you have & what you want to achieve in order to get a good answer here.
It looks like your question boils down to:
I want to define the shooting corouitines(sic) on the Weapon classes
Yeah, we can do that. Let's start by looking at the bits we'd need. In this scenario, it makes sense that we use an interface:
public interface IWeapon
{
bool weaponFiring {get;}
IEnumerator StartWeaponFire ( Player player );
}
Let's look at a sample weapon:
public class WaterPistol : IWeapon
{
public bool weaponFiring { get; private set; }
public IEnumerator StartWeaponFire ( Player player )
{
weaponFiring = true;
Debug.Log ( "Squirt!" );
// Do your weapon logic/animation/cooldown here ..
yield return new WaitForSeconds ( 0.5f );
// We can acccess the 'player' data because we've sent a reference as an argument.
player.currentHealth -= 1;
Debug.Log ( "..." );
weaponFiring = false;
}
}
Now, to run the StartWeaponFire is just as easy as if the coroutine were actually on the player, but it's on the IWeapon instead.
public class Player : MonoBehaviour
{
// An example of data on this player class.
public float currentHealth { get; set; }
// A reference to the current weapon. Has the coroutine we want to start.
public IWeapon currentWeapon { get; set; }
// This can be used to manually stop a coroutine if needed.
private Coroutine _weaponCoroutine;
private void Update ( )
{
if ( Input.GetMouseButton ( 0 )
&& currentWeapon != null
&& !currentWeapon.weaponFiring )
{
_weaponCoroutine = StartCoroutine ( currentWeapon.StartWeaponFire ( this ) );
}
}
}
Notice we're starting a coroutine which has been defined on the currentWeapon, and we're sending through a reference to the Player class. The other method, the 'coroutine' in this case, can then call the public fields, properties and methods of the Player instance.
This is great way to enable an item to define a "coroutine" but allow a specified object to run that coroutine code. This scenario would allow you to have multiple 'players' be able to run the same coroutine, and you don't need to clutter your `Player' class with code for each individual weapon you might include in the game.

When I'm trying to set a value for a base class from a child class (inheritance) it does not work (Unity C#)

I'm creating an enemy (from EnemyCreator1 class) with both EnemyMove1 and MarkusEnemy scripts (EnemyMove1 is a parent class to MarkusEnemy class). In EnemyCreator1 class I set value mainState of the script EnemyMove1 to "CHASE", but when I'm trying to access it from that class it says that mainState is "IDLE" (Please read my coments below because there are more explanations about what am I trying to achieve)
public class EnemyMove1 : MonoBehaviour
{
public enum mainStates { IDLE, CHASE }
public mainStates mainState;
void Update()
{
Debug.Log(mainState); //mainstate == IDLE, but should be CHASE
}
}
public class EnemyCreator1 : MonoBehaviour
{
[SerializeField] private GameObject enemyPrefab;
public void CreateEnemyAndSetItsStateToChase()
{
GameObject enemy = Instantiate(enemyPrefab);
enemy.GetComponent<EnemyMove1>().mainState = EnemyMove1.mainStates.CHASE;
}
}
public class MarkusEnemy : EnemyMove1
{
void Update()
{
EnemyMove enemyMoveScript = GetComponent<EnemyMove>();
Debug.Log(enemyMoveScript.mainState); //mainstate == CHASE
}
}
From the above code it looks like you are inheriting from a different base class EnemyMove, not EnemyMove1.
Thank you guys for helping me, after searching for the information about base classes I decided that it is impossible to access directly it's variables from another objects' scripts so I just simply call methods with variables as arguments (I put variables in round brackets of the method)

C# shared property & field inheritance

I've been trying to perfectly structure this project I'm working on in different classes while maximizing the benefits of inheritance. So far however, it's given me more headaches than benefits.
Consider this:
public class SuperClass : MonoBehaviour
{
[SerializeField] protected Camera _camera;
}
and this
public class SubClass : SuperClass
{
}
Both scripts are attached to different game objects in the scene.
The Camera is to be assigned by dragging it in the inspector
I tried this, and unity seemed to tell me that I had to assign the camera to the SuperClass game object AND to the subclass game object, which makes no sense to me.
How can I assign a camera to SuperClass.cs, which is then used and shared by all of its subclasses?
Thanks in advance!
shared by all of its subclasses
Shared by classes could can only be achieved by using "static" (static variable or singleton).
A workaround could be
public class SubClass :SuperClass
{
[SerializeField] Camera camera;
void Awake()
{
if(camera!=null)
{
_camera=camera;
}
}
// Start is called before the first frame update
void Start()
{
camera=_camera;
}
}
To further extend the solution, you could write a editor script or just get the camera from the code.
You need to create public static Camera property somewhere and reference it in your code, using property:
public static class StaticValues
{
public static Camera Camera {get; set;}
}
public class SuperClass : MonoBehaviour
{
[SerializeField] protected Camera _camera
{
get
{
return StaticValues.Camera;
}
set
{
StaticValues.Camera = value;
}
}
}
public class SubClass : SuperClass
{
}

Return multiple types from single method in C#

I am working on a basic game and 2D engine in Xna/C# and I am trying to simplify a few things in it. I have a base class of Entity2D from the engine and two classes specific to the game that inherit from it: Tower and Enemy. In my engine, rather than having two separate lists, one for Towers and one for Enemies I would like to combine them together into a single generic list. I then I have the problem of when I need to return a Tower from the list or an Enemy from the list. I know that I can use typecasting from the engine object:
class Entity2D {...} //engine object
class Tower : Entity2D {...} //game specific
class Enemy : Entity2D {...} //game specific
//In engine:
public Entity2D GetEntity(int index) { ...return objects[index];}
//Somewhere in the game
{
Enemy e = GetEntity(0) as Enemy;
if(e != null)
//Enemy returned
Tower t = GetEntity(0) as Tower;
if(t != null)
//Tower returned
}
Of course this seems really inefficient.
I have also looked into the is keyword a bit, and it seems that works like so:
Entity2D entity = GetEntity(0);
if(entity is Tower)
{
Tower t = (Tower)entity;
t.DoTowerThings();
}
Still that results in returning a base object and using even more memory to create a second object and typecast into it.
What would really be nice is if there is a way to do something like this:
//In engine:
public T GetEntity(int index)
{
if(T == Tower) //or however this would work: (T is Tower), (T as Tower), etc
return objects[index] as Tower;
else if(T == Enemy)
return objects[index] as Enemy;
else return null;
}
Enemy e = GetEntity(0);
But then that breaks the engine portion of having the engine and game be seperate
I am looking for the clearest as well as most memory efficient way to go about this while still having Entity2D be engine based and avoid having Tower or Enemy in the engine at all.
Any suggestions would be welcome!
Thanks!
Nearly there!
//In engine:
public T GetEntity<T>(int index) where T : Entity2D
{
return objects[index] as T;
}
//Somewhere else:
Enemy e = GetEntity<Enemy>(0);
Note: if objects[index] is NOT a T, it will return null instead.
However, if it was my game, I would just keep separate lists for each type of object.
If you have to disambiguate the return value, then the structure of the code is bad, the objects are not logically similar and you would be better off having two lists with a separate accessor for each type.
However, if the types are very similar and you only need to disambiguate between them rarely, then do this:-
abstract class GameEntity : Entity2D
{
abstract public void TowerOnlyFunction (args); // need to look up exact syntax, but you get the idea
abstract public void EnemyOnlyFunction (args);
void CommonFunctions (args);
}
class Tower : GameEntity
{
public void TowerOnlyFunction (args)
{
// code
}
public void EnemyOnlyFunction (args)
{
// empty
}
}
class Enemy : GameEntity
{
public void TowerOnlyFunction (args)
{
// empty
}
public void EnemyOnlyFunction (args)
{
// code
}
}
//Somewhere in the game
void DoSomethingWithTower ()
{
GameEntity e = GetEntity(0);
e.TowerOnlyFunction ();
}
You can do this, (full code on Github)
public T GetEntity<T>(int index) where T : Entity2D
{
return list.ElementAt(index) as T;
}
If the element is not the expected type it will return null.
Tower t = GetEntity<Tower>(0);

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