Eidolon

LD 40

incoming

i haven't been able to finish a game jam in over a year now. so let's make the game

  • [aseprite] -- yeah
  • [sunvox] -- easily the best non-DAW music production tool out there.
  • [unity] probably but honestly i hate unity. so maybe something homegrown with [love], [moonscript] and [tiled]
  • provided unity is used, [cinemachine] has a fairly cool camera system that can make impressive results even in 2d
  • i've been exploring some [rust] gamedev stuff, but i think the iteration cycle is still a bit unwieldy for something like a jam. not anywhere near as bad as C++, but still an issue. libraries include [ggez], [gfx], [cpal], [amethyst] and [specs]

some arbitrary thoughts

it's custom to announce yourself as being "in" and say all the tools you want to use, but i worry of the expectations it may impose on a new participant. so, here's imo better idea: here are my goals for this jam

  • scope correctly and finish the game -- this is a given, but it's one of the hardest things to accomplish and one of the major reasons why game jams are a good exercise.
  • avoid bikeshedding and overfocus on technology -- i have made a habit of spending weeks in technical preparation for a jam only to worry about technical minutiae to the point of forgetting to do any game design. the effect of this is reproducing tropey designs that are neither interesting nor fun explorations of the theme or in game design at all, but the game itself is technically interesting given the time constraints. it's easier to fall into this trap if you're a programmer by trade, i think.
  • stretch often -- i don't need another shoulder injury just because i wanted to make a video game

LD 43

here's some love2d build pipeline template code

https://github.com/HybridEidolon/love2d-vore-template

it's called vore. it requires node 8+ and npm at minimum.

  • "watch" build support for automatically rebuilding scripts and assets
  • compile tiled maps to .lua modules
  • compile moonscript sources to lua
  • share a module path for lua and moonscript sources seamlessly
  • compile aseprite files to animation json and sheet png
  • bundle windows and mac fused executables, .love redistributable
  • publish fused games directly to itch.io with butler

sorry, I can't get linux appimage fusing working before the jam. all you should need to do is use squashfs-tools to extract the love2d appimage and then append your .love file to the love, then mksquashfs the directory again. but squashfs-tools is not available on all platforms, so I have opted to avoid it for now. 7-zip on windows supports modifying squashfs archives, so you might consider that as an alternative.

I'm trying to get some other base code done (asset and module hot reloading systems for tiny-ecs in particular). that will be stored in a separate repo with just moonscript sources you can copy into your project. no guarantees though. you'll have to go pure data-driven entities to make full use of it; think storing asset paths as strings in your entities instead of image/sounddata references, system modules pure w/o side effects on require, etc.

i added code hot reloading to vore

https://github.com/HybridEidolon/love2d-vore-template

it's under contrib/tinyx

from doc/SystemReload.md:

SystemReload can be used to automatically reinitialize systems during runtime. It works by checking a set of file paths on an interval for updates, and rerunning a lua chunk that exports a function for setting up world systems. It requires the lua require path be unmodified from love2d's default.

Bootstrapping your world in main.moon:

world = tiny.world!

initSystems = require 'initsystems'
initSystems world

Inside initsystems.moon:

(world) ->
  SystemReload = require 'tinyx.SystemReload'
  systemInitModule = 'initsystems'
  moduleRoots = {'systems', 'tinyx', 'sub.path'}

  worldddSystem (SystemReload systemInitModule, moduleRoots)

Your systems' internal state will be destroyed on reload. This is vitally important to understand; you should never assume onAdd/onRemove will only ever be called once or a given entity at runtime, because the systems themselves get recreated. If you need things to only happen once, store that information on the entity itself.

Second, do not store references to systems or system data inside your entities' components. This will easily break hot reloading at runtime. You need to make sure that whatever is used to index system-specific data is only stored as a handle or index that can be recreated by that system; alternatively, on the system's removal, delete those handles so that the next version of the system can recreate them. If there is data that should persist between reloads, is not pure Lua data, and isn't tied to a specific entity (e.g. an asset manager), store it on the world object because the world itself will persist between reloads.

For example: instead of storing an Image directly in an entity for use by your system that handles rendering, store the string path to that resource in the entity, have a system manage loading that asset into a world-global asset manager, then index into the asset manager in the render system when looking at that component again.

Essentially, you need to make your systems as functionally pure as possible, and stick any transient state into the world itself.

Bonus: if you keep your systems pure and entities pure-data, you can create systems that manage unique IDs for each entity. You can then have references to other entities in such a way that saving your game state for debugging becomes as simple as serializing a table of every entity table in your world.

the final stretch: a hot reloading asset manager for vore

https://github.com/HybridEidolon/love2d-vore-template

once more doing some groundwork to save some time, and sharing the code.

