topical media & game development
#perlin-landscape.ax
#perlin-landscape.ax
[swf]
flex
/*
Written by:
Dustin Andrew
dustin@flash-dev.com
www.flash-dev.com
*/
package {
import flash.media.Camera;
import flash.media.Video;
import flash.display.*;
import flash.geom.*;
import flash.filters.*;
import flash.events.*;
import flash.net.*;
import flash.ui.*;
public class @ax-perlin-landscape extends Sprite {
private var vid:Video;
private var _bmpPerl:BitmapData; // BitmapData that will hold the perlin noise
private var _numPerlW:Number = 200; // Perlin noise width
private var _numPerlH:Number = 200; // Perlin noise height
private var _numGridW:Number = 16; // Tile grid width
private var _numGridH:Number = 16; // Tile grid height
private var _sprTiles:Sprite; // Sprite that will hold all the tiles
private var _numTileW:Number = 25; // Tile width
private var _numTileH:Number = 12; // Tile height
private var _arrBaseY:Array; // Array to record each tile's base y
private var _numMoveX:Number = 0; // X offset for perlin noise
private var _numMoveY:Number = 0; // Y offset for perlin noise
private var _numMoveSX:Number; // Speed that x offset increments by
private var _numMoveSY:Number; // Speed that y offset increments by
private var _numColor:Number; // Tile Color
private var _menuDLSource:ContextMenu; // Right-click menu for downloading source
// Constructor
public function @ax-perlin-landscape() {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// Create bitmapdata to draw perlin noise on
//vid = new Video();
//vid.attachCamera(Camera.getCamera());
_bmpPerl = new BitmapData(_numPerlW, _numPerlH, false, 0);
// Uncomment this if you want to see the perlin noise
var bmp:Bitmap = new Bitmap(_bmpPerl);
//_bmpPerl.addChild(vid);
this.addChild(bmp);
_sprTiles = new Sprite();
//_sprTiles.addChild(vid);
_sprTiles.cacheAsBitmap = true;
createTiles();
// Center tiles
_sprTiles.x = (stage.stageWidth / 2) - _numTileH;
_sprTiles.y = stage.stageHeight / 3;
this.addChild(_sprTiles);
// Start with random values
onMouseDown(new Event(""));
// Add eventlisteners
this.addEventListener("enterFrame", onEnterFrame);
this.addEventListener("mouseDown", onMouseDown);
// Add right-click menu to download source
createSourceLink();
}
// Called to create tiles based on grid width and height
private function createTiles():void {
// Rows
_arrBaseY = new Array();
for (var r:Number = 0; r < _numGridH; r++) {
// Columns
_arrBaseY.push(new Array());
for (var c:Number = 0; c < _numGridW; c++) {
var shpTile:Shape = new Shape();
//var shpTile:Sprite = new Sprite();
//shpTile.addChild(vid);
shpTile.name = "tile_" + r + "_" + c;
drawTile(shpTile);
// Line up tiles from back to front
if (c > 0) {
shpTile.x = shpLast.x - (shpLast.width / 2);
shpTile.y = shpLast.y + (shpLast.height / 2);
} else {
shpTile.x = (shpTile.width / 2) * r;
shpTile.y = (shpTile.height / 2) * r;
}
// Record last added tile
var shpLast:Shape = shpTile;
_sprTiles.addChild(shpTile);
// Record base y
_arrBaseY[r].push(shpTile.y);
}
}
}
// Called to draw tile graphic based on tile width and height
private function drawTile(shpTile:Shape):void {
shpTile.graphics.clear();
shpTile.graphics.moveTo(0, _numTileH / 2);
shpTile.graphics.beginFill(_numColor, 1);
shpTile.graphics.lineTo(_numTileW / 2, 0);
shpTile.graphics.lineTo(_numTileW, _numTileH / 2);
shpTile.graphics.lineTo(_numTileW / 2, _numTileH);
shpTile.graphics.lineTo(0, _numTileH / 2);
shpTile.graphics.endFill();
}
// Called on mouse down to randomize x,y speed and color
private function onMouseDown(event:Event):void {
_numMoveSX = (Math.random() * 25) - 12;
_numMoveSY = (Math.random() * 25) - 12;
_numColor = Math.random() * 0xFFFFFF;
}
// Called on enter frame to update perlin noise and y of each tile
private function onEnterFrame(event:Event):void {
// Create perlin noise based on current x,y offset
_bmpPerl.perlinNoise(175, 175, 1, 333, false, false, 7, true, new Array(new Point(_numMoveX, _numMoveY)));
// Rows
for (var r:Number = 0; r < _numGridH; r++) {
// Columns
for (var c:Number = 0; c < _numGridW; c++) {
var shpTile:Shape = _sprTiles.getChildByName("tile_" + r + "_" + c) as Shape;
// We get the color of the perlin noise at the general pixel location that
// the tile is, based in the tile grid. We then bring that color number down to
// a size that we can work with. In this instance, it gives us a range from around
// 0 to 75, thats what gives us the y offset.
var numSetY:Number = _bmpPerl.getPixel((_numPerlW / _numGridW) * c, (_numPerlH / _numGridH) * r) / 100000;
// Affect tile alpha and tint based on y offset
shpTile.y = _arrBaseY[r][c] + (numSetY * -1);
var colTrans:ColorTransform = new ColorTransform();
var numTint:Number = (numSetY * .01) + .4;
colTrans.color = _numColor;
colTrans.blueMultiplier = numTint;
colTrans.greenMultiplier = numTint;
colTrans.redMultiplier = numTint;
colTrans.alphaMultiplier = numTint;
var trans:Transform = new Transform(shpTile);
trans.colorTransform = colTrans;
// Create a drop shadow thats distance and blur is affected by the tile's y offset
var numBlur:Number = numSetY * .05;
var filShad:DropShadowFilter = new DropShadowFilter(numSetY * .8, 90, _numColor, .5, numBlur, numBlur * 2, 1, 1, false, false, false);
shpTile.filters = new Array(filShad);
}
}
// Increment x,y offset based on x,y offset
_numMoveX -= _numMoveSX;
_numMoveY -= _numMoveSY;
}
// Called to add right-click menu option to download source
private function createSourceLink():void {
_menuDLSource = new ContextMenu();
var menuDL:ContextMenuItem = new ContextMenuItem("Download Source");
menuDL.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, downloadSource);
_menuDLSource.customItems.push(menuDL);
this.contextMenu = _menuDLSource;
}
// Called to download source
private function downloadSource(event:ContextMenuEvent):void {
var reqUrl:URLRequest = new URLRequest("PerlinLandscape.zip");
navigateToURL(reqUrl);
}
}
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.