Project review/advice

Get answers to all your basic programming questions. No Ogre questions, please!
User avatar
TWO
Halfling
Posts: 61
Joined: Sat Jan 26, 2008 9:30 pm
Location: Germany

Project review/advice

Post by TWO »

Hello member of my favorite developer community!

I am a self-taught 21-year-old hobby programmer from Germany and as such I never got feedback on the way I structure my projects, my coding or commenting style. You would do me a huge favor with some constructive criticism.

https://bitbucket.org/SirPolly/polyengine/src

The project exists merely for educational purposes, I love writing complex systems.

Thank you very much :D

Please note: I don't want an actual review from a user perspective. The project is far from usable! I just want comments on my coding style and how the project is structured.
Last edited by TWO on Sat Nov 17, 2012 7:34 pm, edited 2 times in total.
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: Project review/advice

Post by drwbns »

An overview of what it is might be helpful :)
User avatar
TWO
Halfling
Posts: 61
Joined: Sat Jan 26, 2008 9:30 pm
Location: Germany

Re: Project review/advice

Post by TWO »

It's a (small) game engine. The core is supposed to be platform independent with extensions providing all platform specific systems. The API should feel like Ogre does.

Root directory:
CMake - Script required by CMake
Dependencies - Most of the dependencies except Ogre, Boost and RakNet
Docs - Doxygen files
PolyMain - Engine source
Vertex - Editor source
bin - Empty
extensions - System plugin sources (Ogre, irrKlang, PhysX, ..)
Short overview (outdated):
https://bitbucket.org/SirPolly/polyengi ... at=default
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: Project review/advice

Post by drwbns »

Ah ok, component based design eh? I'll have to check it out and post back to you.
User avatar
saejox
Goblin
Posts: 260
Joined: Tue Oct 25, 2011 1:07 am
x 36

Re: Project review/advice

Post by saejox »

This is a lot like Unity3D engine. http://docs.unity3d.com/Documentation/S ... nents.html

Are you going to implement it? or just an outline?
Nimet - Advanced Ogre3D Mesh/dotScene Viewer
asPEEK - Remote Angelscript debugger with html interface
ogreHTML - HTML5 user interfaces in Ogre
User avatar
TWO
Halfling
Posts: 61
Joined: Sat Jan 26, 2008 9:30 pm
Location: Germany

Re: Project review/advice

Post by TWO »

Yes, the GameObject system mirrors the one used in Unity.

I will continue to write on the project as long as I'm having fun. Is that what you meant?

