Design pattern for linking UI events to editor code?

Started by
5 comments, last by LorenzoGatti 8 years, 8 months ago

When I started writing my terrain editor, I had few UI events so I just had their IDs stored in an enum and called a function to process the event in my editor whenever the event occured. As the number and type of events grew, the code became messy. Basically a giant nested switch statement.

What would be a good way to handle this situation? I have various event types such as:

- Setting parameters (floats, integers, bools, strings, etc..)

- Changing render modes / view modes / paint modes

- 'Orders' such as new, load, save, etc...

And then there is of course the fact that this has to be general enough to be integrated with an Undo/Redo system.

"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
Advertisement

Command pattern might be what you are looking for, it separates all actions into different classes and supports undo-commands (though you still have to implement the undo-operation yourself, unless you store the whole games state and copy/store that for every undo command...).

But then wouldn't you end up with a large amount of command classes?

class SetBrushRadius : public ICommand;

class SetBrushStrength : public ICommand;

class SetBrushType : public ICommand;

etc...

And if you choose to have a single class called SetParameter instead, you'd still have to do a giant if statement inside to determine which parameter to set.

"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "

But then wouldn't you end up with a large amount of command classes?

Depends. Generally yes, but you are not going to avoid that alltogether. Its way better to have a lot of classes then a giant if statements because 1) the classes are independant of each other and thus 2) all the classes can be organized and managed better. You still have to realize that if you have different parameters that you want to couple to your UI, you will at least have to write SOME code for letting your application know that this parameter exists and what to do with it.

But if you want to reduce the amount of code for parameters, here is what you can do. Instead of writing a different class for each parameter, you use a template class (for the type) and store a function pointer:


template<typename Type, typename Object>
class ParameterCommand : public ICommand
{
	using FunctionPointer = void ()(Type);
public:
	ParameterCommand(Type value, Object& targetObject, FunctionPointer targetFunction),
		pTargetObject(&targetObject), targetFunction(targetFunction)
	{
	}
	
private:
	
	Type value;
	TargetObject* pTargetObject;

	FunctionPointer targetFunction;
	
}

And then you can just do:


ParameterCommand<float, Brush> radiusCommand(5.0, brush, &Brush::SetRadius);

This is just an example and might not even perfectly fit your use-case, but you get the idea. Command pattern, unlike your nested if-list, allows you to use all the class/template magic of C++ to reduce the amount of things you have to write. But you have to write some code for each parameter... wait, you are using C++, right? There might be even easier tools in other languages based on reflection, but command pattern is still a viable top-level solution which allows you to solve the specific subsets of your problem the way that your language makes it the easiest.

On an unrelated note, was the brush-example an artifical example or do you really plan on making those undoable too? I'd advice against it, I hate nothing more than wanting to undo a series of changes I made, and having the application undo all my brush/tool changes in the mix. Might be personal opinion but not many applications even do that which I've seen.

I do like the template and function pointer approach. I think I will check just how many parameters I will have at the end and see if the extra complexity is worth it.


On an unrelated note, was the brush-example an artifical example or do you really plan on making those undoable too? I'd advice against it, I hate nothing more than wanting to undo a series of changes I made, and having the application undo all my brush/tool changes in the mix. Might be personal opinion but not many applications even do that which I've seen.

I didn't think about that. You're right I think I'll only undo actual changes to the terrain. So set parameter and similar commands won't be put on the Undo stack.

"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "


When I started writing my terrain editor, I had few UI events so I just had their IDs stored in an enum and called a function to process the event in my editor whenever the event occured. As the number and type of events grew, the code became messy. Basically a giant nested switch statement.

When I read your question and this part, my first thought was MVVM. But I seem to be wrong in that assumption.

Beginner in Game Development?  Read here. And read here.

 

You might be able to consolidate multiple command objects into the same class (or the same function, using techniques like Julean's template), initialized in different ways.

For example, a AlterBrushCommand class containing all brush parameters as members could be equipped with with chainable setters or something of the sort and used to change any combination (usually only one) of radius, strength, type etc.(e.g. executing new AlterBrushCommand(currentBrush).radius(brushRadiusSlider.currentValue()), new AlterBrushCommand(currentBrush).type(brushTypeSelector.currentValue()), and so on),

Omae Wa Mou Shindeiru

This topic is closed to new replies.

Advertisement