🤑 Indie game store🙌 Free games😂 Fun games😨 Horror games
👷 Game development🎨 Assets📚 Comics
🎉 Sales🎁 Bundles

chimerror

6
Posts
5
Topics
3
Followers
2
Following
A member registered 1 year ago · View creator page →

Games

Recent community posts

Forgot about these questions!
  • What did Lisp enable you to do well in this entry?
Clojure's rigidity on mutability drove me to organize my code in a pipeline based system, and favor strict separation of concerns. Its loose type system kept me from getting too bogged down in making type hierarchies.
  • What challenges did Lisp present in making your entry happen?
I definitely felt Clojure's functional nature was at odds with Phaser's object oriented nature at times. Phzr helped, but not 100%.
  • If you are comfortable answering, please you mention how long you have used lisp and describe previous gamedev experience, if any.
I first mainly used lisp back in college, but have returned to it for my own pleasure over the past 4 or 5 years. I have attempted to make my own games throughout my coding career, and never really had the time or success to dive into it until now. I'm batting 0 on jams, but the future is bright!

What I Learned

Going through all of this really did help cement a lot of the things that I had really not gathered from going through the Phaser tutorials. Basically, all of the challenges I faced with that probably will not be repeated, and I will find its actions much more predictable than I did.

I additionally found out a few lessons about organizing game code. The first, and most important, is to let objects handle their own rendering/positioning, rather than doing it as part of an update loop. That is, when a party member was moved from one hex to another, I had been trying to do the positioning update right then and there. It was vastly easier to just move it to the group and then have the group "fix" its members, and it looked better in the end. It also handled taking members out of the middle of the group better.

The next is the basic way an entity-component system works with immutability. I had made small games in Clojure before, and knew the necessity of passing a state object to functions. I did not really get how this "pipeline" method of working and threading state through could be made easier, through returning an "updated" version of the state object. I really did not "get" the -> and ->> threading operators until they become so necessary to avoid writing messy code.

But in a wider sense, reasoning about what would happen on update became easier as I divided up responsibility between namespaces. I now understand that namespaces in Clojure(Script) are somewhat like the equivalent of classes in object-oriented programming languages, just that they are (ideally) limited to functionality rather than also keeping track of data as with a class. So this makes them very much like static-only classes in C#, my normal language.

So all together, if one namespace (system) determines it needs to update an entity, it can delegate the update to a different namespace, and get back the new state object, not needing to know the gory details, and move on. This made a very neat and clean pipeline. The tricky thing is that the phzr/Phaser objects are instead "mutable" rather than immutable. So that became an additional "pipeline" where a phzr object was passed off to a method, that returned the same object after it was updated. Working with those could definitely be cleaner...

Expanding on working with phzr objects, my original intention was to go very deep into splitting out object into entity components. I would have entities that had separate gameplay components and phzr object components. For example, an entity would have an ExplorationGroup component for the game-level data, and a Group component for the phzr object. That was probably an abstraction too far. I eventually needed to do one check on the game-level data, and then another call to get the phzr object to update it, and was doing this constantly, leading to repetitive code. I started just including the phzr object as a property of the game-level component, which made for much shorter code, especially when I figured out how to use map destructuring.

The last thing I feel like I learned is to strongly consider when you actually need to have things participate as an entity. Many of the components I made ended up being singletons. This added repetitive code because I would use brute's functions to get all the entities with a specific component, and then immediately pass it to first. I didn't write up a function wrapping that up until very late. Comparatively, I did not place the phzr game object in an entity and just accessed it through a normal property on the state object. That probably would have made more sense in the long run for the singletons. Basically, if you may have multiple "instances" of an object, using the entity system makes sense. But if you know you're going to have only one, ever, make your life easier and make it visible at the top as a property.

So to sum up:

  • Understand the ins and outs of your engine
  • Delegate very specific code to namespaces handling certain "systems"
  • Tie your systems into a pipeline that operate on the game state
  • Don't divide things up into components until you're sure you want to
  • Don't divide things up into entities until you're sure you want to

What I'm Going to Do Next

I do want to finish up the game, though it's going to have vastly different flavor than I originally intended, simply because I don't think it's worth me to dive down too deep into making this the most perfect game I had originally intended. It's just not a story or gameplay experience I care that much about. I'll also probably do some work to pull out the more common code into a template so I can make a Phaser game all that much quicker.

