I’m still compiling my feedback from the jam (I have a lot ) but I felt that the scripting workflow in particular could use some good discussion, so I’m posting my thoughts here. I’m really excited about how far Wick has come and its potential as a very robust animation and game development tool, and resolving the issues below would be an important step in realizing that.
Note that I’m not a JavaScript expert, so please correct me if some of these are points are inaccurate or have alternate solutions.
In summary, the way Wick handles scope and context can be difficult to deal with.
-
Functions defined like below in one code tab or one frame of a timeline should be accessible in others. They would attach to the parent clip, or
root
if there is none.function foo () { console.log("hi!"); } //in the next frame... foo(); //error
-
Currently, I have to do this:
this.foo = function () { console.log("hi!"); } this.foo();
-
-
Functions sometimes refer to the wrong scope. In the example file ParentAndChild, there is a Clip named
Clip
and a child clip inside it.-
//ATTACHED TO ROOT TIMELINE //(OR ATTACHED TO THE PARENT CLIP ITSELF, SAME RESULT) Clip.foo = function () { Clip.x += 100; }
-
//INSIDE CHILD CLIP's TIMELINE this.parentClip.foo(); //returns an error (Clip is not defined) because there is no //Clip called "Clip" around to increase the x value of.
-
When I call this, I want it to run from
Clip
's scope, not its child’s scope. (Naming the parent clip something else doesn’t change the result.)- Note that replacing the first snippet with
this.foo = function () { this.x += 100; }
and moving it to the Clip itself works as intended; the parent object shifts its position.
- Note that replacing the first snippet with
-
-
Undeclared variables can cause trouble. (These are variables that are never declared with
var
or as a property of an object. They automatically attach toWindow
and behave differently than other variables.)-
If I, in a root timeline script, define an object like so:
Foo = {}; Foo.bar = function () { rootTimelineClip.play(); console.log(otherRootTimelineClip.identifier); }
-
then call it within
rootTimelineClip
like this:Foo.bar();
, weird errors can happen because it is running from the Clip’s scope rather than the root timeline’s scope.- Case in point: in the example file “ProjectStops2”, I have some functions defined like this in Frame 1 of layer “Actions”:
Game = { //stuff }; Game.caption = function(text) { alert("Setting caption to \""+text+"\""); Caption.text.setText(text); alert("all done"); } Game.guessLetter = function(letter) { alert("Game.guessLetter("+letter+") is running"); Game.caption(letter); }
-
In frame 3 of the Clip “Menu”, I have this code, which runs both of the functions above. However, they silently fail without throwing errors, probably because they are accidentally being executed from a lower scope.
-
if (Utils.isStringLetter(key)) { alert("About to run Game.guessLetter(key). key = "+key); Game.guessLetter(key); alert("THIS alert() NEVER GETS RUN FOR SOME REASON"); }
-
Here’s what happens when I run this project:
- The alert box says
Setting caption to
some unrelated introductory text, since I callGame.caption
when the frame is first entered. TheCaption
object’s text is set successfully. - Alert box:
all done
- I click the pink button (
Menu
) and type the letter “a”. (Any letter of the alphabet will do.) - Alert box:
About to run Game.guessLetter(key). key = a
- Alert box:
Game.guessLetter(a) is running
- Alert box:
Setting caption to "a"
- Nothing changes on-screen. The caption is never set.
- The alert box says
-
Solutions
- What if Wick automatically attached undeclared variables (like
Foo
above) to the Clip that is calling the function? So if a Clip calledmyClip
callsmyVariable = 3
, Wick will check if there is currently amyClip.myVariable
defined previously. If not, it will treat the statement as though you typedthis.myVariable = 3
. (This applies whether the script is attached to the Clip or on its internal timeline.) For the root timeline, it attaches toroot
orproject
. - You could also ban undeclared variables – meaning, Wick throws an error when it finds one. I’ve read that they are bad coding practice anyway; they can cause hard-to-find ambiguities in code, and since they attach to
Window
they can easily overwrite (or be overwritten by) other code. However, this means that users must make sure to declare every variable they use. (Like this:var foo;
and I thinkthis.foo;
counts too.)
- What if Wick automatically attached undeclared variables (like
-
I used a ton of undeclared variables in my jam game before I found out how dangerous they were. Almost every game-state variable is attached to one of 3 big global objects:
Game
,Match
, andUtils
, which meant I had to type stuff likeMatch.blahblahblah
every single time I wanted to access something. I would like to avoid this problem next time and be able to write less verbose code. (See below.)
-
-
When I was scripting inside Clips’ timelines, I felt like I had to use the
this
keyword constantly.-
//Most of this is real code, some has been adjusted for clarity this.clipLength = 30; //Number of times this clip has passed on a potential puzzle this.numPasses = 0; this.visited = []; this.qna = {}; this.qnas = []; this.loadPuzzle = function(variant) { this.stop(); this.numPasses = 0; //mark that you've been here this.visited[this.currentFrameNumber] = true; if (variant !== undefined) { this.qna = variant; } else { this.qna = this.qnas[random.integer(0, this.qnas.length-1)]; } }
-
Could Wick’s script execution be adjusted so that instead I can put:
-
var clipLength = 30; //Number of times this clip has passed on a potential puzzle var numPasses = 0; var visited = []; var qna = {}; var qnas = []; function loadPuzzle(variant) { stop(); numPasses = 0; //mark that you've been here visited[currentFrameNumber] = true; if (variant !== undefined) { qna = variant; } else { qna = qnas[random.integer(0, qnas.length-1)]; } }
-
…And still have other Clips be able to access
clipLength
and the other variables?
-
-
-
I’d also like the ability to use my browser’s dev console to print the root timeline and its children. Currently, I can’t find where it stores the hierarchy of Clips that you access through scripting. Perhaps there could be an object attached to
Window
calledWickRoot
or something, which contains all the child Clips, named according to their identifier. Then users could easily read their values and debug them whenever they want - no need to implement a custom debugger tool! (For example, typeWickRoot.object1.x
) to get object1’s x value.) -
I also want to be able to run functions like
setTimeout
from the scope of a Clip. Currently, it throws reference errors, probably due to incorrect scope (fromWindow
rather than from the WickObjects). Wick could have asetTimeout
wrapper function to work around this.- This script, attached to the root timeline, logs an error to the browser console:
"ReferenceError: gotoAndStop is not defined"
setTimeout(() => { gotoAndStop(2); }, 1000);
- This script, attached to the root timeline, logs an error to the browser console:
Example Files
BugReport_ParentAndChild.wick (1.8 KB)
BugReport_ProjectStops2.wick (432.1 KB)
BugReport_FooBetweenFrames.wick (1.9 KB)
BugReport_SetTimeOut.wick (1.7 KB)
Wow, that was a lot. I’ll be posting more scripting-related feedback later - mainly about the UI and missing features like Find & Replace. I encourage everyone to leave your own feedback, issues, or potential solutions here!