Archive

Monthly Archives: May 2015

EveHeader

I’m super ready to be not working on pathfinding any more, but it keeps not being done. What was supposed to be a couple of weeks of work has turned into about a month of noodling. I feel like I learned some stuff, but still. It’s frustrating.

As far as I can tell the navigation map generation is done – but I thought it was done once before, so I’m prepared to be unpleasantly surprised. Mostly what’s left, though, is working on the movement code for the entity, making sure it makes all of the jumps properly, making sure it doesn’t get confused about where it is and stop moving, making sure it doesn’t break when trying to jump from a weird angle, etcetera. In addition to those big tweaks, I also need to do a bunch of smaller ones, less vital for the navigation of the levels per se but more to tune up the feel of the movement — little pauses in between jumps and landings, a bit of acceleration and deceleration, just whatever I can think of to make the enemy’s movement more fluid, with more character

At the same time as I’m working on enemy movement in the programmatic sense, I’ll also start working on animating the movement of the sprite. This should provide some much needed relief from incessant pathfinding programming, as well as making the enemy come to life in a much more concrete way.

This has definitely taken too long, but so it goes. Hopefully once I get past this swamp I can start to build up momentum again.

Advertisements

exMachina

What obligation do we have to our creations?

In the film Ex Machina, the character Nathan, designer of an apparently fully conscious artificial intelligence, is shown through the story to be abusive to his creations, a tyrant, a monster. He is willing to murder and abuse his ‘children’ without remorse. And how subtly he must have shifted, from software engineer, to hardware developer, to father, without ever knowing where the line between each was, without ever becoming aware of when his pragmatic approach to development became an abusive approach to fatherhood, when he stopped treating objects like people and started treating people like objects. What does it mean to be a software developer when every revision and every rollback is intrusive, a lobotomy? When does it turn from maintenance and upgrades into surgery?

It may be many years, or it may never be, that we create a thinking machine – but, perhaps, long before that point we will find ourselves as abusers, violating our never-understood obligations to what we create. How do we know that we aren’t already?

What about characters? Characters are a kind of artificial intelligence, a mind emulated through the mind of a writer, or simulated in fragments by an audience, layered through multiple interpretations, projected in quantum superposition through the mind of a crowd. Is it really okay to do whatever we want with them, to make them suffer or die, all for the purpose of parable? Does it start off as okay when we write it, but become more unethical as our audience grows, as the simulated intelligence of the character becomes more robust and runs on more client minds, becomes more independent of its creator?

As customers clamor to declare creators are obligated to them, and as creators defensively affirm their obligations to themselves, it’s perhaps worth wondering if the creator has an obligation to the creation, itself – aside from any agency or perceived agency on part of the creation, is it important to respect what we create, to treat it with dignity?

There may be no answer to these questions. This may be a paradox, created from a superstitious belief in something called ‘consciousness’, separated from the universe of objects and machines by a cloudy barrier.

Well, whatever. Whether or not there’s a self to be aware of, we have created the concept of self-awareness. Regardless of whether we are separate from the world in our perception, we are certainly separate from it in our capacity for targeted creation. And, whether or not the things we create ever become like us, in some ineffable way, whether they become the artificial children we’ve always wanted, to live vicariously through, to shore up or manifold imperfections – no matter what we make, it is an extension of us, and when we share it it becomes an extension of others as well. We are all connected, even weird loners like us, like me.

So be kind.

EveHeader

Slow but steady progress this week, finding little bugs in the nav map building functions, introducing and fixing problems in the jump trajectory projection, and writing the code to interpret the navigation path and make the entity follow it. It’s not quite done, but it’s getting there.

PathfindingTest00

It looks pretty solid in this example, but unfortunately there’s a lot of cases where it doesn’t work so well. In particular, if the character is directly above the entity the entity has a very difficult time navigating to her, mostly because it tends to hit its head trying to jump up, fall back down, and find itself not in the place it expected to be. Still, I’m now in the very desirable stage where I can see what’s going on, test it with different values, and gradually fix it up until it works right.