vore is a love2d game template leveraging the gulp build tool from the node ecosystem to watch your game source for changes and recompile and bake your assets automatically. accompanying it are extensions for tiny-ecs and (now) an asset manager that both fit well into this watch-reload pattern, allowing you to reload both system code and assets at runtime simply by saving them in your editor. vore also automatically packages and uploads your game to itch.io through butler. it supports moonscript, aseprite, and tiled compilation to loadable assets built-in, and is relatively easy to extend.

per the documentation:

Asset Manager

AssetManager is a stateful object that combines a few functions:

  • Loading and caching of various asset types by string path
  • Storage of runtime-generated assets by a unique transient index object
  • Retrieval of cached assets (assuming they are already loaded)
  • Reloading of loaded assets

Examples (Moonscript)

Construct a new instance:

import AssetManager from require 'AssetManager'

manager = AssetManager!

Add an extension-based loader. The return value of the loader func will be stored in the cache.

manager\setLoader 'png', love.graphics.newImage
manager\setLoader 'wav', (path) -> love.audio.newSource path, 'static'
manager\setLoader 'lua', love.filesystem.load
manager\setLoader 'json', myJsonLoader

Load an asset (for later retrieval). The loader used will be based on the extension.

manager\load 'sprite.png'

Retrieve an asset and use it

sprite = manager\get 'sprite.png'

love.graphics.draw sprite, 0, 0

Insert a dynamic asset into the cache and create an opaque index key for it. Store the key if you want to reference the asset later. (Note: if you need to e.g. serialize entity state, you'll need to delete this from the output)

image = love.image.newImageData 512, 512
key = manager\insert image

Retrieve a dynamic asset from the cache. You should not store this reference; keep it only for as long as you need it, because you can retrieve it later. Holding onto the asset will just make hot reloading not work.

dynamicImage = manager\get key

Replace a dynamic asset in the cache, reusing the key. release will NOT be called on the object. You can replace an asset with nil to fully remove it from the cache.

anotherImage = love.image.newImageData 128, 128
oldImage = manager

eplace key, anotherImage oldImage elease!

-- remove it
oldImage = manager

eplace key, nil oldImage elease!

Check and reload updated assets. release will be called on the values if it exists. If a file is removed, it will not be removed from the cache, but obviously it won't be present in future runs.

manager\update!

Usage in ECS

Store the AssetManager on your World. Use a System to first gather all of the asset references in your scene that need to be loaded, and load them. For example:

tiny = require 'tiny'
ProcessingSystem = require 'tinyx.ProcessingSystem'

class LoadSpriteImages extends ProcessingSystem
  new: =>
    super!

  filter: tiny.filter 'sprite'

  process: (e, dt) =>
    if not @world.assetManager\get e.sprite.imageKey and type(e.sprite.imageKey) == 'string'
      @world.assetManager\load e.sprite.imageKey

LoadSpriteImages

If you want to periodically hot reload all your assets (almost certainly why you're using this):

tiny = require 'tiny'
System = require 'tinyx.System'

class ReloadAssets extends System
  new: (reloadInterval) =>
    super!
    @interval = reloadInterval

  update: (dt) =>
    @world.assetManager\update!

ReloadAssets

Of course, you can get the assets you need in the systems e.g. responsible for drawing or starting sound sources.

i guess i'm not doing love2d after all; here's my idea

the design i've landed on is going to be using 3d, so i'm probably going to use unity instead of love2d. so have fun with the vore template i guess, lol

this game is a sort of bullet hell gladiatorial combat game. in between battle rounds, you must sacrifice a capability or item to buy another item or capability; the options are randomized between rounds, and as you play you'll be cycling the items you have access to. each round pits you against a boss enemy with various partly randomized characteristics. as you progress in the rounds, the threat increases, amplifying their characteristics and making them more dangerous. you lose when you run entirely out of hull points. oh, and hull points can be exchanged for items too (but not so many that you would instantly lose during the buy phase).

LD 44

I decided on Godot, it's neat

I dig it.

Capture3.PNG

It also exports to WebAssembly instantly and painlessly, at ~11MB runtime. Highly recommended for a game jam game, of course.

The new tile set editor is a saving grace; 3.0's lack of one was the only thing holding its 2D tooling back. It's a welcome improvement.

I'm not certain where I'm taking this game, but I have some unresolved feelings about life and living as it pertains to my relationship with capital, if you catch my drift. So we'll see.

Ludum Dare 45

I didn't think I'd be doing this

I really think this theme kind of sucks but it was open ended enough to do... well, basically anything.

So I did.

LD45ObviousTheme 10em5/em2019 12em54/em53 AM.png

Godot Engine 3.1, Aseprite, so on so forth.