Jump to content

  • Log In with Google      Sign In   
  • Create Account






Design Roadblock

Posted by TheChubu, 03 December 2013 · 595 views

java terrain generator blocks in the road
So for this entry, text, text, a bit of code, and more text. I'm going to talk about a few issues I'm having with the design part of the generator, in particular when adding new tools, with their own operations.

Design Roadblock


In my previous entry I talked about a bit of eye candy I did for the generator and lightly touched the issue I am having right now, but I'll go ove rit again for the sake of explainin'.

Perspective

Before I started with the whole editor/tool/thing, I had a simple setup for the terrain generator: You would have parameters, fill those in, hit the corresponding generate buttons in order, and that was it.

This makes everything simpler, you do stuff in the wrong order, it breaks, so you shouldn't do so. But the whole "Editor" part means that you dear user shouldn't follow those strict rules right? What if you didn't liked that ridge you put there in the north and you're all the way on the last pass of the generator? You should be able to go back and change it, then go forward and pick up where you left it.

All of this imposes several challenges on a model that is strictly dependent on the order you do things. First the ridges, then the blurring, then the rivers, then the MDI, then finally the Midpoint-Inverse (or better, Diamond-Square).

So you're in step 4, Midpoint Inverse Pass, and want to add a ridge? That's gonna cost considerable time.

First, throw of the window the current map (delete it and reallocate it or re initialize it, both work), then draw the old ridges, then the new ridge... but that's just to get the desired changes written in the map. Then you have to get to where the user was before, that means, blur the map (pretty slow for now), recalculate all river paths (throwing away a lot of stored river positions in the process), do the MDI pass and only then we're back where we started, for just a single ridge in the whole map.

Hell, maybe the user doesn't goes back to the MDI pass but just returns to the river drawing tool (which means that the rest of the stuff would be recalculated anyway).

Other functions

A common function in any editor is the undo function, it poses exactly the same kind of challenges. For example, river undoing.

Say that you actually don't change the tool, but just want to undo a river that you just drew. Its a quite demanding thing actually, the river has to be removed from the generator, then the heightmap has to be reset because the river that you unmade affected the heightmap, then the particle map has to be reset too because the river particle is written there, then you have to draw everything again because you just unmade the last three passes with this process! (ridge drawing, blurring, river generation).

That require some kind of structure to handle those kind of changes. It would be really easy to just add methods to handle each particular case, that's how it is handled right now:
public void undoRiverPaint ( final int mapIndex )
{
    // Retrieve both generators corresponding to the currently selected map.
    final GeneratorRiver genRiver = riverGenList.get( mapIndex );
    final GeneratorRidge genRidge = ridgeGenList.get( mapIndex );
    
    // Check if there is any river to undo.
    if ( genRiver.isAnyRiverLeft() )
    {
        // Retrieve currently selected map.
        final ElevationMap map = mapList.get( mapIndex );
 
        // Remove last added river from generator.
        genRiver.removeLastRiver();
        // Reset heightmap 
        OpsTerrain.resetHeightState( map );
        // Reset particle map.
        OpsTerrain.resetParticleState( map );
        // Write ridges again.
        genRidge.writeRidgeLines( map );
 
        // Retrieve blur associated with the map.
        final BlurringMap blurMap = blurList.get( mapIndex );
        // Force blurring of the map with previous blur settings.
        blurMap.setBlurred( false );
        blurMap.blur( map, blurMap.getLastRadius());
        // Rewrite rivers.
        genRiver.writeRiverLines( map );
    } 
}
Now I dunno about you but to me it looks pretty wasteful.

Not only that but also that's a method in my Controller class, which is very restrictive. It means that for each kind of thing you did (draw a river, draw a ridge, do an MDI pass), you'd need to add a specific method in the Controller class to handle it.

More extensions

I wanted to leave the amount of "tools" you can use open, say for example that I want to add more land features that aren't ridges, like canyons, valleys, and such. Or maybe other water features, like an ocean level.

So for supporting the basic do/undo functions I need a more robust system to handle those, a "Tool Manager" if you will.

I can't seem to figure out a way to do this, ideally, adding a new tool would mean just extending an "AbstractTool", adding it to the manager, make corresponding changes on the UI (buttons, settings panel, etc), and that should be it.

Given that the tools have somewhat different requirements (they need to have different kind of knowledge on the maps, generators, and such) I'll could try to make a tool interface, that these tools would implement.

I'm trying to follow an MVC pattern here for the whole architecture, that's why I already have going a "ToolManager" for the UI part, which is in charge of switching the Listeners that know what method to call (which I hear isn't at all efficient but oh well), and the settings panel that is appropriate for the selected tool.

This one makes working with it pretty simple:
toolAdmin.switchTo( tool );
As long as the tool is set up properly, it shouldn't have many problems. The "bad" part is that the river tool needs knowledge about two settings panels, blurring and river, so that one is done under the same interfaces, but in its own class.

More abstractions

I'd like to have something similar going on for the "Controller" part. An easy way to switch tools, with their draw and undo behaviors, but coming down to a common subset of functionality among the tools that I have (and that I will have), and how they would interact is kinda hard.

Well, that's it for the wall o' text. Bye, until the next entry! :)




I just store all the map data for each undo step in my editor.

I'm already using up to 200Mb of memory so I'd prefer not to go through that route since I'll probably use a lot of more memory (I don't have only height data but direction data, state, particle at each point, etc).

 

But I did thought of a limited set of "undo operations". Maybe 10, or simply user defined. With a save/load system it shouldn't be too catastrophic. That way simply storing the whole ElevationMap doesn't seems that bad, it will have an upper limit.

 

In any case storing the state of the heightmap is not enough, also the generators need to know which river/ridge has been removed. So that part has to be done anyway.

April 2014 »

S M T W T F S
  12345
6789101112
13141516171819
202122 23 242526
27282930   

Recent Entries

Recent Comments

PARTNERS