May 25th, 2014

I had hoped to get the display part of this thing up and running this week, but illness happened. The code part of it is complete, but doing the necessary additions to related code and making it capable of actually compiling still need to be done.

You might recall last week that I decided to make sprite caching operate by having parent scale/tint/rotation/etc applied to the cache texture instead of the individual cached sprites that make up the texture. At this point I had the idea of storing a second set of world coordinates for each of these cached sprites to keep track of where they really were in the world rather than where they were relative to their cache texture.

This idea was rather naive in that I considered world coordinates to be calculated the same way as if the cache wasn’t there. Of course in reality scaling up a texture that has a sprite in it isn’t the same as scaling that sprite up directly- its position ends up shifting as part of the scale operation! Once my head had cleared I ended up shifting to a system where collision coordinates are converted between the render targets as needed for nested cache sprites, as well as other systems such as the map camera.

May 18th, 2014

I suppose you could split the implementation of this thing into 4 parts: display (inheriting parent properties, drawing to screen including complexities like caching, etc), events (detecting collision types and dispatching relevant events, handling those events), layout generation (arranging children in more sophisticated manners), and ui widgets. That first part is nearing completion in terms of code written, though fixing/testing that code to actually run hasn’t started yet. It’s hard to estimate how long these things are going to take since a number of unknown factors are involved. It could be worse, I guess?

A fair number of new design problems popped up while implementing this thing. But none of them are terribly interesting. Ended up going with the “scale/tint/rotation/etc of a cache renderer node are applied to the cache texture instead of being inherited” model once I realized that fonts aren’t scaled up and would instead properly resize the cache texture for proper readability. Decided to move refreshing (the queuing of re-applying inheritance rules that is delayed until the next update) to its own handler so that later on we could have refreshing that only applies to things that depend on each other (ie you change the tint which has no dependencies it only refreshes the tint) and so that component objects have a more restricted knowledge rather than having access to the entire node. Decided to let individual nodes decide whether they use a stable sort on their children or not, since in many cases it doesn’t matter while in a few (namely windowing) it does. A little bit of premature optimization there that might bite me later when I forget how it works. Nothing exciting, just a few details that get missed in planning.

I’d really like to get this thing done this month (marking 2 months down the drain for it), but that isn’t looking likely at the current rate of progress. Troubling. Had a thought about how to visually handle NPCs yesterday that cheered me up, since it solves a big problem with the story lacking emphasis.

May 11th, 2014

At long last, planning on the new sprite/ui system has come to a close. This week has nothing really special to talk about. The majority of the remaining problems were all about filling in the last few things that hadn’t been fully documented for the latest changes (dual graph system, collision handling, scrolling, etc). Implementation is going smoothly so far, but since I made the unenviable choice of doing it on the C++ engine side I know full well that there is going to be some heavy debugging costs later on.

Not just that, but large swathes of the existing game are going to have to be updated for the new system (how maps are managed, battle backgrounds will accessed very differently, map objects are going to be handled as sprites instead of tiles, how every sprite in the game needs to be handled is changing, etc). So there’s still a lot of work ahead. On the plus side I feel like the last parts of the core engine that I was displeased with are finally getting into order. Once this work is done I feel like I could use the engine to make future games easily, instead of the weirdly cobbled together game-specific mess it started out as.

Unforeseen Consequences: Collisions Collide!

Only one design entry to talk about this week since there weren’t that many. Last week I decided to split the graph into two: one to inherit display/position properties, and one to indicate draw order. There was one thing I hadn’t considered when I did that, which is that linking those two things is extremely useful when it comes to collisions. By having every child be within every parent with the transform graph, it allows the property of only checking children for a collision when it collides with their parent. By having the layer graph order indicate draw order, it allows collisions to be intercepted by sprites towards the top of the draw order- ie if the user clicks on a window that’s on top of another window, only the top window actually receives the collision. These two properties are crazy useful, but by splitting the graph I had to choose one or the other.

At the end of the day the layer graph won out, since it’s a useful property rather than just an efficient property. But I didn’t just discard the transform graph’s filtering, I just made it an option for parents to pass collisions to children even if they themselves don’t collide (alternately, they can just encompass the entire world). Since the majority of the two graphs are identical only the few exceptions need concern themselves about this. It’s not ideal (more because these details are easily forgotten and create problems later, than from inefficiency), but it’s good enough.

 

May 4th, 2014

I think planning is finally actually coming to a close this week. This is probably the third week I’ve said that. But I think I mean it this time. I’m eager to see how implementation time pans out.

This week’s problems:

1. Who’s renderer is this anyway?

As previously discussed, sometimes you want to pre-render complicated unchanging visuals to a texture and then just draw that instead of each individual element every time. Naturally this means coordinates need to start being relative to a sprite’s parent. It also means that the renderer object- the thing that decides whether it’s doing a dynamic or cached render- needs to start being what decides what to do with those relative coordinates. A dynamic renderer is going to want to use the accumulated xy positions of its parents. A cache renderer is going to want to start fresh since it’s having its children draw to it instead of directly to the world.

This caused a great deal of pain in terms of deciding whether the object handling all general positional information should deal with these final coordinates, or whether the renderers that changed the behavior to begin with should handle the coordinates. Eventually the renderers themselves won out at the logical place to put it.

2. Draw order is a pain.

Generally the draw order of a scene graph is determined by the ordering of the graph itself. This causes some issues in a 2d game. The scenario I use to illustrate the problem is this: characters have nametags positioned above them. Logically, these nametag sprites should be attached to the characters since their positions are related. But the draw order of these things is very different. Since characters are drawn in y-order, you end up with nametags being placed underneath characters when they should always be above all characters!

This doesn’t seem to be that commonly discussed of a problem online. I’m guessing most people just work around this relatively rare case by manually positioning such nodes elsewhere in the code, but that defeats part of the point of using a scene graph to begin with! (in early drafts of my work around I tried building this type of functionality directly into sprites, but ran into it quickly becoming a mess). In one case I saw a library using parts of OpenGL directly to accomplish differing draw order in special cases, with a host of caveats attached to it. A friend I asked used the technique of having draw order completely unrelated to the graph by having sprites associated with layers that determine their draw order.

I didn’t like any of these solutions because using the scene graph for draw order is extremely useful to me. You want a window’s contents to be drawn on top of the window? That’s the default behavior! You want to move a window to the top of the window draw order when it gets selected? Simple as moving it to the top of its parent’s child ordering. You want JUST these sprites to be y-ordered? Set their ordering metric to their y values when they change. It allows for dealing with complicated draw order problems in a simple manner, especially when it comes to UI.

So I finally settled on an unnervingly complicated solution. There are now two graphs: the transform graph (inheriting position etc) and the layer graph (determining draw order). Most of the time these graphs are identical, but in cases where they need to diverge they can by giving a sprite a different layer parent than their transform parent. I don’t really like how complicated this makes things. Bugs are almost certainly going to arise from me forgetting which graph I’m concerned about at a given moment. It’s wasting some resources for every sprite that only a few sprites need to worry about. But it does solve the problem.

3. Scrolling is pain.

Supporting UI scrolling is basically death by a thousand cuts. You need to a scroll offset to shift children around to create a scrolling effect, but you must only pass that offset to your children instead of using it yourself. You must be a specific type of sprite so that you know to create scrollbar children to adjust you. You must use clipping/masking on your children to deal with partial visibility. Scrolling has its fingers in a lot of different pies, which makes structurally containing it a nightmare even if the individual parts aren’t so complex.