C
C#β€’2mo ago
unluqy

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
unluqy
unluqyβ€’2mo ago
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
m!ke
m!keβ€’2mo ago
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.
unluqy
unluqyβ€’2mo ago
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?
Becquerel
Becquerelβ€’2mo ago
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; }
m!ke
m!keβ€’2mo ago
Just files that you store class data in. An example would be to use a JSON file to store the details about the buttons.
unluqy
unluqyβ€’2mo ago
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
Becquerel
Becquerelβ€’2mo ago
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
m!ke
m!keβ€’2mo ago
The morally correct way would to pass the variable as a parameter in the constructor.
Becquerel
Becquerelβ€’2mo ago
instead i would look up the definitions of the terms 'local variable' and 'field' in c# $helloworld
m!ke
m!keβ€’2mo ago
I may have missunderstood OP’s question. πŸ˜…
unluqy
unluqyβ€’2mo ago
oh okay
Becquerel
Becquerelβ€’2mo ago
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
unluqy
unluqyβ€’2mo ago
(im still new and in high school so sorry if i am a lil slow)
m!ke
m!keβ€’2mo ago
No no, it’s fine
unluqy
unluqyβ€’2mo ago
i tried referncing the man file in my other class but couldnt find the variable i need
No description
unluqy
unluqyβ€’2mo ago
thats what im tryna get a hold of (gameState)
No description
unluqy
unluqyβ€’2mo ago
idk if im doing that wrong ooo thanks
Becquerel
Becquerelβ€’2mo ago
what's the error you get when you write out 'newgame.gameState'?
unluqy
unluqyβ€’2mo ago
doesnt exist in current context
Becquerel
Becquerelβ€’2mo ago
πŸ€” weird, should be. are you typing it exactly correct, capitalisation included?
unluqy
unluqyβ€’2mo ago
(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
m!ke
m!keβ€’2mo ago
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:
public class screenManager
{
private string _gameState;
public screenManager(string gameState)
{
_gameState = gameState;
}
}
public class screenManager
{
private string _gameState;
public screenManager(string gameState)
{
_gameState = gameState;
}
}
Though with this method, the gameState parameter would not change if it changes in the main object.
unluqy
unluqyβ€’2mo ago
ur a life saver :3bigtears:
No description
unluqy
unluqyβ€’2mo ago
oh which method would be better?
m!ke
m!keβ€’2mo ago
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.
unluqy
unluqyβ€’2mo ago
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
m!ke
m!keβ€’2mo ago
Alright, do that then. By saving the string parameter as a variable, you are basically making a copy of it.
unluqy
unluqyβ€’2mo ago
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
unluqy
unluqyβ€’2mo ago
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
No description
No description
unluqy
unluqyβ€’2mo ago
so that in my game1 code i can just be like screenManager.Draw() or screenManager.Load() ig?
Becquerel
Becquerelβ€’2mo ago
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
unluqy
unluqyβ€’2mo ago
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
Becquerel
Becquerelβ€’2mo ago
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
private object _spriteBatch;
private object _contentManager;
private object _vector;

public ScreenManager(object spriteBatch, object contentManager, object vector)
{
_spriteBatch = spriteBatch;
_contentManager = contentManager;
_vector = vector;
}
private object _spriteBatch;
private object _contentManager;
private object _vector;

public ScreenManager(object spriteBatch, object contentManager, object vector)
{
_spriteBatch = spriteBatch;
_contentManager = contentManager;
_vector = vector;
}
unluqy
unluqyβ€’2mo ago
ohh
Becquerel
Becquerelβ€’2mo ago
and then when you do 'new ScreenManager(...)' you would pass in everything it asks for
unluqy
unluqyβ€’2mo ago
im not getting why we do _spritebatch -= spriteBatch from the arguemnets, wouldnt that just be an extra step?
Becquerel
Becquerelβ€’2mo ago
no unfortunately
unluqy
unluqyβ€’2mo ago
oh
Becquerel
Becquerelβ€’2mo ago
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)
unluqy
unluqyβ€’2mo ago
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
Becquerel
Becquerelβ€’2mo ago
sorry i misunderstood you
unluqy
unluqyβ€’2mo ago
oh all good
Becquerel
Becquerelβ€’2mo ago
the answer is yes, this is a very common pattern when you are defining classes
unluqy
unluqyβ€’2mo ago
got itt
Becquerel
Becquerelβ€’2mo ago
a class has some stuff it needs, it asks for that stuff in its constructor, and the constructor sets up the stuff it needs
unluqy
unluqyβ€’2mo ago
thats alot more clear now!
Becquerel
Becquerelβ€’2mo ago
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
unluqy
unluqyβ€’2mo ago
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
Becquerel
Becquerelβ€’2mo ago
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
unluqy
unluqyβ€’2mo ago
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
Becquerel
Becquerelβ€’2mo ago
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); }
unluqy
unluqyβ€’2mo ago
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
Becquerel
Becquerelβ€’2mo ago
πŸ™‚ it hurts everyone's brain initially
unluqy
unluqyβ€’2mo ago
would this concept even work / be correct isntead of using gameState? that gives me comfort πŸ˜†
Becquerel
Becquerelβ€’2mo ago
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
unluqy
unluqyβ€’2mo ago
what is the IDrawable? part?
Becquerel
Becquerelβ€’2mo ago
idrawable is an interface i defined here
unluqy
unluqyβ€’2mo ago
oooh
Becquerel
Becquerelβ€’2mo ago
if you aren't familiar, interfaces are one way of doing polymorphism
unluqy
unluqyβ€’2mo ago
ya i was not sorry haha
Becquerel
Becquerelβ€’2mo ago
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)
unluqy
unluqyβ€’2mo ago
riight couldnt i just put them in a list and refer to the list to do the same?
Becquerel
Becquerelβ€’2mo ago
what would the type of the list be?
unluqy
unluqyβ€’2mo ago
idek if its possible but a type of Screen (being a class) so a list of classes
Becquerel
Becquerelβ€’2mo ago
ah yes, that would work. it's the other main way of doing polymorphism besides interfaces
unluqy
unluqyβ€’2mo ago
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!
Becquerel
Becquerelβ€’2mo ago
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 πŸ™‚
unluqy
unluqyβ€’2mo ago
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)
Becquerel
Becquerelβ€’5w ago
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
unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
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;
unluqy
unluqyβ€’5w ago
what is throw new notimpelementedexceptiuon?
Becquerel
Becquerelβ€’5w ago
oh, sorry that's just shorthand because i don't want to actually think of anything realistic for those methods to do lol
unluqy
unluqyβ€’5w ago
ohh
Becquerel
Becquerelβ€’5w ago
you can use that when you have code you've not finished yet but you still want your project to compile essentially
unluqy
unluqyβ€’5w ago
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?
Becquerel
Becquerelβ€’5w ago
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
unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
technically only methods but you can have things in interfaces which are 'like' variables called properties
unluqy
unluqyβ€’5w ago
oh
Becquerel
Becquerelβ€’5w ago
public interface IScreen { string ScreenName { get; } } as an example
unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
i would review this post of mine and see if you understand it
unluqy
unluqyβ€’5w ago
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?
Becquerel
Becquerelβ€’5w ago
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.)
unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
don't worry, it's not you. i'm just also performing a production release from hell atm :awesome:
unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
here's a full worked example:
public class ScreenManager
{
private IScreen? _activeScreen;

public ScreenManager()
{
// Set a reasonable default on startup
_activeScreen = new MainScreen();
}

// Someone can pass this method either a main screen or a credits screen
public void UpdateActiveScreen(IScreen screen)
{
_activeScreen = screen;
}

public void DoSomethingWithActiveScreen()
{
// This might be either main screen or credits screen
_activeScreen.DoStuff();
}
}

public interface IScreen
{
void DoStuff();
}

public class MainScreen : IScreen
{
// ...
}

public class CreditsScreen : IScreen
{
// ...
}

public class ScreenManager
{
private IScreen? _activeScreen;

public ScreenManager()
{
// Set a reasonable default on startup
_activeScreen = new MainScreen();
}

// Someone can pass this method either a main screen or a credits screen
public void UpdateActiveScreen(IScreen screen)
{
_activeScreen = screen;
}

public void DoSomethingWithActiveScreen()
{
// This might be either main screen or credits screen
_activeScreen.DoStuff();
}
}

public interface IScreen
{
void DoStuff();
}

public class MainScreen : IScreen
{
// ...
}

public class CreditsScreen : IScreen
{
// ...
}

unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
of course, you can do whatever makes most sense to you
unluqy
unluqyβ€’5w ago
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
Becquerel
Becquerelβ€’5w ago
a stack is definitely one way i've seen that be implemented
unluqy
unluqyβ€’5w ago
mhm! i cant take credit tho i didnt thin kof it myself
Want results from more Discord servers?
Add your server