Here I present an idea for a ground up re-design of Construct's event system. This is purely for the logic portion and doesn't cover engine features. It's not entirely fleshed out and there are details I'm probably forgetting. The purpose is purely for fun, and may never see the light of day.
conditions
First off conditions are greatly simplified.
Here are the system conditions:
* "if" which is basically the same as system->compare
* "else" this will differ from C2's else in that it doesn't pick, it's only if the previous event block was false.
* "loop" which will cover all looping: and will look like "loop: var i=0 to 10", "loop: var i=sprite.count",...etc. More on what "var" is later.
* "split filter" my solution to else. It's like "filter" below but the unpicked instances will be put in another type. Example "split filter: sprite, sol other: sprite.x>0", after which "sprite" will be all the instances below 0 and "other" will be all the instances above zero.
Object conditions will be:
* "filter" which is the catch all picking. For example "sprite: filter sprite.x=2" will replace "sprite: pick by x=2". It still follows the rule if nothing is picked then the following conditions in the block don't run.
"sort" the idea with this one is is an object type is a list of objects and can be sorted. The closest in C2 already is the for each ordered. One example use would be "sprite: sort sprite.y" which would sort the object list from low to high instead of it's current order.
actions
Actions as well will be simplified. Basically for values, instead of "sprite: set x to 10" it would be "sprite.x=10". More on other kinds of actions later.
variables
Next up are variables definitions. The big thing here is you can put them anywhere you need them. A list of possible places:
* in between event blocks, like C2 already does
* inside event blocks
* in the actions column.
* special cases: var in "loop", and sol in "split filter".
Next we have two kinds of variables:
* "var" this is basically the same as C2's variables. aka. number and text. However this can be extended to array, object, dictionary, etc...
* "sol" this defines a new type on the fly, which will replace families and make picking two seperate instances simpler. From the point it's defined it acts like any other object type.
Family example:
sol family=sprite, sprite2, sprite3
+----------------------------+
| family: filter family.x<10 | family.x = family.x+1
+----------------------------+[/code:3j88tc5m]
General picking example:
[code:3j88tc5m]+----------------------------+
| sol other= sprite | sprite.x=200
| sprite: filter sprite.x=10 | other.x = 11
| other: filter other.x=11 |
+----------------------------+[/code:3j88tc5m]
[b]expressions[/b]
Referencing seperate instances with expressions will be improved.
You can still do the familiar pattern for an action: "sptite.x = sprite.x+1" which will add 1 to the x of every picked instance.
You can also use "sprite[0].x" which is about the same as c2's "sprite(0).x" but will reference the first picked instance of sprite instead of just the first instance. You can also do stuff like this:
x of first picked sprite: "sprite[0].x"
x of last picked sprite: "sprite[-1].x"
It even applies to the action:
[code:3j88tc5m]+----------------------------+
| sprite: filter sprite.x<10 | sprite[0].x = 11
| | sprite[-1].x = 22
+----------------------------+[/code:3j88tc5m]
Also objects can be assigned to variables.
[code:3j88tc5m]+----------------------------+
| start of layout | sprite.child = sprite2
+----------------------------+
+----------------------------+
| sprite: filter sprite.x<10 | sprite.child.y = 11
+----------------------------+[/code:3j88tc5m]
Another reason for this is to make create an expression if you don't want to affect the sol:
[code:3j88tc5m]+----------------------------+
| start of layout | var new = create("sprite")
| | new.x =33
+----------------------------+[/code:3j88tc5m]
Of course you can use create as normal as well which only picks that new sprite. At this time of design the same top level picking as with C2 is used.
[code:3j88tc5m]+----------------------------+
| start of layout | create("sprite")
| | sprite.x =33
+----------------------------+[/code:3j88tc5m]
[b]Functions[/b]
This is the most significant re-design. The goal is to make functions be able to be used perfectly as a condition, action or expression.
First off parameters are named and can be object types.
[code:3j88tc5m]+-----------------------------+
| on function "turn" (ot, deg)| ot.angle = ot.angle+deg
+-----------------------------+
+-----------------------------+
| start of layout | call turn (sprite, 90)
| | call turn (sprite2, 45)
+-----------------------------+[/code:3j88tc5m]
Next the return action will actually exit the function instead of just setting the return value.
[code:3j88tc5m]+-----------------------------+
| on function "dist" (a, b) | return distance(a.x,a.y,b.x,b.y)
+-----------------------------+
+-----------------------------+
| start of layout | sprite.width=call.dist(sprite1, sprite2)
+-----------------------------+[/code:3j88tc5m]
Next in order for a function to modify a sol, returnSol is used instead. This allows it to be used as a condition. ReturnSol can have multiple values.
[code:3j88tc5m]+-------------------------------------+
| on function "indist" (a, x,y,dist) | returnSol a
| a: filter distance(a.x,a.y,x,y)<dist|
+-------------------------------------+
+-------------------------------------+
| call "in dist"(sprite, 0,0,100) | sprite.angle = sprite.angle+1
+-------------------------------------+[/code:3j88tc5m]
The synatax of calling sould simplified somehow. Above are just a few ideas.
Anyways that's a rough overview. I'll have to prototype it in order to flesh out a few of the details.