(after:) stops unexpectedly on click

I’m having trouble with Twine’s (after:) macro - Harlowe 3.2.2 in Twine 2.3.14. Here’s an example of what I’m working with:

You feel strange.(after: 1s)[

Not necessarily bad.](after: 2s)[

Just strange.](after: 3s)[

You appear to be in a shopping centre.](after: 4s)[

You are with friends. ^.^](after: 5s)[

Just you and 30-50 of your absolute besties all having a wonderful time.]

The goal is to have each new line appear after a brief delay. Currently it all works as expected, but only if the reader doesn’t click while it’s doing its thing. As soon as you click anywhere on the passage (even to open up Debug View when testing), the next line will fail to appear.

I realise (after:) is still pretty new and can confirm that just using (live:) and (stop:) in its place will solve the problem - hopefully that’ll help anybody who might find this while trying to resolve the same issue. Still, I do prefer the more concise syntax for (after:) and have rather a lot of these to write for this particular game, so if anybody happens to know what’s causing the problem or how to solve it for the (after:) macro specifically then I’d be very glad of the help.

1 Like

Yeah, the (optional) second argument of (after:) seems to cause problems if you leave it out. :frowning: Try changing them all to (after: 1s, 0) or similar.

1 Like

The ‘optional’ 2nd argument of the (after:) macro isn’t really optional if you don’t want any mouse or keyboard events interfering with your timers. However as explained by Josh Grams, simply passing a zero 0 as the 2nd argument disables that macro’s monitoring for such mouse & keyboard events.

A warning about about the possible side effects of having multiple (after:) or (event:) timers active at the same time.
As explained in the Harlowe manual the (after:) macro is a short-cut for the (event:) macro, which in turn is a short-cut for a (live:) plus (stop:) macro combination. So when you write something like…

(after: 3s)[...do this thing...]

…you are basically writing…

(event: when time > 3s)[...do this thing...]

…which in turn is basically the equivalent of writing…

(live: 20ms)[
    (if: time >= 5s)[
        (stop:)
        ...do this thing...
   ]
]

So as seen by the above the condition you pass to either the (after:) or (event:) macro is checked 50 times a second.

What isn’t explained in the documentation is that each time that check if performed the user’s ability to interact with the page is affected, and the scale of that interference multiples by each of those macros you have active at the same time. And the complexity of the check being performed influences how long each of those interruption lasts.

eg. if you have 3 of those macros active at the same time then the user’s ability to interact with the page is interrupted 150 times a second (3 * 50), if you have 5 of those macros active then it 250 times a second.

3 Likes

This is exactly the kind of simple solution I was hoping for - thanks!

Thanks for the comprehensive explanation! I’m hoping that what I’m doing is simple enough that it won’t have a significant impact on performance, though I have noticed that things tend to break down a little when using (live:) extensively (particularly with times under a second). I’d ideally like to set the delay with a variable, though - so that an impatient reader could avoid long waits - and I realise that might make for a more complex check.

If (after:) is set to refresh every 20ms specifically, would this make (live: 1s) a more suitable choice? That is, does specifying 1s in (live:) avoid unnecessarily frequent checks? If so, I might put up with the extra typing for the sake of performance.

Also, do the (after:) macros stop interfering with the user’s ability to interact with the page once their conditions are met? I imagine most of my clickable links would come towards the end of a passage, with very few (after:) macros left to run at that point. I could certainly avoid throwing in links while a lot of macros would still be active.

Also, do the (after:) macros stop interfering with the user’s ability to interact with the page once their conditions are met?

Yes, the timer associated with each of those macro calls ends when the macro’s condition is met.
eg. the equivalent of a (stop:) is done internally.

There are many ways you could re-implement your example so that less timers are active at the same time. The following is one example that still uses the same (after:) macros call you did, except it only has one such macro active at a time, and it uses Hidden Hooks combined with the (show:) macro to help control the placement of the ‘revealed’ sections of text.

You feel strange.

|line2)[Not necessarily bad.]

|line3)[Just strange.]

|line4)[You appear to be in a shopping centre.]

|line5)[You are with friends. ^.^]

|line6)[Just you and 30-50 of your absolute besties all having a wonderful time.]

{
	(after: 1s)[
		(show: ?line2)
		(after: 2s)[
			(show: ?line3)
			(after: 3s)[
				(show: ?line4)
				(after: 4s)[
					(show: ?line5)
					(after: 5s)[
						(show: ?line6)
					]
				]
			]
		]
	]		
}

note: the indentation and line-breaks I’ve used to format the above example aren’t required for the solution to work, they just make it easier to see the way I’ve structured the delayed calling of each (after:) macro.

2 Likes

Thanks again! I’ve so far not run into any problems while testing this (at least on a fairly capable machine) but this does look like a more sensible approach overall.