tag:blogger.com,1999:blog-24034775774769516012024-03-13T18:12:06.137-07:00PlayTechs: Programming for funDabbling and babblingJames McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.comBlogger245125tag:blogger.com,1999:blog-2403477577476951601.post-72155575165569614012023-03-11T15:32:00.001-08:002023-03-13T05:49:39.852-07:007DRL 2023: Lurk, Leap, Loot<p>Once again, I've participated in the <a href="https://itch.io/jam/7drl-challenge-2023">Seven-Day Roguelike Challenge</a>. My entry's called <a href="https://mcneja.itch.io/lurk-leap-loot">Lurk, Leap, Loot</a>. It iterates on the stealth gameplay I've developed over previous 7DRL entries.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtiTRzy_bm2ayeEYkfnMsOCpED1VTB2cE_IE4JngXz_CFx5QmNb4Bhvq56GtnW1yBSfHFzRJrXJeTn8GIcujlZ07R_asRLHkynpCIV4hnvzghFVa9J7EfwXz-gEGZtX0VwkiqE3llT_Ml8yeD09SJGP6Zkvxf0U-tYNdCl4GM4w-JLVFzSQRBJYIK9/s1678/lurk-leap-loot-screen-1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1288" data-original-width="1678" height="493" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtiTRzy_bm2ayeEYkfnMsOCpED1VTB2cE_IE4JngXz_CFx5QmNb4Bhvq56GtnW1yBSfHFzRJrXJeTn8GIcujlZ07R_asRLHkynpCIV4hnvzghFVa9J7EfwXz-gEGZtX0VwkiqE3llT_Ml8yeD09SJGP6Zkvxf0U-tYNdCl4GM4w-JLVFzSQRBJYIK9/w640-h493/lurk-leap-loot-screen-1.png" width="640" /></a></div><br /><p>In the lead-up to the game jam I had several different game ideas from my notebook that I was developing. I came very close to doing a version of Paradroid, an old C64 game. But I changed my mind at the last minute and decided to return to stealth mechanics. When I mentioned this on the roguelikedev subreddit, <a href="https://spillz.itch.io/">Damien Moore</a> contacted me asking if I'd like to collaborate. We made this game together and it turned out much better than I would have been able to do on my own. Damien created a new tile set and did the entire audio end of things. The game has music, sound effects, and voiced dialogue! Evan Moore (Damien's son) recorded the guard voices; it adds a lot of character to the game.<br /></p><p>More importantly, he proved an invaluable design partner. One of the things he pushed for was for guards to move on predictable patrols rather than wandering semi-randomly. It took me about a day and a half to come up with a patrol route generation system, but I think it worked out pretty well.<br /></p><p>A game ideally gets the player into a state where they are absorbed in anticipating and predicting what will happen, and then correcting based on their observations of how things actually play out. Ideally not only on a moment-to-moment level but also on longer time-frames. Patrol paths serve this purpose; players can watch, plan, and then try to execute their plan. It doesn't always go as expected, which is what keeps it interesting.</p><p>The patrol path generator shuffles a list of all the room adjacency pairs, then adds each pair
if each room has zero or one edges already connected to it. This
produces long chains and sometimes loops, with the occasional room that
gets left out. To improve on this, I first chop up long chains into
pieces to get down to a target length, and then insert side trips to the
left-out rooms. The end result is that every room is on a single patrol
path. Here's an example; I've hand-drawn over the patrol routes:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinNosYRTAxH4W75dVQVZK8jGYUBUew1skiDO1lE3gbh_CRLIIYM9VfXhqENPyQYQbh8L6dEwykZcBpYtoU4tKkAufwqoPQPT7e7H4UwZQJsaejs6zuwG0tTI7AQRekJf0UcxlwuWbbNTuw96VbQNpiT88lDR-RUrXQ0Ss_Lf9R0ObVUqRMqaknNjml/s1205/patrol-paths-example.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="692" data-original-width="1205" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinNosYRTAxH4W75dVQVZK8jGYUBUew1skiDO1lE3gbh_CRLIIYM9VfXhqENPyQYQbh8L6dEwykZcBpYtoU4tKkAufwqoPQPT7e7H4UwZQJsaejs6zuwG0tTI7AQRekJf0UcxlwuWbbNTuw96VbQNpiT88lDR-RUrXQ0Ss_Lf9R0ObVUqRMqaknNjml/w640-h368/patrol-paths-example.png" width="640" /></a></div><p><br />The lower left route is a loop; the rest are lines that the guards go back and forth along. Longer routes mean a lower overall guard density; this is from an earlier level in the game so the routes are allowed to be long. At the endpoints, the algorithm looks for a point of interest in the room for the guard to stand by for a few turns. Highest priority is windows: if there are any windows, the guard will stand looking out of one. Next highest priority is sitting in a chair, then standing near loot. As a final resort the guard will attempt to stand two spaces in from the door, which gives the player the opportunity to sneak into the room from behind them. This is important for some of the tiny dead-end rooms.</p><p>The other big design challenge I set myself was to try to move from the eight-way movement of ThiefRL2 to four-way movement. <a href="https://dragonxvi.itch.io/skyrogue">Skyrogue</a> was an inspiration. Guards are still allowed to move diagonally if the space is clear on either side of the move. The player, instead, has a leap move. In my case it moves two spaces instead of one, and can go over some obstacles. The eight-way movement had given the player a speed advantage by allowing diagonal movement even if the spaces on either side were solid. This is similar to how in Pac-Man the player character can get around corners slightly more quickly than the ghosts. The leap move gives the player the advantage when moving in a straight line, which is a contrast to the corner-cutting.</p><p>Lastly, I ported in torches that can be lit or doused, from the very first ThiefRL game. I'd left it out of ThiefRL2 in the interests of simplicity, but it gives players a mechanism with a few tradeoffs. First, guards really want all the torches to be lit, so they'll interrupt their patrols to do that. This can be used to slow them down a bit if you need to do something elsewhere on their route. Standing in a lit room allows you to be seen from much farther away, so having torches unlit is good from that perspective. On the other hand, torches allow you to see which floor boards are creaky, so there's a slight reason for having them lit.<br /></p><p></p><p>This is my first game made in TypeScript. <a href="https://mcneja.itch.io/amulet-raider">Last year's 7DRL entry</a> was written in JavaScript. In the leadup to this year's jam I ported it to TypeScript and then ported a bunch of my ThiefRL2 code from the C++ and Rust versions. It mostly went smoothly. The one gigantic gotcha in TypeScript/JavaScript is that any data type beyond a boolean or number will be passed around by reference instead of by value. I used 2-dimensional coordinates extensively throughout, and more than one time accidentally ended up pointing at a coordinate stored in something when I intended to copy it. It's ironic that scripting languages like Python or JavaScript try to insulate programmers from pointers, but then hit you with this. Languages that are clearer (like Rust) or simpler (like Haskell) avoid the problem.</p><p>I also used <a href="https://parceljs.org/">Parcel.js</a> to run a server that automatically rebuilds whenever you save a source file. It worked great about 95% of the time, but whenever we did something like merge code in Git, it would break down. The fix appears to be clearing its .parcel-cache directory, and I got into the habit of doing that regularly. Feels kind of junky; you don't ever quite trust that you're seeing the version of the program that you just edited. I would make trivial changes in a place where it'd be immediately obvious if the program had updated.</p><p>We used Howler.js to play audio, although Damien did all the work of setting that up and using it. One thing we discovered while testing on various platforms is that Safari does not have built-in support for playing Ogg files. They aren't new so it's kind of annoying.</p><p>Overall I did not get anywhere close to the amount done on the fundamental game design as I would have wished. It still feels very much like the previous games in its series. On the final day I did a little bit of work to try to give the game an ending and a score, but it's very basic.</p><p>However, I'm happy with how it turned out. It's fairly polished and fun. The sound effects for player actions add a ton of great feedback; it's very satisfying to collect loot, based on the sound alone. (It's a bunch of Australian 50-cent pieces in a sock.)<br /></p>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com2tag:blogger.com,1999:blog-2403477577476951601.post-33707448359509891722022-03-12T07:20:00.002-08:002022-03-12T07:20:36.236-08:007DRL 2022: Complete<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgdqChiILpHdiF6JnPfHMbyCyBD2wH6gC75caEe0t7D3_FJexi1RxNyF-FStHJDtWVwIQj9khdSXdcXDz71kWWxN-3EtfVu8M4_EvfstTCkaIKYI-lF6nATYbKm85S2Az1lGXFjW0YS391G53ke4pnV3kMFGV2DE0657VBdh9P0eqr4YqRkHpmmN9Le=s1180" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1180" data-original-width="1151" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEgdqChiILpHdiF6JnPfHMbyCyBD2wH6gC75caEe0t7D3_FJexi1RxNyF-FStHJDtWVwIQj9khdSXdcXDz71kWWxN-3EtfVu8M4_EvfstTCkaIKYI-lF6nATYbKm85S2Az1lGXFjW0YS391G53ke4pnV3kMFGV2DE0657VBdh9P0eqr4YqRkHpmmN9Le=s320" width="312" /></a></div><br /> <p></p><p>I'm excited to share my entry for this year's <a href="https://itch.io/jam/7drl-challenge-2022">Seven-day Roguelike Challenge</a>: <a href="https://mcneja.itch.io/amulet-raider">Amulet Raider</a>. It uses Rogue's setting (dungeon, amulet, potions, etc.) and XQuest's gameplay (fast mouse-controlled action). Here's a video of it in action:</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/7QtCDPRwYbY" width="320" youtube-src-id="7QtCDPRwYbY"></iframe></div><br /><p>The game is written entirely in JavaScript using WebGL shaders. It's by far the largest JavaScript program I've ever written. The code quality is not great; I was putting things in at a furious pace. JavaScript is not too bad for small things. I found myself increasingly relying on VSCode's syntax highlighting, which tries to show unused variables and function signatures. A lot of the bugs I had were the dumb variety (misspellings, calling functions with the wrong parameters). These are the things that type systems were created to catch. Perhaps next time I will try TypeScript. The edit/test cycle was really fast for this though. It made the shader programming in particular really fun.<br /></p>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com2tag:blogger.com,1999:blog-2403477577476951601.post-73059046717867843832022-03-09T05:28:00.006-08:002022-03-09T05:47:02.994-08:002022 7DRL: Midpoint<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhcmID-Dlx8qQi3T5R8T_eQPnQ4SneuUy0C8DL7KnuWB2SiHkZyGZclkAEXRABHak4cK9SDGuhIw1FoejQnY6bxN3OsBjikG0FeJovzXTRE4sGNkGGtCF3vJ-d9EMzEh3tqBf3wW5g2zg3gMBEhed6vJYIZfG67A1HAMQUMjtiRRW1bZrFipbrx_Xf4" style="display: block; padding: 1em 0px; text-align: center;"><img alt="" border="0" data-original-height="480" data-original-width="640" src="https://blogger.googleusercontent.com/img/a/AVvXsEhcmID-Dlx8qQi3T5R8T_eQPnQ4SneuUy0C8DL7KnuWB2SiHkZyGZclkAEXRABHak4cK9SDGuhIw1FoejQnY6bxN3OsBjikG0FeJovzXTRE4sGNkGGtCF3vJ-d9EMzEh3tqBf3wW5g2zg3gMBEhed6vJYIZfG67A1HAMQUMjtiRRW1bZrFipbrx_Xf4" /></a></div>
<p>It's that time of year again! Time to wake up the blog for the annual <a href="https://itch.io/jam/7drl-challenge-2022">Seven-day Roguelike Challenge</a>. This year I tried to do some planning ahead of time but I haven't really gone with any of my plans, specifically.</p><p>My first idea was one I've had in my list for a long time, which is to try to do a Roguelike homage to the (recently Hugo-award-winning) <a href="https://www.marthawells.com/murderbot.htm">Murderbot</a> novella series by Martha Wells. Murderbot mostly does computer hacking in a fairly hand-wavy way, fighting in a slightly less hand-wavy way, and watching telenovelas in a completely hand-wavy way. So I thought it'd be interesting to try to come up with ways to see sections of the level through security cameras, alter what enemies see through those cameras, and other hackery things. Ideally I wanted the game to keep to the Roguelike ideal of slightly more than one keystroke per turn, though, and I've had trouble thinking of how that should work, exactly. Oh, and also there was a <a href="https://github.com/thebracket/secbot-2021-7drl">7DRL entry</a> last year based on Murderbot! I had a bit of fun playing it.<br /></p><p>My second idea had been to do a riff on <a href="http://www.asceai.net/meritous/">Meritous</a>, a somewhat monotonous action Roguelike with a one-button combat mechanic. I like its stripped-down mechanics but I have only been able to complete a game a couple of times. The map has thousands of nearly-identical rooms and a handful of slightly more interesting bosses.</p><p>The third idea, which I ended up going with, is to mash up <a href="https://en.wikipedia.org/wiki/Rogue_(video_game)">Rogue</a> and <a href="http://www.swallowtail.org/xquest/">XQuest</a>. (XQuest itself is based on <a href="https://en.wikipedia.org/wiki/Crystal_Quest">Crystal Quest</a>, an old Macintosh game). {X/Crystal} Quest has a novel mouse-based movement system; moving the mouse changes the player character's velocity directly. Firing is in the direction the player is moving, as a multiple of the player's speed. It can be a bit squirrelly to learn but it has a high skill ceiling. I spent countless hours playing XQuest and XQuest2 back in the day. Here's some example video of it:</p><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/g8e91kfmh6s" width="320" youtube-src-id="g8e91kfmh6s"></iframe></div><br /><p></p><p>Work's been going OK. The in-development version can be played <a href="https://mcneja.github.io/7drl-2022/">here</a> and the source is on <a href="https://github.com/mcneja/7drl-2022/">Github</a>. I'll put the final version on <a href="https://mcneja.itch.io/">Itch.io</a>. You will need a good mouse; I'll add sensitivity options before I'm
done but it's hard-coded for now. You will probably a decent video card
to play; it uses WebGL but I'm not pushing crazy amounts of data at it.
Also, Firefox seems to be really slow as compared to Chrome, Edge, or
Safari. I use Firefox for my day-to-day browsing but I must be doing
something in my games that doesn't sit quite right with it.<br /></p><p>I started from a very simple JavaScript <a href="https://mcneja.github.io/fmmweb/index.html">game</a> that I'd made to demonstrate the <a href="https://math.berkeley.edu/~sethian/2006/Explanations/fast_marching_explain.html">fast marching method</a>. So far I have a rudimentary dungeon generator and some turret enemies. For the player character I have movement, shooting, and the beginnings of melee behavior. Today's work will be developing a melee enemy and hopefully getting the melee to a point that feels right.<br /></p>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-37061053986653917352021-03-13T22:03:00.000-08:002021-03-13T22:03:26.963-08:002021 7DRL: Finished<p> <a href="https://mcneja.itch.io/disguiser-2021-7drl">Here</a> is the 7DRL submission on Itch.io. <a href="https://mcneja.github.io/disguiser/">Here</a> is the latest version on Github.io.</p><p>Long ago I spent a miserable year in graduate school. The research assistant job I had before I dropped out was in the cancer wing of the university's hospital. The radiation treatment facilities were adjacent and I'd gotten a tour of them when I started my job. It was a row of rooms with twisty entrance passages to break the lines of fire.<br /></p><p>My parents came to visit me shortly after I had dropped out. I took them to see where I had been working. It was a Sunday and the radiation wing was largely deserted. Eventually, though, we were confronted by a woman who said "I don't think you should be in here!" and threatened to summon security. I hustled on out of there, chagrined. It really drove home that I no longer belonged at the school.</p><p>This feeling of being accosted where you don't belong was what I had in mind for this year's 7DRL challenge. I played the HITMAN reboot games recently and enjoyed the disguise mechanics. My primary goals for this year were:</p><ol style="text-align: left;"><li>Produce a web-playable game</li><li>Experiment with disguises in the framework of my existing thief roguelike game</li></ol><p>Getting a web-playable game took about half the time. I was using languages, platforms, etc. that I haven't really worked with before. Working on the disguise mechanics took the other half. I don't know that I've succeeded in making a really fun disguise system yet, but there is a fair amount that went into it.</p><p>All the new tech:<br /></p><p>Rust is not bad. I'm not sure yet if it's where I want to write all my code going forward, but it isn't bad. The compiler gives good error messages, and the game seemed to perform adequately. I didn't do any profiling. I did run into one crazy problem with the compiler; it doesn't properly handle excluding library features on a per-platform basis. I asked on a forum and the nightly build has a fix for it. In the end I just targeted WebAssembly alone; I haven't got a native target. My framework is simple enough that I expect I could write a Win32 version of it fairly easily in Rust.</p><p>WebAssembly still feels half-baked. I had trouble with wasm-bindgen versioning, so I ended up just wiring up the imports and exports myself. I stuck to simple integral data types in the function parameters and didn't try to do any memory sharing.<br /></p><p>Javascript is also not bad. It always seems to work pretty much the way I expect it to. I only wrote around 450 lines of Javascript for this project.<br /></p><p>WebGL is very similar to OpenGL. It works okay. I'm not a huge fan of the OpenGL way of doing things, but I am familiar with it so that helped.</p><p>Github.io was new to me. It turns out to be a really great way to set up a static website. Just point a Git repo at it and away you go. I'm told you can set up Github actions to automatically build the site when a repo over on Github changes. I'll probably try to set that up; I ended up manually doing that step and it was getting annoying.</p><p>The new game design elements:</p><p>Since the player's thief can look like the enemies I added a little overhead caret to mark him. I added bump-to-interact functionality (for changing clothes) which wasn't in the previous game. (It was in the first ThiefRL so I referred back to that.)<br /></p><p>I created two different colors of guards, in order to have two different disguises (plus your default outfit). I set it up so one class of people is not allowed in the private rooms of the house; if the private-wing denizens see that outfit they'll attack. The public area is patrolled by both the public and the private guards. I'm not thrilled with how this turned out; bifurcating these already-small levels results in more un-patrolled space, since guards try not to go into a room where they will have to go back out via the same door. I have thought about changing the patrolling behavior to allow for going into dead ends; maybe they would stop and stand for a bit. Haven't gotten to that yet though.</p><p>Guard awareness got some adjustments. Since you are in disguise they can't just attack you, which means you can be doing things in their view like picking up loot or climbing on tables and that looks weird. When the player does anything "suspicious" it sets a flag for the next guard update. If they see the player, and the player is being "suspicious" then they escalate. In the old thief game if you got spotted you could duck into a bush or under a table in full view of the guard and hide successfully. This is no longer possible. I felt like I needed to nerf hiding somewhat to make the disguises serve more of a purpose.</p><p>Once I hit on the idea that disguises would effectively cut guards' maximum distance they can see you at down to one or two squares it was pretty fun to try to maneuver around them in the rooms to avoid being too close. Right at the end I realized that the inner-room disguise was strictly better than the outer-room disguise, which was not very fun. I ended up making it so that people who match the disguise are not as suspicious as people who don't. It doesn't make a lot of sense logically, but it means you want to be wearing the outfit that matches the area you're in (and the people who are in it) which gives a reason to switch back and forth. It's still not much of a reason.<br /></p><p>I experimented with having special "boss" guards who could see through disguises from a distance. This was an idea borrowed from Hitman. It complicated things too much, I felt, so I removed it.</p><p>For a while I disallowed hiding in bushes or under tables (or underwater) while in disguise. This is potentially interesting; it gives much more of a mode shift between running around in the thief outfit and wearing a disguise. It means the thief outfit has its own perks and isn't strictly inferior to the disguises. I took it out because I felt like it was complicating the rules. It also made for some really difficult maneuvering sometimes in the current levels. It's worth further consideration though.</p><p>I made the one-way windows so the player can see through them both ways. I'd tried this out on the original thief game and rejected it because I didn't want players to feel like they had to run around the house to peek in all the windows and uncover as much of the map as possible before going in. However I think this is a really positive change. One of my big design tenets is that you should have areas you can see but not get to easily and this serves that goal handily. Often you'll go past a window and see a disguise in the room on the other side and it gives you a goal to work toward.</p><p>Placing the disguises so it will be satisfying to find them is something I haven't really fully worked out. Right now they're placed toward the back of their respective zones, so you will have to move through at least some of the zone without the benefit of its disguise. I really would like there to be more of a sense of accomplishing something when you get to a disguise, though.</p><p>Overall it was not my strongest game but it should hopefully be at least somewhat fun. Disguises make things easier, and they give you more detailed interactions with guards. Both of these present challenges to keeping the game fun. I think there are lots more things that could be done with disguises though. A couple ideas I wanted to try:</p><ul style="text-align: left;"><li>Identify a particular guard who is a secret ally. To do this you need to see the faces of guards from close range; they'll get marked off as they're identified as either your ally or not.</li><li>Confront a particular person when none of the other guards are nearby.</li><li>Disguises that provide environmental protection (from cold, or dust storms, say)</li><li>Ways to influence the patrolling behaviors of guards. Could be by activating "activity stations" that will occupy a guard for a time (cleaning up a mess or something). Or it could be by opening and closing doors, and guards would assume that closed rooms (that aren't on the main path) don't have to be checked but open rooms should be checked.</li><li>Add stationary guards; "bouncers" to make it much harder to get into parts of a level without the right disguise.<br /></li></ul>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-21048156293500150632021-03-11T22:02:00.001-08:002021-03-11T22:02:27.757-08:002021 7DRL: Continued<p>The work-in-progress is playable <a href="https://mcneja.github.io/disguiser/">here</a>. It is basically the thief game with a disguise added. (The port of the old game, for comparison, is playable from <a href="https://mcneja.github.io">here</a>.)</p><p>If you find the outfit (generally in a dead-end room in the tiled part of the house) you can swap clothes. Guards don't see through the disguise unless you are very close. If they are suspicious you can move away and keep things from escalating.</p><p>I tried having one guard who was specially marked and could see through the disguise but that was not adding much. I'm trying making it so when wearing the disguise you can't hide under tables or in bushes. That seems promising. I'll probably also make it so you can't steal things while seen without raising suspicion.</p><p>I've also managed to fix a few bugs along the way. The most long-standing one, dating back to the original game, was that guards who couldn't move would spin in place. This was just due to how it updated their facing when the movement vector was zero.</p><p>I'm currently working on having three different sets of people, with distinct disguises that work for each. It will be interesting to see if this adds. The people will occupy different (possibly overlapping) parts of the house and will only see through the disguise that matches their own outfit. This might be too easy; I don't know.<br /></p>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-47761657937495917152021-03-09T10:24:00.002-08:002021-03-09T10:27:22.749-08:002021 7DRL: Begin<p>I'm participating in this year's <a href="https://7drl.com/">Seven-day Roguelike Challenge</a> after a couple of years away. It always seems like a bad time in terms of whatever is going on in my life, but participating in previous years has been really rewarding for me personally.</p><p>This year I am starting from my 2016 7DRL entry, <a href="https://mcneja.itch.io/thiefrl2-2016-7drl">ThiefRL2</a>. It was a simple game of stealth. My main goals are to make something playable on the web, and to try to implement a disguise mechanic along the lines of the Hitman games.</p><p>For starters I have ported ThiefRL2 to Rust+Javascript, using WebAssembly. The port is mostly complete and playable <a href="https://mcneja.github.io/">here</a>. I'll probably be rearranging that website as I figure out what I'm doing. The source code is on <a href="https://github.com/mcneja/thiefrl2">Github</a>.<br /></p><p>The main gameplay feature that isn't yet implemented in this port is that the guards don't hear each other shouting. Other features that aren't yet implemented are viewport resizing and scaling.</p><p>Otherwise it seems to work pretty well! I had originally done the port to Rust using a library called <a href="https://github.com/ryanisaacg/quicksilver">Quicksilver</a>, but performance was not good and the library's creator ended up dropping it. I asked around on the roguelikedev reddit and somebody mentioned <a href="https://tryjumping.com/blog/2017/12/25/dose-response-ported-to-webassembly/">Dose Response</a>, a Roguelike that <a href="https://sedovic.cz/">Tomas Sedovic</a> had created and then ported to Webassembly. The blog post linked above was really helpful for me. He started from an ultra-simple <a href="https://github.com/richardanaya/rust-roguelike">example</a> by Richard Anaya. I started from the same point and was able to bootstrap my way up to a working framework. Fortunately my needs were really simple.</p><p>I ended up using WebGL for the rendering, which I'd never used before. WebGL hews very closely to OpenGL, for better and worse; in my case since I was already familiar with OpenGL it made things pretty easy to put together. Dose Response was using a memory buffer exposed from the WebAssembly module for collecting the tiles to be rendered. That is probably a faster method than what I'm doing, which is to collect the geometry on the Javascript side. As a result there's one call from the WebAssembly to Javascript per rendered quad. In practice that seems to work fine.</p><p>The current interface between the Javascript and the Rust is very narrow. Javascript calls a function to start the game, passing in a 64-bit random seed. It then calls a function each time a key is pressed, and another function when it wants the canvas drawn. Rust, in turn, calls a function for rendering an untextured quad; another function for rendering a textured quad; and a function to request that the canvas be redrawn. That's it!</p><p>The Javascript loads up the textures ahead of launching the webassembly; the Rust code just refers to them by index. The WebAssembly interface only handles basic integral and floating-point types; I had some issues trying to get the fancier wasm-bindgen stuff to work so I skipped that.<br /></p>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-62959504804998872052018-11-11T21:18:00.000-08:002018-11-12T07:28:26.167-08:00Interior-point constrained nonlinear optimizationHere's a boring-looking plot of something I've finally made some progress on after years of trying to learn it:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0Kn8jWrF6qjjq5PgDEoOMlaSzLUgIEH0DIgnUL1okQ8QmTHVAcL7nOzNIvQ5vb9jN_CR6SIRQ7FuP0AZC0GdQUZSr8s_ieRL6Je1UICwkf5zFUqkkyQhbzBlRKa41qHv8cpn4qwkfw6M/s1600/dual_cubic_trajectory_01.gif" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0Kn8jWrF6qjjq5PgDEoOMlaSzLUgIEH0DIgnUL1okQ8QmTHVAcL7nOzNIvQ5vb9jN_CR6SIRQ7FuP0AZC0GdQUZSr8s_ieRL6Je1UICwkf5zFUqkkyQhbzBlRKa41qHv8cpn4qwkfw6M/s1600/dual_cubic_trajectory_01.gif" data-original-width="320" data-original-height="320" /></a><br />
<br />
This is constrained nonlinear optimization on a very tiny problem. It's a trajectory (in one spatial dimension) composed of two cubic segments (colored yellow and blue). The top plot is displacement over time, and the bottom plot is acceleration over time.<br />
<br />
The objective is to minimize the total time of the trajectory. In these animated plots the total time is decreasing as the animation proceeds, but the plot is scaled to keep the same width so it's a bit misleading.<br />
<br />
The cubics have fixed endpoint positions; the position at the boundary between the two cubic segments is also fixed. In this example it is closer to the left end of the curve, so the yellow cubic has a smaller displacement than the blue cubic. The velocity at the start and the end is fixed at zero, while the velocity at the boundary between the cubics is a free variable. The time durations of the two segments are the other two free variables.<br />
<br />
The problem is constrained by limiting the maximum/minimum allowed acceleration, which is represented by the top and bottom extents of the bottom plot. Because cubics have their most extreme acceleration at their endpoints the constraints are applied there. There are eight potential acceleration constraints, because each cubic has two endpoints, and each endpoint has a lower bound and an upper bound on its acceleration.<br />
<br />
If the midpoint between the segments is equidistant from the endpoints (as in the animated image below), then the optimum trajectory is to accelerate at maximum for the duration of the yellow segment, and then decelerate at maximum for an equal duration in the blue segment. This is a trajectory made of two parabolas, due to the constant accelerations:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQY8_UCowByOQ4_5HToiw6uPieUqAnd30lEyZx9siRUye2cRXrr5xTvsgMgEZyzQxsFHhAvfoj9BNoDocqTc_iv1fa7ZalHfdX15JziAhh2Z_DQF2OJSYT3V7vy0cR1yRGXqQjg4s9E3A/s1600/dual_cubic_trajectory_02.gif" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQY8_UCowByOQ4_5HToiw6uPieUqAnd30lEyZx9siRUye2cRXrr5xTvsgMgEZyzQxsFHhAvfoj9BNoDocqTc_iv1fa7ZalHfdX15JziAhh2Z_DQF2OJSYT3V7vy0cR1yRGXqQjg4s9E3A/s1600/dual_cubic_trajectory_02.gif" data-original-width="320" data-original-height="320" /></a><br />
<br />
Because the first plot has an offset midpoint, only the shorter-duration segment can be at maximum acceleration; the blue segment needs to have a varying deceleration so it can hit the target position and velocity simultaneously. Note that if we were to break up the trajectory into more segments we could get shorter overall travel time. Here's another animation of the problem being solved, with the midpoint displacement shifted the opposite direction:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyEYZvTyJ2viyK9XpfOjTX7OJbTXIb61CtgjgGc7AuqNbOyU3_fReZMYBIC15esLwHBuTP10LGc-Rz6V9tTm0UZ01FpPV5SCsUipsL5jghlTZObpZZKbztyxaoHUe3Fv8LdHMgD7NJCAU/s1600/dual_cubic_trajectory_03.gif" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyEYZvTyJ2viyK9XpfOjTX7OJbTXIb61CtgjgGc7AuqNbOyU3_fReZMYBIC15esLwHBuTP10LGc-Rz6V9tTm0UZ01FpPV5SCsUipsL5jghlTZObpZZKbztyxaoHUe3Fv8LdHMgD7NJCAU/s1600/dual_cubic_trajectory_03.gif" data-original-width="320" data-original-height="320" /></a><br />
<br />
Solving constrained problems like this can be done in a couple of broad ways, both of which involve taking a guess at a solution and iteratively making it better via a series of steps. In all of the examples shown my initial guess is to have the midpoint velocity be zero and the segment durations be long enough that the accelerations are within limits.<br />
<br />
<em>Active-set methods</em> try to keep track of which constraints are active and move in a way that improves the objective score without violating the active constraints. As the solution is iteratively improved, the set of active constraints may change. You could think of it as sliding downward in the objective direction along the boundary of the constrained area, bumping along from surface to surface of the different constraints.<br />
<br />
<em>Interior-point methods</em>, in contrast, keep all of the constraints active all the time, and instead adjust their strengths until the solution gets very close to the constraint boundary. They are kind of like landing a rocket on the surface; the solutions start out in the middle and settle down toward the constraint surface. The advantage of interior-point methods is that the structure of the problem stays the same as the solution is improved.<br />
<br />
The animated solutions here are interior-point movement. There is a “slack” variable that controls how far from the constraint surface we're aiming to be (roughly). In the animations shown I'm controlling it by hand. I do a few iterations at a given level and when the solution looks like it's converging I reduce the slack by a factor of ten.<br />
<br />
Both of these methods make use of first and second derivatives of the constraints and objective to come up with a likely direction to move. It involves building and solving a system of linear equations; the size corresponds to the number of variables and constraints in the problem. (It's called the Karush-Kuhn-Tucker system; there are lots of names in this area.) This gives a movement direction and expected ideal distance, which then needs to be trimmed down (backtracking) to avoid violating constraints or making things worse in any other ways.<br />
<br />
References:<br />
<ul><li><a href="https://epubs.siam.org/doi/pdf/10.1137/16M1062569">An Introduction to Trajectory Optimization: How to Do Your Own Direct Collocation</a>, by Matthew Kelly, is a good introduction to trajectory optimization.</li>
<li><a href="https://epubs.siam.org/doi/book/10.1137/1.9780898718577">Practical Methods for Optimal Control and Estimation Using Nonlinear Programming</a>, by John Betts, covers active-set methods.</li>
<li><a href="http://stanford.edu/~boyd/cvxbook/">Convex Optimization</a>, by Stephen Boyd and Lieven Vandenberghe, covers interior-point methods (in its last chapter).</li>
<li><a href="https://www.springer.com/us/book/9780387303031">Numerical Optimization</a>, by Jorge Nocedal and Stephen Wright, covers interior-point methods in its last chapter as well.</li>
</ul>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-15220687630676360022018-04-25T17:19:00.000-07:002018-04-25T17:19:36.759-07:00Pico-8 Thrust-alike WIPThis is what a mid-life crisis looks like for a game developer in my age bracket:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVzRkQg02kSoWx5GGLGnohv-kQYXRTOeOZlHO2D_3NAynT0OuQaWIQBQJPoAAIFazYWE_AaDEyEzCxt3PGQaaYCD-98betn9ms_SM380XqGSvMHZXHQ5BLB11w307qi0pHcAfZv7XZVYc/s1600/thrust_1.gif" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVzRkQg02kSoWx5GGLGnohv-kQYXRTOeOZlHO2D_3NAynT0OuQaWIQBQJPoAAIFazYWE_AaDEyEzCxt3PGQaaYCD-98betn9ms_SM380XqGSvMHZXHQ5BLB11w307qi0pHcAfZv7XZVYc/s1600/thrust_1.gif" data-original-width="256" data-original-height="256" /></a><br />
<br />
Most men in their 40s buy something they were into in their teens. I tell my wife she's lucky I wasn't into cars or airplanes or anything like that. The Pico-8 fantasy console costs $15 or so. I've been adapting my rocket lander game to it.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPil5kkLWPEtd6HIi2ZfyzD4kH41dIj_peZRAF3hhDtam0M_aA-8XHcCoTkWL-dG6vmBL6Tw1znPQ3EdrJQFZuHgNsKoZ_t1XETX71Yss5P8GR353LSFuo1ACdftu6mdgZfu8OLtHt4ew/s1600/thrust_2.gif" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPil5kkLWPEtd6HIi2ZfyzD4kH41dIj_peZRAF3hhDtam0M_aA-8XHcCoTkWL-dG6vmBL6Tw1znPQ3EdrJQFZuHgNsKoZ_t1XETX71Yss5P8GR353LSFuo1ACdftu6mdgZfu8OLtHt4ew/s1600/thrust_2.gif" data-original-width="256" data-original-height="256" /></a><br />
<br />
The controls are changed up quite a bit to make the game play faster. It still has a braking line, though.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-76271206092424736052018-04-12T05:54:00.002-07:002018-04-12T05:54:53.256-07:00Dijkstra fill in PythonThere was a thread on the <a href="https://www.reddit.com/r/roguelikedev/">Roguelike development Reddit</a> with some quite alarming versions of <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra's algorithm</a> for computing graph distances, so I threw one together to contribute.<br />
<br />
<a href="https://gist.github.com/mcneja/e2d0c3090ade6b718723dddbbfd3d387">Here it is.</a><br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-46299531837721902362018-04-03T06:55:00.001-07:002018-04-03T06:55:43.021-07:00Pico-8 Orrery<a href="https://www.lexaloffle.com/bbs/?tid=31077">Super-simple solar system</a>, implemented on the <a href="https://www.lexaloffle.com/pico-8.php">Pico-8 retro fantasy console</a>. Left/right to adjust time, up/down to adjust zoom.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLkDWbTFRb3PrpsypEi0F9ue5B98ol9_eNJYXv1zJVUuljVIipIKwvZIa_v80noIm4EiWj8NRs11xVum9gLVU9LYyovlQjJOoKb9aKhrTCHPFg4r6_w4D_ZgvDMCQDfZMnudj1QxMCTFo/s1600/orrery_0.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLkDWbTFRb3PrpsypEi0F9ue5B98ol9_eNJYXv1zJVUuljVIipIKwvZIa_v80noIm4EiWj8NRs11xVum9gLVU9LYyovlQjJOoKb9aKhrTCHPFg4r6_w4D_ZgvDMCQDfZMnudj1QxMCTFo/s1600/orrery_0.gif" data-original-width="256" data-original-height="256" /></a></div><br />
Here's the "cartridge" which is a PNG with the whole program embedded inside it:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://www.lexaloffle.com/bbs/cposts/5/51245.p8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4j24bYqG99Ce5RuZmdX7MH2TGmN2uzjtnn8g_ik3_kSebaYLHNOjlzImxOM1poqrW8sMUjkd4F799Hntrsu81H6znPQut17IuBXLCX4XtON5m_ueR5oORkvdwM0SZZsLysEmEcCgGyNM/s1600/orrery.p8.png" data-original-width="160" data-original-height="205" /></a></div><br />
The Pico-8 has 16.16 fixed-point arithmetic, which makes working on things that span a wide range of scales challenging.James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-80109284799291129412018-03-10T18:14:00.001-08:002018-03-10T18:14:40.049-08:002018 7DRL: Sword HordeThe game's up for download now over at <a href="https://itch.io/">Itch.io</a>: <a href="https://mcneja.itch.io/sword-horde">https://mcneja.itch.io/sword-horde</a><br />
<br />
I marked it as an Incomplete in the 7DRL challenge because it is very short and doesn't feel much like a Roguelike. The closest thing to it is probably <a href="http://store.steampowered.com/app/506870/Unexplored/">Unexplored</a>, an action Roguelike with a similar top-down view. Unexplored has some nice dungeon generation techniques. I felt like its combat was underwhelming, though.<br />
<br />
<em>Sword Horde</em> was an attempt to work on group movement and formations. I didn't get very far on that because I needed a core combat mechanic, which is something I'd been putting off for a while. It was good to spend some focused time on developing the core though. With some tuning I feel like this could be a workable base for a bigger game.<br />
<br />
I had talked with a friend about Dynasty Warriors since that is the main franchise I can think of that handles a hero versus an army. I have played a little bit of Dynasty Warriors over the years but probably not more than a couple of hours. Consequently I was working mainly from my own imagination and from previous combat prototypes that I've made.<br />
<br />
<hr/><br />
Some of the ideas that were on the list and didn't make it in:<br />
<br />
<strong>Enemy types.</strong> The obvious things: a boss who's bigger, slower, hits harder, has more hit points. A guy with a shield on one side. Projectile launching guys.<br />
<br />
<strong>Formations.</strong> I was thinking the guys would be in groups of three or four, with a marked leader. Any group with a leader would attack in a pattern. If you kill the leader the guys attack in a less coordinated fashion until they can hook up with another leader. Whether patterned or chaotic attacks would be harder to handle is unclear; ideally the former though.<br />
<br />
<strong>Combos.</strong> This is the core of Dynasty Warriors and I did not get this in at all. It would have been relatively easy to do a combo meter and have some area-of-effect attacks that you can discharge when the meter fills to certain points.<br />
<br />
<hr/><br />
One of the things that has bothered me about these kinds of games is that the player has free run of the whole battlefield. There's very little feeling of enemies denying access to spaces. My initial experiments were aimed at trying to produce a well-defined territorial boundary that would move as you fought the battle. In the end I scrapped it and let the allies run around on the battlefield with you.<br />
<br />
I suppose one of the problems with having a well-defined front is that it reduces the dimensionality of the encounter space. In a 2D-surface-based game you have a line where the action is occurring. With ranged weapons that might be a little less of a hard line, but it's still a smaller space for action, and at any given time you're not using the whole space. I think the idea of a battle front is still useful, though, to try to guide the player toward the action.<br />
<br />
Figuring out how to make armies look like they're fighting but still keep the player as the driver of the action is an interesting challenge. In the little bit of Dynasty Warriors I've played it felt like they were lazy on this front. Guys are mostly just standing around when I come upon them.<br />
<br />
Combat targeting is a hard problem to solve. I have some ideas of improvements that could be made but it's hard to know what will work until you try it. The characters kind of flip themselves 180 degrees if they think it will help them swing at a better target.<br />
<br />
Combat flow is hard, too. <em>Sword Horde</em> makes use of <a href="https://en.wikipedia.org/wiki/Gabriel_graph">Gabriel graph</a> structure to decide who is eligible to do a running-charge attack at the player. Only people who have an unobstructed sphere of space between them and the player are allowed to attack. Once they have started charging they keep charging, which can mean they are trying to find their way through crowds to get to you. But the initial decision is based on clearance.<br />
<br />
The biggest problem, I feel, is that it's hard to predictably avoid getting hit accidentally while swinging at someone. I did a lot of tuning—adjusting elasticity and friction, mass and moments, sword lengths, attack timings, attack steering directions, stun durations—to try to come up with something that would reliably separate the characters after a hit. It's not really there yet. It seems like maybe it's close. All of the afore-mentioned parameters interact with each other, though. I spent a ton of time instrumenting and testing the charge attack.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY2spJFI728wuA2Ryvwa0kyQBRQjsTBQgdsAe1GueQA_zn-wJQ4HbjKueW16be1fgyVeQfVCUi5qcQPtOy-96KMMtOqdjLc57kaItyYKZGE6n3Po3tqPwo_d3FTZDC0AWTAKvFKMHMy1o/s1600/dynasty_1.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY2spJFI728wuA2Ryvwa0kyQBRQjsTBQgdsAe1GueQA_zn-wJQ4HbjKueW16be1fgyVeQfVCUi5qcQPtOy-96KMMtOqdjLc57kaItyYKZGE6n3Po3tqPwo_d3FTZDC0AWTAKvFKMHMy1o/s1600/dynasty_1.png" data-original-width="286" data-original-height="246" /></a><br />
<br />
You can see some of the thinking in the debug display above: the orange guy is moving toward the pink disc which is offset to the left side of the yellow player (because orange is planning to make a counter-clockwise swing). The player's not moving, so its predicted position (the tiny pink disc) is centered in the yellow disc. The orange guy is predicting that based on where he wants to be and how fast the distance is currently closing, he should launch his attack when the gray disc touches the yellow player disc. If the player were to lunge toward the orange guy the gray disc would expand accordingly, triggering the attack earlier.James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com1tag:blogger.com,1999:blog-2403477577476951601.post-69088841070156194072018-03-10T15:12:00.000-08:002018-03-10T15:12:47.823-08:002018 7DRL: Day 7<iframe width="560" height="315" src="https://www.youtube.com/embed/7PgF-rvJGNI" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe><br />
<br />
Tidying things up for release. Today's work so far:<br />
<br />
<ul><li>Give the player a bit bigger of a sword than the rest</li>
<li>Tune combat flow</li>
<li>Ditch the territory and let allies run around as a pack and “help” you</li>
<li>Add a very simple level progression and a screen fade between levels</li>
</ul><br />
I think it will probably be called <em>Sword Horde</em>.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-30000569256904216972018-03-09T21:41:00.000-08:002018-03-09T21:41:43.235-08:002018 7DRL: Day 6<iframe width="560" height="315" src="https://www.youtube.com/embed/Y6aZqrIaDFk" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe><br />
<br />
It ain't looking great. I've got the thirty seconds of fun (as <a href="https://www.engadget.com/2011/07/14/half-minute-halo-an-interview-with-jaime-griesemer/">Jaime Griesemer said once</a> about Halo) but that's about it. There is still a fair amount of tuning to do on that thirty seconds, too.<br />
<br />
Today's work:<br />
<br />
<ul><li>Link statically to the C runtime library, so I don't need to have people install the DLL</li>
<li>Fool around with an enemy territory mechanic, with friendly soldiers and enemy soldiers marshaling on either sides of the front</li>
<li>Simplify the debris system</li>
<li>Add a player health meter</li>
<li>Tune the runnning-charge enemy attack</li>
</ul><br />
As part of doing the health meter I ended up learning about OpenGL scissoring, so I could ensure that if the window was resized you wouldn't be able to see outside the play area. I'm using the area outside to spawn in enemies now so I want them to move in across the edge.<br />
<br />
There is still a lot of tuning and bug fixing on the core combat feel, without going into new features like a boss or combo attacks. The game really needs things like the latter to give the player interesting things over a longer time scale. I also don't have any text rendering (or texturing) capabilities right now. So the game's very bare-bones.<br />
<br />
The territory was kind of a waste of time. I'd thought perhaps it could help serve as a place for the player to retreat to for a breather, or could give a medium-term goal of pushing the battle front to the right. But it doesn't really add anything in its current form.<br />
<br />
I'll put the game up on Itch.io at the end of the day tomorrow for anyone who wants to try it out. I'm not sure if I'll enter it in the Roguelike challenge for judging; it really isn't a Roguelike in any meaningful sense. At least I've gotten a chance to work on some things I've wanted to flesh out for a while, and it forms a good basis for further experiments.James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-45986077083279565322018-03-08T17:37:00.000-08:002018-03-08T17:37:09.350-08:002018 7DRL: Day 5<iframe width="560" height="315" src="https://www.youtube.com/embed/88bzOqEl5Kw" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe><br />
<br />
Getting some basic combat in, finally. This is my daughter playing the game. It still needs tuning and so forth.<br />
<br />
The green zone is friendly territory but it's not doing anything in this video.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-18403444559596342162018-03-07T21:17:00.000-08:002018-03-07T21:17:37.660-08:002018 7DRL: Day4<iframe width="560" height="315" src="https://www.youtube.com/embed/FQ23UVJXVUY" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe><br />
<br />
It's looking increasingly unlikely that I'll have anything even remotely resembling a Roguelike by the end of this week. On the plus side I've got some cool crowd motion.<br />
<br />
This morning was spent working on the enemy steering behavior so they would behave better in groups. It's all a bunch of damped spring type things that generate forces on the enemies. There is a force toward/away from the target; a much smaller lateral force to bring orbiting to a halt; and forces to repel enemies from each other. The neighbor repulsion force never has any component pointing toward the target, though. This keeps large groups from compressing in on the target, and reflects how people avoid each other; they mostly only pay attention to the people in front of them. Finally, the desired separation distance between neighbors is a function of distance from the target. This lets groups move close together to approach the target and then spread out when they reach combat range.<br />
<br />
The afternoon was spent trying to improve the player control scheme, with only minor success. I tried a couple of schemes. One involved “dragging” the sword like a water-skier behind a boat. Another went for simple dual-stick control: one stick to move and another to swing the sword. I've always thought about trying this, so I'm glad I did, but it really doesn't work. It takes too long to move the right stick for the speed of gameplay I'm targeting, especially if you have to swing it through an arc.<br />
<br />
In the end I settled on a couple of refinements to the prior scheme, which involves auto-targeting the nearest enemy and then swinging the sword into a forehand or backhand stance relative to that target. I've got some adjustments to help minimize rotation when switching targets; it will switch from a forehand stance to a backhand and vice versa.<br />
<br />
Tomorrow I will work on enemy windups and attacks. With luck I'll have a simple combat game by the end. Maybe with a boss enemy who is bigger, more dangerous, etc.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-13781984956390093922018-03-06T20:57:00.002-08:002018-03-06T20:57:10.535-08:007DRL 2018: Day 3<iframe width="560" height="315" src="https://www.youtube.com/embed/sblOVVd4N-I" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe><br />
<br />
I ended up pushing through and keeping the Chipmunk physics engine in place. I'm glad I did. Once I'd managed to get back to where I had been in terms of the movement feel I was able to quickly get the sword contact working, which would have been quite a bit more work to do myself.<br />
<br />
It took a couple of tries to figure out the best way to handle movement. The Chipmunk forums suggest tying the main physics body to a kinematic body via constraints, and then setting target velocities on the kinematic body. I found it was much easier to just use forces and torques. The things I'm doing aren't stiff enough to require anything more complicated. I ended up sub-stepping the physics sim anyway, to enable better sword collisions. It's running at 240 Hz right now. We'll see whether that holds up as I add more people.<br />
<br />
I'm still behind where I wanted to be. It's not technically a game yet because you can't fail. It's starting to be a bit of a fun toy, though.<br />
<br />
Tomorrow I'm going to turn this into a real game. The enemies will try to fight back. There will be more than one, which means I have to revisit the player control scheme. Right now the player character orients toward the closest enemy. Pressing the button swings the sword between forehand and backhand stances, but with the re-orientation to face new enemies that can do some weird things. It also doesn't really say what to do when there are no enemies around.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-29516434546637062622018-03-05T20:26:00.001-08:002018-03-05T20:26:43.733-08:007DRL 2018: Day 2It's been a dispiriting day.<br />
<br />
My goal has been to start with basic movement and one-on-one combat and expand outward from there. By the end of Sunday I had a decent-feeling movement and sword-swinging action. I didn't have any collision between swords and people yet, though. The thought of doing that myself was somewhat daunting so I decided to bite the bullet and switch over to a 2D physics engine. I've used Chipmunk in the past so I went with that.<br />
<br />
What followed was the usual wrestling with Git to get the project set up. Eventually I did, and converted things over. But I haven't been able to recreate the feel of what I had. In particular, the AI movement is really loose now.<br />
<br />
I think it may be quicker ultimately to go back to doing things myself, implementing sword collision myself. I'm weighing it. I need to get on to group movement patterns and challenge gameplay.James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-81962625450972236282018-03-04T09:43:00.000-08:002018-03-04T09:43:15.909-08:007DRL 2018: BeginTap, tap. Is this thing on?<br />
<br />
It's time to reanimate the blog for the annual <a href="https://itch.io/jam/7drl-challenge-2018">Seven-day Roguelike Challenge</a>. I've participated the last three years; you can find those games on <a href="https://mcneja.itch.io/">Itch.io</a>.<br />
<br />
The 7DRL is always a high point of the year for me. I'm a professional big-budget game developer, and those types of games can take a long time to make. The last one I shipped came out in August 2014. It's refreshing to push a game all the way through to release on a regular basis. In addition I've helped out a bit with 7DRL judging, and it's really energizing to see the creativity everyone puts into their games.<br />
<br />
This year I'm intending to make a game along the lines of <a href="https://en.wikipedia.org/wiki/Dynasty_Warriors">Dynasty Warriors</a>, albeit with very crude 2D graphics. Also I am not a Dynasty Warriors player, so I'm working mainly from second-hand descriptions. It should be great! If you're unfamiliar with the franchise, it's about a super-hero with a sword going up against vast armies of soldiers. The main franchise is set in the Three Kingdoms era of Chinese history; they've done spin-offs into European history, Gundam, Zelda, Dragon Warrior, other anime, etc. etc. It's a prolific line of games.<br />
<br />
So far I have a simple framework set up on top of <a href="http://www.glfw.org/">GLFW</a>; it looks something like this:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSq1FJtbGS8q4uWJ_TalB808JF_qc4iVQdR947mZ1JZMGVFk3hSQpjYSOkuWbf_Uypv9u0h9n36CDMoAOtsuNfcI2YWGFGYSNaNKwwhHvoyT5cKFCjJXZ6hjyg_U8O7CGqTyH1LdbjlbY/s1600/dynasty_0.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSq1FJtbGS8q4uWJ_TalB808JF_qc4iVQdR947mZ1JZMGVFk3hSQpjYSOkuWbf_Uypv9u0h9n36CDMoAOtsuNfcI2YWGFGYSNaNKwwhHvoyT5cKFCjJXZ6hjyg_U8O7CGqTyH1LdbjlbY/s1600/dynasty_0.png" data-original-width="512" data-original-height="512" /></a><br />
<br />
The yellow circle is the player and the pinkish circles are enemies. You can move around with a game controller and the enemies move toward you.<br />
<br />
Today's goal is to work out an acceptable one-on-one combat mechanic.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-74419162082479294062018-03-04T09:19:00.001-08:002018-03-04T09:19:50.708-08:00Large-Tile ThiefRL2I'm starting the 2018 7DRL but I had a little bit of time before my official start so I added a feature request to <a href="https://mcneja.itch.io/thiefrl2-2016-7drl">ThiefRL 2</a>. Pressing the number keys 1-4 will adjust the zoom level for the main tile display. This may help when playing the game on very large monitors.James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-41272083840078830602018-01-02T12:43:00.001-08:002018-01-02T12:43:20.633-08:00Slight update to ThiefRL2I had a little bit of time over the holidays so I fixed a couple of bugs in <a href="https://mcneja.itch.io/thiefrl2-2016-7drl">ThiefRL 2</a> that show up in rare circumstances.<br />
<br />
When a guard was moving to the player's last known position, if the player moved into their path they'd move on top of the player. This has been fixed.<br />
<br />
When there were windows adjacent to both sides of the corner of a room, the corner would not be visible from that room. I kind of hacked in the one-way visibility for the windows and it had some unintended side effects. I completely overhauled the visibility portal system which was incredibly boring but it now supports one-way portals, making the hacks unnecessary.<br />
<br />
Guards now turn to face noises, which makes noises more risky than they were. Previously you pretty much had to just not make two noises in a row and you were fine.<br />
<br />
Finally, I experimented with having guys face in the direction of their intended next move, instead of facing the direction of their last move. It looked weird though so I left it out.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-48954424174403625352017-08-27T19:45:00.001-07:002017-08-27T19:45:18.224-07:00Fast Marching Method pursuit<iframe allowfullscreen="" frameborder="0" height="344" src="https://www.youtube.com/embed/vZdHmivxB-I" width="459"></iframe><br />
<br />
I've been experimenting to learn more about the fast marching method, which is a really nice way of generating distance fields that take into account cost fields.<br />
<br />
First, FMM is used to compute a signed distance field to the obstacles (the dark gray boxes). This distance field is the basis for a cost field, which is then used by FMM for computing distance from the mouse cursor. The cost field smooths the paths around corners, which makes it easier for groups to avoid getting snagged.<br />
<br />
The red shading represents the cost function, while the contour plot represents the cost-influenced distance field to the mouse cursor. The orange dots move downhill on this field to approach it.<br />
<br />
I think this is roughly similar to the "FM2" method outlined by Alberto Valero-Gomez et al. My cost-from-obstacle-distance function is totally ad hoc though. I still need to dig up the real math for that.<br />
<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-30350286532150325442017-03-12T13:08:00.000-07:002017-03-12T13:08:22.874-07:007DRL 2017: Development build historyFor reference, here are all the versions of the game through the week that I released to testers:<br />
<br />
<ul><li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-07.zip">Tuesday</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-08.zip">Wednesday</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-09.zip">Thursday #1</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-09-2.zip">Thursday #2</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-10.zip">Friday</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-11-1.zip">Saturday #1</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-11-2.zip">Saturday #2</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-11-3.zip">Saturday #3</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/DriveRL-2017-03-11-4.zip">Saturday #4</a></li>
<li><a href="https://s3.amazonaws.com/james-mcneill-scratch-area/UndeathAndTaxis-2017-03-11.zip">Saturday (final)</a></li>
</ul>James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-2652535254061772072017-03-11T20:47:00.000-08:002017-03-11T21:29:05.700-08:007DRL 2017: Day 7 and DoneIn <a href="https://mcneja.itch.io/undeath-and-taxis">Undeath and Taxis</a>, you are the driver in a zombie apocalypse. Ferry militia from the fort to the abandoned farm houses dotting the countryside to mount a last stand against the shambling horde. Your car is not just a taxi; it's a weapon. Hunt for other abandoned vehicles, or hidden bunkers with supplies.<br />
<br />
This game uses the old-fashioned <a href="https://en.wikipedia.org/wiki/Racetrack_(game)">graph-paper race track game</a> as the core of its movement system. Combat with zombies puts you on the offensive side of the <a href="https://en.wikipedia.org/wiki/Homicidal_chauffeur_problem">homicidal chauffeur problem</a>.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8h9XD-8ijg7u6AXG2iUaqIvOHLBnPnW5sPeFn9Lxf2k2OFCDLc1mrIzAPDCZWCFJbsE79XFZhRCCw3mUj5nz-zBLsCKv5V-316WybuiOC_OiV29NH3MmjmamDbj0UO5I4ScJi8n_Nbvw/s1600/undeath-screen-01.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8h9XD-8ijg7u6AXG2iUaqIvOHLBnPnW5sPeFn9Lxf2k2OFCDLc1mrIzAPDCZWCFJbsE79XFZhRCCw3mUj5nz-zBLsCKv5V-316WybuiOC_OiV29NH3MmjmamDbj0UO5I4ScJi8n_Nbvw/s320/undeath-screen-01.png" width="320" height="234" /></a><br />
<br />
Today's work:<br />
<ul><li>Reskin herbs to be bunkers</li>
<li>Add multiple vehicles and parking lots to switch between them</li>
<li>Damage/healing numbers that float over vehicle</li>
<li>Muzzle flashes from gunfire</li>
<li>Alternate control schemes</li>
<li>Zombies dodge the vehicle's path</li>
</ul>The very last thing I did was to make the zombies be a little smarter about how they move. They try to approach the vehicle but stay out of its predicted path. This changed the game completely. Previously you could just do back-and-forth sweeps with the car and mow them down as they shuffled into the path of the car. Now you have to do curving paths without letting your speed drop low enough they can take a swipe at you, and you have to look carefully at your move placements when you're dealing with one or two.<br />
<br />
Because the zombies are better at dodging, dealing with large crowds takes longer, so I had to re-balance the rest of the game. I'm not sure it's completely balanced but it is generally winnable. Maybe a bit on the easy side.<br />
<br />
The other big change today was getting the multiple vehicles in. I'm not convinced they're particularly well-balanced either, but they offer some fun changes of pace. They offer another reason to explore the map, too.<br />
<br />
Big thanks to my wife for holding down the fort while simultaneously being cookie mom for two Girl Scout troops, and to my friend Tom Elmer for lots of testing!<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com2tag:blogger.com,1999:blog-2403477577476951601.post-54332981501423880582017-03-10T21:26:00.000-08:002017-03-10T21:28:51.838-08:007DRL 2017: Day 6I woke up early this morning with a headache. Played a couple of hours of Mad Max in a despondent funk. While I was doing that I came up with a gameplay plan to try.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbl0nX09DEK1mapBBsy1Yj1amLDGFO3sbw4gOzq7LH46mLDagchfXkr0_3B76UXfroVRZqhbCNOuFXwQintyJyN5qBwk740i_AkuWK4IEtSpyFnAt9nJKQPk318T0TDmz-SyGdPXku3pw/s1600/driverl-screen-06.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbl0nX09DEK1mapBBsy1Yj1amLDGFO3sbw4gOzq7LH46mLDagchfXkr0_3B76UXfroVRZqhbCNOuFXwQintyJyN5qBwk740i_AkuWK4IEtSpyFnAt9nJKQPk318T0TDmz-SyGdPXku3pw/s1600/driverl-screen-06.png" /></a><br />
<br />
In yesterday's version I had chests to collect; a leftover from the Goblin Gold game I'd started with. The monsters collected around them. It kind of reminded me of zombies collecting around defended houses. Plus, running people over with cars is pretty bad; zombies are about the only valid targets for that kind of thing. It pains me to make a zombie game, but there you go.<br />
<br />
I thought that maybe I could replace the chests with control points, like in a Battlefield game or something. You'd drive soldiers to the abandoned farmhouses, they'd fortify them, the zombies would go after them, etc. I worked through a fair chunk of the day getting that put together. I thought I'd have something where your expanding controlled area would present a harder-to-defend front against the zombies. So I had the zombies only go after the defended houses. This was ridiculous. You'd fortify one house, and wait while all the zombies came to it. Couldn't be easier. I returned to having zombies collect around all of the houses, fortified or not. But then what's the point of fortifying them?<br />
<br />
Eventually I resorted to the oldest trick in the book: spawning more monsters. Zombies spawn on a regular schedule. Fortifying a house ensures they don't collect as heavily around it, because the soldiers shoot the zombies. The zombie-spawning schedule ramps up as you fortify houses, too, to amplify the feeling of panic. When you get down to the last house there is usually a giant mob of zombies milling around it and they all surge toward you when you roll into view.<br />
<br />
There was a lot of logic involved in making the soldier run out of the headquarters (once there aren't any zombies around and you're stopped within an acceptable distance), then exit your vehicle once you're stopped near an abandoned farmhouse and there aren't any zombies immediately threatening. It's kind of half-baked right now in terms of pathing and so forth, but it proves out the concept. I added a bunch of dialogue lines from the guy to help guide the player through the process as well. You can see the first one in the screenshot above.<br />
<br />
Tomorrow is polish. I would dearly love to get multiple playable vehicles in, but haven't tried it yet to see if it holds water. I'm thinking there'd be a truck that is slow but doesn't take environmental damage; a dune buggy that is faster off-road and middling on the road; a car that is fast on the road and slower off-road; and a motorcycle that goes blisteringly fast everywhere but takes damage more readily.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0tag:blogger.com,1999:blog-2403477577476951601.post-50907658522957372872017-03-09T21:28:00.000-08:002017-03-09T21:28:16.254-08:007DRL 2017: Day 5Today was mostly devoted to getting some terrain features and monsters going again.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoWDRj6tj0BGHSSayVgcLrNWl0AssgOpsEIurqMnVCyffNQ0rdCGtgtTGh64nsl_ULLIE3LMuOxWMg2y283GMFGH94ba_JAEF28_6ezzlL9e8mSgD6q9r-VPFnNmkpcMIm8y1kbmPD3sQ/s1600/driverl-screen-04.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoWDRj6tj0BGHSSayVgcLrNWl0AssgOpsEIurqMnVCyffNQ0rdCGtgtTGh64nsl_ULLIE3LMuOxWMg2y283GMFGH94ba_JAEF28_6ezzlL9e8mSgD6q9r-VPFnNmkpcMIm8y1kbmPD3sQ/s640/driverl-screen-04.png" width="640" height="320" /></a><br />
<br />
The monster AI I was using before was way too expensive for the size of map I have now. I replaced it with a small Dijkstra map centered on the player. If monsters are on it, they use it to approach the player. Otherwise they use a cheaper long-distance distance field that just sends them to the nearest cabin.<br />
<br />
Right at the end of the day I tried a long skinnier map instead of a square one. I think it fits with the idea of driving down a road better.<br />
<br />
The game's still not very interesting, and I don't have a lot of time left to work on it. Oh well; we'll see what can be done. I think the driving is kind of interesting; it is a bit challenging to learn how to do. Right now you just drive over monsters to kill them; kind of a high-speed version of bump-to-attack. They will hit the car if they are next to it on their turn.<br />
<br />
The car has an indicator that looks like a 3x3 grid of dots (with the center dot replaced by a circle):<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixBNsMTgzyi6LYKz7gSockr3raWXmj4T2tTBvgXvAdD0wVjW-JRoXhmyOUki9qnoiIlgB8ewJdApGN12IyVJOpvBPxrq2NK-5F_InjXhEd0FEw_8vaEO_7ljUSSUo7uPL5GtMyWJFDUpc/s1600/driverl-screen-05.png" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixBNsMTgzyi6LYKz7gSockr3raWXmj4T2tTBvgXvAdD0wVjW-JRoXhmyOUki9qnoiIlgB8ewJdApGN12IyVJOpvBPxrq2NK-5F_InjXhEd0FEw_8vaEO_7ljUSSUo7uPL5GtMyWJFDUpc/s1600/driverl-screen-05.png" /></a><br />
<br />
If you don't accelerate, you'll go to the circle in the center next turn. (You do that by pressing the 5 key in the middle of the numpad.) If you press any of the other numpad keys you'll accelerate/decelerate, which will place the car at the corresponding white dot. Dots marked red mean the car can't do them; this happens when you are at the top speed for the terrain you're on, for instance, or if you ran off the road and are forced to decelerate.<br />
James McNeillhttp://www.blogger.com/profile/08901649215141005959noreply@blogger.com0