Idea: make async easier with "Then" event

Discussion and feedback on Construct 2

Post » Tue Apr 14, 2015 9:06 pm

@Kyatric Thanks for the reply!

I tried out some more things. Conclusion i get is that every thing has to be separated to work correctly.

This way i need a lot of events to get the simplest results..

Below is what i tried and it works but well.. that's a lot of events for something simple.

Is this for now the way to go?

P.s. here is the capx: ... .capx?dl=0
Posts: 163
Reputation: 2,507

Post » Tue Apr 14, 2015 9:36 pm

I think that the "Then" idea is only useful for cases that only requires a single value check like AJAX and Pathfinder. But for those cases I think the current system with custom conditions is more descriptive of what it does.

For storage I would prefer to process groups or batches of values at once, otherwise it would be a PITA. Like setting together the X and Y of an object from LocalStorage in a single action, instead of storing the returned values in local vars as buffers:
Code: Select all
Sprite: Set position to ( LocalStorage.get("X") , LocalStorage.get("Y") )

I propose adding tags to each 'get item' action, like this:
Code: Select all
>Keyboard: On Space pressed
-LocalStorage: Get item "PlayerX" under tags: "SpriteAttributes", "SpritePosition"
-LocalStorage: Get item "PlayerY" under tags: "SpriteAttributes", "SpritePosition"
-LocalStorage: Get item "PlayerHealth" under tags: "SpriteAttributes"
-LocalStorage: Get item "PlayerShield" under tags: "SpriteAttributes"
-LocalStorage: Get item "PlayerWeapon" under tags: "SpriteAttributes"

Then it would be possible to test both when all the items of a specific tag are ready, or when a single item is ready:
Code: Select all
>LocalStorage: On all items from tag "SpriteAttributes" ready
-Sprite: set position to ( LocalStorage.get("PlayerX") , LocalStorage.get("PlayerY") )
-Sprite: set variable "Health" to LocalStorage.get("PlayerHealth")
-Sprite: set variable "Shield" to LocalStorage.get("PlayerShield")
-Sprite: set variable "Weapon" to LocalStorage.get("PlayerWeapon")

>LocalStorage: On all items from tag "SpritePosition" ready
-Sprite: set position to ( LocalStorage.get("PlayerX") , LocalStorage.get("PlayerY") )

>LocalStorage: On item "PlayerWeapon" ready
-Sprite: set variable "Weapon" to LocalStorage.get("PlayerWeapon")

In my opinion this system can be more flexible and indicates more clearly what it does.
I also think that renaming the 'LocalStorage' plugin to just 'Storage' would make things less verbose without compromising the understanding of what it does.


I thought a bit more and while the tag system can work, it would require to think and track different tags if you want to get the same values multiple times along an event sheet. Now I see that the "Then" proposal is all about a scoping system for asynchronous events to relate only to the events that called them (without the need to explicitly name them).

I always felt the need for something like this when using timers, and yes, it would be useful for all kind of asynchronous events.

Why would the "Then" trigger only be able to have a single async action in the previous event? Couldn't it run like an 'all completed' for the previous event async actions, and use explicit key references in it's actions like my suggestion above? I think the use of 'LocalStorage.ItemValue' instead of an explicit reference like 'LocalStorage.get("PlayerWeapon")' is what it's limiting it. If you store all the loaded values in a buffer under the hood you could explicitly reference them all.

Another thought is that since this is a problem of scope representation at hearth, maybe sub-events can be used somehow for an elegant solution. I'm not sure how, but it may be a possibility consistent with how local vars scope works.
Last edited by Animmaniac on Wed Apr 15, 2015 3:51 am, edited 4 times in total.
Scirra Employee
Posts: 709
Reputation: 17,521

Post » Wed Apr 15, 2015 12:47 am

I only have one thing to say, please do not use "then" because just like you say, If..then. It would confuse me heavily if I was newcomer. (with the if..then in mind)

"On done" feels better.
Posts: 447
Reputation: 10,735

Post » Wed Apr 15, 2015 2:42 am

A "cache" logic might reduce the response time and the complex of reading action.
For example, a cache with dictionary structure -
User could load this dictionary cache by reading all key-value pairs into memory, then these values could be read immediately.

The structure stored in local storage might be
- Index: A JSON sting to store the keys
- Content: Key - value pairs
Plugin first read index, then read all key-value pairs. And the manipulation of this dictionary cache is just like official dictionary object.

