Contact Info / Websites
Ever try to run an ancient DOS game on a modern PC? It's not easy, right? Imagine a day when the same thing happens to the Flash movies on Newgrounds. You want to watch The Final Task, but you can't. Even today, it's a struggle to watch a Newgrounds cartoon on your phone or tablet.
Newgrounds has 15 years of Flash content. That's 15 years of history and great animations that people could miss out on!
This is one of the main reasons that I've been working on Swivel, a new SWF-to-video converter. We want to preserve the legacy content on NG and keep it easily accessible, so that it can be watched for another decade!
Even forgetting about past content, it's been notoriously difficult for current users of Flash to get their movies out of the program. "How do I convert my Flash to video?" was the #1 question that every animator would ask me! Animators simply couldn't use the Flash software in the way they'd like. Very frustrating to hear.
But now Swivel is publicly released! It's been a series of narrow escapes from near impossibility, but I truly think Swivel is the best choice for converting your Flash animations to high-def video, so please give it a shot. Hope it helps!
A few weeks ago, I had the pleasure of attending Flash Camp Philadelphia. It was a great conference -- nice atmosphere and interesting people! I'm looking forward to it again next year.
I was also invited to speak at the conference, so I gave a talk on ActionScript 3 game programming. I spoke about how games are built, the pros and cons of the standard game inheritance hierarchy, and a few alternatives to it. I also talked about some techniques such as:
- Timing using getTimer()
- Decoupling game logic and animation from Flash Player's frame rate
- Rolling your own display list for benefits such as depth sorting
- Using the Flex Builder profiler to optimize your game
A lot of these techniques are used by the newer game frameworks such as Flixel, so it's good to have an understanding of what's going on behind the scenes!
I've uploaded the slides and sample code. Hopefully someone finds it useful!
Not too long ago, my Flash port of Doom was nominated for the FHM's 2009 Web Game Awards. With the help of you awesome NG users, it managed to win the contest, including a £3000 cash prize!
It's cool that the game won, but I wasn't crazy about taking the cash prize. The folks at id Software are the ones who created this incredible game -- all I did was recompile it into Flash. That's nothing compared to creating original and great Flash games like Robokill and Portal!
So I've decided to donate the prize to a good cause. I've donated half of the winnings to the Canary Foundation. The Canary Foundation is dedicated to finding simple tests for detecting cancer early, when it's most treatable. You can read a good article on The Canary Foundation over at Wired.
I've donated the other half of the winnings to the Free Software Foundation. id Software has always been a supporter of free software and is kind enough to publicly release the source code to its old games. This lets hackers like me tinker and learn! It seems only fitting to give back to the free software movement. :)
To go along with this blog post, I was planning to update Flash Doom with some bugfixes. Well, I got a little carried away -- because I added support for Heretic and Hexen by Raven Software! Instead of flooding the Portal with conversions, I've packaged them all into the Doom Triple Pack! I did add mouse control, but Flash isn't very good at it, so unfortunately you have to click and drag. All three games have medals to collect. Enjoy!
The player is at position (playerX, playerY), and an enemy is at (enemyX, enemyY). You want the enemy to move 5 units directly toward the player. A lot of times, you'll see people do:
dx = player.x - enemy.x;
dy = player.y - enemy.y;
angle = Math.atan2( dy, dx );
speedX = 5 * Math.cos( angle );
speedY = 5 * Math.sin( angle );
enemy.x += speedX;
enemy.y += speedY;
It took us three hefty trigonometry operations: atan2, sin, and cos. First, we're going from the x and y components (dx and dy) to the angle using atan2. Then we're going BACK to the components using sin and cos! Surely we can avoid running in a circle like this! (haha, in a circle, get it?)
It's a little easier if you think with vectors. We already have a vector pointing in the direction we want: the <dx, dy> vector points straight from the enemy to the player! All we have to do is resize it to our desired speed.
dx = player.x - enemy.x;
dy = player.y - enemy.y;
length = Math.sqrt( dx*dx + dy*dy );
dx /= length; dy /= length; // normalize (make it 1 unit length)
dx *= 5; dy *= 5; // scale to our desired speed
enemy.x += dx;
enemy.y += dy;
We normalize the vector by dividing it by its length. Now our vector has a length of one unit, so we can scale it by our desired speed. Instead of three trig functions, we now have just a sqrt!
It's common to rotate your enemy to face the player. In this case, you DO want to use atan2 to get the angle. You can still avoid the sin and cos, though, by doing what we did above.
Just thought I'd share this little tip, hope it's helpful to someone. Here's a bad diagram:
What an amazing time!
The London meet easily took the Newgrounds community to the next level. There were NG users as far as I could see in every direction. Seriously, just look at everyone! It was totally humbling and inspiring to be surrounded by so many awesome people.
It was my first time out of the US, so I did manage to do a bunch of touristy stuff. What really blew me away about London was the architecture. There are tons of ridiculously old buildings, and you really don't see that in the States. The best part is the contrast between these ancient structures and the funny looking modern buildings, like "The Leaning Tower of Pizzas" and this very phallic tower.
Some brief highlights:
- Watching the Eagles game with Bob, Tim, Poozy, and Swain
- Weebl's surprise appearance
- Tom breakdancing
- Apologies to Kirk-Cocaine, whose pint I lost, and Evildog, who was the target of my unbridled rage :)
- A rapping hobo
- Shalashaska, the skeletal gimp
Check out Luis's page for some nice memories. It really was a pleasure to meet all of you, and I hope we can meet again sometime!
There are a few things missing in the port:
- No music. Doom's music files are MIDI, and Flash can't natively play MIDI files. I was tempted to include OCRemix's Doom soundtrack as MP3, but even a few of the songs would be bigger than 2.5 meg Flash file!
- No mouse control. Flash has no way of "locking" the mouse to the game area, so it's impossible to do true Quake-style mouselook. I'll be ranting about this more in a future post.
- Bad keyboard controls. Doom's original keyboard controls (ALT, CTRL, etc.) don't get along with Flash and caused odd behavior on different platforms. I changed them around, but what I really need to add is configurable controls.
- Yea, the secret is missing in E1M1 and the BFG isn't there. These weren't in the shareware version! :)
As per the GPL license, the source code for the port is publicly available! Feel free to play around with it here:
Also, check out Max's AS3 Doom engine. He actually reprogrammed the DOOM-style raycasting engine in AS3, before Alchemy was even announced! Wow!
I wish I could rig it up to run in Flash 10, but unfortunately the Flash implementation of Pixel Bender doesn't support loops -- bummer!
edit: Glaiel made a Mandelbrot renderer in PB a few months back -- check it out!
I started playing around with Adobe's Pixel Bender, the image processing language that will be integrated into Flash 10. Pixel Bender lets you make things like custom filters and blend modes, so I'm sure we'll see all kinds of cool effects pop up.
After reading through the Pixel Bender spec, I was impressed that it had good support for conditionals and loops, which is a tough spot for these shader languages. So what do I do? Push it to the max and make a raytracer, of course. :)
It's your run-of-the-mill raytracer featuring ambient, diffuse, and specular lighting, reflection, and shadows. There are a few sticking points I had to work around. For one, there's no recursion in Pixel Bender, so spawning a tree of rays from a single ray would be tough. This rules out having objects that are both reflective and refractive, for example. Secondly, there's no indirection. This makes it difficult to have different type of primitives, so I'm rendering spheres only.
The Pixel Bender toolkit renders using the GPU, so its really cool to see the picture update at 60fps. :) It's even more awesome to think that this could run inside Flash Player 10! Unfortunately, it looks like that's too good to be true. For one, Flash 10 only supports a subset of the Pixel Bender spec. You could work around this, but even then, all signs point to Flash 10 running these shaders on the CPU only. Setting the Pixel Blender toolkit to run in CPU mode slows the raytracer to a crawl. :(
Watching the GPU do all this crazy stuff makes me wonder about the future of graphics hardware. As we add things like branch logic to our GPUs, they become more and more like a generalized CPU. Will we get to a point where the GPU/CPU distinction doesn't even exist, and your "graphics card" is just used as another core? Or will the GPU continue to be distinct as a very specialized, parallel number cruncher? I'm not really a hardware guru, so maybe I'm way off base here.
In Flash, throw a movie clip on the stage and give it an instance name of "clip". Go to Modify -> Transform -> Flip Horizontal. Then do a trace(clip._xscale); 100 is traced, even though you might expect -100. What gives?
Flipping horizontally is the same as flipping vertically and rotating 180 degrees. This means that _xscale and _yscale can either be positive or negative. Flash can't really tell which you've done, so it assumes positive.
The position info of every graphic in Flash is stored as a 3x3 homogeneous matrix:
[[ a b tx ]
[ c d ty ]
[ 0 0 1 ]]
This is a combination of a scale, rotation, skew, and translation.
A scale transformation looks like:
[[ x 0 0 ]
[ 0 y 0 ]
[ 0 0 1 ]]
where x and y are the amount of scaling on the x and y axis. Note that _xscale = x*100
A rotation transform is:
[[ cos(t) sin(t) 0 ]
[ -sin(t) cos(t) 0 ]
[ 0 0 1 ]]
where t is the amount of rotation.
Combine these by matrix multiplication, and you get:
[[ x*cos(t) x*sin(t) 0 ]
[ -y*sin(t) y*cos(t) 0 ]
[ 0 0 1 ]]
Flash only knows the final values (a, b, c, d). We know a = x*cos(t) and b = x*sin(t). You can start to see the sign ambiguity appear already -- whenever you multiply two values, you lose some information about the signs of those values.
To calculate _xscale, Flash has to solve for x. Your first thought might be x = a/cos(t), but that requires you to find out t. A more elegant way to solve this is to realize that the ( x*cos(t), x*sin(t) ) in the first row is just a vector x units long, in the direction of t. So x is just the length of the vector:
x = sqrt( a^2 + b^2 )
This makes sense intuitively, too -- because a scale transformation just scales a basis vector, (1, 0), by x. Rotation changes this more, but it doesn't affect vector length! So getting the magnitude of this vector tells you the amount of scaling.
You can chug through the math to see that this identity holds:
sqrt( a^2 + b^2 ) = sqrt( (x * cos(t))^2 + (x * sin(t))^2 )
= sqrt( x^2 * cos^2(t) + x^2 * sin^2(t) )
= sqrt( x^2 * ( cos^2(t) + sin^2(t) ) )
= sqrt( x^2 * 1 );
= +/- x
Since _xscale and _yscale are the result of a square root, we get two solutions, either + or -.
When you do _xscale = -100 in ActionScript, why does Flash trace(_xscale) as -100 then? Because whenever you set _rotation, _xscale, _yscale, Flash actually caches the value you passed and returns that, instead of wastefully recalculating it!
For you code-heads out there, the Flash Player 10 Beta is out!
There are lots of new features:
- The ability to generate sound dynamically! You can thank Andre Michelle and his Adobe, Make Some Noise! campaign for that one. In Flash 9, this was only possible using a clever hack, but now Adobe has added a very nice, compact API to pass data to the sound card. What's this mean? An all-encompassing Flash/AIR media player, and a better visualizer, of course. :)
- 3d transforms! You can now move and rotate interactive DisplayObjects in 3d space. It'll be exciting to see PaperVision, Away3d, et al be updated to take advantage of this.
- Pixel shaders! Finally, we can easily make the directional motion blur we all want. Also, keep an eye out for cool normal mapping type effects. :)
- 'Skeletal' IK animation. I'm personally not too excited for this one, but maybe I'll see some cool demos or animations that'll change my mind.
- Possibly the most boring feature is the most exciting to me: Strictly typed arrays! In Flash 9, arrays were not typed, so each time you accessed an array, you would cause a runtime type check -- slooooow. Creating a typed array will increase performance and promote type safety!
- A few other nice-ities, like being able to fade, rotate, and stretch device fonts. :)
Exciting stuff! I'm anxious to start playing with it, but I'm still crunching on Castle Crashers. Keep up the good work, Adobe!