I've been playing with Wick Editor a bunch, trying to get some simple Newgrounds.io API widgets working in advance of the Wick Editor Game Jam.
Edit: The Newgrounds.io widgets are available for download now!
One of the appealing things about Wick Editor (besides being 100% free) is how similar it is to older ActionScript 2.0 versions of Flash, but it's definitely lacking a few things, and has a bunch of quirks.
So I wrote up a couple chapters/tutorials for using Wick Editor that may help people used to working a certain way in Flash, or other game frameworks.
Understanding "this" context
One of the most jarring things for me was figuring out what the 'this' scope refers to in different places.
In AS2 Flash, you could select a MovieClip and put code directly onto it with functions like onClipEvent(load) and onClipEvent(enterFrame). Within this code, if you used 'this', it would refer to your MovieClip instance.
In Wick Editor, you can do just about the same thing. You can put code directly on a Clip using 'function load()' and 'function update()'. Just like in Flash, using 'this' will refer to your Clip instance.
Now, if you were to try putting code on the timeline of your respective clips, you hit a major difference. If you add scripting to a key frame within a MovieClip, 'this' still refers to the MovieClip instance.
In Wick Editor, if you put code on a key frame, 'this' actually refers to the frame itself, not the Clip. To reference the clip from code on a keyframe, you instead need to use this.parentObject.
This is important to remember, especially if you put code on multiple key frames and expect it to reference code from older frames. Using 'this' on a Wick Frame literally only refers to that frame.
Let's say on frame 1, you use the following code:
this.alert_text = "Hello World";
Then on frame 2, we call:
alert(this.alert_text);
The alert will say 'undefined', because each Wick Frame is a separate object.
If you instead do this on frame 1...
this.parentObject.alert_text = "Hello World";
... and this on frame 2...
alert(this.parentObject.alert_text);
You will get the expected Hello World result.
Scoped Variables
Flash never really had global variables. If you wanted something to be universal, you would set it with _root.varName = "value";. Also, any variable not attached to an object, or _root, had to be declared with var varName = "value";
Because Wick Editor really just uses JavaScript, there's a bit of a difference in variable scopes and how to use them.
Any variable you set without a 'var' or 'let' declration, will be a global variable. (TECHNICALLY, it's attached to the Window object, but for all purposes, this is considered global).
If I write the following ANYWHERE in my code...
alert_text = "Hello World";
...I can access that value from any frame or object, no matter what (at least after it's been set).
If I write
var alert_text = "Hello World";
It's only accessible by whatever scope it's written in, or anything below that scope. If I wrote it at the top of a script on frame 2 of my timeline, only code in that frame could access it. If I put any functions in that same block of code, they can access it as well. If I put it within a function, code outside of that function would not be able to access it.
Examples:
var outer_value = "outer"; function test_inner() { var inner_value = "inner"; alert(outer_value); // alerts 'outer' alert(inner_value); // alerts 'inner' } test_inner(); alert(outer_value); // alerts 'outer' alert(inner_value); // alerts 'undefined'
Extending Clips
One big thing lacking from Wick Editor is a way to attach an external script to a clip, like Flash's 'Export for ActionScript' would let you do. There's lots of ways you could work around this, but you always want to keep duplicate code and memory management to a minimum.
One way to do this is to write single functions for controlling objects you intend to use in multiple places, such as a game enemy.
Because there's no support for external js files yet, I found the best way to do this, and keep things organized, is to create a layer and a single key frame for every object I want to write code for.
So I might add a layer and name it "Enemy1 Code". Then I'd add a keyframe on frame 1 and add this code to it:
Enemy1 = function() { // prevent this stuff from running more than once. if (this.extended) return; this.extended = true; // fires when the sprite is loaded this.load = function() { // start at the left side of the screen this.x = 0; }; // fires every game tick this.update = function() { // move the thing sideways, just to show this works. this.x += 10; }; };
Now I would create a new Clip. It would have to be on a lower layer, or later frame to ensure the above code had a chance to run. I would double click the Clip to edit it, and on it's first frame, I would add this code:
Enemy1.call(this.parentObject);
If you test your game, your object should see your Clip slide across the screen.
One thing I figured out is any code you put in a Clip's first frame will execute before it's load and update methods. If you put the code on the clip itself, this isn't always the case.
So what we are doing is using JavaScript's call method to execute all of the code in the global Enemy1 function, using the Clip instance as the 'this' scope, before the Wick engine calls it's load or update methods. When the Clip has loaded, those methods are ready to go.
That worked pretty well, but I realized if I ever wanted to clone this Enemy1 clip, it would create new versions of the load/update functions for every instance. This could mean a potential memory leak, and we want to avoid that.
The next thing I did was move those into static functions attached to the Enemy1 function object, and just reference them in the main Enemy1 function. Since we're referencing static functions, they won't need to be created for each instance anymore:
Enemy1 = function() { // prevent this stuff from running more than once. if (this.extended) return; this.extended = true; // fires when the sprite is loaded this.load = Enemy1.load; // fires every game tick this.update = Enemy1.update; }; // these always exist, and won't need to be re-created for every instance Enemy1.load = function() { this.x = 0; }; Enemy1.update = function() { // move the thing sideways, just to show this works. this.x += 10; };
Faking a Library
One glaring omission to how Wick Editor currently works is the asset library only holds your image and media files. In Flash it contained all the Graphics, Buttons and MovieClips you created, and you could attach names to them so you could dynamically add them to your stage.
Wick doesn't have anything like that right now. The best you can do right now is make all of your clips, and hide them off-stage somewhere, cloning them as needed.
Using this method, you want to make sure your "library" of clips aren't executing any significant code, but make sure when you clone them that they behave as expected.
I figured a great way to do this is to create a master LibraryAsset function that could handle registering clips and creating new instances with a subclass attached.
I ended up making a little demo where a bunch of space ships fly across the screen at varying scales and speeds.
To start, I made my global LibraryAsset function:
/** * name - The string name you will use to get clones of the asset * clip - A reference to the actual Wick Clip * subclass - A reference to the subclass this asset will use when cloned **/ LibraryAsset = function(name, clip, subclass) { // only add a clip once if (LibraryAsset.assets[name]) return false; // make a reference to the subclass we'll be using clip.subclass = subclass; // make me invisible, just to be safe clip.opacity = 0; // store a reference to the clip by name LibraryAsset.assets[name] = clip; }; // stores references to our library assets LibraryAsset.assets = {}; // Use this to get a cloned asset, by name, with it's subclass applied. LibraryAsset.get = function(asset_name) { // throw an error if we try getting an undefined asset. if (typeof(LibraryAsset.assets[asset_name]) == 'undefined') { throw('Invalid asset name: ' + asset_name); } // get a reference to the asset clip we want var asset = LibraryAsset.assets[asset_name]; // create a clone var clone = asset.clone(); // make it visible clone.opacity = 1; // apply the subclass so the clone actually does stuff. asset.subclass.call(clone); return clone; };
Then I made the subclass to control my space ships:
Ship = function() { // reference our static functions to save memory this.load = Ship.load; this.update = Ship.update; }; // on load, we want to set a starting position, scale & speed. Ship.load = function() { // set the starting position this.x = -100; this.y = randomInt(0, project.height); // scale our ship and set it's speed var scale = randomFloat(0.5, 1); this.speed = 30 * scale; this.scaleX = scale; this.scaleY = scale; }; // on update, we make the ship move right until it's off-screen, then reset it Ship.update = function() { // move the ship this.x += this.speed; // if it's off-screen, call our load function again if (this.x > project.width + 100) { this.load(); } };
Next I drew my space ship and made it into a Clip. I double clicked that to edit it, and on the first frame I added the following code:
LibraryAsset('ship', this.parentObject, Ship);
This basically told my LibraryAsset function that I want this Clip to be called 'ship', and to use my Ship subclass to control it.
If I test my game at this point, I basically have a blank screen because the LibraryAsset function hides my ship, and it isn't using the subclass at all right now.
To finis the demo, I added this code to the root timeline:
for(var i = 0; i < 20; i++) { var ship = LibraryAsset.get('ship'); }
This gets 20 copies of my ship asset WITH the subclass applied. When I test my game now, I have a screen full of ships zipping across as intended.
You can see my working demo and grab the .wick file at https://www.newgrounds.com/projects/games/1327369/preview
Hopefully somebody finds my experiences with Wick Editor useful and is inspired to make something cool for the game jam!