Writing action might be triggered after ticking (in tick2() maybe), to write key-value pairs with dirty bit = 1.
Posts: 4,387
Reputation: 136,964

Post » Wed Apr 15, 2015 3:51 am

I agree with Rex. When I suggested a model to deal with the change for Android and to switch over to a memory management similar to AJAX triggers. I suggested a cache. I still suggest a cache.

Since session is removed as it does seem redundant. Why not offer Cache storage as part of LocalStorage. When using cache storage there is always a running memory copy that is like a dictionary and behaves just like webstorage. Cache storage is loaded at the beginning of the app and regularly writes to storage location. So now you get the benefit of the immediate old style, but deals with work around of using the DB styles. This then means you don't need "Then" as a follow up.

Also add save frequency based on how often the cache should save. A sample would be "Data Change, LayoutEnd, Once a Minute, Never". Then also have an option to "save cache".

So now you get the best of both worlds. high memory data should not be in cache. where as small memory data would be.
Posts: 2,455
Reputation: 15,013

Post » Wed Apr 15, 2015 5:17 am

1 - agree with suggesting "cache"
2 - please don't use "then" because It would confuse
3 - will this new treak really optimise performance because we use webstorage generally on special even like game over or start of game when everything is not moving and activating so that will not affect a lot
4 - any way thanks a lot but need more explainations
Posts: 783
Reputation: 8,238

Post » Wed Apr 15, 2015 7:33 am

I like the sound of jayderyu's idea. It seems to make more sense and seems more flexible.
Posts: 1,097
Reputation: 11,180

Post » Wed Apr 15, 2015 9:20 am

I agree with rexrainbow and jayderyu idea. It seems to be the better implementation considering I am storing and planning to continue a lot of data on webstorage and in the future, local storage.
Posts: 248
Reputation: 8,694

Post » Wed Apr 15, 2015 9:40 am

I am not convinced, I mean would not that be exactly like using a dictionnary to store the keys while saving them? And if so, would that not compromise the whole point of it being asynchronous (Aka:whendealing with a lot of keys)?
unless I misunderstood and you mean having basically a dictionary with a "Push to Local storage" action when needed, but even then, I feel something is not quite right..
Game design is all about decomposing the core of your game so it becomes simple instructions.
Posts: 2,111
Reputation: 16,771

Post » Wed Apr 15, 2015 9:58 am

No, I don't think a cache is a good idea. I previously considered it to keep it compatible with WebStorage, but decided not to for two reasons:

- performance: the speed at which you can read and write values to the actual storage is proportional to the total amount of data in storage. So suppose you had 300mb of data in storage, and your app wants to read a single number, change it, then write the number back (e.g. a simple play count). That involves reading 300mb of data, plucking out a single value, then writing 300mb of data again.
- it's always going to be unreliable: you can't really solve the problem of how to write the cache to the actual storage. At any time the user could just close the browser, and then there is no opportunity to do an asynchronous write to storage, and the changes in the cache are lost. There aren't any good options to mitigate that. Writing storage every time it changes will completely hammer performance (imagine writing 300mb every time any key changes), and throttling it to a timer means you can still lose data (e.g. if you write every minute, you can still lose up to a minute's worth of data).

Besides you can do this yourself already if you really want to: just store the JSON data of a dictionary object in storage - but you'll probably have subtle and frustrating issues with data being lost randomly.

I agree "Then" is a poor name... I think I'll go with "Next" for the time being.

Reading @Animmaniac's post, I think actually it could be a good idea to make "Next" act like "All completed", so it doesn't have the one-async-action limitation. The problem is then how to access multiple storage keys, but I think it could load multiple keys at once by a comma-separated list, e.g.:

- Get item "level1score,level2score,level3score"

> Next
- Set level1score to LocalStorage.ItemValue("level1score")
- Set level2score to LocalStorage.ItemValue("level2score")
- Set level3score to LocalStorage.ItemValue("level3score")

This could of course use three separate "Get item" actions, but I think it's clearer with a comma-separated list: there's only one trigger that fires for the one action, instead of three triggers firing and "Next" only really triggering on the third, which could make it tricky to identify which values should be available to the ItemValue expression (since it should only make available values that the trigger is firing for).
Scirra Founder
Posts: 24,106
Reputation: 190,410


Return to Construct 2 General

Who is online

Users browsing this forum: Yahoo [Bot] and 7 guests