swarm-game / swarm

Resource gathering + programming game
Other
842 stars 52 forks source link

DSL for time- and space-varying display attributes #2176

Open kostmo opened 1 month ago

kostmo commented 1 month ago

Currently, our hack for producing visual variation within a swath of homogeneous entities is to inject a different entity with slightly different display attributes among the rest. For example, a "wavy water" entity within a body of "water".

Our current DSL has sufficed so far in the following cases:

  1. For terrain, we have been content to just select arbitrary different terrains for visual styling, as we have rarely made use of tangible properties of terrain up to this point.
  2. Sometimes the entity variations are not just for display, but we really do want to distinguish the "behavior" of the variants.
  3. We can assign multiple related entities the same "tag" (see #1631), and programmatically treat them the "same" for certain purposes.

However, there are also occasions in which we want indistinguishable behavior between visual variants. It's also just good engineering practice to separate concerns of "presentation" from "logic".

For a given terrain or entity, we could have a DSL that maps coordinates to predefined attributes. The existing DSL should suffice for this; it would simply operate on the domain of "attr" rather than "terrain/entity". Perhaps it is as easy as swapping a type parameter.

As an extension, in addition to x and y, it would be cool to add the "wall-clock time" t to the DSL to support animations. This could be used for wave crests that rise and subside, or to simulate pulsing, glowing lava fields.

byorgey commented 1 month ago

Great idea! It should not be hard to add something for attributes to the existing world DSL --- I will give it some thought and come back with a proposed design.

As for a t variable, that does sound cool, I will look into adding that as well. The only potential issue is that if we do it in a naive way it could mean redrawing the entire world every frame which might be slow.

byorgey commented 1 month ago

@kostmo It sounds like you're imagining something where we would use a DSL to specify attributes for a given entity, something like

entities:
  - name: foo
    display: <some DSL term>
    ...

I have a different idea and would love to hear what you think: leave entity descriptions the same (including specifying default attributes), but enhance the world DSL itself to be able to attach attributes to things. For example, instead of just {stone, tree} as the value of a cell you could write something like {stone, tree[char:'Y', fg:blue]}. So e.g. in the classic world we could have something like

overlay
[ {dirt, water}
, mask ((x + y) % 2 == 0) {dirt, water[char:'~']}
]

instead of using a wavy water entity.

It seems to me like this would give us everything we would want without adding extra complication to the scenario format, and with only a small tweak to the world DSL.

We could also get slightly more sophisticated and make attribute expressions first-class. Imagine something like this:

let wavy = mask ((x + y) % 2 == 0) [char:'~']
in overlay
    [ {dirt} <> {water}[wavy]
    , mask (abs pn1 < 0.1) ({dirt} <> {sand}[wavy])
    ]

Attributes would form a monoid, and you could attach any expression of type World Attr to any Cell value. This would allow reuse of attribute expressions and also help with separation of concerns.

kostmo commented 1 month ago

enhance the world DSL itself to be able to attach attributes to things

Yes, that would work.

Regarding the time-varying aspect, ideally the design would facilitate the old-school color cycling effect. In that case we would want to tie spatial sequencing to a color sequence without too much indirection.