• entries
11
15
• views
16561

# Fighting the code backfire

2585 views

Hello

While it's on my mind, I wanted to write here few lessons I learned in last few days.

1. If the language supports polymorphism, USE IT.
2. Design before coding.
3. Having properly structured code helps. A LOT.
4. Keep the objects closely related on one heap.

Those points don't seem to be related, right? Allow me to explain.

I've started to hunt coop related bugs in the game. Code, on the first look, seems to work perfectly; however, most code is structured like:if (multiPlayer == 0){ // do single player behavior}else{ // do co op behavior}
or a variation of that code, depending on player which "activates" part of the code.

So, here's lesson 1: Why making numerous comparisons like that through the whole class - some of which are surprisingly volatile - when I can make new class which inherits the current one and override specific methods to adapt them for co-op mode of the game. With that, I'm also avoiding the problem of pointless allocation of resources (time and memory) for object related to co-op mode.

Sound simple, right? Well, lessons 2 and 3 strike here at the same time. Due to "designing on the fly", I have to rewrite and refactor big parts of the code to adapt them for polymorphism. This means a lot of wasted time, due to the though process:

"Hmm, I'd like to add . Well, I can add this code here, and that code there... *writing code* Oh cool, this works! Yaay!"
"Now, to add ... *writing* Crap, code isn't good here anymore... *moving and/or rewriting code* Good, now works."
"OK, is next... oh not again, is broken. *rewriting and/or moving code*"
"ARRRRRGH, NOT AGAIN!" (I'm now at this point)

Result: lots of wasted time trying to improve the structure of the game while trying to preserve current functionality (a.k.a. trying to NOT break it).

However, while I'm rewriting the code, I have to be careful. Some parts of the code, with best example being Draw(GameTime) method where last drawn object is on top, require executing in specific order. So, I can't simply do this:public class A : GameScreen{ // ... public override void Draw(GameTime gameTime) { // ... }}public class B : A{ // ... public override void Draw(GameTime gameTime) { // ... spriteBatch.Draw(player2texture, player2rectangle, Color.White); base.Draw(gameTime); }}
because Player 2's sprite would end on bottom of everything, which may not be desirable.

Solution for that problem that I came up with is to extract relevant parts of A.Draw() and raise them to Protected level:public class A : GameScreen{ // ... public override void Draw(GameTime gameTime) { PartA(); PartB(); } protected void PartA() { // ... } protected void PartB() { // ... }}public class B : A{ // ... public override void Draw(GameTime gameTime) { PartA(); spriteBatch.Draw(player2texture, player2rectangle, Color.White); PartB(); }}
This is also why properly structured code is necessary. Instead of having massive amount of code inside one method, having the same code split over several methods improves maintainability and readability.

Lesson 4 is connected to 2 and 3 as well. Inside my Gameplay class (the one having actual game logic) I had few... awkward? objects:Texture2D player1Texture;byte player1spawnID;Texture2D player2Texture;byte player2spawnID;
Why is that?Player player1;Player player2;public override void LoadContent(){ player1 = ScreenManager.Player1; player2 = ScreenManager.Player2;}
In other words, I have objects related to players, whose objects persist through whole game, being created, disposed and recreated inside the class having game logic. Memory problems aside, not having player sprites stored inside player classes also forces me to needlessly duplicate the code and use additional checks to decide whose texture I need to move. Luckily, I don't need to do much to restructure the code and eliminate that annoyance.

Suddenly, improving level fie doesn't seem so important.

So, what did I learn from all that for next project (which is already defined in my head)?

I wasted too much time restructuring current project to enable modifications and upgrades. In order to avoid this in next project, I need to write Game Design Document and Tech Document in order to precisely define project and save time.

I hope that I won't repeat mistakes in the next project (Snake clone with 3D camera.)

After reading some topics on GameDev.Net, especially this one, I realized I have to learn the following:

• Garbage collector
• Making unit tests

Thanks for reading, I'm returning to my code.

Thanks for the for the quick lesson and warnings, I appreciate it and make sure I remember it for later. :)

I also liked your composition example.

Anyway, what I wanted to point out with "lesson 1" is to use what language has to offer. I probably didn't express myself properly.

Going back to my code, instead of possible branching dozens of times I used what C# has to offer. So, I decided to solve co-op through inheritance and just extract co-op parts into the inheriting class because 90% of code used by both modes is basically the same, so I just had to extend the functionality to cover 2nd player, hence the inheritance. If problem was different, I would use different solution to it. Isn't that what programming basically is? :)

Also a tip for your renderer would be to not have game objects draw themselves but create a render list that you renderer handles. This way you can contain all of the drawing order logic within the renderer and you can update your game objects out of draw order. There is other benefits to this as well in that you can cull render commands that will not make the viewport early as well, without having to sacrifice an update on the object.

## Create an account

Register a new account