automatic navigation generation

by wrotenodoc
the world starts as a big rectangle
you add obstacles into the world
partition the world nicely
---------------
it's a tree
how to implement path finding
flatten the tree and run dijkstra?
---------------
neighbor cell logic is invalid
M is a neighbor of L
M is subdivided
=> wrong connection (M is no more leaf)
---------------
neighbor finding done
need to implement path finding
♥0 | Line 104 | Modified 2016-03-28 03:28:22 | MIT License
play

ActionScript3 source code

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

package {
    
    import flash.geom.Point
    import flash.geom.Rectangle
    import flash.display.Sprite
    
    public class FlashTest extends Sprite {
        
        public function FlashTest() {
            // write as3 code here..
            var cell0:Cell = new Cell(new Rectangle(50, 50, 300, 300))
            /*cell0.divide(new Rectangle(200, 200, 50, 30))
            cell0.divide(new Rectangle(30, 30, 60, 70))
            cell0.divide(new Rectangle(70, 200, 20, 100))
            cell0.divide(new Rectangle(100, 100, 220, 20))
            cell0.divide(new Rectangle(150, 0, 20, 400))*/
            for(var i:int=0; i<10; i++){
                cell0.divide(new Rectangle(50+Math.random()*300, 50+Math.random()*300, 20+Math.random()*50, 20+Math.random()*50))
            }
            
            render(cell0)
            
            var leaves:Array = cell0.collectLeaves()
            findNeighbor(leaves)
            
            for each(var L:Cell in leaves){
                for each(var M:Cell in L.neighbors){
                    graphics.lineStyle(2, int(Math.random() * 0xff) << 16, 1)
                    graphics.moveTo(L.shape.x + L.shape.width/2, L.shape.y + L.shape.height/2)
                    graphics.lineTo(M.shape.x + M.shape.width/2, M.shape.y + M.shape.height/2)
                }
            }
        }
        
        public function render(cell:Cell):void {
            if(cell.isLeaf){
                graphics.lineStyle(1, 0x0, 1)
                graphics.beginFill(Math.random() * 0xff, 0.3)
                graphics.drawRect(cell.shape.x, cell.shape.y, cell.shape.width, cell.shape.height)
                graphics.endFill()
            }else{
                for each(var sub:Cell in cell.subs) render(sub)
            }
        }
        
        private function findNeighbor(leaves:Array):void {
            var n:int = leaves.length
            var a:Rectangle, b:Rectangle
            for(var i:int=0; i<n; i++){
                for(var j:int=i+1; j<n; j++){
                    a = leaves[i].shape.clone()
                    b = leaves[j].shape.clone()
                    var edge:Boolean = (near(a.left,b.right) || near(a.right,b.left)) && (near(a.top,b.bottom) || near(a.bottom,b.top))
                    a.inflate(1, 1)
                    b.inflate(1, 1)
                    if(a.intersects(b) && !edge){
                        leaves[i].neighbors.push(leaves[j])
                        leaves[j].neighbors.push(leaves[i])
                    }
                }
            }
            function near(x1:Number, x2:Number):Boolean { return Math.abs(x2-x1) < 0.05 }
        }
        
    }
    
}

////////////////////////
// outside of package //
////////////////////////
import flash.geom.Rectangle

// node class
class Cell {
    
    public var shape:Rectangle
    public var neighbors:Array = []
    public var subs:Array
    
    public function Cell(shape:Rectangle = null) {
        this.shape = shape
    }
    
    public function divide(obstacle:Rectangle):void {
        if(shape.intersects(obstacle) == false) return
        if(isLeaf){
            subs = []
            push(shape.left, shape.top, obstacle.left, obstacle.top)
            push(obstacle.left, shape.top, obstacle.right, obstacle.top)
            push(obstacle.right, shape.top, shape.right, obstacle.top)
            push(shape.left, obstacle.top, obstacle.left, obstacle.bottom)
            push(obstacle.right, obstacle.top, shape.right, obstacle.bottom)
            push(shape.left, obstacle.bottom, obstacle.left, shape.bottom)
            push(obstacle.left, obstacle.bottom, obstacle.right, shape.bottom)
            push(obstacle.right, obstacle.bottom, shape.right, shape.bottom)
        }else{
            for(var i:int=0; i<subs.length; i++){
                if(obstacle.containsRect(subs[i].shape)){
                    subs.splice(i, 1)
                    i--
                }else subs[i].divide(obstacle)
            }
        }
        function push(x1:Number,y1:Number, x2:Number,y2:Number):Cell {
            if(x2 > x1 && y2 > y1){
                x1 = Math.max(x1, shape.left)
                y1 = Math.max(y1, shape.top)
                x2 = Math.min(x2, shape.right)
                y2 = Math.min(y2, shape.bottom)
                var cell:Cell = new Cell(new Rectangle(x1, y1, x2-x1, y2-y1))
                subs.push(cell)
                return cell
            }
            return null
        }
    }
    
    public function collectLeaves():Array {
        var Q:Array = [this]
        var leaves:Array = []
        while(Q.length){
            var C:Cell = Q.shift()
            if(C.isLeaf) leaves.push(C)
            else for each(var child:Cell in C.subs) Q.push(child)
        }
        return leaves
    }
    
    public function get isLeaf():Boolean { return subs == null }
    
}

Forked