And then, make more even more games!

Created a new topic Fossa Postmortem

Sorry for being so late at getting this out, my schedule got a little crazy. You can see my finished code on GitHub, and see how far I got during the jam on the GitHub Pages Site. I still do intend on finishing the game in some state, so I may update it further!

What I Intended to Do

My game idea was new, but based on a riddle I had seen in a TED-Ed video. In that riddle, you are an explorer trying to escape from a temple. There are too many ways to explore by yourself, but luckily you have eight teammates. Unluckily, two of them have been cursed by the temple, and will lie to attempt to lead you the wrong way. You can't tell who's a liar beforehand, you'll need to figure out a way to determine the right path.

My intention was to extend the riddle to multiple iterations, adding more liars as the player got closer to the exit or made mistakes. I decided to change up the flavor slightly, making it about grad students exploring a space-time anomaly. If the player survived, they would be able to find out how exactly the space-time anomaly was created. The characters were going to be rats, because rats are cute!

So in the end, this would be a browser-based game with mouse-based controls (and possibly keyboard controls if I got far enough). I intended to create the art, sounds, and music myself along with the code.

What I Actually Did

At the end of the jam, I had just started really making progress on the gameplay portion. The code at the end of the jam allowed the player to send out the party members to explore, showed the results of their explorations (with liars possibly lying), and let the party then move through a hard-coded 3-room dungeon I made for testing. There were no penalties applied to the player yet for incorrect choices. I got part of the way through coding up a dialogue system when I realized I was out of time.

What Went Well

My focus on this project was overall very good, it consumed most of my time. Despite not finishing, I got much further along on this game jam than any I've tried in the past. There's an honest seed for a game there that got done. Also, despite my difficulties in deciding how to organize my code, as well as working with Phaser, I know have a much clearer idea, and what I have is definitely something I can use to make the process faster in the future.

In particular, the advice to prioritize things between "now", "soon", "later" was very helpful. I would need them was great advice, because it let me become much harsher about putting things further back in the backlog. I think the vast majority of the stuff I put in the "soon" category on the first day, I never got to, and had I tried to get to them, I would have not made as much progress. It also made it easier for me to push the small rendering bugs I ran into back there, especially as I was going to replace the art any way.

The instant feedback of figwheel to display my code changes was a mixed blessing, but for the most part a benefit. It definitely gave me a system to do debugging without actually using a debugger, so I was able to do all my work in vim and the command-line, using no IDE at all! However, editing features of an IDE like Cursive would have probably been helpful just to speed up coding.

What Went Poorly

I did not get into really doing gameplay code until the last three days of the jam, and I didn't get to any asset work at all, which was something that really interested me. My main issue was figuring out how best to use phzr and brute together, as well as understanding input.

In particular, I struggled with integrating Phaser's event system, which was based on callbacks with brute, which ran every frame. Phaser definitely intends for its users to use its callback-based system. While it offers some functions that can be used to poll, (for example, justPressed), these take in a threshold of milliseconds, and will continue to return success throughout that threshold. I eventually introduced some "blackout" properties on my game state that kept track of when the last time I had performed a change based on input. Only after enough time had passed since the last blackout would I perform another change. This seemed to work well enough, but introduced boilerplate code I was not very happy about. I think in the future I may use ClojureScript's concurrency features along with the callbacks.

I additionally had a great deal of trouble with positioning sprites. Phaser uses the very common Cartesian coordinate system, but allows sprites to be placed in groups, as well as be the child of other sprites. Within the group, the origin of the coordinate system is moved to the location in the group. This meant that if tried to use the world coordinates, the sprite would not end up where I expected. This also led to problems with how input worked. Dropped sprites would be moved to be over another hex and then considered "dropped" on that hex because of the threshold. The ability to change the "anchor" of a sprite or group made it even worse. In retrospect, it was not that hard of a problem, but I did not have an easy time working with it, and Phaser's documentation does not really describe the system in-depth.

