I'm looking to make an abstract class Entity which then has few classes that derive from it like Enemy, Friendly and Player. The reason I do this is because the classes have a lot of properties/fields that are alike. I also have 2 methods: updateEntity and drawEntity. The reason I have the update and draw entity is that drawEntity & updateEntity is the same for most of the classes that inherit from it. This is the code of my entity class:
public abstract class Entity
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private Texture2D texture;
public Texture2D Texture
{
get { return texture; }
set { texture = value; }
}
private Vector2 position;
public Vector2 Position
{
get { return position; }
set { position = value; }
}
private int health;
public int Health
{
get { return health; }
set { health = value; }
}
private Color entColor;
public Color EntColor
{
get { return entColor; }
set { entColor = value; }
}
public Entity(string name, Texture2D texture, Vector2 position, int health, Color entColor)
{
this.name = name;
this.texture = texture;
this.position = position;
this.health = health;
this.entColor = entColor;
}
public virtual void updateEntity(GameTime gameTime)
{
//update stuff here
}
public virtual void drawEntity(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height), entColor);
}
}
And this is how I envision my Enemy class :
public Enemy(string name, Texture2D texture, Vector2 position, int health, Color entColor)
{
Name = name;
Texture = texture;
Position = position;
Health = health;
EntColor = entColor;
}
Can anybody tell me if this is a good use of abstract class or if I'm doing something completely wrong in game design/architecture way?
You usually use an abstract class when its implementation is not complete to work with but it contains properties and/or methods that are common for other types that are derived from it or it provides an interface that should be shared by derived types but cannot be implemented at this lever of abstraction and thus it is not possible to instantiate it.
Such an example could be an abstract class Fruit that has a Color property that is common to all fruits and doesn't have to be implemented by each one of them. It can also have a method Grow() without implementation. This class alone makes no sense yet. You need to implement a concrete fruit like an Apple type and implement the Grow() method for this particular fruit.
In your case the Entity would be such a fruit and the apple could be a rectangle or a circle that implement their own drawing logic.
Base entity:
public abstract class Entity
{
public abstract void Draw(); // no implementation here
public virtual void UpdateEntity(GameTime gameTime)
{
// default update
}
}
Rectangle:
public class Rectangle : Entity
{
public override void Draw()
{
// draw a rectangle here
}
}
Circle which uses a different logic for UpdateEntity:
public class Circle : Entity
{
public override void Draw()
{
// draw a circle here
}
public override void UpdateEntity(GameTime gameTime)
{
// custom update for circles
}
}
Related
Im working on a level editor in monogame for my engine.
I want to make a class where i can call a simple function and it will draw a sprite.
This is the function i want to call - and as you may know you have to be able to load and unload content and use the draw method.
Question: How would I make this be able to use those so that all I have to do is call this function and it works?
Here is the function:
public static void DrawSprite(Texture2D Texture, string Path, Vector2 Position, Color Color)
{
}
If you are going to leave the drawing to a single static method then you would be restricting what you are able to draw. I suggest creating an interface and do some abstraction.
Interface
public interface IGameObject
{
void Update(GameTime gameTime);
void Draw();
}
Utility Class
public sealed class GameUtility
{
private static GameUtility instance = null;
private static readonly object _lock = new object();
public ContentManager ContentManager { get; private set; }
public SpriteBatch SpriteBatch { get; private set; }
public static GameUtility Instance
{
get
{
lock (_lock)
{
if (instance == null)
{
instance = new GameUtility();
}
return instance;
}
}
}
public void SetContentManager(ContentManager contentManager)
{
this.ContentManager = contentManager;
}
public void SetSpriteBatch(SpriteBatch spriteBatch)
{
this.SpriteBatch = spriteBatch;
}
public GameUtility(ContentManager contentManager, SpriteBatch spriteBatch)
{
this.contentManager = contentManager;
this.spriteBatch = spriteBatch;
}
}
Game Objects
public class Hero : IGameObject
{
private Texture2D texture;
private Vector2 position;
private Color color;
public Hero(string path)
{
texture = GameUtility.Instance.ContentManager.Load<Texture2D>(path);
}
public void Update(GameTime gameTime)
{
// Do game update logic
}
public void Draw()
{
GameUtility.Instance.SpriteBatch.Begin();
GameUtility.Instance.SpriteBatch.Draw(texture, position, color);
GameUtility.Instance.SpriteBatch.End();
}
}
Game Class
Initialize the GameUtility
GameUtility.Instance.SetContentManager(contentManager);
GameUtility.Instance.SetSpriteBatch(spriteBatch);
Create the game objects
gameObects = new List<IGameObject>();
gameObjects.Add(new Hero("some path"));
Utilize the interface
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
foreach (IGameObject gameObject in gameObjects)
{
gameObject.Draw();
}
base.Draw(gameTime);
}
The beauty of this approach is you can perform different drawings based on your needs. For example, you could use a Rectangle instead of Vector2 based on different scenarios. You can also draw a sprite font or something else.
For unloading content, there is only one option which is
GameUtility.Instance.ContentManager.Unload();
You better unload content during your transition to the next level as calling ContentManager.Unload() will dispose all resources. As to why it disposes everything in one go, I don't really understand but that is the design.
Hope this answer give you some insight. I would not suggest creating this public static void DrawSprite.
I have a base class called Projectile and a child class called SaiBlast. In my SaiBlast class, I want to use methods inherited from Projectile, but still use const variables belonging to SaiBlast in these inherited methods.
Here's a minimal example.
base class:
class Projectile
{
protected const float defaultSpeed = 50;
public void Shoot( float speed = defaultSpeed ) //optional parameter
{
//code
}
}
child class:
class SaiBlast : Projectile
{
protected new const float defaultSpeed = 100;
}
Now if I say:
SaiBlast saiBlast = new SaiBlast();
saiBlast.Shoot();
Shoot() should use a value of 100 since that is the default speed for sai blasts. Right now it uses the default speed for Projectiles in general which is 50.
I was half expecting this to work because of polymorphism, but I figured I'd run into this problem because the compiler fills in the hard values for constants at compile time.
How can I accomplish this?
class Projectile
{
protected virtual float DefaultSpeed { get { return 50; } }
public void Shoot(float? speed = null)
{
float actualSpeed = speed ?? DefaultSpeed;
//Do stuff
}
}
class SaiBlast : Projectile
{
protected override float DefaultSpeed { get { return 100; } }
}
I want to override a method while it's object initialization, something like this:
Button = new Button(parameter1, parameter2){
public override onClicked(){
//implementation
}
};
This it's what a got:
public class Button:Entity
{
protected Texture2D texture2D;
public Vector2 vector2;
public Button(Texture2D image, Vector2 position
{
this.image = image;
this.position = position;
this.action = action;
}
public abstract void onClicked();
}
abstract class Entity
{
public Vector2 position;
public int radius = 20;
protected Texture2D image;
public virtual void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(image,position,Color.White);
}
}
I just try to make an implementation like the one I speak before but it does not compile. How one can get this to compile or implement such "per-instance" overrides?
public class Button:Entity
{
//Vector, Radius and texture are already part of Button, since it extend Entity
public EventHandler onClicked;
public Button(Texture2D image, Vector2 position)
{
this.image = image;
this.position = position;
this.action = action;
}
}
abstract class Entity
{
public Vector2 position;
public int radius = 20;
protected Texture2D image;
public virtual void draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(image,position,Color.White);
}
}
And use it this way:
Button = new Button(parameter1, parameter2){
onClicked = new EventHandler(NameOfYourMethod);
};
I have one base class:
class Tile{}
And few others which extends tile
class Free : Tile{}
class Wall : Tile{}
Each tile have its own texture, it isn't string but its Texture2D which has to be loaded upon initialization. I imagine code will look similar to this but I'm not sure how to create this properly:
class Tile{
static Texture2D texture; //Static will use less ram because it will be same for inherited class?
static string texture_path; //This is set by inherited class
public Tile(){
if(texture==null)
texture = LoadTexture(texture_path);
}
}
class Free : Tile{
static string texture_path = "Content/wall.png";
}
With other words, all Free tiles have same texture and all Wall tiles have same textures - that is why in my opinion I should use static.
How to do this properly?
What you need to do is declare the property in base class and provide an option for the child class to override it. This will allow you to also provide a default value if you want to.
Some thing like this:
public class Tile
{
private string _texturePath = String.Empty;
private Texture2D _texture;
protected virtual string TexturePath { private get { return _texturePath; } set { _texturePath = value; } }
public Tile()
{
if (!string.IsNullOrWhiteSpace(TexturePath))
_texture = LoadTexture(TexturePath);
}
private Texture2D LoadTexture(string texturePath)
{
throw new NotImplementedException();
}
}
internal class Texture2D
{
}
public sealed class Free:Tile
{
protected override string TexturePath
{
set
{
if (value == null) throw new ArgumentNullException("value");
base.TexturePath = "Content/wall.png";
}
}
}
In case you do not want to provide a default texture path, you can plan to make the property and the base class abstract.
If you want your base class to have access to texture_path you should declare it in your base class.
A baseclass doesn't know anything about fields, properties or methods declared in its subclasses. This is by design BTW...
According to your question, you want all instances of Free to share a texture and all instances of Wall to share a texture. This means that you want the static fields texture and texture_path to be in the child classes, not the parent.
Ex:
public class Tile { }
public class Free : Tile
{
private static Texture2D texture;
private static string texture_path;
}
public class Wall : Tile
{
private static Texture2D texture;
private static string texture_path;
}
If you want Tile references to have texture and texture_path properties so that you can access the shared texture or texture_path from an instance, you need a virtual or abstract property.
Ex:
public abstract class Tile
{
public abstract Texture2D Texture { get; }
public abstract string TexturePath { get; }
}
public class Free : Tile
{
private static Texture2D texture;
private static string texture_path;
public override Texture2D Texture { get { return texture; } }
public override string TexturePath { get { return texture_path; } }
}
// and similarly for Wall
By way of an intro, I'm creating a basic Quadtree engine for personal learning purposes. I'm wanting this engine to have the capability of working with many different types of shapes (at the moment I'm going with circles and squares) that will all move around in a window and perform some sort of action when collision occurs.
After asking a question on the topic of generic lists earlier, I have decided on using an interface for polymorphism. The best interface for this would be an interface utilising Vector2 due to the fact that every object that appears in my Quadtree will have an x,y position and Vector2 covers that nicely. Here is my code as it currently stands:
public interface ISpatialNode {
Vector2 position { get; set; }
}
public class QShape {
public string colour { get; set; }
}
public class QCircle : QShape, ISpatialNode {
public int radius;
public Vector2 position {
get { return position; }
set { position = value; }
}
public QCircle(int theRadius, float theX, float theY, string theColour) {
this.radius = theRadius;
this.position = new Vector2(theX, theY);
this.colour = theColour;
}
}
public class QSquare : QShape, ISpatialNode {
public int sideLength;
public Vector2 position {
get { return position; }
set { position = value; }
}
public QSquare(int theSideLength, float theX, float theY, string theColour) {
this.sideLength = theSideLength;
this.position = new Vector2(theX, theY);
this.colour = theColour;
}
}
So I'll be eventually wanting to have an interface that works to the point that I can use the generic list List<ISpatialNode> QObjectList = new List<ISpatialNode>(); and I can add shapes to it using the code QObjectList.Add(new QCircle(50, 400, 300, "Red")); or QObjectList.Add(new QSquare(100, 400, 300, "Blue")); or something along those lines (keep in mind that I'll be wanting to add different shapes later along the line).
Problem is, this code doesn't seem to work when I call it from here (Initialize() is the XNA method):
protected override void Initialize() {
QObjectList.Add(new QCircle(5, 10, 10, "Red"));
base.Initialize();
}
So my question has two parts:
1. Why does this code give me a stackoverflow error at the set {
position = value; } part of my QCircle and QSquare classes?
2. Would this be an efficient/effective way of utilising interfaces for
polymorphism?
The problem is in your property it is setting itself in circular loop
public Vector2 position { get ; set ; }
Or declare a private field
private Vector2 _position;
public Vector2 position {
get { return _position; }
set { _position = value; }
}
Stack overflow is because:
public Vector2 position {
get { return position; }
set { position = value; }
}
the set actually sets the same again. You may want this:
private Vector2 _position;
public Vector2 position {
get { return _position; }
set { _position = value; }
}
or its short version:
public Vector2 position { get; set; } //BTW, the c# standard is to use upper camel case property names
Regarding the use of polymorphism, it seems right in this scenario.