No comments yet :(
User avatar
saejox
Goblin
Posts: 260
Joined: Tue Oct 25, 2011 1:07 am
x 36

Re: Project review/advice

Post by saejox »

i am making a quite similar engine too.
Let me comment on some stuff,

I dont like component design in this context, because you are wrapping Ogre for the most part.
Render engine is there why not just expose it instead of wrapping
Wrapping is a seriously tedious work.
Take for instance ICameraComponent, you will writing wrapper for 50 functions, and still you wont get same functionality of Ogre::Camera (listener, renderqueue, LOD, etc...)
If you were to write you own rendering engine it would be okay.

Passing GameObject to scripts is a neat idea implemented in many engines.
but script languages are not as competent as C++. They dont have generics, some dont even have virtual calls.
Will be able to pass those components to scripts?
Also keep in mind that every script language comes with their own garbage collection. This also might spoil you design.
Don't think scripting as an afterthought, think it as the center of your engine.

XML's are convertable to scenes and GameObjects, are scenes and GameObjects convertible to XML files?
I think it should be. Because in development it really helps to switch between editor/gameplay.

I would like to see your Vertex level editor. I recommend Command Pattern and MVC strongly.
You are gonna be overwhelmed if you dont pick a good design pattern.
http://en.wikipedia.org/wiki/Model%E2%8 ... controller
http://en.wikipedia.org/wiki/Command_pattern
If you have chosen QT signals/slots would be great for editor ui. Overall Qt is superior to Wx imo. It is just more modern.

These are subjective of course. I might be missing the point.
Nimet - Advanced Ogre3D Mesh/dotScene Viewer
asPEEK - Remote Angelscript debugger with html interface
ogreHTML - HTML5 user interfaces in Ogre
User avatar
TWO
Halfling
Posts: 61
Joined: Sat Jan 26, 2008 9:30 pm
Location: Germany

Re: Project review/advice

Post by TWO »

Thank you very much for your feedback!

I see you concentrated mainly on the GameObject system. Yes I've noticed myself that wrapping Ogre is a stupid idea. As nice as it is to have a core which can be compiled without any dependencies, it's far too much work to do it properly. I will rewind it and unify the interface like it was before.
The components need to be able to expose some kind of interface to the editor. All the strings used to identify the gameobject type, the component (family) type, the components properties, all this leads to errors and is slow to use and execute. I need to figure a way out to make this faster and more comfortable to work with. I don't like looking up stuff in the docs, the code must explain itself and provide you with a list of possible names and types.

Although there is a ScriptSystem in the code I want to go a different route than most projects. In my demo Cargo the C++ game code resides inside a "game.dll" which can be loaded and unloaded at runtime. What I do now is to watch for changes in the source files and if that's the case I rebuild and copy the new binaries over the old ones (all in a background process and while the game is running). After loading the new code the player will still be on the same place he was before. If the new code even contains said player that is. I got the idea from Unreal. It takes less than 1s from Shift-S to save the code until the game is playable with the new code thanks to precompiled headers. It could even go as far as to automatically generate header files or to add new features such as coroutines.

The editor is only a bare bone scene viewer for now. Because I got no formal education it's pretty hard to wrap my head around MVC and how to implement it properly. When looking at Sinbads wxOgreMVC it looks more like a burden than a proper structure. On my local revision I've already implemented the command pattern coupled with an undo/redo system. Well, QT does indeed like much more modern. But everything I need I can find in wxWidgets. QT is a huge framework which I don't want to have in my source. Not for the sole reason of making it look nice.

More feedback please :)
User avatar
vitefalcon
Orc
Posts: 438
Joined: Tue Sep 18, 2007 5:28 pm
Location: Seattle, USA
x 13

Re: Project review/advice

Post by vitefalcon »

Having just skimmed through your code, my first impression was the 'overall structuring' of code. Personally, I see no need to divide files to 'include' and 'src' directories as:
  • You're not making an SDK or library, you're making a game-engine. If you were creating an SDK or library, it would make sense to have files divided that way because not all header files are intended to be shared. But I still think that should be part of the 'installer' script to ignore header files if all files were under one directory.
  • It saves you on compile time. Having the corresponding header and source files in the same directory means you can include the header files in the form `#include "myheader.h"` instead of `#include <myheader.h>`. The difference being, the former first checks the current directory of the file for the header before looking into include directories, while the latter only searches the include directories. The compilation time would be time consuming as the number of files in your project grows. In your case, you've included all header files in the former manner (with double-quotes), which means it would first search in current directory of the source file and fail always before looking into the 'include' directory. Depending on how you've setup your include directories, it could be looking at all the wrong places before finding the header file.
  • Like others have already mentioned, it might be better to stick with one rendering engine and not try to wrap it. I too went that path once and found that it was not only time consuming, it also took toll on my morale. You would end up taking more time to get something trivial done and failing to get good results with a lot of effort will have a 'hit' on your morale.
  • I would argue the same with Physics engines. Since we've got numerous Ogre3D wrappers, it (may/) may not be that hard to switch engines if you find it's not what you'd want to use.
Image
User avatar
TWO
Halfling
Posts: 61
Joined: Sat Jan 26, 2008 9:30 pm
Location: Germany

Re: Project review/advice

Post by TWO »

Thank you very much for your replies!

