depth sort

by andyshang
use depth index table to sort.
the collision detect using math round so it not so perfect which might impact the sorting result.
♥1 | Line 293 | Modified 2011-03-05 17:04:36 | MIT License
play

ActionScript3 source code

/**
 * Copyright andyshang ( http://wonderfl.net/user/andyshang )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/yebs
 */

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	
	[SWF(width="465", height="465")]
	public class Main extends Sprite
	{
		private var keyManager:KeyManager = new KeyManager();
		
		public function Main()
		{
			var canvas:Canvas = new Canvas();
			
			drawDebugRect = function(x:int, y:int):void
			{
				graphics.clear();
				graphics.lineStyle(2,0xAB0000);
				graphics.drawRect(
					x * Tile.tileSize + canvas.viewPort.x,
					y*Tile.tileSize + canvas.viewPort.y
					, Tile.tileSize, Tile.tileSize);
			};
			
			
			addChild(canvas);
			canvas.viewPort = new Rectangle(0,0,stage.stageWidth, stage.stageHeight); 
			canvas.pan(canvas.role.x * 32, canvas.role.y*32);
			
			keyManager.listen(stage); 
		
			addEventListener(Event.ENTER_FRAME, function(event:Event):void
			{
				if(keyManager.isDown(Keyboard.UP))
				{
					canvas.role.move(0,-1)
				}
				if(keyManager.isDown(Keyboard.DOWN))
				{
					canvas.role.move(0,1)
				}
				if(keyManager.isDown(Keyboard.LEFT))
				{
					canvas.role.move(-1,0)
				}
				if(keyManager.isDown(Keyboard.RIGHT ))
				{
					canvas.role.move(1,0)
				}
			})
		}
	}
}

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.KeyboardEvent;
import flash.geom.Matrix;
import flash.geom.Rectangle;
 
class Canvas extends Sprite
{
	public static var mapWidth:int = 12;
	
	private var _viewPort:Rectangle;
	public function set viewPort(viewPort:Rectangle):void
	{
		_viewPort = viewPort;
		draw();
	}
	
	public function get viewPort():Rectangle
	{
		return _viewPort;
	}
	
	public var role:Role;
	
	private var tiles:Vector.<Tile> = new Vector.<Tile>;
	private var depthIndexTable:Array = []
		
	public function Canvas()
	{
		var tile:Tile;
		for(var i:int=0;i<pathMap.length;i++)
		{
			if(pathMap[i] == "x")
			{
				tile = new Block();
			}
			else if(pathMap[i] == "A")
			{
				role = new Role();
				tile = role;
			}
			else
			{
				continue; 
			}
			tile.x = i % mapWidth;
			tile.y = i / mapWidth;
			tile.container = this;
			tiles.push(tile);
			if(isNaN(depthIndexTable[tile.y]))
			{
				depthIndexTable[tile.y] = 0;
			}
			depthIndexTable[tile.y]++;
		} 
	}
	
	public function updateDepth(object:Tile, from:int, to:int):void
	{
		//look up depth table first
		var depth:int = 0;
		depthIndexTable[from] --;
		depthIndexTable[to] ++;
		for(var i:int;i<=to;i++)
		{
			depth += depthIndexTable[i];
		}
		setChildIndex(object.asset, depth);
		if(depth == 0 || depth == numChildren)
		{
			return;
		}
		if(object.asset.y < getChildAt(depth-1).y)
		{
			depth -= depthIndexTable[i-1];
			setChildIndex(object.asset, depth);
		}
		//now the object's depth is highest in the same line.
		//adjust by asset.y , to see if it should be put to next line.
		//for the map is closed, we do not check out of range.
		if(object.asset.y > getChildAt(depth+1).y)
		{
			depth += depthIndexTable[i];
			setChildIndex(object.asset, depth);
		}
	}
	
	public function pan(x:int ,y:int):void
	{
		_viewPort.x -= x;
		_viewPort.y -= y;
		draw();
	}
	
	public function panTo(x:int ,y:int):void
	{
		_viewPort.x = x;
		_viewPort.y = y;
		draw();
	}
	
	public function draw():void
	{
		for each(var tile:Tile in tiles)
		{
			tile.render(_viewPort);
		}
	}
}

class Tile
{ 
	public static var tileSize:int = 64;
	
	public var x:int;
	public var y:int;
	
	public var container:Canvas;
	public var asset:Shape;
	protected var rect:Rectangle;
	
