Send data between objects?

Started by
1 comment, last by _the_phantom_ 13 years, 6 months ago
Hello game programmers,

I've been coding professionally for most of my life, sometimes games, sometimes other stuff. The reason I write this post is that I feel that I keep make (at least) one reoccuring "newbie design flaw" over and over again.

Let me try to explain with the current example:
I build a game. It's object oriented C#, everything is beautifully encapsulated and working fine.
There is a main "game" class and declarations of my objects:
public class MySuperGame : Microsoft.Xna.Framework.Game    {        MyPlayerClass thePlayer;        MyTilemapClass theTilemap;        //(...)    }

Problems begin when these objects need access to each other.
In this fabricated example, the "Player" class is doing collision checking with stuff on the Tilemap.

So, my options, I can either
1) Break out the logic, and do everything in the game class
MySuperGame.DoCollisionStuff(MyPlayerClass thePlayer, MyTilemapClass theTilemap)

or
2) cross-reference the pointers, for example initialize the player class with a reference to the tilemap
public MyPlayerClass(MyTilemapClass theTilemap [, textures and stuff]

or
3) just pass a pointer when it's needed:
protected override void Update(GameTime gameTime)   {      thePlayer.HandleCollisions(theGameTilemap);      //(...)   }


I have been mostly doing #3, but I feel that it's flawed design and it quickly becomes cluttered with unnecessary cross-referencing pointers and variables.

My next step is to make an "achievement system".
I imagine an AchievementHandler class that keeps track of everything that happens in the game, so this class needs to be accessible from every single corner of the code.
   MyPlayerClass.DoJumpyStuff()   {      theAchievementHandler.Add(AchievementType.PlayerJumpCount, 1)      //(...)   }   MyLevelHandler.StartNewLevel()   {      theAchievementHandler.Add(AchievementType.LevelsPlayedTotal, 1)      //(...)   }   //etc.etc.


This makes me think even more urgently of a "good code"-solution to this dilemma.

I hope this makes sense. Thanks for reading, I value all feedback.

Cheers,
Murmix

PS: The game in question is Turtle Boogie, a little arcade action fun.
A concept prototype demo download is available here:
http://www.murmix.com/TurtleBoogie


Daniel Molnar
MCTS: MS SQL 2008 and .NET Framework 4
[email="daniel@murmix.com"]daniel@murmix.com[/email]

Murmixsoft
http://www.murmix.com
Advertisement
I prefer an own service (or sub-system if you like that term more) for e.g. collision detection, that is aware of structures especially to solve collisions but nothing else. Each object that want to participate in collision detection then has to register its appropriate structure with the service e.g. when the object is added to the scene. Perhaps like so:
void Player::onAddition( Scene & scene ) {   // registering with services   scene.collisionService->add( this->collisionVolume );   ...}void CollisionService::detectAndCorrect( ) {   ...}

This is a classic case of not applying the "single responsibility principle"; your player class, instead of just worrying about representing a player to the world is now worried about representing it AND how to collide with things.

The solution is to do what haegarr says and pull the logic out of the player class.

A setup I personally like for a 'player' class is not not have the player do much of anything, instead if acts more like a collection for various things.

// excuse the variable names, they are for example onlyclass Player{    Renderable myModel;    CollisionVolume myCollisionMesh;    Controller myController;  // gives the player instance input    // etc}


The advantage here is that you don't need to worry about 'how' things are implemented, just that they are.

Your 'renderable' could be anything, from a model to a texture, came deal for the collision volume, and an input controller makes things like hooking network input up easy as it would translate both 'local' and 'remote' inputs into what is expected by the player logic.

You could even go one step further and have the 'update logic' be nothing more than a collection of function pointers/delegates which can be swapped/changed depending on game state.

This topic is closed to new replies.

Advertisement