4 ms·
I would concur and add that the main risk one runs in deploying any new, widespread abstraction to game code is an architectural meltdown, where perf bottleneck
by buzzybee 10y ago
I would concur and add that the main risk one runs in deploying any new, widespread abstraction to game code is an architectural meltdown, where perf bottlenecks are appearing everywhere, too many code paths have been locked in by the abstraction so you can't iterate on them fast anymore, you have race conditions you can't analyze properly, etc.
Iteration times across the whole development lifecycle are hard to optimize because in the near term the iteration problem is specific to writing basic functionality, then later on it's adding and adjusting a wide variety of assets, and then even later it's debugging and optimizing. Care too much about one and you mess up the others.
If you soak up pain up front to keep the core of the code in an unadorned imperative style, crunching on plain data, avoiding deeply nested callstacks or polymorphism, you get a huge assurance that you can handle anything that happens later on - it follows the grain of the tooling and the happy path of the optimizer.
The way in which I last approached the live-reload problem was to write a data model, and then bolt a scripting language on to generate data. Then reload the scripts - you get the fast iteration, without being particularly invasive on the main loop.
Edit: And similarly I've focused most of my abstraction braincycles on making it easier to access and swap out assets. One of the biggest recurring problems in engine code is deriving runtime assets from combinations of static assets and parameters. This has led me down the road of developing an addressing scheme.
- s_m_t 10y agoI've just started to program a game engine and to my surprise the most difficult to structure aspect of the programming has been essentially, I'm not really sure how to word this, but mapping things to other things. Making sure that a keypress eventually leads to the right function being called is a good example. It seemed really simple at first but then I figured that the keypress shouldn't directly call the function because then you'd need to recode or reparameterize some giant state machine because in certain contexts a keypress can do many things or control many different objects in the game (even controlling multiple objects at the same time, and what if you want to be able to control the game remotely or from two controllers at once?). Before I started I thought the 3d movement and physics stuff would be the hardest... but I've found it was actually pretty simple, I just iterate through a list of objects and just call their respective member functions to make the movement happen and it seems to work fine for now.
- jstimpfle 10y agoSee my simple Tetris Game, https://github.com/jstimpfle/tetris-on-a-plane/blob/master/tetris.js https://github.com/jstimpfle/tetris-on-a-plane/blob/master/t..., at the very bottom. This implements a state machine in Javascript. It's a very simple case with only 2 states, "playing" and "paused". Each state registers its own event handlers on entrance, and unregisters them on leave. This approach avoids the need to answer the question "where am I? what should I do?" every time an event handler is called. While I think the approach is nice, the code is not so nice from a superficial point of view. The more general problem is that event-style sucks. Look up CSP by Tony Hoare, and Occam the language. What we need is better formalisms for sequential programs that include non-determinism like user events (i.e. view the user as part of the program). (And, of course, also parallel execution of these sequential threads, and also sub-states that can access parent states in a way. Look up Harel's Statecharts. A good example would be a form with two text input boxes. We could view them as parallel sub-threads of the form thread).
- s_m_t 10y agoNice, I implemented something very similar, except in my game not every controllable entity a) implements every control, and b) implements controls the same way, so I store what a control would do as a member function of each object and store an array with the names of these functions in each object. The indices of the array with the names of the functions match the indices of an array that stores the key codes I listen for, from there I match the indices, grab the name of the function and call it from the object being controlled.
- jstimpfle 10y agoIn Javascript, you have to install event handlers. There is no control when they are executed, which is a problem. When writing a game engine, you typically create events yourself at the top of the game loop (reading the input sources in a non-blocking fashion). You have better control what handler is called and when, but what handler should be called probably still shouldn't be decided in a central location. So I figure your object-based approach is a good solution. (The individual handlers can rely on the fact that they are only called at the start of the loop). I realize a Javascript app could easily emulate the game loop style by letting handlers write to a queue.