Thursday 17 July 2014

Getting Things in Order

So I guess I'd like to bring this blog up to speed now by talking a bit about HTP's procedural generation system and it's current graphics. This one will be a fairly technical I warn you.

I've always been a big fan of procedural generation in games, I guess you could say it's not only the calling card, but the saviour of indie game developers. With tiny teams and limited resources, why not get the CPU to do the leg-work for you? But PGC (I've had a couple beers and don't fancy typing about procedurally generated content more then once) can seem very lifeless and boring if not treated carefully. I feel PGC should help the developer fill in the blanks. Provide the world with a good starting point for custom content, and if possible, be clever enough to hopefully provide some emergent gameplay experiences while it's at it.

For HTP, I wanted to be able to define how different nodes (pretty much everything in HTP is represented by a node: computers, networks, cities, etc.) should be generated depending on the size, security, population, etc. of it's parent node. This is defined in a JSON file that's easy enough to hand edit at the moment that I don't feel the need for an editor. For example, the following is the current definition of an ISP that might be generated in a city (if it's large enough to have one):

{
    "ShouldScale": true,
    "MinSize": 0.1,
    "MaxSize": 0.1,
    "Needs": ["Power", "ExternalNetwork"],
    "Provides": ["Network", "ExternalNetwork"],
    "Structure":
    [
        {
            "Type": "Router",
            "Serves":
            [
                {
                    "Type": "Firewall",
                    "MinSecurity": 0.3,
                    "Serves":
                    [
                        {
                            "Type": "Computer",
                            "Role": "Webserver",
                            "Max": 3
                        },
                        {
                            "Type": "Switch",
                            "Serves":
                            [
                                {
                                    "Type": "Computer",
                                    "Role": "Workstation",
                                    "PerPerson": 0.75,
                                    "Hours": ["Work", "LazyNights"]
                                }
                            ]
                        }
                    ]
                },
                {
                    "Type": "WiFiAccessPoint",
                    "MaxSecurity": 0.1,
                    "Serves":
                    [
                        {
                            "Type": "Mobile",
                            "PerPerson": 0.2,
                            "Hours": ["Work"]
                        }
                    ]
                }
            ]
        },
        {
            "Type": "FuseBox",
        }
    ]
}

There's a few interesting things here. As you might be able to see, if this ISP is generated with a low enough security rating (ie. it's got pretty shitty security), then some terrible network admin might have inadvertently plugged a Wifi access point directly into their main router, in front of the firewall. Massive security risk, and something I wanted there to be a chance of encountering in the wild. I can also specify the hours that a given node might be active. So for the employee workstations in this ISP, they will always be active during work hours, but with the added possibility of being active during the night if an employee forgot to turn it off or just likes wasting power.

There's still a lot more work to do here, but my goal is to make these definition files very moddable and extensible, as well as easy to edit.

At this point I was generating some pretty busy worlds, with the largest cities having their own power plants, ISPs and residential neighbourhoods, and smaller cities feeding off those large cities with network and power substations (I still really need to figure out the real names for those :P). But things were getting very cluttered and disorganised, I had no choice but to simple randomly place nodes anywhere within their parent node's bounds, resulting in a lot of ugly overlap. I spent some time looking into box packing algorithms to try and make some more sense of this mess, but it turns out hierarchical box packing is a bit of an NP problem.

Then along comes physics to the rescue. I love physics, it makes extremely hard to solve analytical problems just sorta "pan out". I read up on force-driven layouts. This technique applies attraction and repulsion forces to a set of nodes and will, given some time, settle them in the lowest energy state, which very fortunately, usually looks quite nice :]

I'm still working on the layout system, so take the following video as a work in progress, but here it is so far:



This brings this blog pretty much up to date to where I am now. I'm hoping to post once or twice a week with the latest developments from my lunch-break programming adventures, I hope you keep checking in :]

No comments:

Post a Comment