Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines
(3 edits) (+2)

I gravitated toward editing the script for the whole card because that's the model I'm used to. I started out trying to draw directly on the card, and later realized I needed to add widgets to get the script to work. Procedural drawing must go on a canvas, is that right?

It's easy to bounce between editing and running the whole card by hitting ctrl+e and escape. Do you use any hotkeys for switching between editing a specific widget and running the whole card/deck?

One thing I didn't share was that the string I make to dance is much longer and wraps. And I was using the 4-element position when drawing text to make it wrap. This works beautifully now:

local margin:15
me.text[y (margin,margin,me.size-margin*2)]

I don't quite see how to make center alignment work with 4-element positions and text wrap. This doesn't do any centering or wrapping at all:

me.text[y (me.size/2, me.size) "center"]

Does text wrapping work with center alignment?

Does the choice of anchor affect how the `pos` argument of canvas.text is interpreted? The only way your code makes sense to me is if I assume that the pos is specifying the center of where to draw the text and not the start..

(+3)

It is possible to directly manipulate the card background (card.image) instead of using a canvas widget, but it's limited in some ways; see the Image Interface documentation. If you have a hand-drawn card background this can also make it easy to accidentally destroy your doodles, so use caution! For a quite elaborate example of such an animation, try clicking the first "e" in "Decker" on the title screen of the guided tour deck.

When I'm frequently making changes to a script I do often defer logic to the card-level script for editing convenience, possibly by giving the widget a stub script like:

on click do
 reset_game[]
end

With "reset_game" defined on the card or deck script. It is possible to quickly jump to a widget's script by enabling "File -> X-Ray Specs" from within the script editor and then ctrl+clicking in the widget's bounding box to view its script; ctrl+clicking outside any widgets switches to the card script. This is a very useful tool for getting a "bird's eye view" of what's happening on a card. Alternatively you could use the F-keys on your keyboard to switch between Interact and Widgets mode (F1 and F2, respectively), click a widget, and press cmd/ctrl+R to edit its script.

I think in your example you may be tripping over Lil's order of operations (or lack thereof). Without parentheses, expressions are carried out strictly right-to-left. Parens may be useful for visually grouping arguments, but do not inherently denote lists. The following expressions are equivalent:

(me.size/2, me.size)
me.size/(2, me.size)
me.size/2,me.size

I think you intended:

(me.size/2),me.size

When the position for canvas.text[] is specified as an (x,y) pair, anchors control the positioning of the text relative to that point: "center" means the string will be centered upon that point.

When the position for canvas.text[] is instead specified as a (x,y,w,h) rectangle, anchors control the alignment and justification of text within that rectangle. Thus, to wrap and center text within the bounds of the canvas you'd want something like 

canvas.text[somestring 0,0,canvas.size "center"]

Or, incorporating a margin,

local margin:15
canvas.text[somestring margin,margin,me.size-margin*2 "center"]


How's that?

(1 edit) (+3)

Thanks! That's perfect. Just the F1/F2 hotkeys are a huge improvement.

The thing that's been tripping me up the most: "whitespace" (the boundary between function args)  has lower precedence than everything else, including comma. The right-to-left precedence only happens within each function argument, right? So in this line:

canvas.text[somestring margin,margin,me.size-margin*2 "center"]

..the 3 arguments are first split up, and then operations within them are run independently. Is that an accurate mental model?

(+2)

In C, expressions are explicitly terminated with a semicolon (;). In Lil, expressions are implicitly terminated when they are no longer "incomplete"; that is, their rightmost token is not a primitive or other syntactic form which "expects" an additional subexpression to the right. Outside comments and string literals, all whitespace in Lil is equivalent, so we can sequence "statements" with newlines between them:

ax:2+3
bx:ax*5

...or we could run them together on a single line:

ax:2+3 bx:ax*5

In this particular example we could even remove the space separating the two statements, because Lil identifiers may not begin with a number; splitting the "3" from the "bx" is unambiguous. I do not recommend using such a style in practice:

ax:2+3bx:ax*5

Lil interprets all three variations as the sequence of tokens (shown separated by whitespace):

ax : 2 + 3 bx : ax * 5

Whitespace is only required when Lil would otherwise "see" a single token but multiple tokens are intended:

onfoo   # reference to a variable named "onfoo"
on foo  # the keyword "on" followed by the identifier "foo"

The bracketed argument list for a function call is not a special case; just like the "do...end" of a function body, it accepts any sequence of expressions, each implicitly terminated. If the argument-expressions are complex, it may be stylistically clearer to parenthesize them and/or use whitespace to produce a visually apparent grouping, but this does not change how Lil interprets the expression. Consider:

x:11
y:first range 10
z:3*5
foo[x y z]

Versus the following equivalent alternatives:

foo[11 first range 10 3 * 5]
foo[(11) (first range 10) (3 * 5)]
foo[
 11
 first range 10
 3 * 5
]

Or, my preference for this particular situation,

foo[11 (first range 10) 3*5]

The comma operator (,) should always be understood as a primitive operator, rather than special syntax; it's of the same nature as the operators plus (+) or times (*).

Does that help clarify?

(1 edit) (+2)

💯 Thank you.