Вложений: 2
Можно как-то вот так. [см ниже]
Не спорю с тем, что можно сделать проще (наверное) и оптимальнее (точно) , но для примера вполне пойдет:
P.S. Только что понял, что не очень-то понял задачу.
Тов. Snopka, объясните подробнее, как себя должны вести линии при различных условиях. И как вообще строиться.
Код AS3:
package gridExample.grid
{
import flash.geom.Point;
/**
* Класс модели отрезка.
* Координаты конца и начала -- координаты сетки, а не дисплейные
* @author chu
*/
public class LineSegment
{
private var _start : Point;
private var _end : Point;
private var _color : uint;
public function LineSegment(start : Point, end : Point, color : uint = 0x0)
{
_start = start;
_end = end;
_color = color;
}
//*** public ***//
public function get start():Point
{
return _start;
}
public function get end():Point
{
return _end;
}
public function get color():uint
{
return _color;
}
public function set color(value : uint):void
{
_color = value;
}
public function hasCoincidence(start : Point, end : Point):Boolean
{
return hasDirectCoincidence(start, end) || hasDirectCoincidence(end, start);
}
//*** private ***//
private function hasDirectCoincidence(start : Point, end : Point):Boolean
{
return this.start.equals(start) && this.end.equals(end)
}
}
}
Код AS3:
package gridExample.grid
{
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Point;
public class Grid extends Sprite
{
private static const CELL_SIZE : uint = 70;
private static const BG_FILL_COLOR : uint = 0xAAAAAA;
private static const BG_LINES_COLOR : uint = 0x555555;
private static const BG_LINES_THICKNESS : Number = 2;
private static const BG_BORDER_THICKNESS : Number = 6;
private static const CELL_COLOR : uint = 0xFFFFFF;
private static const SEGMENTS_LINE_THICKNESS : uint = 4;
private static const COLLISED_PREVIEW_ALPHA : Number = 0.5;
private static const DEFAULT_ALPHA : Number = 1;
// model
private var _rows : uint;
private var _cols : uint;
private var _currentColor : uint;
private var _allowReplacing : Boolean;
private var _segments : Vector.<LineSegment> = new Vector.<LineSegment>();
private var _currentSegment : LineSegment;
// subview
private var _bg : Shape;
private var _linesContainer : Shape;
public function Grid()
{
getControls();
}
//*** public ***//
public function clearLines():void
{
_segments.splice(0, _segments.length);
_linesContainer.graphics.clear();
}
public function setSize(cols : uint, rows : uint):void
{
_rows = rows;
_cols = cols;
drawBg();
drawSegments();
}
public function setCurrentColor(color : uint):void
{
_currentColor = color;
}
public function setAllowReplacing(value : Boolean):void
{
_allowReplacing = value;
}
public function buildLine(x : Number, y : Number, preview : Boolean = false):void
{
var col : int = Math.floor(x/CELL_SIZE);
var row : int = Math.floor(y/CELL_SIZE);
var segment : LineSegment;
if(hasOutside(col, row))
{
return;
}
segment = getNearestSegment(x, y);
handleNewSegment(segment, preview);
drawSegments();
}
//*** private ***//
private function hasSlotBused(segment : LineSegment):Boolean
{
var oldSegment : LineSegment = getSegmentByPosition(segment.start, segment.end);
return oldSegment != null;
}
private function handleNewSegment(segment : LineSegment, preview : Boolean):void
{
var isBusy : Boolean = hasSlotBused(segment);
if(preview || (isBusy && !_allowReplacing))
{
_currentSegment = segment;
return;
}
if(isBusy && _allowReplacing)
{
getSegmentByPosition(segment.start, segment.end, true);
}
_segments.push(segment);
}
private function getSegmentByPosition(start : Point, end : Point, remove : Boolean = false):LineSegment
{
var numSegments : uint = _segments.length;
while(numSegments--)
{
var segment : LineSegment = _segments[numSegments];
if(segment.hasCoincidence(start, end))
{
if(remove)
{
_segments.splice(numSegments, 1);
}
return segment;
}
}
return null;
}
/**
* Возвращает вектор нормали от указанной точки до ближайшего отрезка
* пикселы
*/
private function getNormal(x : uint, y : uint):Point
{
var xLen : Number = x - Math.round(x/CELL_SIZE)*CELL_SIZE;
var yLen : Number = y - Math.round(y/CELL_SIZE)*CELL_SIZE;
var isVert : Boolean = Math.abs(yLen) < Math.abs(xLen);
var dirX : Number = isVert ? 0 : xLen;
var dirY : Number = isVert ? yLen : 0;
return new Point(dirX, dirY);
}
private function getNearestSegment(x : uint, y : uint):LineSegment
{
var normal : Point = getNormal(x, y);
var startX : uint;
var startY : uint;
var endX : uint;
var endY : uint;
if(normal.x)
{
startX = (x - normal.x)/CELL_SIZE;
startY = Math.floor(y/CELL_SIZE);
endX = startX;
endY = Math.ceil(y/CELL_SIZE);
}
else
{
startX = Math.floor(x/CELL_SIZE);
startY = (y - normal.y)/CELL_SIZE;
endX = Math.ceil(x/CELL_SIZE);
endY = startY;
}
return new LineSegment(new Point(startX, startY), new Point(endX, endY), _currentColor);
}
private function getControls():void
{
_bg = new Shape();
addChild(_bg);
_linesContainer = new Shape();
addChild(_linesContainer);
}
private function drawSegments():void
{
var graph : Graphics = _linesContainer.graphics;
graph.clear();
for each(var segmentParam : LineSegment in _segments)
{
drawSegment(segmentParam, graph);
}
if(_currentSegment)
{
var isCollision : Boolean = hasSlotBused(_currentSegment);
var alpha : Number = isCollision ? COLLISED_PREVIEW_ALPHA : DEFAULT_ALPHA;
drawSegment(_currentSegment, graph, alpha);
}
}
private function drawSegment(segment : LineSegment, graph : Graphics, alpha : Number = DEFAULT_ALPHA):void
{
// ячейки
var start : Point = segment.start;
var end : Point = segment.end;
//проверка на вхождение отрезка в зону отображения
if(hasPointOutside(start) || hasPointOutside(end))
{
return;
}
// пикселы
var startX : uint = start.x * CELL_SIZE;
var startY : uint = start.y * CELL_SIZE;
var endX : uint = end.x * CELL_SIZE;
var endY : uint = end.y * CELL_SIZE;
graph.lineStyle(SEGMENTS_LINE_THICKNESS, segment.color, alpha);
graph.moveTo(startX, startY);
graph.lineTo(endX, endY);
}
private function hasPointOutside(point : Point):Boolean
{
return hasOutside(point.x, point.y);
}
private function hasOutside(col : Number, row : Number):Boolean
{
return (col < 0) || (col > _cols) || (row < 0) || (row > _rows);
}
private function drawBg():void
{
var graph : Graphics = _bg.graphics;
var width : uint = CELL_SIZE * _cols;
var height : uint = CELL_SIZE * _rows;
graph.clear();
// бордюр и фон
graph.beginFill(BG_FILL_COLOR);
graph.lineStyle(BG_BORDER_THICKNESS, BG_LINES_COLOR);
graph.drawRect(0, 0, width, height);
// остальные линии
graph.endFill();
graph.lineStyle(BG_LINES_THICKNESS, BG_LINES_COLOR);
for(var col : uint = 1; col < _cols; col++)
{
var currentX : uint = CELL_SIZE * col;
graph.moveTo(currentX, 0);
graph.lineTo(currentX, height);
}
for(var row : uint = 1; row < _rows; row++)
{
var currentY : uint = CELL_SIZE * row;
graph.moveTo(0, currentY);
graph.lineTo(width, currentY);
}
}
}
}
Остальное в приложенных исходниках.
Результат примерно такой:
|