[improve] ClassicMaskBuilder

This commit is contained in:
2020-01-15 17:05:26 +03:00
parent 1f5a8de4be
commit fc9d43c938
9 changed files with 141 additions and 51 deletions

View File

@@ -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);

View File

@@ -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<PartBound>;
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<Part> = [];
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) {
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);

View File

@@ -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 = {

View File

@@ -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();
}

View File

@@ -18,9 +18,9 @@ class RenderUtil {
public static function resolveImage(source:ImageSource):Promise<BitmapData> {
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);
}
}

View File

@@ -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<GraphicsPathCommand>(),
data: new Vector<Float>(),
}
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;
}
}

View File

@@ -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);
}
super.createBound(path, fromY, fromY, toX, toY, type);
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);
}
}
}

View File

@@ -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;

View File

@@ -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);
}
}