May 27

I was struck with a dissapointing blow today when I both got a better understanding of E4X, and a bit of frustrating setback in my normal way of coding thanks to FDT3 (which besides a few slight annoyances is the best IDE of all time for flash AS3 IMHO).

E4X allows you to grab XML data from an XML datasource really quickly and efficiently. I love being able to load an XML file and then just use logical groupings to loop through it like:

for each(var x:XML in xmlSource..content..items..item){

// PARSE DATA FROM EACH item NODE HERE

}

Isn't that handy now? It is indeed!

But, you see, I'm doing something here I didn't intend to. The double dot operator actually means find ALL possible matches. So, if my XML contains:

<content>

<items>

<item id="1">

</items>

<items>

<item id="2">

</items>

</content>

For example... I'm going to grab two item nodes with the code above, which is really handy most of the time, but not if you only want to focus on nodes under the specific items node you want to look at. Well, it's as simple as taking one of those dots away! Easy no?... well no it's not because I'm using FDT3, and FDT3 sees the single dot operator as an object notation reference, not an E4X reference. I'm hoping they fix this soon, because the only way not to get a horde of warnings in my code is to use the full on .child('items')..item notation which is FUGLY compared to .items..item I'm sure you'll agree.

Ah well, If we must we must!

I'll be sure to report if FDT fixes this, they should have a new release around the corner here :)

Cheers!

-AG Strout

May 22

It's fairly interesting to try working with a 3D API in order to do 2D graphics but that is exactly what it looks like I'm going to be doing when it comes to developing for the iPhone if I want to build any of the typical retro games that I enjoy making. Granted, I plan to move into making 3D games a bit more now that I have a good platform for doing so, but in my search for a good library to write 2D games on the iPhone with I'm coming up a bit short. The Cocos2d engine which is based on an engine written for Python is turning out to be not so helpful in this regard. After some looking about I've learned that the use of the 3D Open GLES API for 2D on the iPhone is the way to go, however, the Cocos2D engine uses the Texture2D class which was given out as a part of the SDK. This isn't going to cut it for me really since I would much rather not bother with the whole quad rendering issue, and would prefer to work with Point Sprites which are, from my understanding, orders of magnitude faster, which is why they're used in game creation for particle effects in 3D games. So now my goal is to find a way to either update Coco2D (doubtful) or to create my own set of classes to use in this endeavor. I hope you will all wish me luck as I dive further into the Open GL ES library and try to build my very first interactive iPhone entertainment application.

Cheers All!

-AG Strout

May 15

I was pondering for a moment how the distortion map was used in my previous post to create a paint spreading effect. I realized it probably has been done before, but I've never seen it done quite this way. In Photoshop there's a very handy tool for smearing bitmap content and I find it to be very useful there. I've recreated the effect here with a smooth edged brush. The dog you see is Sadie, my great dane, and subject of some recent photography by my wife.

Without further ado, here's the example, followed by the source code. The trickiest part was to make the effect "add" to the smear, rather than just to re-apply a new smear factor. I accomplished this by using the SUBTRACT and ADD blend modes.

