Poll of the Day > Another programming question

Topic List
Page List: 1
Yellow
09/08/18 5:21:29 AM
#1:


In my game engine, I've got a class hierarchy. This is my first time using class inheritance.

I've got
abstract WorldObject ->
abstract AnimatedObject ->
abstract PhysicsObject ->
Creature

I don't think I like this too much... but I do see the point. The child class can access the position of the WorldObject, and they have access to every other inherited function. I do feel I could do most of this system by turning them into standalone objects, though, instead having

class Creature {
WorldObject world_object;
AnimatedObject animated_object;
PhysicsObject physics_object;
}

At the same time, I hear there's something called an "Interface" I could be using that I still don't know about.

Anyway, my question.

AnimatedObject : WorldObject { // has a
public virtual void Update(float step) // function.
}

PhysicsObject : AnimatedObject { // has a
public override void Update(float step) // function.
}

The problem is, I want

Creature : PhysicsObject { // to have a
public override void Update(float step) // function as well.
}

Preferably I'd be able to call the base Update() function for each and every Update() function the child inherits. Googling got me nowhere, so here I am.
... Copied to Clipboard!
Yellow
09/08/18 5:35:32 AM
#2:


@Mead

Tell me what to do.
... Copied to Clipboard!
green dragon
09/08/18 10:12:48 AM
#3:


Beep boop
---
Just because you're trash doesn't mean you can't do great things.
It's called garbage can, not garbage cannot.
... Copied to Clipboard!
Sahuagin
09/08/18 1:34:26 PM
#4:


I have to leave for work but here's some quick comments.

when you posted before about learning inheritance I wanted to post this then, but note that inheritance is not really as good a tool as it seems at first. it does have its place, but the relationships it creates are too tightly coupled and lead to less flexible data models. try not to overdo inheritance.

Yellow posted...
AnimatedObject : WorldObject { // has a

note that inheritance is an "is a" relationship, not a "has a" relationship

Yellow posted...
At the same time, I hear there's something called an "Interface" I could be using that I still don't know about.

yes an interface is usually better than inheriting from a class. an interface just defines some public properties and methods that an implementing class agrees to have available, and you can implement as many interfaces as you like (while you can often only inherit from a single class; C++ does have multiple inheritance though). the general rule of thumb for interfaces is to break them apart and keep them simple. don't put like 10+ members in one interface. rather, have many different interfaces with 1-2 members each. then, for example, maybe if a function really just uses a single property of the object it's asking for, maybe make an interface for just that property, and ask for objects that implement that single-property interface.

two important concepts that are related to this are:
Program to an interface, not an implementation
Favor composition over inheritance

the composition one especially. for example rather than:

AnimatedObject : WorldObject {
public override void Update(float step)
}
}


this can be much much more flexible:

AnimatedObject {
private WorldObject mWorldObject;

public void Update(float step) {
mWorldObject.Update(step);
}
}


but then... maybe, maybe not, it does depend on the whole picture as well. sometimes inheritance is ok. though it's usually definitely better not to make deep inheritance hierarchies. if you do use inheritance, it should be 1 level deep, and you should have really good reasons for adding more levels to it.
---
... Copied to Clipboard!
Yellow
09/09/18 5:16:34 AM
#5:


green dragon posted...
Beep boop

https://www.youtube.com/watch?v=QEzOE7mW5eI" data-time="


@Sahuagin

Those are a lot of quick comments.

I think I agree with you, and will not use a hierarchy tree. I'm not sorry I made this though, since the whole goal of my project is to make something that makes sense above just working correctly. Every mistake I catch I don't have to dig out and break everything undoing.

I think the way these objects are accessed, it's not important that they can be accessed all at once in a streamlined way. I'll just make my abstract classes not abstract and use them directly in my current child classes.

An interface seems like a way to get rid of that extra layer. I'll look into that.
... Copied to Clipboard!
Sahuagin
09/09/18 2:35:51 PM
#6:


a lot of advice will be "rules of thumb", which are guiding principles which definitely help when followed, but also have exceptions a lot of the time as well. and it's hard to just explain them and get you to understand why it's important. (should try to avoid "cargo cult programming", but it's not so easy when you're learning.)

inheritance: rule of thumb is to make "wide and shallow" inheritance hierarchies. upon learning about inheritance, the instinctual reaction is often to make "narrow and deep" inheritance hierarchies. (sometimes it can make sense to make one "narrow and deep", though, it depends exactly what you're doing. "usually" you don't want to.)

it's not that it won't work if you implement it that way, in fact it will. it's that the design becomes harder modify and is not very modular. your program becomes harder and harder to maintain. there's a lot of ways to make your program harder to maintain, but the goal is to make it easier to maintain so that you can make it bigger and bigger and keep it alive.

interfaces: rule of thumb is to only have 1 or 2 (maybe 3... but each additional one should be used with caution) members per interface, not including inheriting from other interfaces. have lots of simple interfaces so that they apply to as broad a range of objects as possible. (and again there are exceptions).

some quick examples:
"wide and shallow" inheritance: a couple places I've written an importer. an "importer" is a thing that, given some starting info, will go pull data from somewhere else and bring it here in a consistent form. but there are a dozen or more "somewhere else" locations, and I want to be able to add more as necessary. so then: abstract class ImporterBase, and implement a new importer for each kind of import. (in some ways though this could be thought of as a delegate or strategy pattern.)