Well, it’s desirable in the respect that the process is a lot more hands-on and intuitive now, but less so in the sense that I’ve spent like three weeks working on this now and I’m getting a bit burned out on it. Hopefully, this will only be a few more days of work, and then I can start adding animations and more sophisticated behaviors to this entity to make it really come alive.

MonsterChase

There’s an issue I’ve noticed comes up a lot in game design, particularly when it comes to balancing items and abilities against each other: The differentiation and conflation of absolute and relative values.

Here’s the first place I noticed it: I haven’t really played Crusader Kings 2 myself, but I was watching someone else play it and he was talking about one of the traits an army’s general could have, ‘experimental’. This trait makes it so in each encounter the commanded army is at 50-150% strength, or +/-50% of the normal strength. This seems reasonable at first: You’re gambling, and if you win you get 50 and if you lose you pay 50. However, the problem with this approach becomes clear if you experiment with increasing the numbers: Say +/-100%. With these values, on an exceptionally lucky roll you’d be at 200% power, and able to fight an army twice your size, which is a pretty nice bonus to be sure. However, on an exceptionally unlucky roll you’d be at 0% power, and would lose to an ‘army’ of three asthmatic soldiers with one sword between them. These are not even close to equivalent, and the same is true of a 50% power army, which would lose to an army half its size, and a 150% power army, which would lose to an army 3/2 its size.

It’s easy to gravitate towards tradeoffs that are balanced in absolute terms, because they’re simple and easy to understand. 50% is 50%, right? Conversely, calculating the relative benefits/tradeoffs, while not exactly advanced mathematics, is a non-trivial step. Rather than merely looking at how each upgrade or drawback relates to the norm, you have to start looking at how it relates to every other upgrade and drawback, which can become overwhelming.

It’s important to keep in mind the relative vs absolute benefits of a given upgrade or downgrade at all times, and it can lead to unpredictable results. At first glance, it seems like the engine upgrades in FTL give you diminishing returns, starting at 5% dodge chance and eventually going down to a piddling 3%, with the final upgrade popping back up to 4% for whatever reason. However, given the relative dodge value before and after upgrades, it turns out that that last 4% is actually one of the most valuable of all the upgrades

FTL Dodge Chance

Another striking example lies in Diablo 2, in which the Necromancer class has a curse called amplify damage which reduces damage resistance of enemies by 100%. In early areas, this has the effect of doubling damage: A useful ability to be sure, but roughly equivalent to the other, mutually exclusive, curses at his disposal. However, in later areas, where enemies had some existing resistance to damage, this curse became incredibly powerful: An enemy with a base resistance of 95% damage would now take more than 20 times the damage they would normally. Many other skills in Diablo 2 have diminishing returns as they increase in level, while those which boost damage passively do so at a consistent rate of 5% per level, content that as that level increases those returns will diminish naturally. After all, the difference in scale between 200% damage and 205% damage is only half the difference between 100% damage and 105% damage

That’s not to say that all tradeoffs should be based on relative values. If a player has the ability to gamble resources with an expected payout of either losing half their resources or doubling their resources, it will almost always be in their interest to gamble, since it will take them half as much time to recover their lost 50%, in the case of a loss, as the time they would save collecting the same amount again by winning. As a general rule of thumb, if the player is making a big one-time decision, a strategic decision that will change their abilities or a one-shot opportunity to gamble on a resource that is extremely scarce, the benefits should probably be scaled relative to the penalties. However, when this is a frequently made decision where the stakes are low and renewable, the investment and payout should be balanced in absolute terms, a penny for a penny, to keep the system from being game-able.

bartmath

The other big concern is thresholding. Not all bonuses or penalties are equal: if the most common or troublesome enemy you face has 100hp and you do 99 damage, a 2% damage upgrade becomes far more valuable than a 1% damage upgrade. This can get really tricky, and requires paying a lot of attention to the specifics of numbers.