This movie requires Flash Player 9

 
package com.agstrout.smear {
 
 import flash.display.MovieClip;
 
 import flash.display.BitmapData;
 
 import flash.display.Bitmap;
 
 import flash.filters.DisplacementMapFilter;
 
 import flash.display.Loader;
 
 import flash.events.Event;
 
 import flash.net.URLRequest;
 
 import flash.geom.Rectangle;
 
 import flash.display.BitmapDataChannel;
 
 import flash.geom.Point;
 
 import flash.display.Graphics;
 
 import flash.events.MouseEvent;
 
 import flash.display.BlendMode;	/**
 
  * com.agstrout.smear.Smear
 
  * @author Arne G Strout
 
  * Created : May 15, 2009
 
  * Re-creates the Smear tool effect from Photoshop using DistortionMapFilter
 
  */
 
 public class Smear extends MovieClip {
 
 	public var hit:MovieClip; // Click button
 
 	public var holder:Bitmap; // Result Bitmap Holder
 
 	public var bmp:BitmapData; // The source bitmap
 
 	public var output:BitmapData; // The result bitmap
 
 	public var distort:BitmapData; // The distortion map
 
 	public var filter:DisplacementMapFilter; // The distortion map filter
 
 	public var loader: Loader; // loader to load the image to be modified
 
private var _lx:Number; // The last mouse X position
 
 	private var _ly:Number; // The last mouse Y position
 
private static const MY_URL : String = "http://www.agstrout.com/images/image.jpg"; // Image to load
 
 	private var paint : MovieClip; // Paint layer
 
/**
 
 	 * Smear Constructor
 
 	 */
 
 	public function Smear() {
 
 		paint=new MovieClip(); // creates the painting layer
 
 		loader=new Loader(); // creates the loader
 
 		loader.contentLoaderInfo.addEventListener(Event.COMPLETE,_onImageLoaded); // loader listener
 
 		loader.load(new URLRequest(MY_URL)); // Load the constant URL
 
 	}
 
/**
 
 	 * Image Loaded handler
 
 	 */
 
 	private function _onImageLoaded(event : Event) : void {
 
 		// Create the output area and source
 
 		holder=new Bitmap();
 
 		bmp=Bitmap(loader.content).bitmapData; // Use the loaded Bitmap (JPG, PNG, or GIF) for the source BitmapData
 
 		var r:Rectangle=bmp.rect;// the size of the source bitmap
 
 		distort=new BitmapData(r.width,r.height,false,_argb(256,128,128,128)); // Make the distortion map the same size with 128 in the X/Y (R/B) registers on all pixels
 
 		output=bmp.clone(); // Copy the source for the output
 
 		holder.bitmapData=output; // assign the output bitmapdata to the holder
 
 		addChild(holder); // Add the holder to the stage
 
// Filter
 
 		// Use RED / BLUE registers for X/Y displacement, and 100 amplification for a nice effect, clamp so the edges are solid.
 
 		filter=new DisplacementMapFilter(distort,null,BitmapDataChannel.RED,BitmapDataChannel.BLUE,100,100,"clamp");
 
// Create the click button
 
 		hit=new MovieClip();
 
 		var g:Graphics=hit.graphics;
 
 		g.beginFill(0x000000,0); // transparent square
 
 		g.drawRect(0, 0, r.width, r.height); // same size as the source bitmapdata
 
 		g.endFill();
 
 		addChild(hit);
 
 		hit.addEventListener(MouseEvent.MOUSE_DOWN,_onMouseDown); // PRESS
 
 		stage.addEventListener(MouseEvent.MOUSE_UP,_onMouseUp); // RELEASE
 
_update(); // UPDATE
 
 	}
 
// ON MOUSE DOWN, set the lx/ly
 
 	private function _onMouseDown(event : MouseEvent) : void {
 
 		stage.addEventListener(MouseEvent.MOUSE_MOVE,_onMouseMove);
 
 		_lx=mouseX;
 
 		_ly=mouseY;
 
 	}
 
//
 
 	private function _onMouseMove(event : MouseEvent) : void {
 
 		var dx:Number=mouseX-_lx; // diff x
 
 		var dy:Number=mouseY-_ly; // diff y
 
 		var col:Number;
 
 		var mc:MovieClip=paint;
 
 		var g:Graphics=mc.graphics;
 
 		g.clear();
 
 		var i:int;
 
 		// red
 
 		for(i=0;i&lt;128;i+=4){
 
 			col=_argb(256-i*2,Math.floor(Math.abs(dx)),0,0);
 
 			g.lineStyle(64*(1-i/128),col,1,false,"normal");
 
 			g.moveTo(_lx,_ly);
 
 			g.lineTo(mouseX,mouseY);
 
 		}
 
 		if(dx&gt;0)distort.draw(mc,null,null,BlendMode.SUBTRACT);
 
 		if(dx&lt;0)distort.draw(mc,null,null,BlendMode.ADD);
 
// blue
 
 		g.clear();
 
 		for(i=0;i&lt;128;i+=4){
 
 			col=_argb(256-i*2,0,0,Math.floor(Math.abs(dy)));
 
 			g.lineStyle(64*(1-i/128),col,1,false,"normal");
 
 			g.moveTo(_lx,_ly);
 
 			g.lineTo(mouseX,mouseY);
 
 		}
 
 		if(dy&gt;0)distort.draw(mc,null,null,BlendMode.SUBTRACT);
 
 		if(dy&lt;0)distort.draw(mc,null,null,BlendMode.ADD);
 
_lx=mouseX;
 
 		_ly=mouseY;
 
 		_update();
 
 	}
 
private function _onMouseUp(event : MouseEvent) : void {
 
 		stage.removeEventListener(MouseEvent.MOUSE_MOVE,_onMouseMove);
 
 	}
 
private function _update() : void {
 
 		output.applyFilter(bmp, bmp.rect,new Point(0,0), filter);
 
 	}
 
private function _argb(a:uint,r:uint,g:uint,b:uint):uint{
 
 		return (a&lt;&lt;24 | r&lt;&lt;16 | g&lt;&lt;8 | b); // Create a color value from a,r,g,b data
 
 	}
 
 }
 
}
May 11