Phaser also has z-level sorting of sprites, but it seems like it will automatically "update" the z scores at times (probably the results of calls I made...). This led to party members, for example, appearing behind hexes, or on top of the results dialog. This came to a head with the group issues mentioned earlier, because I had added my party member sprites to a separate "stage" group that is always above the "world" group, where I had added everything else. I strongly feel that this needs to be better explained within the Phaser documentation.

The last little hurdle that I think is worth mentioning is that Phaser's default units for rotation are radians rather than the more familiar degrees. I later found out there's a way to use degrees, but I spent a lot of time trying to get the mice to rotate towards their eventual destination. This is probably more of a problem of me diving too deep into a problem, though.

I'm definitely working on it, I decided to take Friday off to decompress a little and I spent Saturday just trying to beat the heat. I'll probably try to work some Sunday morning!

OK, I tried to get it all in by the deadline, but despite some great progress, I'm not going to be finished in the next 45 minutes. I could stress myself out, or know when I'm beat. I'll probably take the rest of the weekend to finish it up at least, because I'm about a day out or so.

I now can move through my dungeon, sending out party members to explore, and getting their results, but there is no penalties for doing so. I don't have any other screens done, but am in the middle of adding dialogue trees. Perhaps I could also replace the terrible programmer art I just drew.

I'll at least still upload it to itch when I'm finished.

This was fun, I'll have to do this again!

Streaming in a couple of minutes, finally writing game play code, which I figure is much more interesting than my struggles with Phaser: https://www.twitch.tv/foobardog