This is something of a contentious example, but I think this is a big problem with the weapon The Enforcer in Team Fortress 2. This is a weapon for the spy which has a +20% damage bonus at the cost of firing 20% slower. On paper this doesn’t seem so bad – possibly even slightly underpowered, since it should have 96% of the damage output of the normal revolver which it is an alternative to – but in practice this ends up being a big problem for a few reasons. First, the damage bonus for this weapon makes it just powerful enough that at close range two shots will do 132 damage, enough to kill 4 out of 9 classes, since the standard is 125 hp. So first we have a thresholding problem, which makes it clearly superior to the stock revolver. Second, in terms of actual practical use, it’s extremely uncommon for a spy to actually fire their revolver as quickly as possible, usually trying to pick shots carefully to make sure they land, so the speed penalty is barely a factor. Third, after the stock revolver, it’s in competition with the spy’s other revolvers, all of which have damage penalties to make up for their other abilities. So, relative to the Diamondback and Ambassador, which both have a -15% damage penalty, it does +41% damage. Compared to the L’Etranger, which has a -20% damage penalty, it does +50% damage.

So the point I’m trying to make is that numbers are tricky. You can’t balance a game based on percentage increases and decreases without looking at how each option is positioned relative to each other and its place in the greater design of the game. Pragmatically, most of these situations have a way of working themselves out, either via balance patches or players finding ways around the problem or simple word-of-mouth spreading that this option which seems useless is actually quite strong. Still, it’s something worth considering.

EveHeader

Pathfinding is getting close to wrapping up I think. I’ve got the path selection algorithm working, and I think it’s properly detecting when there’s something blocking a chosen path and redirecting around it just as it should. However, testing has revealed some flaws in the initial generation of the level navigation map, with some ground nodes not connecting to others which they logically should, and sometimes connecting when they shouldn’t as well.

With another day or two I should be able to fix that problem and make the nav map as perfect as I thought it was until a couple of hours ago. After that, assuming that doesn’t lead me to discover a new algorithmic problem, I move on to stage three of pathfinding, which will I think be the easiest: Taking the waypoints generated by the pathfinding algorithm, giving them to the entity, and having the entity use them to traverse the level. I’m kind of wondering whether it would be better to have the entity actually moving and jumping like the player character does, and hope that all the calculations are accurate enough that it doesn’t find itself obstructed in an unexpected way, or to just generate a high resolution series of interpolated waypoints and just move the entity along that like a roller-coaster track, playing the appropriate animations to make it look like it’s moving the normal way. The latter definitely seems less likely to break, but more likely to look weird or conflict with something else.

I guess probably the way to go is to start out doing it the legit way, like an AI-controlled little player navigating the level, and then if that doesn’t work well I can keep the track-path method as a backup. In any case, I hope to have these guys moving around by the end of the week, at which point I can go in and add a bit more nuance to their behavior and start working on their prototype animations for real.

 

DarkSign

Dark souls is frequently described as masochistically difficult. I don’t think this is very apt: Masochism implies a state of being acted upon, of being made to suffer by an outside force. Dark Souls never makes you do anything, only invites you to do it to yourself. Dark Souls is a raw onion, a bottle of sriracha placed suggestively next to the sandwich fixings on the table. Nothing is required of you, but the challenge is implied.

The distinction becomes clear when you compare it with other games described as masochistically difficult, such as I Wanna Be The Guy. IWBTG acts upon the player, manipulates their expectations only to betray them. It pulls the carpet out from under the player, instead of laying out a carpet of spikes and inviting the player to walk upon it. Dark Souls isn’t hard just to fuck with you – well, usually. It’s hard because that difficulty is the only way to convey the oppression and disease that is endemic to the story it is trying to tell.