I was contacted by a colleague of mine  from a previous employer who asked if I still had the source code for an effect I had created for one of our projects. The effect was built to mimic the look of pouring paint onto glass which is being sprayed by a high pressure air nozzle. This effect is a simple use of math combined with a displacement map filter. I've got a few ideas how this could be made more interesting, such as adding a "spin" to the air by altering the angle just slightly on each pixel using the distance to set the amount.

This movie requires Flash Player 9

SOURCE FILE:

http://www.agstrout.com/files/Spreader.as

SOURCE CODE:

 
package com.agstrout.spread {
import flash.display.MovieClip;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.filters.DisplacementMapFilter;
import flash.geom.Point;
import flash.events.Event;
import flash.display.BitmapDataChannel;
import flash.display.Graphics;
import flash.utils.setInterval;
/**
* com.agstrout.spread.Spreader&lt;br/&gt;
* @author Arne G Strout
* Created : May 11, 2009&lt;br/&gt;
* A paint spreading effect which simulates paing being poored onto glass with a high pressure air hose applied to the glass.
*/
public class Spreader extends MovieClip {
public static const EFFECT_WIDTH:Number=320; // Movie Width
public static const EFFECT_HEIGHT:Number=240; // Movie Height
public static const EFFECT_FORCE:Number=.4; // Force of the "wind"
public var bmp:Bitmap; // The bitmap container for display
public var lmouseX:Number; // last mouse x , for line drawing
public var lmouseY:Number; // last mouse y , for line drawing
private var _bd:BitmapData; // the bitmap data the effect will be applied to
private var _filterbd:BitmapData; // the filter data for the effect
private var _f:DisplacementMapFilter; // the actual filter
private var _paint:MovieClip; // paint layer for drawing paint strokes to _bd
private var _col:Number; // the current paint color
 
/**
* constructor
*/
public function Spreader() {
_paint=new MovieClip(); // This MC will be used for the paint line drawing
 
// sets initial values for the "last mouse X" and "last mouse Y" values
lmouseX=mouseX;
lmouseY=mouseY;
 
// Create the bitmaps, with the effect W/H constants
bmp=new Bitmap();
_bd=new BitmapData(EFFECT_WIDTH,EFFECT_HEIGHT,true,0x00000000);
_filterbd=new BitmapData(EFFECT_WIDTH,EFFECT_HEIGHT,true,0x00000000);
 
// Creates the filter bitmap, using math to determine the angle to store for each pixel.
for(var i:uint=0;i&lt;EFFECT_WIDTH;i++)
for(var u:uint=0;u&lt;EFFECT_HEIGHT;u++){
var deltaX:Number=EFFECT_WIDTH/2-i; // The distance on the X axis between the center and this pixel
var deltaY:Number=EFFECT_HEIGHT/2-u; // The distance on the Y axist between the center and this pixel
var angle:Number=Math.atan2(deltaX,-deltaY); // angle in radians from the center to this pixel
var d:Number=Math.sqrt(deltaX*deltaX+deltaY*deltaY); // distance in pixels from the center
var dx:uint=Math.sin(angle)*(128-d/3)+128; // displacement (0 to 256) on the X axis, 128 for none
var dy:uint=-Math.cos(angle)*(128-d/3)+128; // displacement (0 to 256) on the Y axis, 128 for none
_filterbd.setPixel32(i,u,_argb(1,dx,dy,1)); // set the pixel value, using the _argb method to convert displacements to a color value
}
 
// Create the displacement map using the red and green channels and the EFFECT_FORCE constant
_f=new DisplacementMapFilter(_filterbd,new Point(0,0),BitmapDataChannel.RED,BitmapDataChannel.GREEN,EFFECT_FORCE,EFFECT_FORCE,"clamp");
addEventListener(Event.ENTER_FRAME,_onFrame); // apply the displacement map once per frame
setInterval(_shift,1000); // change paint color on a 1 sec interval
bmp.bitmapData=_bd; // Add the bitmapdata to the Bitmap container for display
addChild(bmp); // add the container to the stage.
_shift(); // set the initial color
}
 
/**
* Changes the paint color
*/
private function _shift() : void {
_col=_argb(256,                // A
128+Math.random()*128,    // R
128+Math.random()*128,    // G
128+Math.random()*128    // B
); // random color, but brighter than half luminance
}
 
private function _onFrame(event : Event) : void {
_bd.applyFilter(_bd,_bd.rect,new Point(0,0),_f); // Applies the "wind" effect
var g:Graphics=_paint.graphics; // gets the graphics context to draw the lines
g.clear(); // clears previous lines
g.moveTo(mouseX+(mouseX==lmouseX &amp;&amp; mouseY==lmouseY?2:0),mouseY); // sets start point of stroke at current X/Y pos (shift two pixels if no movement
g.lineStyle(16,_col);// sets the current color and brush size
g.lineTo(lmouseX,lmouseY); // draws the stroke to the previous X/Y pos
_bd.draw(_paint); // draws the paint layer onto the effect bitmap
lmouseX=mouseX; // record current X/Y pos for next frame
lmouseY=mouseY;
}
 
private function _argb(a:uint,r:uint,g:uint,b:uint):uint{
return (a&lt;&lt;24 | r&lt;&lt;16 | g&lt;&lt;8 | b); // Create a color value from a,r,g,b data
}
}
}
May 07