ok "narrow and deep" inheritance: hard to explain concisely, but windows "list" controls have a hierarchy. at the top is a general "ListControl", with ComboBox, ListBox, and CheckedListBox at the bottom. I've wrapped this hierarchy with my own, creating like at least 2 ListControl wrappers, and at least 3 wrappers each for the 3 concrete controls. There's a dozen or more classes in the hierarchy. it works, though because most of the code is at the root of the hierarchy, and most of the wrappers are nothing more than a constructor or two. also this code rarely changes. they all share basically the same functionality, but allow you to decide on a couple varied implementations.

eh... anyway, I could ramble on and on.
---
... Copied to Clipboard!
Yellow
09/10/18 5:45:42 AM
#7:


Good. I'm writing my own game engine in MonoGame atm. Ironically, I have zero drive to make my game. I just really enjoy writing game engines. I have no desire to get things right the first time, or even ever.

Right now I'm just writing my own massive library to do... everything. Maybe I'll store it away for some bizarre project I have down the line. Maybe I won't do anything with it and it will die with me.

I'm making my own widget system using interfaces now. The usefulness of Interfaces is pretty apparent, I'm glad I found out about them. It makes me want to dig up the old YouTube Tutorials I learned everything I know from and actually finish them.

To get a better grip on the whole concept I just started something new, so I can come back to WorldObjects and do it the right way.

MonoGame never made a widget system, the one available looks rough around the edges. Mine has

public interface IWidget
{
void Update(float step);
void Draw(ref SpriteBatch sprite_batch, ref SpriteFont sprite_font, Vector2 offset);
}


And then I have

class Layout : IWidget
{
public List<IWidget> widgets = new List<IWidget>();
...
}


So I can essentially nest Widgets in Widgets if I want to. That seems like a pretty standard widget.

@Sahuagin posted...
...

I'm taking a while to respond because your posts give me a lot to think about. I do get everything you said, though, I get the general idea.

I combined all my World Object classes to basically inherit WorldObject. WorldObject currently has all the PhysicsObject and AnimatedObject code sloppily thrown in, because ctrl+z couldn't save me after I did that, and I have to split them up again. But I'll just do WorldObject { AnimatedObject m_animated_object; PhysicsObject m_physics_object; } and use that as the abstract base object for things like "Creatures" "BackDrops" and "Items".

abstract class WorldObject
{
AnimatedObject m_animated_object;
PhysicsObject m_physics_object;
...
}

class Creature : WorldObject
{
...
}
... Copied to Clipboard!
Sahuagin
09/10/18 12:22:35 PM
#8:


Yellow posted...
because ctrl+z couldn't save me after I did that

if you aren't already you should be using version control. I recommend mercurial mostly because of how easy it is to make a repo and commit things to it. alternative is git, but I haven't used it. also, they can be confusing to use, especially to do advanced things like merge, but the simple act of committing creating a version history for each of your files is extremely valuable.

the windows GUI version of mercurial is tortoise hg:
https://tortoisehg.bitbucket.io/

there's a good tutorial for command line hg here:
http://hginit.com/
---
... Copied to Clipboard!
Sahuagin
09/10/18 12:26:26 PM
#9:


void Draw(ref SpriteBatch sprite_batch, ref SpriteFont sprite_font, Vector2 offset);


maybe you have a reason but I don't see why SpriteBatch or SpriteFont would be ref parameters. you would only do that if you wanted to get back a different SpriteBatch than the one you passed in.

otherwise, yes your `IWidget` interface is the right idea.
---
... Copied to Clipboard!
Dikitain
09/10/18 12:33:04 PM
#10:


Sahuagin posted...
Yellow posted...
because ctrl+z couldn't save me after I did that

if you aren't already you should be using version control. I recommend mercurial mostly because of how easy it is to make a repo and commit things to it. alternative is git, but I haven't used it. also, they can be confusing to use, especially to do advanced things like merge, but the simple act of committing creating a version history for each of your files is extremely valuable.

the windows GUI version of mercurial is tortoise hg:
https://tortoisehg.bitbucket.io/

there's a good tutorial for command line hg here:
http://hginit.com/


To add: Git is better then Mercurial, but if you are just starting out with version control then I would stick with Mercurial, it is simpler to learn and a lot harder to screw yourself over with.

Also, if you aren't already, I would recommend using an IDE. Not only does it give you simple things like syntax highlighting and real-time compilation, but it also integrates in with version control so you know what files have changed since your last check-in (and can compare them really easy). Since it looks like you are working in Java (haven't followed the full conversation), I would recommend IntelliJ Community Edition:

https://www.jetbrains.com/idea/download/#section=windows

It is the same platform that Android Studio is built off of if you are at all familiar with it.
---
I am a senior software engineer. If you see me post here, I am tired of writing TPS reports.
... Copied to Clipboard!
Sahuagin
09/10/18 1:10:21 PM
#11:


yay jetbrains

so far I've been using NetBeans for Java stuff, which so far I've liked more than eclipse, but I should definitely try out jetbrains's ide.

OP is using C# though AFAIK (MonoGame).
---
... Copied to Clipboard!
Dikitain
09/10/18 1:48:07 PM
#12:


Sahuagin posted...
yay jetbrains

so far I've been using NetBeans for Java stuff, which so far I've liked more than eclipse, but I should definitely try out jetbrains's ide.

OP is using C# though AFAIK (MonoGame).

NetBeans is pretty good as well, I was using that when I got my certification in Java a few years back. I just like IntelliJ more because they have so many cool things you can do with it, and it just supports so much stuff out of the box unlike Eclipse.

Jetbrains has a C# IDE as well, but I can't in good conscience recommend it because it is not free (except for a 30 day trial). Still, I imagine there has got to be some free ones out there given how popular C# is.
---
I am a senior software engineer. If you see me post here, I am tired of writing TPS reports.
... Copied to Clipboard!
Topic List
Page List: 1