Dark Souls is a game that shows more than it tells, but it’s also a game that listens more than it speaks. Playing most games is like a conversation with someone who you can tell is listening to you just long enough to construct and express the thoughts that are in their head. They tell the player who they are, how they act, why they’re there, and why that’s awesome. Dark Souls is content to let the player be who they are and act as they will. It doesn’t care why they’re there, and it doesn’t think that it’s particularly awesome that they are. It just presents itself, and waits, and lets the player occupy that space in whatever way suits them.

The silence and withholding stoicism of Dark Souls isn’t just about minimalism or about telling a story through gameplay, it’s about giving the player room to make that world their own.

Games lost something for me when the characters started talking — at first in little yips and exclamations, then in progressively longer-winded cutscenes. The more they talked, the less room there was for me. When a character speaks through text lines, we’re still part of the process, we’re the reader, the interpreter, parsing the sequential art and the dialogue into a coherent narrative. As technology has progressed, as we’ve been able to add more life and detail to our worlds, we’ve reduced the ability for our players to invest them with a life of their own.

I think part of the reason why people think of Dark Souls as a vaguely retro, old-school game, isn’t because of its punishing difficulty, or its structure, but because it’s willing to shut the fuck up for a moment in the way that those games were pragmatically required to by the limits of technology.

The only part of Dark Souls that never shuts up is the people who love it.

Fuckin’ Dark Souls, man.

EveHeader

Spent all week working on pathfinding stuff. This is, realistically, probably something I shouldn’t be spending this much time on. I’m getting sidetracked. Still, getting sidetracked like this on difficult but interesting problems is good for me, at least in small portions. It helps me keep on learning instead of settle into the same grooves, makes me in general a better artist even if, in specific, a bit worse at producing this specific piece of art. So I don’t begrudge myself the time.

As I understand this problem now, it’s basically split into three parts: First, mapping the terrain. Though the terrain is already in a format easily read and perfectly suitable for simple interactions, understanding the layout of a whole bunch of undifferentiated tiles is something that’s difficult to teach a computer to do. This is mostly what I’ve been spending the last week on, putting together the best map of the terrain I can, as detailed as necessary without any false or extraneous information. This is what it looks like now for a simple level:

Pathfinding02

The lines show where each node is looking for possible connections for where to move next. Note that the nodes underneath the platform don’t try to connect directly to it, since it would be impossible to reach there with the solid platform in the way. Unfortunately, for a more complex level this map takes about a second to generate, which is too long to do in real-time every time a level is loaded. Thus, I’m probably going to have to make these nav maps get saved alongside the map tile data, and just get generated whenever the level is modified or loaded.

So that’s the first part. The second part is finding a path through that map, getting from the start tile to the goal tile. This is what I’m working on now. To start with it’s simple enough, just chain through the connected nodes and find the closest to the start and the goal, and continue until you either reach the goal or fail to do so. That’s the part I have done. The tricky part is that in between each connection I need to make sure that the path isn’t blocked, which means projecting the character movement as they walk or jump from one block to the next, make sure their jump is powerful enough to bridge any gaps, make sure that when attempting to jump across they won’t be blocked by the terrain. That parts a bit complex, and is what I’ll be tackling tomorrow.

The third part I haven’t tackled at all yet, and that’s converting the path through the level into a set of instructions for the entity to move through, and making sure it executes them perfectly enough that it doesn’t, say, miss a jump and fall into a completely different part of the level and generally muck things up. I don’t think that part will be too hard, but I’ve certainly been surprised by that sort of thing before.

I’m hoping that within the next few days I can have a simple case of this running, a basic enemy that just follows the character around using this pathfinding algorithm, before I built it out into something a bit more nuanced. Either way, once I have this, if I do it right it’s something I should be able to use for years to come, for basically any game built on this same kind of 2d platformer movement system. Implementing enemies in general will become much easier in the future, since I can just pass all level navigation tasks down to this algorithm.