There's a tactic that I've been using successfully since AS2, which I find to be an excellent way of handling data communication.
The event driven model which is used in most programming frameworks is a bit heavy for everyday use in lighter applications, and I assume that's why Flex introduced data binding, but even data binding is a bit unwieldy and is only available in Flex.

My approach borrows from a few years of trying different strategies to create a useful mechanism for handling the communication of updates on the Model out to the many views/controllers that use it.

When implemented you can do something as simple as:

FeedMe.instance.subscribe(FEED_KEY,_onFeedKeyUpdate);
// and then later in the code
private function _onFeedKeyUpdate($data:*):void{
// Handle the update to the data feed
}

The feed key here could represent the currently selected character type in a video game, or the mouse state, just about anything really. The nice thing is that many multiple outlying classes can subscribe for updates every time, request in order to get the current value once (or be notified the first time a value is available), or "get" in order to check the existing value for that field.

In combination with Variable Objects especially this approach becomes very powerful.

For more information, see the project, now newly named FeedMe_AS3 on Google Code:

May 06

I've been pondering it and I really thing PHPBB and many other systems should start using Flash in their Captcha implementation.
One great example would be to require the user to perform some simple action within a flash environment, such as dragging a golf ball into a hole. Pretty much anything that a spambot would not be able to do. This would be MUCH less annoying than the current captcha methods, and what with Flash becoming so ubiquitous you'd only really be risking losing users who exclusively use their iPhone to register on forums, cuz that happens so often :).

Thoughts?

May 06

So, I just spent about an hour cleaning spam out of my PHPBB3 install on www.stroutsink.com.

Apparently the Captcha on PHPBB 3.0.4 (the code that creates those annoying images on registration pages) was cracked recently.

As a result I had ~1700  spammer accounts created in a week. At first I was deleting them one by one, but then just switched over to the more logical approach and used SQL to delete all users created after the first spammers showed up (sorry if anyone REAL got caught up in there!)

The next step was to install a random image mod which adds a random image behind the captcha text and those images can be customized. I'm using the defaults right now, but will swap them out as soon as I see that they are no longer working.

Cheers!

-Arne

May 06