I didn't stop working, but I've been heads down on getting input working, so I've been deprioritizing the dev journals. It's also turned out much harder to get input working. (This is too big for itch.io, so I had to severely edit. If you're really interested, check the full journal on GitHub.)

Thursday, August 4th, 2016 - Friday, August 5th, 2016

These days were pretty slow, only got some basic things checked in.

Saturday, August 6th, 2016 - Monday, August 8th, 2016 (Morning)

These ended up being very productive days! Basically my problem was that I was trying to use Phaser's event handling system, which depends on callbacks. I didn't see a good way to tie that in with the constant looping method of brute. Phaser callbacks can take additional information, so it would in theory be possible to pass my system object to my callbacks. However, since these callbacks could possibly update the system object, that would introduce an unpredictability of when the object would be updated.

The system object is saved in an atom, so in theory, it would have been referentially OK to modify it whenever. However, I had gone out of my way to make sure that atom was only modified in one place, core.cljs. This means that most of my "update" functions worked on a copy of the system. This is the whole point of ClojureScript's strict requirements on limited mutability (and is why I like it!).

The atom does mean that querying the system object would never be inconsistent, but most of my functions never query it, but a copy instead. This means that an update from a callback could possibly invalidate work going on in another function. It would be possible to coordinate, but it would introduce a lot of complexity, and that's never good!

I instead moved away from Phaser's system and moved towards using the update functions that brute expects. It ended up working, but it has some downsides. For example, to see if a sprite has been dropped, you can call the justReleased method on it. The time that it considers a sprite "just" released is configurable. However, this is a raw time in milliseconds, not a number of frames. So if a party member has been dropped, there is a window of time it'll continue to be considered "dropped".

This bit me in the tail when my positioning code was not up to snuff yet. I determine if a party member is dropped on an exploration path if their sprite overlaps the hex sprite. I then wanted to align the party member within a group on that sprite, making the party members on a path well-organized, so that's what I did in my update function. However, with the position being off, sometimes, that would move the sprite to a position where it overlapped a different path.

Since justReleased still thought the sprite was "just" released, it moved it to that different path. Which could have done the same thing, and so on. I could modify the threshold for "just", since it was after all at a hefty 500ms (just over 30 frames at 60 fps) but at a low enough number that could lead to drops not being recognized, because a long frame could mean that justReleased returned false before the function can get to it.

In the end, I didn't really "fix" this problem. I made the groupings on the hexes much closer, so they were unlikely to overlap another sprite. I also had the update function only add the sprite to the group and let the group handle positioning it. This made positioning much more reliable, and had the added effect of groups automatically realigning themselves if a party member was taken out from the middle of the list. But, in theory, this bug still exists.

The other issue at play here is the high mutability of JavaScript and therefore Phaser versus the low mutability of ClojureScript. Even when using phzr, most of the heavy lifting is done on mutable objects. ClojureScript handles that idea through the doto special form, which performs a set of actions on a presumably mutable object and then returns it. It basically makes ClojureScript act like an iterative programming language for a bit. However, I confused it with the -> and ->> special forms which allow threading an immutable object through multiple calls. That is, the result of the first call is fed into the second, which is fed into the third, and so on. It's syntactic sugar for the normal Lisp pattern of nested calls. However, it ends up looking very similar to doto, and I got burnt in a few cases.

ClojureScript also has several different special forms for iteration like for and doseq. Similarly, some of these act in a lazy manner, while others act in an immediate manner. Additionally, both of those are more oriented towards working on mutable objects. For proper threading of immutable objects, You pretty much must use loop and recur, which are special forms to make recursion easier. But these also burnt me. Not really the fault of the language, just something I need to get more used to!

At the end of all of this, I was able to drag and drop party members onto exploration paths to add them to groups. It was a frustrating process (I was also working on this on days 4 and 5), but it worked! I could move on to gameplay!

Monday, August 8th, 2016 (Afternoon)

Starting on gameplay, I wanted to first check if I could write a little label on my party members so I could know which ones were which, since I could not remember them by color. This was also a good chance to begin working on bringing fonts, which I knew I would need eventually. Bringing in fonts was actually harder than I thought, but not for any good reason.

I picked out a nice font on Google Fonts that looked like a typewriter font from the era the game is set in. (The equivalent of the 1970s, if you're wondering.) It is a web font, which has the great benefit that the user doesn't have to install it on their computer, nor do I need to have it saved with my game files. The app will download the font at the time it needs it. This is often used on webpages. The downside is that if downloading the font takes too long, you could have a period that text without the font is displayed, and then it "flashes" to the downloaded font. It's annoying on a web page, but in a game like this, it's worse. If the font is not downloaded when you start to create text in Phaser, it'll fall back to another font but you'd have to "update" that text, which is not done "automatically" like it would be on a web page. However, there are solutions.

Google and Typekit have a Web Font Loader JavaScript library that can be used to load web fonts from common font websites and let code know when they've been downloaded. Since it's by Google, it even hooks in well with the Google Closure Library that ClojureScript depends on. The Web Font Loader is available on Google's CDN, which is generally the preferred way to get it. So I tried to add it as a foreign library in my project.clj file through that URL.

However, this seemed to clash with Figwheel, which is sort of a helper for ClojureScript coding that builds the ClojureScript code for you, serves it to you through a local web server, and watches for file updates so it can rebuild the code automatically. This really decreases the length of the code-compile-run cycle. I can just make edits to my ClojureScript source, and in under a minute, I'll see the updated code running in my browser.

For whatever reason, Figwheel was treating the URL to Google's CDN as a local file to be watched, and would crash because Windows knew that wasn't a local file and pushed back. In the end, I just downloaded it, and checked it in to my source tree, which is not preferable. Ideally, you avoid keeping your own copy of an external dependency in your source for many reasons, like dealing with updates to that dependency and legal code redistribution reasons. But, I was already far behind, I didn't need to get bogged down in debugging Figwheel.

Either way, I got the font loaded, wrote the label on the party members, and now, you can drag and drop party members onto hexes. I finished out the day by starting to implement a method for defining the dungeon that the players will traverse through, the first real gameplay code. I'm very hopeful I'll have a full gameplay alpha by the end of Tuesday! Longer than I expected, though. There's no way I'll get in a lot of the nice assets I wanted to add and get gameplay nailed down. But... I learned a bunch, and we'll see what I can do over the next two days. I guess there's technically three, counting the 11th, but I don't think it's in the spirit of the jam to do major work on the 11th. I'll probably consider this a beta, and work on integrating the assets after the Jam is over, basically making a "deluxe" edition.

Whew! A lot to write, and I am probably over-explaining some things to fellow programmers, but I've been linking non-programmers to these journals, so I am assuming very little previous knowledge. Plus, I'm not editing these journals, so I bet I could whittle them down.

Excelsior!

Created a new topic Fossa, Day 3: Et tu, Brute!
(Edited 1 time)

I can't sleep, so I guess I'll write my journal entry.

I sat down to write a draggable component that would expand a sprite so that it could be dragged around and dropped, which was the last real important “general" functionality that I would need to actually begin coding up a gameplay alpha. Phaser is made to be straightforward and exposes a large amount of functionality on the Sprite object itself. So to make a sprite draggable, it's actually really easy in JavaScript:

function createSprite() {
    var mousey = game.add.sprite(0, 0, 'mouse');
    mousey.inputEnabled = true;
    mousey.input.enableDrag(false, true); // Drag from click-point, bring sprite to top
    mousey.events.onDragStop.add(checkDestination);
}
function checkDestination(item) {
    if (item.x > somethingOrAnother) {
        item.input.disableDrag();
    } else {
        doSomethingElse();
    }
}

Properties like input and events refer to specific InputHandler and Events classes, which maintains good code separation.

Similarly, the ClojureScript code is straightforward, once you're used to phzr's paradigms:

(ns example.mousey
  (:require [phzr.core :as p.core]
            [phzr.game-object-factory :as p.factory]
            [pzhr.input-handler :as p.input]
            [phzr.signal :as p.signal]))
(defn create-sprite [game]
  (let [factory (:add game)
        mousey (p.factory/sprite factory 0 0 "mouse")]
    (doto mousey
      (p.core/pset! :input-enabled true)
      (-> :input (p.input/enable-drag true false))
      (-> :events :on-drag-stop (p.signal/add check-destination)))))
(defn check-destination [item]
  (if (> (:x item) something-or-another)
    (-> item :input (p.input/disable-drag))
    (do-something-else)))

Now, in trying to make my things more Clojurey, I first thought that a Draggable component made the most sense. So an entity with a draggable sprite would have to have two components, a Sprite and a Draggable component. But this introduced dependencies, since Draggable would need to get the sprite from Sprite. It also became hard for me to see how I would be able to toggle a sprite's draggability easily. I would need to be able to edit the phzr sprite object both during Create and Update. However, under my design, I didn't keep track of the phzr sprite object after Create. There was no way to get it back during Update.

A darkness warshed over the chimerror…

I began to reconsider the brute demo code. If you look at its component definitions, you'll notice several of them are just empty records. I was confused by this a little. I understood the idea that this was just reifying game concepts as types, but why bother having a record if you're not going to put anything in it?

That's when it hit me. Components were not meant to abstract away engine concepts themselves as future-proofing. They were meant to wrap engine manipulation in types that represent game concepts. For example, the brute demo code defines separate records for Paddle, PlayerPaddle, and CPUPaddle. I had wondered why you wouldn't just have one Paddle record with differing AI functions, which is a pattern I've used elsewhere. The reason why you have separate ones is because rather than thinking in an object-oriented fashion, I should have been thinking with portals functions.

The other namespaces in the brute demo code did not define entity types, but systems for manipulating and managing entities and their components through functions. They have some initialization functions to set up entities, but the heavy lifting happens in a function called process-one-game-tick. That function is called every game loop. So rather than having each component be aware of what steps it should take during each stage, you reduce it down to create and update. This gives you a set of namespaces that handle different aspects of the game, whether that's engine functionality or a particular type of game entity. The core namespace just wires it all together.

So realizing brute and entity-component systems were meant to be a sort of aspect-oriented programming, I sat down to vastly refactor to make my code more match the brute demo code. There's now a Sprite and PartyMember record. I placed helper functions around input into an fossa.input namespace. brute shot back to the front, and I was actually using it to find entities and their components as it had been designed to do. And at the end of the day… I had a mouse I could drag around the screen with my mouse.

Not exactly how much I had hoped to have done by day three, but I now feel like I'm on my way to grokking both entity-component systems, game engine programming, Clojure, and different programming paradigms. I know me writing about this feels a little arcane, but my experience has been that finding descriptions in English of how to architect your game is very hard. There's a big jump from a basic tutorial to a list of engine functions and specific use cases, and very little writing covering that middle section, which is probably the most important one! It's not just a problem with game programming, it's pretty rampant.

But, onward!

Yay, something that can be played! I'd not worry about the autofire, immediately, going pew, pew, pew, pew is fun!

I did get a little confused with the control scheme, I wasn't expecting the arrow keys to resolve into headings. That is, now, to completely turn clockwise 360 degrees from heading towards the top of the screen, you press right, down, left, up. You basically have to switch to the other keys once that heading is hit. My initial assumption was that I'd just be able to hold right.

Either way, doing good!

So I realized this entire method made no damn sense and wasn't how brute was expected to be used, so I refactored everything away. But I now have a little mouse sprite that I can drag around the screen. Yay?

I didn't post a Day One update, so I'll take the chance to make an introduction, and then get into the journal

Introduction

I've long wanted to make small games on the side, and I really love Clojure, so I'm making a game I've codenamed fossa. (Yes, foobardog is me, I've been moving some of my online presence to my new name, chimerror.) I have a title in mind, but I like using a codename first.

My main goal for this jam is to get better at avoiding my major vice of over-engineering and feature creep. I'm a fastidious kitty, and I often deep-dive too often. So the advice on keeping it simple is well taken, I just need the practice.

The basic idea for this game builds off a riddle I saw on TED-Ed they called The Temple Riddle . I've decided to change the flavor and iterate through this riddle a few times to make a longer game of it. Basically, this will be a type of logic game where you need to determine which members of your party are liars so you can escape the temple (well, cross-universe anomaly in my flavor). I may also expand the game by having certain party members having certain tools or abilities that are necessary to explore successfully (like a flashlight, or something).

I'm writing this in ClojureScript using phzr, which are bindings for the Phaser JavaScript library for ClojureScript. I am using brute, an entity-component system library for dependency management purposes. I'm keeping track of tasks and things on this Trello board. When I get to some interesting gameplay coding, I may do some streaming on my Twitch Channel .

Days One and Two Journal (Monday, 2016-Aug-01 to Tuesday, 2016-Aug-02)

So my first task was to figure out phzr and brute. In the pre-work, I managed to implement the Phaser tutorial, which is in JavaScript in ClojureScript. While phzr tries to make things more Clojure-like, that tutorial had me using a lot of global atoms, which I don't think is in the spirit of functional programming, so I was going to pull in brute to manage things in a cleaner way.

I first spun up a basic window, with just a background image and a sprite, using the patterns I had figured out from the pre-work. After that, I began trying to understand how brute could be integrated in. Phaser divides running a game into three stages (well, more than three, but I'm only using three): Preload, Create, and Update. Preload is used to load assets, Create actually creates game entities, and Update is called on every frame of the game loop.

brute is a bit more general than that. You create a system, add entities to that system, and add components to those entities. You then define a chain of system functions (for example, rendering, input, AI) and the system is passed through that chain. Each system function gets the entities and components it needs and handles updating them for their particular purpose.

The brute demo code defines most of its components as Clojure records, as brute handles keeping track of entities. brute exposes a few methods to get all entities with a particular type of component. For this purpose it uses the ClojureScript type function. (Well, when running in ClojureScript. For Clojure, it uses the class function.) Internally, it uses the type information as keys into a map.

So I realized that I would need a way to keep track of which components had actions for which stages. For example, if I was going to have a sprite component, it should make sure to load the image during Preload, and create the sprite during Create. Clojure protocols seemed the perfect abstraction. And it would have worked, perhaps... In Clojure.

The main issue is that ClojureScript does not have as strong run-time reflection support for protocols as Clojure, and that the use of the type function didn't really expose what I can do there. The satisfies? function exists to check protocol satisfaction, but that works on an individual object, not the type information as brute was using for keys. Additionally, it's really a macro and must take a known symbol at compile time. Clojure extends? is what I would have wanted, but that's not available in ClojureScript.

Day 1 was basically lost figuring all this out. I spent the first half of Day 2 continuing trying to make it work. When deciding to cut my losses, I had the realization that I really was not representing my case accurately. I split the Preload functions into an Asset protocol, and added an get-assets to the Component protocol. I completely ignored the brute way of getting components to just doseq through all entities. I didn't want to break brute's contract, but I didn't want to completely discard it. I also wanted to add some defensive coding to my processing functions, but I couldn't get it working, and cut my losses. After all, I didn't get into this to write an entity-component system!

So a frustrating two days, but I'm through that. And yes, this was a little bit of ratholing, but I've been able to cut it off way better than I've ever done in the past. Onward to actually interesting parts!