Too much? No. Looks like a reasonable and logical heirarchy, except the fact your ascii art didn't hold up
The trick and your snags are going to be in the design of your managers and animation logic. Your EntityManager should be clean enough, but its in the inventory, and animation/sprite side where your inter-dependencies are going to get the trickiest. For example, who will own the animation? The entity class? The derived class?
As to your question, I would keep everything at the entity level, so your EntityManager deals only with Entity classes. Make the base as streamlined as possible, nothing superfluous. Load, Destroy, Get, Update and Draw should be about all you need. Either that or make your EntityManager a ( or have access to a ) factory class which is in charge of creating all entities. If you give entity an Update() virtual method, animated classes derived from it can transparently handle animation that way.
Hopefully that made sense.
Thanks for the reply. Currently, this is my Entity base class:
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using CGPLibrary.Managers;
using CGPLibrary;
using System.Collections.Generic;
using System;
namespace CGPLibrary.Entities
{
public class Entity
{
#region NEEDED HANDLES
protected EntityManager entManager;
Animation anim_control;
public HumanPlayer thePlayer;
#endregion
public string name;
public Texture2D texture;
protected Vector2 position;
protected int entHeight;
protected int entWidth;
protected float rotation;
protected Vector2 origin;
protected Vector2 gravity;
protected float scale;
protected Color color;
#region PROPERTIES
protected float zDepth { get; set; }
protected bool bAnimate { get; set; }
public Rectangle srcRect { get; set; }
public Rectangle destRect { get; set; }
#region SCALE PROPERTY
//resizes the destination rectangle when a scale is applied
public float Scale
{
get { return scale; }
set
{
scale = value;
entHeight = (int)(entHeight * scale);
entWidth = (int)(entWidth * scale);
destRect = new Rectangle((int)position.X, (int)position.Y, (int)(entWidth), (int)(entHeight));
}
}
#endregion
#endregion
#region CONSTRUCTOR ENTITY
//Will construct an entity with an animation if the SpriteSheet is non-null
//otherwise it will just use the texture
public Entity(EntityManager entManager, string name, Texture2D texture, Vector2 position, SpriteSheet spriteSheet, float zDepth)
{
scale = 1.0f;
#region IF ENTITY IS ANIMATED
if (spriteSheet != null)
{
anim_control = new Animation(spriteSheet);
this.texture = spriteSheet.texture;
this.srcRect = spriteSheet.srcRect;
this.entWidth = (int)(spriteSheet.frameWidth*scale);
this.entHeight = (int)(spriteSheet.frameHeight*scale);
this.destRect = new Rectangle((int)position.X, (int)position.Y, (int)(entWidth), (int)(entHeight));
bAnimate = true;
}
#endregion
#region IF NO ANIMATION
else
{
this.texture = texture;
this.srcRect = new Rectangle(0,0,texture.Width,texture.Height);
this.entHeight = (int)(texture.Height * scale);
this.entWidth = (int)(texture.Width * scale);
this.destRect = new Rectangle((int)position.X, (int)position.Y, (int)(entWidth),(int) (entHeight));
bAnimate = false;
}
#endregion
#region DEFAULT VALUES
this.zDepth = zDepth;
this.entManager = entManager;
this.gravity = new Vector2(0,5);
this.rotation = 0;
this.origin = Vector2.Zero;
this.color = Color.White;
this.name = name;
this.position = position;
#endregion
entManager.entityList.Add(this);
// entManager.positionList.Add(position, this);
}
#endregion
public void animate(float elapsed)
{
anim_control.animate(this,elapsed);
}
#region MISC METHODS
public bool onScreen()
{
if (position.X < 0 || position.X > GLOBALS.SCREENWIDTH)
return false;
if (position.Y < 0 || position.Y > GLOBALS.SCREENHEIGHT)
return false;
return true;
}
public int distance(Rectangle pos1, Rectangle pos2)
{
Point centre1 = pos1.Center;
Point centre2 = pos2.Center;
double x1 = centre1.X;
double y1 = centre1.Y;
double x2 = centre2.X;
double y2 = centre2.Y;
double xDiff = x2 - x1;
double yDiff = y2 - y1;
double xDiffSq = xDiff * xDiff;
double yDiffSq = yDiff * yDiff;
double sum = xDiffSq + yDiffSq;
double distance = Math.Sqrt(sum);
return (int)distance;
}
#endregion
public virtual void Draw(SpriteBatch batch)
{
batch.Draw(texture, position
,this.srcRect,
Color.White,
rotation,
origin,
Scale,
SpriteEffects.None,
zDepth);
}
public virtual void Update(GameTime gameTime)
{
this.origin = new Vector2(entWidth / 2, entHeight / 2);
//updates dest rectangle
destRect = new Rectangle((int)position.X, (int)position.Y, (int)(entWidth), (int)(entHeight));
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
if(bAnimate)
animate(elapsed);
}
#region ANIMATION CONTROL
public void setAnimFrame(int frame)
{
int width = anim_control.width;
int height = anim_control.height;
if (anim_control.horizontal)
srcRect = new Rectangle(frame*width, srcRect.Y, width, height);
else
srcRect = new Rectangle(srcRect.X, frame * height, width, height);
}
//sets the col/row depending on if the animation is read horiz/vertical
//therebey drawing a new set of frames / new animation
public void setAnimation(int animation)
{
anim_control.setAnimation(animation);
}
#endregion
}
}
As you can see, when an entity is created, it will determine if it needs to be Animated (if SpriteSheet was null test) and add the entity to the list which contains all entities. Currently, it is structured like you said, my update method will animate all entities with an animation. But I am currently trying to implement a HUD.
My idea was, to create a HUD class which contained all textures needed(life bars/armour bars) etc. Problems arose though when I realised I would need too access some attributes of the player,
namely CurrentHealth, CurrentArmour, and I would also need the HUD to show which Weapon was currently equipped. This is when my brain started melting.
EDIT: Also, is it normal for every subclass to have the same constructor as the base class?(minus the extra variables)