I just finished a redesign on the homepage for www.agstrout.com as well as an update to www.stroutsink.com which will add some much needed positive space to the sites. The previous sites were rather cluttered looking and especially on www.stroutsink.com the scrolling wasn't working out for the games and photos. Splitting the photos onto their own page and giving the games list two rows has helped alot. Also, April created some great new button art for the games list. I especially like the Chompy The Great, Chompy's Winter Rescue, and Connect-A-Mals buttons.

Cheers All!

Let me know what you think of the new designs. Any ideas for further improvements?

Apr 19

Wow, just wow.

The last couple of days have been interesting to say the least. I just had one of the PCI slots on my Dell XPS 420 up and die on me. Due to the way the system is built, this effectively made my sound cards (of which I have 2(!)) useless.

Well, this is my video editing machine, so I need a sound card, badly of course.

A thought about something I had run into a couple times.. I thought "Hey self, what about a USB sound card?" I mean, I assumed that the sound card would be drastically lower quality, and that I'd be giving up a lot, but at least I'd be able to hear my sounds, and USB should be cheaper after all.

Best Buy here I come!

Well, I picked out the -only- USB sound card there. The Sound Blaster X-Fi GO!

I'm floored:

  • Not only was it cheap (~$58 with taxes)
  • The sound quality is fantastic
  • It came with a set of headphones that double as  headset for skype
  • It self installs almost instantly
  • It comes with a USB cable extension just in case your USB ports are crowded
  • It doubles as a 1GB thumbdrive(!)

Now call me a sceptic, but I was kind of blown away by this, I mean, the GO! is about a 1 inch x 2 inch block and it outperforms my two "Live"s which are each about five times that size. I mean sure, there isn't a 5.1 audio out port, but I don't have a 5.1 stereo surround sound system so I don't really care. I've spent $128 on a sound card before and it's been much less useful. What's better is, even as a thumb drive, the GO! is much prettier looking than most, with a sliding data lock switch, and a sleak black finish.

I for one am SOLD!

Just thought I'd share :)

-AGStrout

Mar 16

I've heard a lot of companies touting the co-op buzzword lately. Actually, pretty much ever since Halo came out it has been a buzzword. Unfortunately for those of us who love a cooperative gaming experience, there has been a cancer growing in the game marketing community. Co-op mislabeling and badly implemented co-op.

There are a few basic rules companies should be following but have repeatedly screwed up.

1 - CO-OP is not multiplayer. Just because more than one person is playing at the same time does not make it a co-op game.

2 - Every player must be equal. Of note, Fable 2 breaks this rule badly by making the second player a "bodyguard" of sorts to the first player. This makes the second player feel like a third wheel in the story.

3 - CO-OP is only really co-op if you can play the actual game in co-op. Disappointing titles like Mystic Heroes allow you to play with friends, but only in sandbox levels that have no real barring on the story mode at all, and don't unlock anything.

4 - CO-OP is only really co-op if you're helping each-other. In this sense Halo scores lower as a co-op game than Ghost Recon or Army of Two, despite the fact that Halo is a much better game. In the other titles mentioned you can revive your partner, provide him cover fire, etc. You have to work together.

5 - CO-OP is not co-op if you're on your own. We Ski, for example, is not Co-op. You may start out the game in any given mode right next to other players, but guarantee that with in five seconds no camera angle available to you will reveal your "partner". You also have absolutely no way of helping each-other achieve goals, you are actually only able to work as a very ineffective roadblock if anything.

6 - CO-OP games should not be labeled as CO-OP in my opinion, if it requires an entire separate copy of the game and separate television and separate game system in order to play together. These should be plainly labeled as "COOPERATIVE MODES REQUIRE TWO OR MORE COPIES", anything less is false advertising.

Many newly released games break these rules profusely. Making people like me, who love a co-op experience, somewhat nauseous and enraged. The worst though, are the ones who make a game that is CO-OP, meets all of these rules, but is simply not even remotely fun to play. It's hard enough to find a good co-op game, so finding one and having it turn out to be horrid is like a knife to the heart (We're looking at you Alien Syndrome!)

Cheers!
-Arne
P.S. Check out http://www.co-optimus.com/ for the best CO-OP games list I've ever seen, with accompanying reviews, ratings, and categorizations.