Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Shared State and "Singleton" Widgets

A topic by Internet Janitor created 6 days ago Views: 68
Viewing posts 1 to 1
Developer(+4)

Most of the time, the fields and other widgets on different cards of a deck contain entirely different data. Occasionally though, as in this question, you might have data like a game's score counter that you want to display on and modify from many cards. There's an elegant way to (ab)use Prototypes and Contraptions to create this kind of "singleton" widget state:

When the value of a field in a Contraption instance has never been modified, the value of the corresponding field in the Contraption's Prototype is inherited. By exposing a ".value" attribute for our Contraptions which read from and write to a field in the Prototype, rather than the Contraption instance, every instance of the Contraption will share a single value:

on get_value   do card.def.widgets.f.data   end
on set_value x do card.def.widgets.f.data:x end

This becomes slightly more complicated if we want the field to be unlocked and user-editable, since we can no longer rely on inheriting the prototype's value automatically. In this case, we will need to explicitly replicate changes back to the prototype and poll the value from the prototype when the contraption is updated by a view[] event:

on get_value   do card.def.widgets.f.data   end
on set_value x do card.def.widgets.f.data:x end
on change      do set_value[f.data]         end
on view        do f.data:get_value[]        end

As a complete example, here's a "scoreCounter" prototype which uses this mechanism:

%%WGT0{"w":[{"name":"sc","type":"contraption","size":[100,20],"pos":[302,95],"def":"scoreCounter","widgets":{"f":{}}}],"d":{"scoreCounter":{"name":"scoreCounter","size":[100,20],"margin":[0,0,0,0],"description":"an example of a \"singleton\" contraption which shares data across every instance.","script":"on get_value   do card.def.widgets.f.data   end\non set_value x do card.def.widgets.f.data:x end\non change      do set_value[f.data]         end\non view        do f.data:get_value[]        end\n","attributes":{"name":["value"],"label":["Value"],"type":["number"]},"widgets":{"f":{"type":"field","size":[100,20],"pos":[0,0],"style":"plain","align":"center","value":"0"}}}}}

Anywhere a scoreCounter appears within a deck, it will represent an identical view of the same underlying value. A pleasant side-effect of this approach is that scripts on cards can refer to any scoreCounter when they want to read or modify the game's score; there's no need to reach for a "source of truth" on some specific card.

I hope some of you find this to be a useful technique for your projects!