diff --git a/src/haxe/ru/m/puzzlez/core/BoundType.hx b/src/haxe/ru/m/puzzlez/core/BoundType.hx new file mode 100644 index 0000000..2af2e6a --- /dev/null +++ b/src/haxe/ru/m/puzzlez/core/BoundType.hx @@ -0,0 +1,7 @@ +package ru.m.puzzlez.core; + +enum BoundType { + NONE; + OUT; + IN; +} diff --git a/src/haxe/ru/m/puzzlez/core/Game.hx b/src/haxe/ru/m/puzzlez/core/Game.hx index ec5f16c..e1cb6eb 100644 --- a/src/haxe/ru/m/puzzlez/core/Game.hx +++ b/src/haxe/ru/m/puzzlez/core/Game.hx @@ -2,6 +2,8 @@ package ru.m.puzzlez.core; import flash.geom.Point; import haxework.signal.Signal; +import ru.m.puzzlez.core.GameEvent; +import ru.m.puzzlez.core.PartLocation; class Game implements IGame { public var state(default, null):GameState; @@ -26,11 +28,14 @@ class Game implements IGame { public function shuffle():Void { for (part in state.parts) { - if (!part.completed) { - var bound = part.rect.width * 0.25; - part.rect.x = bound + Math.random() * (state.preset.tableRect.width - part.rect.width - bound * 2); - part.rect.y = bound + Math.random() * (state.preset.tableRect.height - part.rect.height - bound * 2); - signal.emit(GameEvent.PART_MOVED(part.id, part.rect.topLeft)); + switch part.location { + case TABLE(_): + var bound = part.rect.width * 0.25; + var x = bound + Math.random() * (state.preset.tableRect.width - part.rect.width - bound * 2); + var y = bound + Math.random() * (state.preset.tableRect.height - part.rect.height - bound * 2); + part.location = TABLE(new Point(x, y)); + signal.emit(CHANGE(PART_UPDATE(part.id, part.location))); + case _: } } } @@ -42,19 +47,21 @@ class Game implements IGame { private function onGameEvent(event:GameEvent):Void { switch event { - case GameEvent.PART_MOVE(id, position): + case ACTION(PART_MOVE(id, point)): var part = partsById[id]; - part.rect.topLeft = position; - signal.emit(GameEvent.PART_MOVED(id, position)); - case GameEvent.PART_PUT(id, position): - var part = partsById[id]; - var d = distance(part.position, position); + part.location = TABLE(point); + signal.emit(CHANGE(PART_UPDATE(id, part.location))); + case ACTION(PART_PUT(id, point)): + var part:Part = partsById[id]; + var target:Point = state.preset.imageRect.topLeft.clone(); + target = target.add(new Point(part.gridX * part.rect.width, part.gridY * part.rect.height)); + var d = distance(target, point); if (d < 70) { - part.completed = true; - part.rect.topLeft = part.position; - signal.emit(GameEvent.PART_COMPLETED(id, part.position)); + part.location = IMAGE; + signal.emit(CHANGE(PART_UPDATE(id, part.location))); } else { - signal.emit(GameEvent.PART_MOVED(id, position)); + part.location = TABLE(point); + signal.emit(CHANGE(PART_UPDATE(id, part.location))); } case _: } diff --git a/src/haxe/ru/m/puzzlez/core/GameEvent.hx b/src/haxe/ru/m/puzzlez/core/GameEvent.hx index 1cb6440..024f0ac 100644 --- a/src/haxe/ru/m/puzzlez/core/GameEvent.hx +++ b/src/haxe/ru/m/puzzlez/core/GameEvent.hx @@ -2,10 +2,19 @@ package ru.m.puzzlez.core; import flash.geom.Point; +enum GameAction { + PART_TAKE(id:Int); + PART_MOVE(id:Int, point:Point); + PART_PUT(id:Int, point:Point); +} + +enum GameChange { + PART_UPDATE(id:Int, location:PartLocation); +} + enum GameEvent { START(state:GameState); - PART_MOVE(id:Int, position:Point); - PART_PUT(id:Int, position:Point); - PART_MOVED(id:Int, position:Point); - PART_COMPLETED(id:Int, position:Point); + ACTION(action:GameAction); + CHANGE(change:GameChange); + COMPLETE; } diff --git a/src/haxe/ru/m/puzzlez/core/GameUtil.hx b/src/haxe/ru/m/puzzlez/core/GameUtil.hx index 191a418..3037fdf 100644 --- a/src/haxe/ru/m/puzzlez/core/GameUtil.hx +++ b/src/haxe/ru/m/puzzlez/core/GameUtil.hx @@ -1,9 +1,11 @@ package ru.m.puzzlez.core; -import ru.m.puzzlez.core.Id.ImageId; import flash.geom.Point; import flash.geom.Rectangle; +import ru.m.puzzlez.core.BoundType; +import ru.m.puzzlez.core.Id; import ru.m.puzzlez.core.Part; +import ru.m.puzzlez.core.Side; class BoundsMap { @@ -92,7 +94,7 @@ class GameUtil { var boundsMap = new BoundsMap(preset.grid); for (y in 0...preset.grid.height) { for (x in 0...preset.grid.width) { - var bounds:Bounds = { + var bounds:PartBounds = { left: boundsMap.getBound(x, y, LEFT), right: boundsMap.getBound(x, y, RIGHT), top: boundsMap.getBound(x, y, TOP), @@ -116,10 +118,9 @@ class GameUtil { id: id, gridX: x, gridY: y, - position: position, - rect: new Rectangle(position.x, position.y, partWidth, partHeight), + location: PartLocation.TABLE(position), bounds: bounds, - completed: false, + rect: new Rectangle(0, 0, partWidth, partHeight), }); } } diff --git a/src/haxe/ru/m/puzzlez/core/IGame.hx b/src/haxe/ru/m/puzzlez/core/IGame.hx index 3d2d68e..c85ddef 100644 --- a/src/haxe/ru/m/puzzlez/core/IGame.hx +++ b/src/haxe/ru/m/puzzlez/core/IGame.hx @@ -7,7 +7,10 @@ interface IGame { public var signal(default, null):Signal; public function start():Void; + public function stop():Void; + public function shuffle():Void; + public function dispose():Void; } diff --git a/src/haxe/ru/m/puzzlez/core/Id.hx b/src/haxe/ru/m/puzzlez/core/Id.hx index 441a3c2..e3260d3 100644 --- a/src/haxe/ru/m/puzzlez/core/Id.hx +++ b/src/haxe/ru/m/puzzlez/core/Id.hx @@ -4,9 +4,11 @@ typedef SourceId = String; abstract ImageId({source:SourceId, id:String}) { public var source(get, never):SourceId; + private inline function get_source():SourceId return this.source; public var id(get, never):String; + private inline function get_id():String return this.id; public function new(source:SourceId, id:String) { diff --git a/src/haxe/ru/m/puzzlez/core/Part.hx b/src/haxe/ru/m/puzzlez/core/Part.hx index 6e666bb..9e55fb4 100644 --- a/src/haxe/ru/m/puzzlez/core/Part.hx +++ b/src/haxe/ru/m/puzzlez/core/Part.hx @@ -1,27 +1,13 @@ 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; + var spike:BoundType; + var side:BoundType; } -typedef Bounds = { +typedef PartBounds = { var left:PartBound; var right:PartBound; var top:PartBound; @@ -32,8 +18,7 @@ typedef Part = { var id:Int; var gridX:Int; var gridY:Int; - var position:Point; + var location:PartLocation; + var bounds:PartBounds; var rect:Rectangle; - var bounds:Bounds; - var completed:Bool; } diff --git a/src/haxe/ru/m/puzzlez/core/PartLocation.hx b/src/haxe/ru/m/puzzlez/core/PartLocation.hx new file mode 100644 index 0000000..46061ef --- /dev/null +++ b/src/haxe/ru/m/puzzlez/core/PartLocation.hx @@ -0,0 +1,9 @@ +package ru.m.puzzlez.core; + +import flash.geom.Point; + +enum PartLocation { + //PANEL(index:Int); + TABLE(point:Point); + IMAGE; +} diff --git a/src/haxe/ru/m/puzzlez/core/Side.hx b/src/haxe/ru/m/puzzlez/core/Side.hx new file mode 100644 index 0000000..892f4c9 --- /dev/null +++ b/src/haxe/ru/m/puzzlez/core/Side.hx @@ -0,0 +1,8 @@ +package ru.m.puzzlez.core; + +enum Side { + TOP; + LEFT; + RIGHT; + BOTTOM; +} diff --git a/src/haxe/ru/m/puzzlez/render/PartView.hx b/src/haxe/ru/m/puzzlez/render/PartView.hx index 6824d5e..c63164e 100644 --- a/src/haxe/ru/m/puzzlez/render/PartView.hx +++ b/src/haxe/ru/m/puzzlez/render/PartView.hx @@ -5,12 +5,14 @@ import flash.display.BitmapData; import flash.display.PixelSnapping; import flash.display.Sprite; import flash.geom.Point; +import ru.m.puzzlez.core.Part; class PartView extends Sprite { public var id(default, null):Int; public var position(default, set):Point; public var completed(default, default):Bool; + public var target(default, null):Point; private function set_position(value:Point):Point { position = value.clone(); @@ -29,16 +31,14 @@ class PartView extends Sprite { private var size:Point; - public function new(id:Int, image:BitmapData, size:Point) { + public function new(part:Part) { super(); #if !android filters = RenderUtil.buildFilters(); #end - this.id = id; - this.size = size; - if (image != null) { - this.image = image; - } + this.id = part.id; + this.size = part.rect.size.clone(); + this.target = new Point(part.gridX * size.x, part.gridY * size.y); } private function redraw():Void { @@ -52,8 +52,13 @@ class PartView extends Sprite { } } - public static function factory(id:Int, image:BitmapData, size:Point):PartView { - return new SpritePartView(id, image, size); + public function complete():Void { + position = target; + completed = true; + } + + public static function factory(part:Part):PartView { + return new SpritePartView(part); } } @@ -70,9 +75,9 @@ class SpritePartView extends PartView { class BitmapPartView extends PartView { private var bitmap:Bitmap; - public function new(id:Int, image:BitmapData, size:Point) { - super(id, image, size); - bitmap = new Bitmap(image, PixelSnapping.AUTO, true); + public function new(part) { + super(part); + bitmap = new Bitmap(null, PixelSnapping.AUTO, true); addChild(bitmap); } diff --git a/src/haxe/ru/m/puzzlez/render/Render.hx b/src/haxe/ru/m/puzzlez/render/Render.hx index 303143b..93ec05d 100644 --- a/src/haxe/ru/m/puzzlez/render/Render.hx +++ b/src/haxe/ru/m/puzzlez/render/Render.hx @@ -12,6 +12,7 @@ import haxework.signal.Signal; import haxework.view.SpriteView; import ru.m.puzzlez.core.GameEvent; import ru.m.puzzlez.core.GameState; +import ru.m.puzzlez.core.PartLocation; import ru.m.puzzlez.storage.ImageStorage; class Render extends SpriteView implements IRender { @@ -20,13 +21,13 @@ class Render extends SpriteView implements IRender { public var scale(get, set):Float; private function get_scale():Float { - return table.scaleX; + return tableView.scaleX; } private function set_scale(value:Float):Float { - var result = table.scaleX = table.scaleY = value; - table.x = (width - state.preset.tableRect.width * value) / 2; - table.y = (height - state.preset.tableRect.height * value) / 2; + var result = tableView.scaleX = tableView.scaleY = value; + tableView.x = (width - state.preset.tableRect.width * value) / 2; + tableView.y = (height - state.preset.tableRect.height * value) / 2; //setSize(table.width, table.height, 'table'); return result; } @@ -35,7 +36,8 @@ class Render extends SpriteView implements IRender { private var image:BitmapData; private var progress:ProgressView; - private var table:Sprite; + private var tableView:Sprite; + private var imageView:Sprite; private var parts:Map; private var activePart:PartView; private var activePoint:Point; @@ -46,9 +48,11 @@ class Render extends SpriteView implements IRender { super(); progress = new ProgressView(); signal = new Signal(); - table = new Sprite(); - table.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); - content.addChild(table); + tableView = new Sprite(); + tableView.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); + imageView = new Sprite(); + tableView.addChild(imageView); + content.addChild(tableView); parts = new Map(); } @@ -56,14 +60,13 @@ class Render extends SpriteView implements IRender { switch event { case START(state): onStart(state); - case PART_MOVED(id, point): + case CHANGE(PART_UPDATE(id, TABLE(point))): var part:PartView = parts[id]; part.position = point; - case PART_COMPLETED(id, point): + case CHANGE(PART_UPDATE(id, IMAGE)): var part:PartView = parts[id]; - part.position = point; - part.completed = true; - table.setChildIndex(part, 0); + part.complete(); + imageView.addChild(part); case _: } } @@ -72,18 +75,20 @@ class Render extends SpriteView implements IRender { clean(); this.state = state; for (part in state.parts) { - var partView = PartView.factory(part.id, null, part.rect.size); + var partView = PartView.factory(part); partView.position = part.rect.topLeft; parts.set(part.id, partView); - table.addChild(partView); + tableView.addChild(partView); } - table.graphics.clear(); - table.graphics.lineStyle(2, 0xCCCCCC); - table.graphics.beginFill(0x555555); - 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(); + imageView.x = state.preset.imageRect.x; + imageView.y = state.preset.imageRect.y; + imageView.graphics.clear(); + imageView.graphics.lineStyle(2, 0xCCCCCC); + imageView.graphics.beginFill(0x555555); + imageView.graphics.drawRect(0, 0, state.preset.imageRect.width, state.preset.imageRect.height); + imageView.graphics.endFill(); + imageView.graphics.lineStyle(); progress.text = "Loading image"; content.addChild(progress.content); imageStorage.resolve(state.preset.image).then(onImageResolved); @@ -119,26 +124,27 @@ class Render extends SpriteView implements IRender { return; } activePart = part; - table.setChildIndex(activePart, table.numChildren - 1); - activePoint = table.globalToLocal(new Point(event.stageX, event.stageY)); - table.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - table.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); + tableView.setChildIndex(activePart, tableView.numChildren - 1); + activePoint = tableView.globalToLocal(new Point(event.stageX, event.stageY)); + tableView.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + tableView.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); + signal.emit(ACTION(PART_TAKE(activePart.id))); } } private function onMouseMove(event:MouseEvent):Void { - var newPoint = table.globalToLocal(new Point(event.stageX, event.stageY)); + var newPoint = tableView.globalToLocal(new Point(event.stageX, event.stageY)); var partPosition = activePart.position.add(newPoint).subtract(activePoint); - signal.emit(GameEvent.PART_MOVE(activePart.id, partPosition.clone())); + signal.emit(ACTION(PART_MOVE(activePart.id, partPosition.clone()))); activePoint = newPoint; } private function onMouseUp(event:MouseEvent):Void { - var newPoint = table.globalToLocal(new Point(event.stageX, event.stageY)); + var newPoint = tableView.globalToLocal(new Point(event.stageX, event.stageY)); var partPosition = activePart.position.add(newPoint).subtract(activePoint); - signal.emit(GameEvent.PART_PUT(activePart.id, partPosition.clone())); - table.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); - table.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); + signal.emit(ACTION(PART_PUT(activePart.id, partPosition.clone()))); + tableView.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); + tableView.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); //save(activePart); activePart = null; activePoint = null; @@ -154,7 +160,9 @@ class Render extends SpriteView implements IRender { private function clean() { for (partView in parts) { - table.removeChild(partView); + if (partView.parent != null) { + partView.parent.removeChild(partView); + } } parts = new Map(); } diff --git a/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx index bdc2aef..0eea81d 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/BaseMaskBuilder.hx @@ -20,7 +20,7 @@ class BaseMaskBuilder implements IPartMaskBuilder { private function createBound(path:DrawPath, fromX:Float, fromY:Float, toX:Float, toY:Float, bound:PartBound):Void { } - public function build(rect:Rectangle, bounds:Bounds):DrawPath { + public function build(rect:Rectangle, bounds:PartBounds):DrawPath { var path:DrawPath = { commands: new Vector(), data: new Vector(), diff --git a/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx index feea67b..59405b0 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/ClassicMaskBuilder.hx @@ -1,6 +1,7 @@ package ru.m.puzzlez.render.mask; import flash.display.GraphicsPathCommand; +import ru.m.puzzlez.core.BoundType; import ru.m.puzzlez.core.Part; import ru.m.puzzlez.render.mask.IPartMaskBuilder; diff --git a/src/haxe/ru/m/puzzlez/render/mask/IPartMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/IPartMaskBuilder.hx index cee85a2..8b5136c 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/IPartMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/IPartMaskBuilder.hx @@ -11,5 +11,5 @@ typedef DrawPath = { } interface IPartMaskBuilder { - public function build(rect:Rectangle, bound:Bounds):DrawPath; + public function build(rect:Rectangle, bound:PartBounds):DrawPath; } diff --git a/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx b/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx index b71048f..0746a6c 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/PartMask.hx @@ -11,7 +11,7 @@ class PartMask extends Shape { private static var builder:IPartMaskBuilder = new ClassicMaskBuilder(); - public function new(rect:Rectangle, bounds:Bounds) { + public function new(rect:Rectangle, bounds:PartBounds) { super(); this.rect = rect.clone(); var offset = rect.width / 4 + rect.width * 0.05; diff --git a/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx b/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx index 8c9498a..386742a 100644 --- a/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx +++ b/src/haxe/ru/m/puzzlez/render/mask/SquareMaskBuilder.hx @@ -1,6 +1,7 @@ package ru.m.puzzlez.render.mask; import flash.display.GraphicsPathCommand; +import ru.m.puzzlez.core.BoundType; import ru.m.puzzlez.core.Part; import ru.m.puzzlez.render.mask.IPartMaskBuilder;