I didn’t closely examine this but let me just say the rules for a underlying abstract class are simple. Call base. from a derived class e.g. base.Spritebatch to access the Game version of the variable. What you need to remember is game1 is doing stuff under the hood that will not be done to your derived class necessarily be it abstract or not, thus from time to time you must update the derived abstracts references or call into base from your abstract class and manually update the variables the problem in that regard is notification and since this is not java there is no super keyword were you can call up you then need some indirection class or must force a coupling. Another thing to note is that for a non abstract this would be the case as well.
spriteBatch = new SpriteBatch(base.GraphicsDevice);
Which begs the question what is the real benefit to placing these in a abstract class.
Note that internally Game is essentially doing this already i.e. its the base class, see in your game1 template
GameWorld:Game and base.Draw, So when you wrap game you have to be careful that when unload or load executes or the device context is reset which windows itself can do or even if the state changes due to some call. Then you need to replace your abstract classes base. reference via abstract.spritebatch = game.spritebatch or in your case grab base.spritebatch ect…
This is actually a difficult way to do it all and it can get confusing and you might actually be unintentionally duplicating things in the derived classes certainly the derived references will be, I had a elaborate base wrapper i still do it is just a regular derived class from game1 that wraps it instead of abstracts it. That just does a ton of default stuff if i pick a method or enum to switch over to different setups, but in hindsite and my newer version that im slowly moving to it is far simpler.
My alternative answer here is below, yes its not elaborate its not elegant but it is simple and it works well.
public static class Eng
{
public static SpriteBatch spritebatch;
public static SetUp(SpriteBatch sb){ spritebatch = sb;}
}
public class SomeClass
{
public void SomeMethod()
{
Eng.spritebatch.Draw(… ect );
}
}
This is now cleaner from the above abstracting is now simpler but the abstraction here is fairly pointless in either case as its not really abstract if its coupled to and relys on Game.
public abstract class SomeAbstractClass
{
public virtual void AutoDraw()
{
Eng.spritebatch.Draw(… ect );
}
}
public abstract class SomeClassB:SomeAbstractClass
{
public void SomeMethod()
{
AutoDraw();
}
}
The problem your encountering now is akin to if you were to override the abstract virtual method used by someclassB above AutoDraw. You would have two separate references were the abstract in this case is akin to Game which then no longer changes SomeClassB’s derived reference.
In this case it would still reference the Eng.Spritebatch reference so that part would work yet they would still be separate method calls base or derived as far as the compiler was concerned.
How i do it is like so.
In game1 any time the application is resized and in your load method pass spritebatch to Eng.setup by that time its fully initialized, that should handle any device resets just fine. Its far simpler, i actually put a bunch of stuff in mine i put a reference to the devicemanager the device the window ect ect. what your passing is just a reference anyways not a full copy.
For default automated stuff make a default class that handles default setups. For abstracts couple them to your Engines globals Eng.somevariable Yes normally coupling is bad but in this case it is actually going to happen anyways your going to call spritebatch one way or another. So In your actual game1 load or when you your graphics device is lost which calls load anyways or when resizing the window in your on windowsclientsizedchanged method that is fired, update engine references to those values you hold.
So keep it simple and as clear as possible.
For gamewindows just poll it or use delegates its really what monogame xna is was doing anyways
But ya if you don’t wanna change it your going to eventually have to call base all over the place, the way you have it setup which sort of defeats the purpose of easily accessing these variables.