ShadowCast: ESCAPE FROM DARKNESS (Growing darkness)
to load an image used this: http://wonderfl.net/c/d8DH/
default image used from this:
using code from here: http://nemonon.de/blog/
there are a lot of function need to be cleaned up...
/**
* Copyright Albert ( http://wonderfl.net/user/Albert )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/pWyt
*/
// forked from Albert's ShadowCast: ESCAPE FROM DARKNESS
// forked from Albert's forked from: forked from: forked from: forked from: forked from: ShadowCast
// forked from Albert's forked from: forked from: forked from: forked from: ShadowCast
// forked from Albert's forked from: forked from: forked from: ShadowCast
// forked from Albert's forked from: forked from: ShadowCast
// forked from Albert's forked from: ShadowCast
// forked from Albert's ShadowCast
// to load an image used this: http://wonderfl.net/c/d8DH/
// default image used from this:
//using code from here: http://nemonon.de/blog/
//there are a lot of function need to be cleaned up...
package {
import flash.geom.ColorTransform;
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.events.*;
import flash.net.*;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.system.LoaderContext;
import flash.geom.Rectangle;
import flash.text.*;
import flash.utils.*;
import com.bit101.components.*;
public class FlashTest extends Sprite {
private var loader:Loader = new Loader( );
private var bd: BitmapData;
private var bm2:Bitmap;
private var loader2:Loader;
private var labeldimension:Label;
private const SIZE:int = 400;
private var loaderA:Loader;
private var loaderB:Loader;
private var input:InputText;
private var bitmap:Bitmap;
public function FlashTest() {
init();
}
private static const URL:String = "http://dl.dropbox.com/u/292449/img/barlang_mockup.png"
// private static const URL:String = "http://www.ujakropolisz.hu/files/ua_images/STATIKUS/Kultura/CIK_labirintus_m_3.jpg"
private function init():void
{
var label:Label = new Label(this, 50, 10, "loading " + URL);
label = new Label(this, 25, 409, "IMAGE URL");
input = new InputText(this, 0, 410, URL);
input.width = 300;
input.x = (465 - input.width) / 2;
var button:PushButton = new PushButton(this, 230, 435, "OK", inputHandler);
button.x = (465 - button.width) / 2;
inputHandler();
}
private function onClick(e:Event):void
{
//clearFOV();
ColorTransformFOV();
getFOV(stage.mouseX, stage.mouseY);
}
private function createTextField(x:Number, y:Number, width:Number, height:Number):TextField {
var result:TextField = new TextField();
result.x = x; result.y = y;
result.width = width; result.height = height;
addChild(result);
return result;
}
/**
* Generates the FOV (field of view) of a pixel based map.
* Imlements the shadow cast algorithm
* Created by: Jörg Mehnert
* Created at: 2010/01/07
*/
// members
// *******************************************************************************
// the base data
private var _worldMap:BitmapData;
// the output data, containing the field of view
private var _fovData:MyBitmapData;
// specifies, whether the output data should be preserved or not
private var _updateOutput:Boolean;
// the color in the output data for the visible pixels
private var _visibleColor:uint = 0xFAFAFA;
// the color in the output data for the invisible pixels
private var _invisibleColor:int = 0xFFFFFF;
// the threshold color for the scan, pixel colors beneath this color will be invisible
private var _blockedColor:uint = 0x000001;
private var _colorTransform:ColorTransform = new ColorTransform(1,1,1,1,1,1,1,0);
// rounded point of view coordinates to improve performance
private var _ceiledPovX:int;
private var _ceiledPovY:int;
// constructor
// *******************************************************************************
/**
* Constructor
* @param givenWorldMap
* @param preserveOutputData - default = false
*/
public function ShadowCaster(givenWorldMap:BitmapData, preserveOutputData:Boolean = false):void {
worldMap = givenWorldMap;
_updateOutput = !preserveOutputData;
}
// getter/setter
// *******************************************************************************
/**
* Gets the world map
* @return BitmapData
*/
public function get worldMap():BitmapData {
return _worldMap;
}
/**
* Sets the world map
* @param newWorldMap
*/
public function set worldMap(newWorldMap:BitmapData):void {
if (newWorldMap == null) {
throw new Error("World map (flash.display.BitmapData) cannot be null.");
}
_worldMap = newWorldMap;
fovData = _fovData;
}
/**
* Indicates, whether the output data should be preserved or not
* @return Boolean
*/
public function get isOutputUpdated():Boolean {
return _updateOutput;
}
/**
* Preserve the output data or not
* @param value
*/
public function set isOutputUpdated(value:Boolean):void {
_updateOutput = value;
}
/**
* Gets the output data
* @return BitmapData
*/
public function get fovData():MyBitmapData {
return _fovData;
}
/**
* Sets the output data
* @param newFovData
*/
public function set fovData(newFovData:MyBitmapData):void {
if (newFovData == null) {
_fovData = new MyBitmapData(_worldMap.width, _worldMap.height, false, _invisibleColor);
} else {
_fovData = newFovData;
}
}
/**
* Gets the visible color
* @return uint
*/
public function get visibleColor():uint {
return _visibleColor;
}
/**
* Sets the visible color. The default value is 0xFFFFFF
* @param newColor
*/
public function set visibleColor(newColor:uint):void {
_visibleColor = newColor;
}
/**
* Gets the invisible color
* @return uint
*/
public function get invisibleColor():uint {
return _invisibleColor;
}
/**
* Sets the invisible color. The default value is 0x000000
* @param newColor
*/
public function set invisibleColor(newColor:uint):void {
_invisibleColor = newColor;
}
/**
* Gets the blocked color
* @return uint
*/
public function get blockedColor():uint {
return _blockedColor;
}
/**
* Sets the blocked color. All pixel colors beneath this value will be interpreted as blocked.
* The default value is 0xAAAAAA
* @param newColor
*/
public function set blockedColor(newColor:uint):void {
_blockedColor = newColor;
}
// public methods
// *******************************************************************************
/**
* Computes the field of view, based on the current world data and the given coordinates of the view point
* @param viewPointX - the x coordinate of the view point
* @param viewPointY - the y coordinate of the view point
* @return BitmapData
*/
public function getFOV(viewPointX:Number, viewPointY:Number):BitmapData {
if (_updateOutput) {
_fovData = new MyBitmapData(_worldMap.width, _worldMap.height, false, _invisibleColor);
}
if (viewPointX < 0 || viewPointX > _worldMap.width
|| viewPointY < 0 || viewPointY > _worldMap.height) {
trace("ShadowCaster: The view point is out of bounds. The midpoint of the world map is used instead.");
_ceiledPovX = Math.ceil(_worldMap.width / 2);
_ceiledPovY = Math.ceil(_worldMap.height / 2);
} else {
_ceiledPovX = Math.ceil(viewPointX);
_ceiledPovY = Math.ceil(viewPointY);
}
// call all octants
inspectNorthwestNorth(0, 1, 0);
inspectNorthwestWest(0, 1, 0);
inspectSouthwestWest(0, 1, 0);
inspectSouthwestSouth(0, 1, 0);
inspectSoutheastSouth(0, 1, 0);
inspectSoutheastEast(0, 1, 0);
inspectNortheastEast(0, 1, 0);
inspectNortheastNorth(0, 1, 0);
return _fovData;
}
public function clearFOV( ):void {
_fovData.fillRect(new Rectangle(0,0,_worldMap.width, _worldMap.height), _invisibleColor);
}
public function ColorTransformFOV():void {
_fovData.colorTransform(new Rectangle(0,0,_fovData.width, _fovData.height), _colorTransform);
}
// private methods
// *******************************************************************************
private function inspectNorthwestNorth(depth:int, startSlope:Number, endSlope:Number):void {
var startX:int = _ceiledPovX - Math.ceil(startSlope * depth);
var endX:int = _ceiledPovX - Math.ceil(endSlope * depth);
var currentY:int = _ceiledPovY - depth;
if (currentY < 0) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(startX, currentY) < _blockedColor;
for (var currentX:int = Math.max(startX, 0); currentX <= endX; ++currentX) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = computeSlope(_ceiledPovX, _ceiledPovY, (currentX - 0.5), (currentY + 0.5));
// start recursion for the next depth
inspectNorthwestNorth(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = computeSlope(_ceiledPovX, _ceiledPovY, (currentX + 0.5), (currentY - 0.5));
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectNorthwestNorth(depth, startSlope, endSlope);
}
}
private function inspectSouthwestWest(depth:int, startSlope:Number, endSlope:Number):void {
var startY:int = Math.ceil(startSlope * depth) + _ceiledPovY;
var endY:int = Math.ceil(endSlope * depth) + _ceiledPovY;
var currentX:int = _ceiledPovX - depth;
if (currentX < 0) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(currentX, startY) < _blockedColor;
for (var currentY:int = Math.min(startY, _worldMap.height); currentY >= endY; --currentY) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = -computeInverseSlope((currentX + 0.5), (currentY + 0.5), _ceiledPovX, _ceiledPovY);
inspectSouthwestWest(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = -computeInverseSlope((currentX - 0.5), (currentY - 0.5), _ceiledPovX, _ceiledPovY);
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectSouthwestWest(depth, startSlope, endSlope);
}
}
private function inspectNorthwestWest(depth:int, startSlope:Number, endSlope:Number):void {
var startY:int = _ceiledPovY - Math.ceil(startSlope * depth);
var endY:int = _ceiledPovY - Math.ceil(endSlope * depth);
var currentX:int = _ceiledPovX - depth;
if (currentX < 0) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(currentX, startY) < _blockedColor;
for (var currentY:int = Math.max(startY, 0); currentY <= endY; ++currentY) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = computeInverseSlope((currentX + 0.5), (currentY - 0.5), _ceiledPovX, _ceiledPovY);
inspectNorthwestWest(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = computeInverseSlope((currentX - 0.5), (currentY + 0.5), _ceiledPovX, _ceiledPovY);
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectNorthwestWest(depth, startSlope, endSlope);
}
}
private function inspectSouthwestSouth(depth:int, startSlope:Number, endSlope:Number):void {
var startX:int = _ceiledPovX - Math.ceil(startSlope * depth);
var endX:int = _ceiledPovX - Math.ceil(endSlope * depth);
var currentY:int = _ceiledPovY + depth;
if (currentY > _worldMap.height) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(startX, currentY) < _blockedColor;
for (var currentX:int = Math.max(startX, 0); currentX <= endX; ++currentX) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = -computeSlope(_ceiledPovX, _ceiledPovY, (currentX - 0.5), (currentY - 0.5));
inspectSouthwestSouth(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = -computeSlope(_ceiledPovX, _ceiledPovY, (currentX + 0.5), (currentY + 0.5));
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectSouthwestSouth(depth, startSlope, endSlope);
}
}
private function inspectSoutheastSouth(depth:int, startSlope:Number, endSlope:Number):void {
var startX:int = Math.ceil(startSlope * depth) + _ceiledPovX;
var endX:int = Math.ceil(endSlope * depth) + _ceiledPovX;
var currentY:int = _ceiledPovY + depth;
if (currentY > _worldMap.height) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(startX, currentY) < _blockedColor;
for (var currentX:int = Math.min(startX, _worldMap.width); currentX >= endX; --currentX) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = computeSlope(_ceiledPovX, _ceiledPovY, (currentX + 0.5), (currentY - 0.5));
inspectSoutheastSouth(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = computeSlope(_ceiledPovX, _ceiledPovY, (currentX - 0.5), (currentY + 0.5));
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectSoutheastSouth(depth, startSlope, endSlope);
}
}
private function inspectSoutheastEast(depth:int, startSlope:Number, endSlope:Number):void {
var startY:int = _ceiledPovY + Math.ceil(startSlope * depth);
var endY:int = _ceiledPovY + Math.ceil(endSlope * depth);
var currentX:int = _ceiledPovX + depth;
if (currentX > _worldMap.width) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(currentX, startY) < _blockedColor;
for (var currentY:int = Math.min(startY, _worldMap.height); currentY >= endY; --currentY) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = computeInverseSlope((currentX - 0.5), (currentY + 0.5), _ceiledPovX, _ceiledPovY);
inspectSoutheastEast(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = computeInverseSlope((currentX + 0.5), (currentY - 0.5), _ceiledPovX, _ceiledPovY);
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectSoutheastEast(depth, startSlope, endSlope);
}
}
private function inspectNortheastEast(depth:int, startSlope:Number, endSlope:Number):void {
var startY:int = _ceiledPovY - Math.ceil(startSlope * depth);
var endY:int = _ceiledPovY - Math.ceil(endSlope * depth);
var currentX:int = _ceiledPovX + depth;
if (currentX > _worldMap.width) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(currentX, startY) < _blockedColor;
for (var currentY:int = Math.max(startY, 0); currentY <= endY; ++currentY) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = -computeInverseSlope((currentX - 0.5), (currentY - 0.5), _ceiledPovX, _ceiledPovY);
inspectNortheastEast(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = -computeInverseSlope((currentX + 0.5), (currentY + 0.5), _ceiledPovX, _ceiledPovY);
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectNortheastEast(depth, startSlope, endSlope);
}
}
private function inspectNortheastNorth(depth:int, startSlope:Number, endSlope:Number):void {
var startX:int = _ceiledPovX + Math.ceil(startSlope * depth);
var endX:int = _ceiledPovX + Math.ceil(endSlope * depth);
var currentY:int = _ceiledPovY - depth;
if (currentY < 0) return;
var isLastCellBlocked:Boolean = _worldMap.getPixel(startX, currentY) < _blockedColor;
for (var currentX:int = Math.min(startX, _worldMap.width); currentX >= endX; --currentX) {
if (_worldMap.getPixel(currentX, currentY) < _blockedColor) {
if (!isLastCellBlocked) {
var newScanEndSlope:Number = -computeSlope(_ceiledPovX, _ceiledPovY, (currentX + 0.5), (currentY + 0.5));
inspectNortheastNorth(depth + 1, startSlope, newScanEndSlope);
}
isLastCellBlocked = true;
} else {
if (isLastCellBlocked) {
startSlope = -computeSlope(_ceiledPovX, _ceiledPovY, (currentX - 0.5), (currentY - 0.5));
}
_fovData.setPixel(currentX, currentY, _visibleColor);
isLastCellBlocked = false;
}
}
if (!isLastCellBlocked) {
depth++;
inspectNortheastNorth(depth, startSlope, endSlope);
}
}
private function computeSlope(x1:Number, y1:Number, x2:Number, y2:Number):Number {
return ((x1 - x2) / (y1 - y2));
}
private function computeInverseSlope(x1:Number, y1:Number, x2:Number, y2:Number):Number {
return (1 / ((x1 - x2) / (y1 - y2)));
}
private function inputHandler(event:Event = null):void
{
loaderA = new Loader();
loaderA.contentLoaderInfo.addEventListener(Event.INIT, initHandler);
loaderA.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function():void { } );
loaderA.load(new URLRequest(input.text), new LoaderContext(true));
}
private function initHandler(event:Event):void
{
loaderB = new Loader();
loaderB.contentLoaderInfo.addEventListener(Event.INIT, init2);
loaderB.loadBytes(loaderA.contentLoaderInfo.bytes);
}
private function init2(event:Event):void
{
var loader:Loader = event.currentTarget.loader;
var scale:Number = 0;
if (loader.width < loader.height) scale = SIZE / loader.height;
else scale = SIZE / loader.width;
var bd:BitmapData = new BitmapData(scale * loader.width, scale * loader.height, false);
bd.draw(loader);
if (bitmap) removeChild(bitmap);
bitmap = new Bitmap(bd);
this.addChild(bitmap);
var label:Label = new Label(this, 100, 2, ""+bitmap.width+"x"+bitmap.height);
ShadowCaster(bd, true);
var bmd2:BitmapData;
fovData=null;
bmd2=fovData;
//blockedColor = 0x5050c0;
bm2 = new Bitmap(bmd2);
this.addChild(bm2);
bm2.alpha=1;
//bm2.blendMode = flash.display.BlendMode.MULTIPLY;
bm2.blendMode = flash.display.BlendMode.MULTIPLY;
getFOV(45,65);//
stage.addEventListener(Event.ENTER_FRAME , onClick);
}
}
}
import flash.display.BitmapData;
class MyBitmapData extends BitmapData{
public function MyBitmapData(width:int, height:int, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF)
{
super(width, height, transparent, fillColor);
}
override public function setPixel(x:int, y:int, color:uint):void
{
var colorOld:uint = getPixel(x,y);
if (colorOld - (0xFFFFFF-color) < 0)
super.setPixel(x,y,0);
else
super.setPixel(x,y,colorOld-(0xFFFFFF-color));
}
}