I merged Ogre and PhysX back into the engine, removed Eigen (a math library, BTW I don't know why Ogre is not using Eigen, they are so similar yet Eigen has much more features esp. in regards to speed.) in the process. Source and header files now reside in a single directory. I'm not happy with the entity system so here is my next draft. All allocations and management happen behind the scenes. This is user and script language friendly, at least I hope so.

Code: Select all

Scene scene = sceneMgr->createScene();


// Template
EntityTemplate crateTemplate;

{
	PropertyMap params;
	params["Position"] = Vector3::ZERO;
	crateTemplate.addComponent("Transform", params);
}
{
	PropertyMap params;
	params["Name"] = "crate.mesh";
	params["MaterialName"] = "Material/Crate";
	crateTemplate.addComponent("Mesh", params);
}

entityMgr->addEntityTemplate("Crate", crateTemplate);


// Instance
Entity crate = entityMgr->createEntity(scene, "Crate");

TransformComponent transform = crate.getComponent<TransformComponent>();
transform.setPosition(Vector3::ZERO);
Components do not contain any code, they are mere value holders. Systems implement the logic in a batch processing way. Note that the new code is not in the repo yet.

My aim is to make most of the code using the engine crash safe by hiding implementation details. This allows me to use C++ as scripting language. Code hot-swap, removal of header files, synthetic sugar like assoc arrays, ... should contribute to this.
User avatar
Zonder
Ogre Magi
Posts: 1172
Joined: Mon Aug 04, 2008 7:51 pm
Location: Manchester - England
x 76

Re: Project review/advice

Post by Zonder »

TWO wrote:Thank you very much for your replies!

I merged Ogre and PhysX back into the engine, removed Eigen (a math library, BTW I don't know why Ogre is not using Eigen, they are so similar yet Eigen has much more features esp. in regards to speed.) in the process. Source and header files now reside in a single directory. I'm not happy with the entity system so here is my next draft. All allocations and management happen behind the scenes. This is user and script language friendly, at least I hope so.

Code: Select all

Scene scene = sceneMgr->createScene();


// Template
EntityTemplate crateTemplate;

{
	PropertyMap params;
	params["Position"] = Vector3::ZERO;
	crateTemplate.addComponent("Transform", params);
}
{
	PropertyMap params;
	params["Name"] = "crate.mesh";
	params["MaterialName"] = "Material/Crate";
	crateTemplate.addComponent("Mesh", params);
}

entityMgr->addEntityTemplate("Crate", crateTemplate);


// Instance
Entity crate = entityMgr->createEntity(scene, "Crate");

TransformComponent transform = crate.getComponent<TransformComponent>();
transform.setPosition(Vector3::ZERO);
Components do not contain any code, they are mere value holders. Systems implement the logic in a batch processing way. Note that the new code is not in the repo yet.

My aim is to make most of the code using the engine crash safe by hiding implementation details. This allows me to use C++ as scripting language. Code hot-swap, removal of header files, synthetic sugar like assoc arrays, ... should contribute to this.
I am guilty of what you are doing all the time. abstracting and abstracting.

Would you rewrite the operating system for your project? Ogre is your operating system thing of it like that :)
There are 10 types of people in the world: Those who understand binary, and those who don't...
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Project review/advice

Post by bstone »

I'm not completely sure (read it like 14 years ago) but I believe Herb Schildt had a book on C++. Nothing special overall but there were a few remarkable gems about design. Here's one of them (can't remember the exact words but I will convey the message, they boosted my OOP skill the moment I grasped them): "Abstraction and encapsulation is good, but something has to do the actual job in the code somewhere. The trick is keeping other components clueless about that." So don't overdo the abstraction part - just enough to keep the coupling at low levels, something has to do the real job! :D

And if your "C++ scripting" gives up the static type checking - screw it. Better use a a dedicated scripting engine with C++ bindings or make the "C++ scripting" embrace the power of static typing. There was an article on Gamasutra describing a macro based scripting in C. The guys used it to test a point-click adventure game by scripting all possible player actions through various game walk-through scenarios. There will be even some more power in that when applied to C++.
User avatar
TWO
Halfling
Posts: 61
Joined: Sat Jan 26, 2008 9:30 pm
Location: Germany

Re: Project review/advice

Post by TWO »

That is very valuable advice bstone :) To remember that programming and designing software is not about the most elegant or clever solution but the solution that works and is easy to gasp. Software is complex on its own, no need to add to that.

I rewrote parts of the entity system. Here's on example:

Code: Select all

class _PolyExport PhysicsDynamicComponent : public PhysicsComponent {
public:
	physx::PxRigidDynamic*	rigidDynamic;

							PhysicsDynamicComponent();
		
	virtual void			initialize(Entity entity, const StringVariantMap& values);

	void					setKinetic(bool val);
	bool					isKinematic() const;

							POLY_COMPONENT_INFO;

protected:
	bool					mKinematic;
};

Code: Select all

POLY_COMPONENT_INFO_IMPL(PhysicsDynamicComponent, "PhysicsDynamic", "Physics");

PhysicsDynamicComponent::PhysicsDynamicComponent()
:	mKinematic(false) {
	mProperties.addProperty("PhysicsDynamic/Kinematic", &mKinematic, true);
}

void PhysicsDynamicComponent::initialize(Entity entity, const StringVariantMap& values) {
	PhysicsComponent::initialize(entity, values);

	rigidActor = rigidDynamic = gEnv.physics->createDynamicRigidBody(Vector3::ZERO, Quaternion::IDENTITY, entity);
	rigidDynamic->setRigidDynamicFlag(physx::PxRigidDynamicFlag::eKINEMATIC, mKinematic);

	parseAndCreateShapes(rigidDynamic, mShapeDescription);

	gEnv.physics->addRigidBodyToScene(mEntity.getScene(), rigidDynamic);
}

Code: Select all

class PhysicsEntityLogic : public EntityLogic {
public:
				PhysicsEntityLogic();

	virtual void	getComponentTypesOfInterest(ComponentNameSet& typeNames) const;

	virtual void	updateEntitiesOfInterest(const String& typeName, const EntityList& entities);

protected:
	ComponentNameSet mTypeNameOfInterest;
};

Code: Select all

void PhysicsEntityLogic::updateEntitiesOfInterest(const String& typeName, const EntityList& entities) {
	BOOST_FOREACH(Entity entity, entities) {
		TransformComponent* transformC = entity.getComponent<TransformComponent>();
		PhysicsDynamicComponent* physicsC = entity.getComponent<PhysicsDynamicComponent>();
		if(transformC && physicsC) {
			if(!physicsC->isKinematic()) {
				Vector3 position = physicsC->getPosition();
				Quaternion orientation = physicsC->getOrientation();

				SceneNode* sn = transformC->getSceneNode();
				sn->setPosition(position);
				sn->setOrientation(orientation);
			}
			else {
				SceneNode* sn = transformC->getSceneNode();
				Vector3 position = sn->getPosition();
				Quaternion orientation = sn->getOrientation();

				physicsC->setPosition(position);
				physicsC->setOrientation(orientation);
			}
		}
	}
}
Actually I like the seperation of data (Component) and logic (EntityLogic) much more than the combined model in Unity. In addition to that the model should be faster too. What's missing are bucket updates (tank, then turret) and child/parent relationships, but I don't need either right now.

Please note here that I finally got how I want the engine to behave. It sets up all the stuff needed to get PhysX to run. Creates the scene for you and the dynamic/static actors. Sets up the userdata member to raycast can return the hit Entity to you. But not anything more. You are free to use the original PhysX, no wrapping. In addition to that parts of the code where different people will use different 3rd party libs (scripting, audio, especially gui, ...) are either abstract factories or not included in the engine code. You are free to add them later in the game using the provided architecture.

Would you rewrite the operating system for your project? Ogre is your operating system thing of it like that.
I would love to do that, but ain't nobody got time fo dat.
And if your "C++ scripting" gives up the static type checking - screw it.
That's my biggest problem with scripting these days. Static type checking is just such a great thing, I don't want to live without it. I'm experimenting with AngleScript and Squirrel, but there won't be an implementation in the engine. Scripting is just one of these things where everybody has a different opinion. Maybe I can write an automated wrapper or provide SWIG files.