diff --git a/src/haxe/ru/m/puzzlez/core/Game.hx b/src/haxe/ru/m/puzzlez/core/Game.hx index e5c8a6c..0b93404 100644 --- a/src/haxe/ru/m/puzzlez/core/Game.hx +++ b/src/haxe/ru/m/puzzlez/core/Game.hx @@ -20,9 +20,17 @@ class Game implements IGame { } public function start():Void { + shuffle(); signal.emit(GameEvent.START(state)); } + public function shuffle():Void { + for (part in state.parts) { + part.rect.x = Math.random() * (state.preset.tableRect.width - part.rect.width); + part.rect.y = Math.random() * (state.preset.tableRect.height - part.rect.height); + } + } + private static function distance(a:Point, b:Point):Float { var diff = a.subtract(b); return Math.abs(diff.x) + Math.abs(diff.y); diff --git a/src/haxe/ru/m/puzzlez/core/GameUtil.hx b/src/haxe/ru/m/puzzlez/core/GameUtil.hx index 87ceb40..910f1ef 100644 --- a/src/haxe/ru/m/puzzlez/core/GameUtil.hx +++ b/src/haxe/ru/m/puzzlez/core/GameUtil.hx @@ -2,18 +2,76 @@ package ru.m.puzzlez.core; import flash.geom.Point; import flash.geom.Rectangle; -import ru.m.puzzlez.core.Part.Bounds; -import ru.m.puzzlez.core.Part.BoundType; +import ru.m.puzzlez.core.Part; + +class BoundsMap { + + private var grid:Grid; + private var bounds:Array; + + public function new(grid:Grid) { + this.grid = grid; + bounds = []; + for (x in 0...grid.width + 1) { + for (y in 0...grid.height + 1) { + bounds.push(buildPartBound()); + bounds.push(buildPartBound()); + } + } + } + + public function buildBound():BoundType { + return Math.random() > 0.5 ? BoundType.OUT : BoundType.IN; + } + + public function buildPartBound():PartBound { + return { + spike: buildBound(), + side: buildBound(), + } + } + + public function buildNonePartBound():PartBound { + return { + spike: NONE, + side: NONE, + } + } + + public function revert(type:BoundType):BoundType { + return switch type { + case IN: OUT; + case OUT: IN; + case NONE: NONE; + } + } + + public function getBound(x:Int, y:Int, side:Side):PartBound { + var index = switch side { + case TOP: x + (grid.width + 1) * (y * 2); + case LEFT: x + (grid.width + 1) * (y + 1); + case RIGHT: x + (grid.width + 1) * (y + 1) + 1; + case BOTTOM: x + (grid.width + 1) * (y * 2) + (grid.width + 1) * 2; + } + return switch side { + case TOP | LEFT: {spike: revert(bounds[index].spike), side: revert(bounds[index].side)}; + case _: bounds[index]; + } + } +} class GameUtil { public static function buildPreset(image:ImageSource):GamePreset { + var size = 8; + var offset = 100; + var imageRect = new Rectangle(offset, offset, 1024, 1024); + var tableRect = new Rectangle(0, 0, imageRect.width + offset * 2, imageRect.height + offset * 2); return { image:image, - grid: {width: 8, height: 8}, - tableRect: new Rectangle(0, 0, 1128, 1128), - //imageRect: new Rectangle(0, 0, 2304, 2304), - imageRect: new Rectangle(0, 0, 1024, 1024), + grid: {width: size, height: size}, + tableRect: tableRect, + imageRect: imageRect, } } @@ -21,29 +79,27 @@ class GameUtil { var parts:Array = []; var partWidth = preset.imageRect.width / preset.grid.width; var partHeight = preset.imageRect.height / preset.grid.height; - var topLeft = new Point( - (preset.tableRect.width - preset.imageRect.width) / 2, - (preset.tableRect.height - preset.imageRect.height) / 2 - ); - for (x in 0...preset.grid.width) { - for (y in 0...preset.grid.height) { + var topLeft = preset.imageRect.topLeft; + var boundsMap = new BoundsMap(preset.grid); + for (y in 0...preset.grid.height) { + for (x in 0...preset.grid.width) { var bounds:Bounds = { - left: BoundType.IN, - right: BoundType.OUT, - top: BoundType.IN, - bottom: BoundType.OUT, + left: boundsMap.getBound(x, y, LEFT), + right: boundsMap.getBound(x, y, RIGHT), + top: boundsMap.getBound(x, y, TOP), + bottom: boundsMap.getBound(x, y, BOTTOM), } if (x == 0) { - bounds.left = BoundType.NONE; + bounds.left = boundsMap.buildNonePartBound(); } if (y == 0) { - bounds.top = BoundType.NONE; + bounds.top = boundsMap.buildNonePartBound(); } if (x == preset.grid.width - 1) { - bounds.right = BoundType.NONE; + bounds.right = boundsMap.buildNonePartBound(); } if (y == preset.grid.height - 1) { - bounds.bottom = BoundType.NONE; + bounds.bottom = boundsMap.buildNonePartBound(); } var id = (x << 16) + y; var position = new Point(topLeft.x + x * partWidth, topLeft.y + y * partHeight); diff --git a/src/haxe/ru/m/puzzlez/core/Part.hx b/src/haxe/ru/m/puzzlez/core/Part.hx index ce8e4e3..8432668 100644 --- a/src/haxe/ru/m/puzzlez/core/Part.hx +++ b/src/haxe/ru/m/puzzlez/core/Part.hx @@ -3,17 +3,29 @@ package ru.m.puzzlez.core; import flash.geom.Point; import flash.geom.Rectangle; +enum Side { + TOP; + LEFT; + RIGHT; + BOTTOM; +} + enum BoundType { NONE; OUT; IN; } +typedef PartBound = { + var spike: BoundType; + var side: BoundType; +} + typedef Bounds = { - var left:BoundType; - var right:BoundType; - var top:BoundType; - var bottom:BoundType; + var left:PartBound; + var right:PartBound; + var top:PartBound; + var bottom:PartBound; } typedef Part = { diff --git a/src/haxe/ru/m/puzzlez/render/Render.hx b/src/haxe/ru/m/puzzlez/render/Render.hx index c5ab0a5..20a7b15 100644 --- a/src/haxe/ru/m/puzzlez/render/Render.hx +++ b/src/haxe/ru/m/puzzlez/render/Render.hx @@ -76,6 +76,13 @@ class Render extends SpriteView implements IRender { table.graphics.drawRect(state.preset.tableRect.x, state.preset.tableRect.y, state.preset.tableRect.width, state.preset.tableRect.height); table.graphics.endFill(); table.graphics.lineStyle(); + + table.graphics.lineStyle(2, 0xCCCCCC); + table.graphics.beginFill(0x777777); + table.graphics.drawRect(state.preset.imageRect.x, state.preset.imageRect.y, state.preset.imageRect.width, state.preset.imageRect.height); + table.graphics.endFill(); + table.graphics.lineStyle(); + toUpdate(); } diff --git a/src/haxe/ru/m/puzzlez/render/RenderUtil.hx b/src/haxe/ru/m/puzzlez/render/RenderUtil.hx index 4815f7f..95a52d3 100644 --- a/src/haxe/ru/m/puzzlez/render/RenderUtil.hx +++ b/src/haxe/ru/m/puzzlez/render/RenderUtil.hx @@ -18,9 +18,9 @@ class RenderUtil { public static function resolveImage(source:ImageSource):Promise { return switch source { case ASSET(name): - return Promise.promise(Assets.getBitmapData(name)); + Promise.promise(Assets.getBitmapData(name)); case URL(url): - return new ImageLoader().GET(url); + new ImageLoader().GET(url); } } diff --git a/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx index e8a39bf..bdc2aef 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx @@ -11,10 +11,13 @@ class BaseMaskBuilder implements IPartMaskBuilder { public function new() { } - private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, type:BoundType):Void { + private function createAngle(path:DrawPath, x:Float, y:Float):Void { path.commands.push(GraphicsPathCommand.LINE_TO); - path.data.push(toX); - path.data.push(toY); + path.data.push(x); + path.data.push(y); + } + + private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { } public function build(rect:Rectangle, bounds:Bounds):DrawPath { @@ -22,13 +25,15 @@ class BaseMaskBuilder implements IPartMaskBuilder { commands: new Vector(), data: new Vector(), } - path.commands.push(GraphicsPathCommand.MOVE_TO); - path.data.push(rect.left); - path.data.push(rect.top); + createAngle(path, rect.left, rect.top); createBound(path, rect.left, rect.top, rect.right, rect.top, bounds.top); + createAngle(path, rect.right, rect.top); createBound(path, rect.right, rect.top, rect.right, rect.bottom, bounds.right); + createAngle(path, rect.right, rect.bottom); createBound(path, rect.right, rect.bottom, rect.left, rect.bottom, bounds.bottom); + createAngle(path, rect.left, rect.bottom); createBound(path, rect.left, rect.bottom, rect.left, rect.top, bounds.left); + createAngle(path, rect.left, rect.top); return path; } } diff --git a/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx index 106f0e2..9f83490 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx @@ -6,34 +6,38 @@ import ru.m.puzzlez.render.mask.IPartMaskBuilder; class ClassicMaskBuilder extends BaseMaskBuilder { - override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, type:BoundType):Void { + override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { var dx = toX == fromX ? 0 : (toX - fromX) / Math.abs(toX - fromX); var dy = toY == fromY ? 0 : (toY - fromY) / Math.abs(toY - fromY); var boundLength = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY)); var spikeWidth = boundLength * 0.2; var spikeOffset = (boundLength - spikeWidth) / 2; - var spikeDepth = switch type { + var spikeDepth = switch bound.spike { case NONE: 0; case IN: spikeWidth; case OUT: -spikeWidth; }; - switch type { + var spikeSideOffset = switch bound.side { + case NONE: 0; + case IN: boundLength * -0.04; + case OUT: boundLength * 0.04; + } + switch bound.spike { case NONE: case IN | OUT: path.commands.push(GraphicsPathCommand.LINE_TO); - path.data.push(fromX + spikeOffset * dx); - path.data.push(fromY + spikeOffset * dy); + path.data.push(fromX + spikeOffset * dx + spikeSideOffset * dy); + path.data.push(fromY + spikeOffset * dy + spikeSideOffset * dx); path.commands.push(GraphicsPathCommand.CURVE_TO); - path.data.push(fromX + (spikeOffset * 0.8) * dx - spikeDepth * dy); - path.data.push(fromY + spikeDepth * dx + (spikeOffset * 0.8) * dy); - path.data.push(fromX + (spikeOffset + spikeWidth / 2) * dx - (spikeDepth * 1.1) * dy); - path.data.push(fromY + (spikeDepth * 1.1) * dx + (spikeOffset + spikeWidth / 2) * dy); + path.data.push(fromX + (spikeOffset * 0.8) * dx - spikeDepth * dy + spikeSideOffset * dy); + path.data.push(fromY + spikeDepth * dx + (spikeOffset * 0.8) * dy + spikeSideOffset * dx); + path.data.push(fromX + (spikeOffset + spikeWidth / 2) * dx - (spikeDepth * 1.1) * dy + spikeSideOffset * dy); + path.data.push(fromY + (spikeDepth * 1.1) * dx + (spikeOffset + spikeWidth / 2) * dy + spikeSideOffset * dx); path.commands.push(GraphicsPathCommand.CURVE_TO); - path.data.push(fromX + (spikeOffset + spikeWidth + spikeOffset * 0.2) * dx - spikeDepth * dy); - path.data.push(fromY + spikeDepth * dx + (spikeOffset + spikeWidth + spikeOffset * 0.2) * dy); - path.data.push(fromX + (spikeOffset + spikeWidth) * dx); - path.data.push(fromY + (spikeOffset + spikeWidth) * dy); + path.data.push(fromX + (spikeOffset + spikeWidth + spikeOffset * 0.2) * dx - spikeDepth * dy + spikeSideOffset * dy); + path.data.push(fromY + spikeDepth * dx + (spikeOffset + spikeWidth + spikeOffset * 0.2) * dy + spikeSideOffset * dx); + path.data.push(fromX + (spikeOffset + spikeWidth) * dx + spikeSideOffset * dy); + path.data.push(fromY + (spikeOffset + spikeWidth) * dy + spikeSideOffset * dx); } - super.createBound(path, fromY, fromY, toX, toY, type); } } diff --git a/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx b/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx index 86bd72c..de93d29 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx @@ -4,7 +4,6 @@ import flash.display.Shape; import flash.geom.Rectangle; import ru.m.puzzlez.core.Part; - class PartMask extends Shape { public var rect(default, null):Rectangle; diff --git a/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx index 8d42bd1..8c9498a 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx @@ -6,18 +6,18 @@ import ru.m.puzzlez.render.mask.IPartMaskBuilder; class SquareMaskBuilder extends BaseMaskBuilder { - override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, type:BoundType):Void { + override private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { var dx = toX == fromX ? 0 : (toX - fromX) / Math.abs(toX - fromX); var dy = toY == fromY ? 0 : (toY - fromY) / Math.abs(toY - fromY); var boundLength = Math.max(Math.abs(toX - fromX), Math.abs(toY - fromY)); var spikeWidth = boundLength * 0.2; var spikeOffset = (boundLength - spikeWidth) / 2; - var spikeDepth = switch type { + var spikeDepth = switch bound.spike { case NONE: 0; case IN: spikeWidth; case OUT: -spikeWidth; } - switch type { + switch bound.spike { case NONE: case IN | OUT: path.commands.push(GraphicsPathCommand.LINE_TO); @@ -33,6 +33,5 @@ class SquareMaskBuilder extends BaseMaskBuilder { path.data.push(fromX + (spikeOffset + spikeWidth) * dx); path.data.push(fromY + (spikeOffset + spikeWidth) * dy); } - super.createBound(path, fromY, fromY, toX, toY, type); } }