OOP guidance (for myself)
I'm having a real tough time grasping OOP for a project in school using Monogame, like I can't quite figure out how to reference variables / sprites and such from other classes, maybe i'm just being silly but I was looking for any in depth OOP guides, tips or even talks from people
95 Replies
for context, i have a Game1 class which holds methods such as Draw() and Update() and I've put code into these methods to come up with a homsecreen, but now I'm realising how inefficient that is and that I should've made a different class to handle these screen changes but I don't know how I'd go about doing that and still taking the values from the game1 folder? (such as the spritebatch and vectors) / linking my files together in OOP isntead of coding everything in the game1 update and draw methoids if that makes any more sense
So let me get this straight, you have a home screen with multiple buttons, and each button holds an action that changes the screen?
As for the second part of having different values, while you could hard code them into the constructor, you may want to hold them in data files that you can parse.
Sorta, i still need to add the buttons part to it but essentially yeah, i want to have a menu button thatll take you to the menu etc, wdym by the data files btw?
in OOP, classes talk to each other by using class instances
public class MyClass
{
public void DoSomething()
{
var other = new MyOtherClass();
var data = other.Data;
Console.WriteLine(data);
}
}
public class MyOtherClass
{
public int Data = 43;
}
Just files that you store class data in. An example would be to use a JSON file to store the details about the buttons.
how would you make it go the other way around? so that ur MyOtherClass can reference a variable in your MyClass if that makes sesne?
ohhh okay
in much the same way, you can use the 'new' operator on any class. so you would have a method in MyOtherClass which includes a line like this;
var foobar = new MyClass();
Console.WriteLine(foobar.SomeData);
i would not worry about JSON files and deserialisation for now
The morally correct way would to pass the variable as a parameter in the constructor.
instead i would look up the definitions of the terms 'local variable' and 'field' in c#
$helloworld
I may have missunderstood OPβs question. π
oh okay
i think using that stuff in monogame projects makes total sense, i just think they probably need to be able to walk before they run if you get me lol
(im still new and in high school so sorry if i am a lil slow)
No no, itβs fine
i tried referncing the man file in my other class but couldnt find the variable i need
thats what im tryna get a hold of (gameState)
idk if im doing that wrong
ooo thanks
what's the error you get when you write out 'newgame.gameState'?
doesnt exist in current context
π€
weird, should be. are you typing it exactly correct, capitalisation included?
(also thanks to the both of you for the help i appreciate all of it even if thios doesnt end up working ahah)
mhm!
its thrown me for a loop for the past like 4 hours
Add a constructor to screen manager with a parameter of type Game1. I believe that code would result in continuous instantiation.
For passing down it the game state it would be something like:
Though with this method, the gameState parameter would not change if it changes in the main object.
ur a life saver :3bigtears:
oh
which method would be better?
If you want the variable to sync with the game1 class hold game1 as a variable and access the gameState property whenever you need it.
But it doesnβt really matter in this game. You can make multiple constructors if you need to.
yeah i do! since i only want the game1 to go to this class with the gamestate and it handles which scvreenb to show baseed on the gamestate such as "homescreen" "gameover" "playing" etc?
oh okayy
Alright, do that then. By saving the string parameter as a variable, you are basically making a copy of it.
ohh
thanks!!
so... i did end up linking them by initialisnmg a game1 event instead but how the hell would i get my cxode to run from my game1 folder to my screenamanager and back
everytime i tried it was like "not enouhg memory resources ae available
" or something
so idk if i did something wrong on my monogame but essentially i want to move my code for initalise, loadcontent and draw into my methods i have in my screenamanager for them
so that in my game1 code i can just be like screenManager.Draw() or screenManager.Load() ig?
public class MyClass
{
private ScreenManager _screen;
public MyClass()
{
// Pass in the spritebatch/contentmanager/etc.
_screen = new ScreenManager(new object(), new object());
}
public void DoSomething() { _screen.Initialise(); _screen.LoadContent(); } } public class ScreenManager { private object _spriteBatch; private object _contentManager; public ScreenManager(object spriteBatch, object contentManager) { _spriteBatch = spriteBatch; _contentManager = contentManager; } public void Initialise() { // _spriteBatch.Initialise(); } public void LoadContent() { // mySprite = _contentManager.Load<Whatever>(); } } i commented out lines and used the object type rather than the real types because i can't be bothered loading up a monogame project so don't just copy-paste this; you will have to make edits but let me know if anything in this is confusing and i can explain
public void DoSomething() { _screen.Initialise(); _screen.LoadContent(); } } public class ScreenManager { private object _spriteBatch; private object _contentManager; public ScreenManager(object spriteBatch, object contentManager) { _spriteBatch = spriteBatch; _contentManager = contentManager; } public void Initialise() { // _spriteBatch.Initialise(); } public void LoadContent() { // mySprite = _contentManager.Load<Whatever>(); } } i commented out lines and used the object type rather than the real types because i can't be bothered loading up a monogame project so don't just copy-paste this; you will have to make edits but let me know if anything in this is confusing and i can explain
ill edit once im home, but what does the constructor do where ur doing _screen - new ScreenManager(newobject.... etc) would i have to fill in the brackets with eeverything i want to put in? for exmaple the spritebatch, texture and maybe even vector or cna i just declare them in the screenmanager class? if that makes sense sorry
u might have answered that, i might just be silly haha
so you should think of constructors as just being functions really. they work the same way as other functions
the only special thing about constructors is they are automatically called whenever you use the 'new' keyword
so if you want to pass other things to the ScreenManager constructor (like a Vector), you can
ohh
and then when you do 'new ScreenManager(...)' you would pass in everything it asks for
im not getting why we do _spritebatch -= spriteBatch from the arguemnets, wouldnt that just be an extra step?
no unfortunately
oh
c# doesn't know that _spriteBatch is related to spriteBatch
it won't assign one to the other automatically
(unless you are using some more advanced and modern features)
so wverytime i make a new class ill have to make a new veriable name and assign that to the spritebatch value?
once passed in
right
sorry i misunderstood you
oh
all good
the answer is yes, this is a very common pattern when you are defining classes
got itt
a class has some stuff it needs, it asks for that stuff in its constructor, and the constructor sets up the stuff it needs
thats alot more clear now!
worth emphasising that constructors are just functions and don't have to do this assignment thing
private object _spriteBatch;
private object _contentManager;
public ScreenManager(object spriteBatch, object contentManager, object somethingElse)
{
_spriteBatch = spriteBatch;
_contentManager = contentManager;
somethingElse.CreateDatabase();
somethingElse.SendEmails();
}
this is valid
i also have another question, since its the screenManager and ill have it draw based on like "if (gameState=="main_menu"" draw whatever, would i have to have all these if statements in my methods for the different gamestates or would there be an easier way?
oooh okay
there are a lot of different ways to tackle that problem
your way works but (as you can imagine) is easy to make mistakes in if you have a typo anywhere
or forget a screen
an upgrade is to use enums
public enum States
{
MainScreen,
ExitScreen,
CreditScreen
}
public void Initialise(States state)
{
switch (state)
{
case States.MainScreen:
// do whatever here
case States.CreditScreen
// do whatever here
}
}
the advantage is you don't need to type out strings and such. and c# will try to warn you if you forget to handle one of the parts of the enum
a cleaner and more advanced way is to use polymorphism. which I can explain but is one of the parts of OOP that people tend to find confusing at first
ive been learning polymorphism and its what i was intiially thinking
like making a child of my screenManager class called Screen or something but thats about where my technical thinking stops on what to do
your instincts are right
public void Draw(List<IDrawable> drawables)
{
foreach (var drawable in drawables)
{
drawable.Draw(// etc.);
}
}
}
public interface IDrawable
{
void Draw(SpriteBatch spriteBatch);
}
yeah and having my screenmanager do the methods such as draw if the screen variable is true , like having a list of children and it loops through once to find which one has the variable screenVisihle to true and draws according to thatv
if that makes sense?
but thinking about that hurys my brain to try and figure out the coding
yeah exactly!! haha
π it hurts everyone's brain initially
would this concept even work / be correct isntead of using gameState?
that gives me comfort π
so your method would probably work but not necessarily be the cleanest way
specifically having a variable in the child itself
instead i would do something like this
private IDrawable? _activeScreen;
public void UpdateActiveScreen(IDrawable screen)
{
_activeScreen = screen;
}
public void Draw(List<IDrawable> drawables) { _activeScreen?.Draw(); } this way you can't have multiple screens which accidentally have a ActiveScreen flag set to true at once
public void Draw(List<IDrawable> drawables) { _activeScreen?.Draw(); } this way you can't have multiple screens which accidentally have a ActiveScreen flag set to true at once
what is the IDrawable? part?
idrawable is an interface i defined here
oooh
if you aren't familiar, interfaces are one way of doing polymorphism
ya i was not sorry haha
similar to inheritance but different in certain ways
it essentially means you can have lots of different classes (MainScreen, CreditsScreen, ExitScreen) but treat them as if they're all the same thing (IScreen)
riight
couldnt i just put them in a list and refer to the list to do the same?
what would the type of the list be?
idek if its possible but a type of Screen (being a class) so a list of classes
ah yes, that would work. it's the other main way of doing polymorphism besides interfaces
ohh
well
if its cleaner and more efficient i can try interfaces
but i wont be home for a few hoursand i still have to actually make sure i can move my code from the game1 class ro my screenmanager before anything else π€£
but thanks, i enjoy talking about coding with you!
there are pros and cons to both interfaces and parent classes, so in a lot of cases you can use what you're more comfortable with
and no worries, and thanks π
yup, watched a quick vid on it, so i could technically have screenManager as an interface with a bool value of activeScreen and method isScreenActive which checks if activescreen is true and executes code based on that? but every class would HAVE to have that boolean value and that method right?
(i can see why u said polymorphism hurts brains)
not quite, not if it's an interface
one of the main things about interfaces is they can't contain method behaviours, just method definitions
what you're describing would work for parent/child classes though
9oh
so how would i use an interface for it in my context? i could define a is Screen method and put that in each of the children for it maybe?
its confusing me a bit haha
not quite, instead you would have the interface definition itself tell you if something is a screen
public interface IScreen
{
void Update();
void ShowContent();
void Close();
// whatever else screens do
}
public class MainScreen : IScreen
{
public void Update()
{
throw new NotImplementedException();
}
public void ShowContent()
{
throw new NotImplementedException();
}
public void Close()
{
throw new NotImplementedException();
}
}
you could then assign a MainScreen to an IScreen variable:
var main = new MainScreen();
var other = new OtherScreen();
// both of these work if they both implement IScreen. IScreen screen = main; screen = other;
// both of these work if they both implement IScreen. IScreen screen = main; screen = other;
what is throw new notimpelementedexceptiuon?
oh, sorry
that's just shorthand because i don't want to actually think of anything realistic for those methods to do
lol
ohh
you can use that when you have code you've not finished yet but you still want your project to compile
essentially
ophh r ight
so my screenManager is the interface, it says "this is what each screen should have" in terms of methods and each child in the interface says specifically WHAT bthose mtehods do?
yes, exactly
you can think of an interface as a promise, or a contract
a minimum set of requirements
'everything which is an IScreen will at the bare minimum do X, Y and Z. how it does it might be different but it will do it'
kind of thing
thats actually really smart
so instead of them inheriting every property such as the method or variables they can CHOOSE what the methods / variables do
or does it only pass down methods
technically only methods
but you can have things in interfaces which are 'like' variables
called properties
oh
public interface IScreen
{
string ScreenName { get; }
}
as an example
so hoiw would i put in a variable of bool to check if its a screen or not?
ohh
get isScreen from game1; is that valid?
aaa my brain hurts again
thinking about how to actually check if the screen SHOULD be displayeed
i would review this post of mine
and see if you understand it
im sorta getting it
u make a list of the interface and loop trhough it inm drawables and draw each variable in it
and each idrawable has a private variabnle called activescreen which they get from being passed down?
i think
i guess im confused on the specific line private IDrawable _activeScreen; doesnt that mean ur defining a new instance4 of IDrawable called activescreen?
you keep fixating on this idea of having a variable inside the screen class which decides if it's the active one or not
that's not what i'm suggest
i'm suggesting you have a variable in your ScreenManager which indicates what the active one is
and no. a variable is different from an instance. i.e.
string s = "hello";
s = "foobar";
s = "horse";
s is the variable, and the string literals are the instances there
the _activeScreen in my example is a variable that can hold any IScreen instance (a MainScreen, CreditsScreen, etc.)
oh so we dont have to have = when assigning a variable? or well, u assigned it in the updateactivescreen so that makes sense
sorry if this gets frustrating btw
ohhh
don't worry, it's not you. i'm just also performing a production release from hell atm
:awesome:
oh god good luck, i appreciate all the help tho (:
ima try implement this code tomorrow actually, i forgot i have an appointment later and i get to meet with ym teacher tomorrow so i can ask him any questions too so it works out
or i could if i fidn time today actaully
here's a full worked example:
oh thank you!
yeah this may be throwing me for a loop, is it okay if i try do the list iteration version first? i want to try get something working and then afterwards IF it works i can try improve it by using this method?
i would send all my code screenshots but theres 3 (not much of it is code), dont wanna overwhelm the channel
of course, you can do whatever makes most sense to you
aaa i arn out of time but
i feel useless for not being able to do this simple thing haha
again, appreciate all the help tho
ive just had a revelation in my bed... i was watching people code monogame to see what stuff they did and how i could implement some ideas into my own code and ... a stack would be perfect for the interface onstead of a list right? that way i dont actually have to have a variable for the screen being active, its just whatever is on top of the stack, but idk if i can take much credit since i saw someone else do it so its not that impresive now that i say it out loud
a stack is definitely one way i've seen that be implemented
mhm!
i
cant take credit tho i didnt thin kof it myself