	public function render(rect:Rectangle):void
	{
		this.rect = rect;
		if(!container.contains(asset))
		{
			container.addChild(asset);
		}
		asset.x = x * tileSize + rect.x;
		asset.y = y * tileSize + rect.y;
	}
}

class Role extends Tile
{
	public static const SPEED:Number = 3;
		
	public function Role():void
	{
		asset = new Shape();
		asset.graphics.beginFill(0x0, 0.7);
		asset.graphics.drawRect(1,-tileSize,tileSize,2*tileSize);
	}
		
	public function move(dx:int, dy:int):void
	{
		moved = true
		container.pan(dx * SPEED, dy * SPEED);
		
		var lastY:int = y;
		x = Math.round((asset.x - rect.x) / tileSize);
		y = Math.round((asset.y - rect.y) / tileSize);
		
		//swap depth if y changed
		if(pathMap[y*Canvas.mapWidth + x] == "x")
		{
			container.pan(-dx * SPEED, -dy * SPEED);
			return;
		}		
		
		if(dy != 0)
		{
			container.updateDepth(this, lastY, y); 
		}
		drawDebugRect(x,y);
	}
	
	private var moved:Boolean = false;
	override public function render(rect:Rectangle):void
	{
		if(!moved)
		{
			super.render(rect);
		}
	}
}

class Block extends Tile
{	
	private var colors:Array = [0xFF0000, 0xFFFF00, 0x00FF00, 0x00FFFF, 0x0000FF, 0xFF00FF, 0xFF0000];
	private var alphas:Array = [100, 100, 100, 100, 100, 100, 100];
	private var ratios:Array = [0x00, 0x2A, 0x55, 0x7F, 0xAA, 0xD4, 0xFF];
	
	public function Block()
	{
		asset = new Shape();
		asset.graphics.beginFill(0xABCDEF, 1);
		asset.graphics.lineStyle(1);
		asset.graphics.drawRect(1,-.5*tileSize,tileSize-2,tileSize);
		asset.graphics.beginFill(0x345678, 1);
		asset.graphics.drawRect(8,0,tileSize-16,tileSize-4);
//		asset.graphics.beginGradientFill("linear", colors, alphas, ratios);
//		asset.graphics.drawRect(1,-1.5*tileSize,tileSize,2.5*tileSize);
	}
}

interface IKeyboard
{
	function actPress(keyCode:int, shift:Boolean):void;
	function actRelease(keyCode:int, shift:Boolean):void;
}

class KeyManager
{
	private var _isDownFunc:Function;
	private var downKeys:Vector.<int> = new Vector.<int>(256);
	private var keyboards:Vector.<IKeyboard> = new Vector.<IKeyboard>;
	
	private var isLocked:Boolean = false;
	
	public function addKeyboard(keyboard:IKeyboard):void
	{
		keyboards.push(keyboard);
	}
	
	
	public function lock():void
	{
		isLocked = true;
	}
	
	public function unlock():void
	{
		isLocked = false;
	}
	
	public function listen(stage:Stage):void
	{
		stage.addEventListener(KeyboardEvent.KEY_UP, function(event:KeyboardEvent):void
		{
			actRelease(event.keyCode, Boolean(downKeys[event.keyCode] & 0x100));
			downKeys[event.keyCode] = 0;
		})
		
		stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event:KeyboardEvent):void
		{
			if(isDown(event.keyCode))
			{
				return;
			}
			actPress(event.keyCode, event.shiftKey);
			downKeys[event.keyCode] = 1;
		})
		_isDownFunc = function(keyCode:int):Boolean
		{
			return downKeys[keyCode] > 0;
		}
	}
	
	public function isDown(keyCode:int):Boolean
	{
		return _isDownFunc(keyCode);
	}
	
	public function actPress(keyCode:int, shift:Boolean):void
	{
		for each(var k:IKeyboard in keyboards)
		{
			k.actPress(keyCode, shift);
		}
	}
	
	public function actRelease(keyCode:int, shift:Boolean):void
	{
		for each(var k:IKeyboard in keyboards)
		{
			k.actRelease(keyCode, shift);
		}
	}
}
var pathMap:Array = 
"\
xxxxxxxxxxxx\
x0000000000x\
x00x0000000x\
xx0000A000xx\
x00000x00x0x\
xxxx0000xx0x\
x0000000000x\
xxxxxxxxxxxx\
".
split("");

var drawDebugRect:Function;

Forked