From 418ce312108805f285f140b533dd53afb797822a Mon Sep 17 00:00:00 2001
From: "v.tarantik" <v.tarantik@gmail.com>
Date: Thu, 6 Aug 2015 11:34:49 +0200
Subject: [PATCH] #32 Pieces animations problems fix, custom actions for actors

---
 .../game/games/pursuit/PursuitGame.java       |  40 ++-
 .../pursuit/action/MovePieceToPosition.java   |  38 +++
 .../action/RotateAndMovePieceInPosition.java  |  31 +++
 .../action/RotatePieceToClosestAngle.java     |  32 +++
 .../pursuit/action/SwitchPiecesAction.java    |  26 ++
 .../game/games/pursuit/environment/Grid.java  | 199 ---------------
 .../pursuit/helper/ArithmeticsHelper.java     |   5 +-
 .../game/games/pursuit/model/Grid.java        | 238 ++++++++++++++++++
 .../game/games/pursuit/model/Point.java       |  21 ++
 .../{environment => model}/PuzzlePiece.java   |  10 +-
 .../listener/DragAndRotateActorListener.java  | 112 +++++----
 11 files changed, 480 insertions(+), 272 deletions(-)
 create mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/action/MovePieceToPosition.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/action/RotateAndMovePieceInPosition.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/action/RotatePieceToClosestAngle.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/action/SwitchPiecesAction.java
 delete mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/environment/Grid.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/model/Grid.java
 create mode 100644 core/src/cz/nic/tablexia/game/games/pursuit/model/Point.java
 rename core/src/cz/nic/tablexia/game/games/pursuit/{environment => model}/PuzzlePiece.java (83%)

diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java b/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java
index d3c55eb7e..f6561542a 100644
--- a/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/PursuitGame.java
@@ -5,15 +5,16 @@ import com.badlogic.gdx.scenes.scene2d.Action;
 import com.badlogic.gdx.scenes.scene2d.Actor;
 import com.badlogic.gdx.scenes.scene2d.Group;
 import com.badlogic.gdx.scenes.scene2d.ui.Image;
-
-import net.dermetfan.utils.Pair;
+import com.badlogic.gdx.utils.Array;
 
 import java.util.Map;
 
 import cz.nic.tablexia.TablexiaSettings;
 import cz.nic.tablexia.game.AbstractTablexiaGame;
-import cz.nic.tablexia.game.games.pursuit.environment.Grid;
-import cz.nic.tablexia.game.games.pursuit.environment.PuzzlePiece;
+import cz.nic.tablexia.game.games.pursuit.action.RotateAndMovePieceInPosition;
+import cz.nic.tablexia.game.games.pursuit.action.RotatePieceToClosestAngle;
+import cz.nic.tablexia.game.games.pursuit.model.Grid;
+import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece;
 import cz.nic.tablexia.game.games.pursuit.helper.GameRulesHelper;
 import cz.nic.tablexia.game.games.pursuit.helper.TextureHelper;
 import cz.nic.tablexia.util.Log;
@@ -55,8 +56,8 @@ public class PursuitGame extends AbstractTablexiaGame<Void> {
         }) {
             @Override
             public void selected(float x, float y) {
-                if (dragAndRotateActorListener.getActor() == null) {
-                    dragAndRotateActorListener.setActor(grid.pieceAtPoint(x, y));
+                if (dragAndRotateActorListener.getDraggedActor() == null) {
+                    dragAndRotateActorListener.setDraggedActor(grid.pieceAtPoint(x, y));
                 }
             }
 
@@ -74,18 +75,31 @@ public class PursuitGame extends AbstractTablexiaGame<Void> {
             }
 
             @Override
-            public void dropped(float x, float y, Actor draggedPiece) {
+            public void dropped(float x, float y, final Actor draggedPiece) {
                 if (draggedPiece != null) {
-                    PuzzlePiece puzzlePiece = (PuzzlePiece) draggedPiece;
-                    PuzzlePiece overlappedPiece = grid.pieceIntersectingWithDragged(puzzlePiece.getId());
+                    dragAndRotateActorListener.setPerformingAction(true);
+                    final PuzzlePiece puzzlePiece = (PuzzlePiece) draggedPiece;
+                    final PuzzlePiece overlappedPiece = grid.pieceIntersectingWithDragged(puzzlePiece.getId());
                     Action onPiecesSwitchFinishedAction = new Action() {
                         @Override
                         public boolean act(float delta) {
                             movesCounter++;
-                            dragAndRotateActorListener.setActor(null);
+                            dragAndRotateActorListener.setDraggedActor(null);
+                            dragAndRotateActorListener.setPerformingAction(false);
+                            //cancelling all actions on actor that would take place after piece was moved in correct position
+                            Array<Action> gridActions = grid.getActions();
+                            if(gridActions.size>0){
+                                for(Action action: gridActions){
+                                    if(action instanceof RotatePieceToClosestAngle || action instanceof RotateAndMovePieceInPosition){
+                                        grid.removeAction(action);
+                                    }
+                                }
+                                //in case we canceled rotation animation, rotate piece to correct angle
+                                grid.addAction(new RotatePieceToClosestAngle((PuzzlePiece)draggedPiece));
+                            }
                             if (grid.allPiecesInCorrectPositions()) {
                                 endTime = System.currentTimeMillis();
-                                Log.info(getClass(),"Moves: "+movesCounter);
+                                Log.info(getClass(),"Moves : "+movesCounter);
                                 int starsCount = GameRulesHelper.getNumberOfStarsForMoves(getGameDifficulty().ordinal(),endTime-startTime);
                                 gameComplete(starsCount);
                             }
@@ -96,6 +110,7 @@ public class PursuitGame extends AbstractTablexiaGame<Void> {
                 }
             }
         };
+        dragAndRotateActorListener.setParentActor(grid);
         backgroundImage.addListener(dragAndRotateActorListener);
     }
 
@@ -109,8 +124,7 @@ public class PursuitGame extends AbstractTablexiaGame<Void> {
     private void prepareGrid() {
         TextureRegion mapTextureRegion = getScreenTextureRegion(TextureHelper.getMapFullName(1));
 
-        grid = new Grid(SCREEN_WIDTH / 2 - SCREEN_MIN_HEIGHT / 2, GRID_PADDING, SCREEN_MIN_HEIGHT - 2 * GRID_PADDING, GRID_COLUMNS, mapTextureRegion);
-        grid.shufflePieces(getRandom());
+        grid = new Grid(SCREEN_WIDTH / 2 - SCREEN_MIN_HEIGHT / 2, GRID_PADDING, SCREEN_MIN_HEIGHT - 2 * GRID_PADDING, GRID_COLUMNS, mapTextureRegion,getRandom());
         contentGroup.addActor(grid);
     }
 
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/action/MovePieceToPosition.java b/core/src/cz/nic/tablexia/game/games/pursuit/action/MovePieceToPosition.java
new file mode 100644
index 000000000..e96f3bc25
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/action/MovePieceToPosition.java
@@ -0,0 +1,38 @@
+package cz.nic.tablexia.game.games.pursuit.action;
+
+import com.badlogic.gdx.scenes.scene2d.Action;
+import com.badlogic.gdx.scenes.scene2d.actions.Actions;
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
+
+import cz.nic.tablexia.game.games.pursuit.model.Point;
+import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece;
+import cz.nic.tablexia.util.listener.DragAndRotateActorListener;
+
+/**
+ * Created by Václav Tarantík on 3.8.15.
+ */
+public class MovePieceToPosition extends SequenceAction {
+
+    /*
+    *Moves specified piece in position using built-in actions
+     */
+    public MovePieceToPosition(final PuzzlePiece draggedPiece, Point dest){
+        setActor(draggedPiece);
+        setTarget(draggedPiece);
+        Action postMovementAction = new Action() {
+            @Override
+            public boolean act(float delta) {
+                draggedPiece.setScale(1);
+                draggedPiece.setZIndex(1);
+                return true;
+            }
+        };
+        addAction(Actions.moveTo(dest.x, dest.y, DragAndRotateActorListener.MOVETO_ANIMATION_DURATION));
+        addAction(postMovementAction);
+    }
+
+    public MovePieceToPosition(final PuzzlePiece draggedPiece, Point dest,Action finalAction){
+        this(draggedPiece,dest);
+        addAction(finalAction);
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/action/RotateAndMovePieceInPosition.java b/core/src/cz/nic/tablexia/game/games/pursuit/action/RotateAndMovePieceInPosition.java
new file mode 100644
index 000000000..67669c29d
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/action/RotateAndMovePieceInPosition.java
@@ -0,0 +1,31 @@
+package cz.nic.tablexia.game.games.pursuit.action;
+
+import com.badlogic.gdx.scenes.scene2d.Action;
+import com.badlogic.gdx.scenes.scene2d.actions.Actions;
+import com.badlogic.gdx.scenes.scene2d.actions.ParallelAction;
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
+
+import cz.nic.tablexia.game.games.pursuit.model.Point;
+import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece;
+import cz.nic.tablexia.util.Log;
+import cz.nic.tablexia.util.listener.DragAndRotateActorListener;
+
+/**
+ * Created by Václav Tarantík on 3.8.15.
+ */
+public class RotateAndMovePieceInPosition extends SequenceAction {
+    public RotateAndMovePieceInPosition(PuzzlePiece draggedPiece,Point position, final DragAndRotateActorListener.IOnRotationFinished iOnRotationFinished){
+        setActor(draggedPiece);
+        setTarget(draggedPiece);
+        Action rotationFinishedAction = new Action() {
+            @Override
+            public boolean act(float delta) {
+                iOnRotationFinished.onRotationFinished();
+                return true;
+            }
+        };
+
+        addAction(Actions.parallel(new RotatePieceToClosestAngle(draggedPiece),new MovePieceToPosition(draggedPiece,position)));
+        addAction(rotationFinishedAction);
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/action/RotatePieceToClosestAngle.java b/core/src/cz/nic/tablexia/game/games/pursuit/action/RotatePieceToClosestAngle.java
new file mode 100644
index 000000000..211e24950
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/action/RotatePieceToClosestAngle.java
@@ -0,0 +1,32 @@
+package cz.nic.tablexia.game.games.pursuit.action;
+
+import com.badlogic.gdx.scenes.scene2d.Action;
+import com.badlogic.gdx.scenes.scene2d.actions.Actions;
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
+
+import cz.nic.tablexia.game.games.pursuit.helper.ArithmeticsHelper;
+import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece;
+import cz.nic.tablexia.util.listener.DragAndRotateActorListener;
+
+/**
+ * Created by Václav Tarantík on 3.8.15.
+ */
+public class RotatePieceToClosestAngle extends SequenceAction {
+    public RotatePieceToClosestAngle(PuzzlePiece draggedPiece){
+        setTarget(draggedPiece);
+        setActor(draggedPiece);
+        addAction(Actions.rotateTo(ArithmeticsHelper.getClosestRightAngle(draggedPiece.getRotation()), DragAndRotateActorListener.ROTATION_ANIMATION_DURATION));
+    }
+
+    public RotatePieceToClosestAngle(PuzzlePiece draggedPiece, final DragAndRotateActorListener.IOnRotationFinished iOnRotationFinished){
+        this(draggedPiece);
+        Action afterAction = new Action() {
+            @Override
+            public boolean act(float delta) {
+                iOnRotationFinished.onRotationFinished();
+                return true;
+            }
+        };
+        addAction(afterAction);
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/action/SwitchPiecesAction.java b/core/src/cz/nic/tablexia/game/games/pursuit/action/SwitchPiecesAction.java
new file mode 100644
index 000000000..552c627b3
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/action/SwitchPiecesAction.java
@@ -0,0 +1,26 @@
+package cz.nic.tablexia.game.games.pursuit.action;
+
+import com.badlogic.gdx.scenes.scene2d.Action;
+import com.badlogic.gdx.scenes.scene2d.actions.Actions;
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
+
+import cz.nic.tablexia.game.games.pursuit.model.Point;
+import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece;
+import cz.nic.tablexia.util.Log;
+
+/**
+ * Created by Václav Tarantík on 3.8.15.
+ */
+public class SwitchPiecesAction extends SequenceAction {
+    public SwitchPiecesAction(final PuzzlePiece draggedPiece, Point draggedPieceRelativePosition, final PuzzlePiece overlappedPiece, Point overlappedPieceRelativePosition, Action onActionFinishedAction){
+        addAction(Actions.parallel(new MovePieceToPosition(draggedPiece, overlappedPieceRelativePosition),
+                new MovePieceToPosition(overlappedPiece, draggedPieceRelativePosition)));
+        addAction(onActionFinishedAction);
+
+        int overlappedPieceActualPosition = overlappedPiece.getActualPosition();
+        int draggedPieceActualPosition = draggedPiece.getActualPosition();
+
+        draggedPiece.setActualPosition(overlappedPieceActualPosition);
+        overlappedPiece.setActualPosition(draggedPieceActualPosition);
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/environment/Grid.java b/core/src/cz/nic/tablexia/game/games/pursuit/environment/Grid.java
deleted file mode 100644
index de899e990..000000000
--- a/core/src/cz/nic/tablexia/game/games/pursuit/environment/Grid.java
+++ /dev/null
@@ -1,199 +0,0 @@
-package cz.nic.tablexia.game.games.pursuit.environment;
-
-import com.badlogic.gdx.graphics.g2d.TextureRegion;
-import com.badlogic.gdx.math.Intersector;
-import com.badlogic.gdx.math.Rectangle;
-import com.badlogic.gdx.math.Vector2;
-import com.badlogic.gdx.scenes.scene2d.Action;
-import com.badlogic.gdx.scenes.scene2d.Actor;
-import com.badlogic.gdx.scenes.scene2d.Group;
-import com.badlogic.gdx.scenes.scene2d.Touchable;
-import com.badlogic.gdx.scenes.scene2d.actions.Actions;
-
-import net.dermetfan.utils.Pair;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-import cz.nic.tablexia.TablexiaSettings;
-import cz.nic.tablexia.util.Log;
-import cz.nic.tablexia.util.listener.DragAndRotateActorListener;
-
-/**
- * Created by Václav Tarantík on 17.6.15.
- */
-public class Grid extends Group {
-    private float size;
-    private int numberOfColumns;//number of rows respectively columns
-    private Map<Integer, PuzzlePiece> piecesMap;
-    private TextureRegion textureRegion;
-
-    public Grid(float x, float y, float size, int numberOfColumns, TextureRegion textureRegion) {
-        super();
-        setPosition(x, y);
-        setSize(size, size);
-
-        setDebug(TablexiaSettings.getInstance().isShowBoundingBoxes());
-
-        this.textureRegion = textureRegion;
-        this.numberOfColumns = numberOfColumns;
-
-        setTouchable(Touchable.disabled);
-
-        piecesMap = new HashMap<Integer, PuzzlePiece>();
-        placePieces();
-
-    }
-
-    //creates pieces texture regions and places them in the grid
-    private void placePieces() {
-        for (int i = 0; i < Math.pow(numberOfColumns, 2); i++) {
-            float pieceSize = getWidth() / (float) numberOfColumns;
-            Pair<Float,Float> pieceRelativePosition = getPieceRelativePosition(i);
-            float relativePieceSize = pieceSize / getWidth();
-
-            //TextureRegion divided in parts for each piece
-            Log.info(getClass(), "Texture: " + textureRegion.getTexture() + " RPX: " + pieceRelativePosition.getKey() + " RPSX: " + (pieceRelativePosition.getKey() + relativePieceSize) + ", RPY: " + pieceRelativePosition.getValue() + ", RPSY: " + (pieceRelativePosition.getValue() + relativePieceSize) + ", SIZE: " + relativePieceSize * getWidth());
-            TextureRegion pieceRegion = new TextureRegion(textureRegion.getTexture(), pieceRelativePosition.getKey(), pieceRelativePosition.getValue(), pieceRelativePosition.getKey() + relativePieceSize, pieceRelativePosition.getValue() + relativePieceSize);
-            Pair<Float,Float> piecePosition = getPieceGridPositionInPixels(i);
-
-            PuzzlePiece puzzlePiece = new PuzzlePiece(i, pieceRegion);
-            puzzlePiece.setCorrectPosition(i);
-            puzzlePiece.setActualPosition(i);
-            puzzlePiece.setPosition(piecePosition.getKey(),piecePosition.getValue());
-            puzzlePiece.setSize(pieceSize, pieceSize);
-            puzzlePiece.setOrigin(pieceSize / 2, pieceSize / 2);
-            puzzlePiece.setZIndex(1);
-
-            //in initial state, all pieces are at the correct positions
-            puzzlePiece.setCorrectPosition(i);
-            puzzlePiece.setActualPosition(i);
-
-            piecesMap.put(piecesMap.size(), puzzlePiece);
-            addActor(puzzlePiece);
-        }
-    }
-
-    //method shuffles pieces inside grid and sets its rotation randomly
-    public void shufflePieces(Random random) {
-        //random rotation
-        for (PuzzlePiece piece : piecesMap.values()) {
-            piece.setRotation(90 * (random.nextInt(4)));
-        }
-    }
-
-    //finds piece at specified point that does not have the tabuId
-    public PuzzlePiece pieceAtPoint(float x, float y, int tabuId) {
-        Rectangle point = new Rectangle(x, y, 1, 1);
-        for (PuzzlePiece piece : piecesMap.values()) {
-            if (piece.getId() != tabuId) {
-                Vector2 recalculatedCoords = new Vector2(piece.getX(), piece.getY());
-                localToStageCoordinates(recalculatedCoords);
-                Rectangle currentPieceRectangle = new Rectangle(recalculatedCoords.x, recalculatedCoords.y, piece.getWidth(), piece.getHeight());
-                Rectangle intersectionRectangle = new Rectangle();
-                if (Intersector.intersectRectangles(point, currentPieceRectangle, intersectionRectangle)) {
-                    return piece;
-                }
-            }
-        }
-        return null;
-    }
-
-    public PuzzlePiece pieceAtPoint(float x, float y) {
-        return pieceAtPoint(x, y, -1);
-    }
-
-    public PuzzlePiece pieceIntersectingWithDragged(int draggedPieceId) {
-        PuzzlePiece draggedPiece = piecesMap.get(draggedPieceId);
-        Vector2 pointRecalculatedPoint = new Vector2(draggedPiece.getX(), draggedPiece.getY());
-        localToStageCoordinates(pointRecalculatedPoint);
-        return pieceAtPoint(pointRecalculatedPoint.x + draggedPiece.getWidth() / 2, pointRecalculatedPoint.y + draggedPiece.getHeight() / 2, draggedPieceId);
-    }
-
-    public void unscalePieces(int draggedPieceId, int pieceNotToUnscaleId) {
-        for (PuzzlePiece piece : piecesMap.values()) {
-            if (piece.getId() != pieceNotToUnscaleId && piece.getId() != draggedPieceId) {
-                piece.setScale(1);
-                piece.setZIndex(1);
-            }
-        }
-    }
-
-    public void switchPieces(PuzzlePiece draggedPiece, PuzzlePiece overlappedPiece,Action moveAction) {
-        if (draggedPiece != null) {
-            int draggedPieceActualPosition = draggedPiece.getActualPosition();
-            Pair<Float,Float> draggedPiecePositionInPixels = getPieceGridPositionInPixels(draggedPieceActualPosition);
-
-            if (overlappedPiece == null) {
-                Log.info(getClass(), "PIECE RELEASED ABOVE EMPTY AREA");
-                addAction(Actions.sequence(animatePieceInPosition(draggedPiece, draggedPiecePositionInPixels.getKey(), draggedPiecePositionInPixels.getValue()),moveAction));
-
-            } else {
-                Log.info(getClass(), "PIECE RELEASED ABOVE PIECE: " + overlappedPiece.toString());
-                int overlappedPieceActualPosition = overlappedPiece.getActualPosition();
-                Pair<Float,Float> overlappedPiecePositionInPixels = getPieceGridPositionInPixels(overlappedPieceActualPosition);
-                draggedPiece.setActualPosition(overlappedPieceActualPosition);
-                overlappedPiece.setActualPosition(draggedPieceActualPosition);
-                Log.info(getClass(),"Switching pieces at coordinates....Dragged toooo: "+overlappedPiecePositionInPixels.getKey()+", "+overlappedPiecePositionInPixels.getValue()+".....Overlapped to: "+draggedPiecePositionInPixels.getKey()+", "+draggedPiecePositionInPixels.getValue());
-                addAction(Actions.sequence(Actions.parallel(animatePieceInPosition(draggedPiece, overlappedPiecePositionInPixels.getKey(), overlappedPiecePositionInPixels.getValue()), animatePieceInPosition(overlappedPiece, draggedPiecePositionInPixels.getKey(), draggedPiecePositionInPixels.getValue())),moveAction));
-            }
-        }
-    }
-
-    private Action animatePieceInPosition(final PuzzlePiece piece, final float x, final float y) {
-        Action action = new Action() {
-            @Override
-            public boolean act(float delta) {
-                Action finalAction = new Action() {
-                    @Override
-                    public boolean act(float delta) {
-                        piece.setZIndex(1);
-                        piece.setScale(1);
-                        return true;
-                    }
-                };
-                piece.addAction(Actions.sequence(Actions.moveTo(x, y, DragAndRotateActorListener.MOVETO_ANIMATION_DURATION),finalAction));
-                return true;
-            }
-        };
-        return action;
-    }
-
-    public boolean allPiecesInCorrectPositions(){
-        for(PuzzlePiece piece: piecesMap.values()){
-            float pieceRotation = piece.getRotation()%360;
-            if(piece.getActualPosition()!=piece.getCorrectPosition()||pieceRotation!=0){
-                return false;
-            }
-        }
-        return true;
-    }
-
-    //returns the position of piece inside grid according to piece's actual position
-    private Pair<Float,Float> getPieceGridPositionInPixels(int actualPositionInGrid){
-        float pieceSize = getWidth() / (float) numberOfColumns;
-        Pair<Integer,Integer> pieceOrderNumbers = getPieceOrderNumbers(actualPositionInGrid);
-
-        Log.info(getClass(),"Piece order numbers: "+pieceOrderNumbers.getKey()+", "+pieceOrderNumbers.getValue());
-
-        return new Pair<Float, Float>(pieceOrderNumbers.getKey() * pieceSize, getHeight() - ((1 + pieceOrderNumbers.getValue()) * pieceSize));
-    }
-
-    //Pieces are placed from upper left corner, method returns relative positions according to number of rows and columns
-    private Pair<Float,Float> getPieceRelativePosition(int actualPositionInGrid){
-        Pair<Integer,Integer> pieceOrderNumbers = getPieceOrderNumbers(actualPositionInGrid);
-        float relativeXPosition = (float) pieceOrderNumbers.getKey() / (float) numberOfColumns;
-        float relativeYPosition = (float) pieceOrderNumbers.getValue() / (float) numberOfColumns;
-
-        return  new Pair<Float, Float>(relativeXPosition,relativeYPosition);
-    }
-
-    private Pair<Integer,Integer> getPieceOrderNumbers(int actualPositionInGrid){
-        int xOrderCoord = (actualPositionInGrid % numberOfColumns);
-        int yOrderCoord = (actualPositionInGrid / numberOfColumns);
-
-        return new Pair<Integer, Integer>(xOrderCoord,yOrderCoord);
-    }
-}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/helper/ArithmeticsHelper.java b/core/src/cz/nic/tablexia/game/games/pursuit/helper/ArithmeticsHelper.java
index 25043871e..7cad44dc2 100644
--- a/core/src/cz/nic/tablexia/game/games/pursuit/helper/ArithmeticsHelper.java
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/helper/ArithmeticsHelper.java
@@ -6,6 +6,7 @@ import net.dermetfan.utils.Pair;
 
 import java.util.Random;
 
+import cz.nic.tablexia.game.games.pursuit.model.Point;
 import cz.nic.tablexia.util.Log;
 
 /**
@@ -14,8 +15,8 @@ import cz.nic.tablexia.util.Log;
 public class ArithmeticsHelper {
     public static final int CARDINAL_POINTS_COUNT = 4;
 
-    public static double getAngleBetweenTwoPoints(Pair<Float,Float> firstPoint, Pair<Float,Float> secondPoint) {
-        double degrees = Math.atan2(secondPoint.getKey() - firstPoint.getKey(), secondPoint.getValue() - firstPoint.getValue());
+    public static double getAngleBetweenTwoPoints(Point firstPoint, Point secondPoint) {
+        double degrees = Math.atan2(secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y);
         degrees = (degrees > 0 ? degrees : (2*Math.PI + degrees)) * 360 / (2*Math.PI);
         double angleInsideThreeSixty = (float) degrees % 360;
         double recalcAngle = 360 - angleInsideThreeSixty;
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/model/Grid.java b/core/src/cz/nic/tablexia/game/games/pursuit/model/Grid.java
new file mode 100644
index 000000000..49d18b862
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/model/Grid.java
@@ -0,0 +1,238 @@
+package cz.nic.tablexia.game.games.pursuit.model;
+
+import com.badlogic.gdx.graphics.g2d.TextureRegion;
+import com.badlogic.gdx.math.Intersector;
+import com.badlogic.gdx.math.Rectangle;
+import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.scenes.scene2d.Action;
+import com.badlogic.gdx.scenes.scene2d.Group;
+import com.badlogic.gdx.scenes.scene2d.Touchable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.Stack;
+
+import cz.nic.tablexia.TablexiaSettings;
+import cz.nic.tablexia.game.games.pursuit.action.MovePieceToPosition;
+import cz.nic.tablexia.game.games.pursuit.action.SwitchPiecesAction;
+import cz.nic.tablexia.util.Log;
+
+/**
+ * Created by Václav Tarantík on 17.6.15.
+ */
+public class Grid extends Group {
+    private float size;
+    private int numberOfColumns;//number of rows respectively columns
+    private Map<Integer, PuzzlePiece> piecesMap;
+    private TextureRegion textureRegion;
+    private Random random;
+
+    public Grid(float x, float y, float size, int numberOfColumns, TextureRegion textureRegion,Random random) {
+        super();
+        setPosition(x, y);
+        setSize(size, size);
+
+        setDebug(TablexiaSettings.getInstance().isShowBoundingBoxes());
+
+        this.textureRegion = textureRegion;
+        this.numberOfColumns = numberOfColumns;
+        this.random = random;
+
+        setTouchable(Touchable.disabled);
+
+        piecesMap = new LinkedHashMap<Integer, PuzzlePiece>();
+        placePieces();
+
+    }
+
+    //creates pieces texture regions and places them in the grid
+    private void placePieces() {
+        for (int i = 0; i < Math.pow(numberOfColumns, 2); i++) {
+            float pieceSize = getWidth() / (float) numberOfColumns;
+            Point pieceRelativePosition = getPieceRelativePosition(i);
+            float relativePieceSize = pieceSize / getWidth();
+
+            //TextureRegion divided in parts for each piece
+            Log.info(getClass(), "Texture: " + textureRegion.getTexture() + " RPX: " + pieceRelativePosition.x + " RPSX: " + (pieceRelativePosition.x + relativePieceSize) + ", RPY: " + pieceRelativePosition.y + ", RPSY: " + (pieceRelativePosition.y + relativePieceSize) + ", SIZE: " + relativePieceSize * getWidth());
+            TextureRegion pieceRegion = new TextureRegion(textureRegion.getTexture(), pieceRelativePosition.x, pieceRelativePosition.y, pieceRelativePosition.x + relativePieceSize, pieceRelativePosition.y + relativePieceSize);
+
+            PuzzlePiece puzzlePiece = new PuzzlePiece(i, pieceRegion);
+            puzzlePiece.setSize(pieceSize, pieceSize);
+            puzzlePiece.setOrigin(pieceSize / 2, pieceSize / 2);
+            puzzlePiece.setZIndex(1);
+
+            //in initial state, all pieces are at the correct positions
+            puzzlePiece.setCorrectPosition(i);
+            puzzlePiece.setActualPosition(i);
+
+            piecesMap.put(piecesMap.size(), puzzlePiece);
+            addActor(puzzlePiece);
+        }
+        shufflePieces(random);
+    }
+
+    //method shuffles pieces inside grid and sets its rotation randomly
+    private void shufflePieces(Random random) {
+        //random rotation
+        for (PuzzlePiece piece : piecesMap.values()) {
+            piece.setRotation(90 * (random.nextInt(4)));
+        }
+
+        //random position
+        setRandomPositionsForPieces(random);
+        placePiecesInGrid();
+    }
+
+    //finds piece at specified point that does not have the tabuId
+    public PuzzlePiece pieceAtPoint(float x, float y, int tabuId) {
+        Rectangle point = new Rectangle(x, y, 1, 1);
+        for (PuzzlePiece piece : piecesMap.values()) {
+            if (piece.getId() != tabuId) {
+                Vector2 recalculatedCoords = new Vector2(piece.getX(), piece.getY());
+                localToStageCoordinates(recalculatedCoords);
+                Rectangle currentPieceRectangle = new Rectangle(recalculatedCoords.x, recalculatedCoords.y, piece.getWidth(), piece.getHeight());
+                Rectangle intersectionRectangle = new Rectangle();
+                if (Intersector.intersectRectangles(point, currentPieceRectangle, intersectionRectangle)) {
+                    return piece;
+                }
+            }
+        }
+        return null;
+    }
+
+    public PuzzlePiece pieceAtPoint(float x, float y) {
+        return pieceAtPoint(x, y, -1);
+    }
+
+    public PuzzlePiece pieceIntersectingWithDragged(int draggedPieceId) {
+        PuzzlePiece draggedPiece = piecesMap.get(draggedPieceId);
+        Vector2 pointRecalculatedPoint = new Vector2(draggedPiece.getX(), draggedPiece.getY());
+        localToStageCoordinates(pointRecalculatedPoint);
+        return pieceAtPoint(pointRecalculatedPoint.x + draggedPiece.getWidth() / 2, pointRecalculatedPoint.y + draggedPiece.getHeight() / 2, draggedPieceId);
+    }
+
+    public void unscalePieces(int draggedPieceId, int pieceNotToUnscaleId) {
+        for (PuzzlePiece piece : piecesMap.values()) {
+            if (piece.getId() != pieceNotToUnscaleId && piece.getId() != draggedPieceId) {
+                piece.setScale(1);
+                piece.setZIndex(1);
+            }
+        }
+    }
+
+    public void switchPieces(PuzzlePiece draggedPiece, PuzzlePiece overlappedPiece,Action moveAction) {
+        if (draggedPiece != null) {
+            int draggedPieceActualPosition = draggedPiece.getActualPosition();
+           Point draggedPiecePositionInPixels = getPieceGridPositionInPixels(draggedPieceActualPosition);
+
+            //Piece was released above the empty area
+            if (overlappedPiece == null) {
+                addAction(new MovePieceToPosition(draggedPiece,draggedPiecePositionInPixels,moveAction));
+
+            } else {
+                int overlappedPieceActualPosition = overlappedPiece.getActualPosition();
+                Point overlappedPiecePositionInPixels = getPieceGridPositionInPixels(overlappedPieceActualPosition);
+                addAction(new SwitchPiecesAction(draggedPiece,draggedPiecePositionInPixels,overlappedPiece,overlappedPiecePositionInPixels,moveAction));
+            }
+        }
+    }
+
+    //returns the position of piece inside grid according to piece's actual position
+    private Point getPieceGridPositionInPixels(int actualPositionInGrid){
+        float pieceSize = getWidth() / (float) numberOfColumns;
+        Point pieceOrderNumbers = getPieceOrderNumbers(actualPositionInGrid);
+
+        return new Point(pieceOrderNumbers.x * pieceSize, getHeight() - ((1 + pieceOrderNumbers.y) * pieceSize));
+    }
+
+    //Pieces are placed from upper left corner, method returns relative positions according to number of rows and columns
+    private Point getPieceRelativePosition(int actualPositionInGrid){
+        Point pieceOrderNumbers = getPieceOrderNumbers(actualPositionInGrid);
+        float relativeXPosition = pieceOrderNumbers.x / (float) numberOfColumns;
+        float relativeYPosition = pieceOrderNumbers.y / (float) numberOfColumns;
+
+        return new Point(relativeXPosition,relativeYPosition);
+    }
+
+    private Point getPieceOrderNumbers(int actualPositionInGrid){
+        int xOrderCoord = (actualPositionInGrid % numberOfColumns);
+        int yOrderCoord = (actualPositionInGrid / numberOfColumns);
+
+        return new Point(xOrderCoord,yOrderCoord);
+    }
+
+    private void placePiecesInGrid(){
+        for(PuzzlePiece piece: piecesMap.values()){
+            Point piecePosition = getPieceGridPositionInPixels(piece.getActualPosition());
+            piece.setPosition(piecePosition.x,piecePosition.y);
+        }
+    }
+
+    //Method sets unique random currentPosition values to pieces
+    private void setRandomPositionsForPieces(Random random){
+        //Generating random sequence
+        Stack possibleCardPositions = new Stack();
+        for (int i = 0; i < numberOfColumns*numberOfColumns; i++) {
+            possibleCardPositions.add(i);
+        }
+        //using random seed to shuffle sequence collection
+        Collections.shuffle(possibleCardPositions, random);
+
+        for(PuzzlePiece piece: piecesMap.values()){
+            piece.setActualPosition((Integer)possibleCardPositions.pop());
+        }
+    }
+
+    public boolean allPiecesInCorrectPositions(){
+        ArrayList<Integer> listToBeTransposed = new ArrayList<Integer>();
+        //fills the arraylist with values for default piece rotation (0)
+        for(PuzzlePiece piece: piecesMap.values()){
+            listToBeTransposed.add(piece.getCorrectPosition());
+        }
+        //direction according to the piece rotation: 0 - UP, 1 - RIGHT, 2 - DOWN, 3 - LEFT
+        float firstPieceRotation = ((PuzzlePiece)piecesMap.values().toArray()[0]).getRotation()%360;
+        //recalculating piece rotation in positive range of values
+        if(firstPieceRotation<0){
+            firstPieceRotation = 360+firstPieceRotation;
+        }
+        int firstPieceRotationDirection = (int)firstPieceRotation/90;
+        for (int i = 0;i<firstPieceRotationDirection;i++){
+            listToBeTransposed = transposeList(listToBeTransposed);
+        }
+        for(int i = 0; i<piecesMap.size();i++){
+            PuzzlePiece piece = (PuzzlePiece)piecesMap.values().toArray()[i];
+            float currentPieceRotation = piece.getRotation()%360;
+            //recalculating piece rotation in positive range of values
+            if(currentPieceRotation<0){
+                currentPieceRotation = 360+currentPieceRotation;
+            }
+            if(piece.getActualPosition()!=listToBeTransposed.get(i)||(currentPieceRotation!=firstPieceRotation)){
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    //Method transposes the matrix to check whether the result shape is correctly folded with rotation
+    /*  One usage of this method on values in list does the following:
+        |0|1|2|      |6|3|0|
+        |3|4|5|  ->  |7|4|1|
+        |6|7|8|      |8|5|2|
+     */
+
+    public ArrayList<Integer> transposeList(ArrayList<Integer> listToBeTransposed) {
+        ArrayList<Integer> listToBeReturned = new ArrayList<Integer>(9);
+        int repetitionCounter = numberOfColumns - 1;
+        for (int i = repetitionCounter; i >= 0; i--) {
+            for (int j = 0; j < numberOfColumns; j++) {
+                listToBeReturned.add(listToBeTransposed.get(listToBeTransposed.size() - 1 - ((numberOfColumns * j) + repetitionCounter)));
+            }
+            repetitionCounter--;
+        }
+        return listToBeReturned;
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/model/Point.java b/core/src/cz/nic/tablexia/game/games/pursuit/model/Point.java
new file mode 100644
index 000000000..54f1bbb3c
--- /dev/null
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/model/Point.java
@@ -0,0 +1,21 @@
+package cz.nic.tablexia.game.games.pursuit.model;
+
+import net.dermetfan.utils.Pair;
+
+/**
+ * Created by Václav Tarantík on 3.8.15.
+ */
+public class Point  {
+    public float x;
+    public float y;
+
+    public Point(float x, float y){
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    public String toString() {
+        return "X: "+x+", Y:"+y;
+    }
+}
diff --git a/core/src/cz/nic/tablexia/game/games/pursuit/environment/PuzzlePiece.java b/core/src/cz/nic/tablexia/game/games/pursuit/model/PuzzlePiece.java
similarity index 83%
rename from core/src/cz/nic/tablexia/game/games/pursuit/environment/PuzzlePiece.java
rename to core/src/cz/nic/tablexia/game/games/pursuit/model/PuzzlePiece.java
index 52ae679f0..3823b493b 100644
--- a/core/src/cz/nic/tablexia/game/games/pursuit/environment/PuzzlePiece.java
+++ b/core/src/cz/nic/tablexia/game/games/pursuit/model/PuzzlePiece.java
@@ -1,18 +1,10 @@
-package cz.nic.tablexia.game.games.pursuit.environment;
+package cz.nic.tablexia.game.games.pursuit.model;
 
-import com.badlogic.gdx.graphics.Texture;
 import com.badlogic.gdx.graphics.g2d.TextureRegion;
-import com.badlogic.gdx.math.MathUtils;
 import com.badlogic.gdx.math.Vector2;
-import com.badlogic.gdx.scenes.scene2d.Actor;
-import com.badlogic.gdx.scenes.scene2d.InputEvent;
-import com.badlogic.gdx.scenes.scene2d.InputListener;
 import com.badlogic.gdx.scenes.scene2d.Touchable;
 import com.badlogic.gdx.scenes.scene2d.ui.Image;
 
-import cz.nic.tablexia.util.Log;
-import cz.nic.tablexia.util.listener.DragAndRotateActorListener;
-
 /**
  * Created by Václav Tarantík on 17.6.15.
  */
diff --git a/core/src/cz/nic/tablexia/util/listener/DragAndRotateActorListener.java b/core/src/cz/nic/tablexia/util/listener/DragAndRotateActorListener.java
index 8a7ebaa50..86662b639 100644
--- a/core/src/cz/nic/tablexia/util/listener/DragAndRotateActorListener.java
+++ b/core/src/cz/nic/tablexia/util/listener/DragAndRotateActorListener.java
@@ -1,6 +1,7 @@
 package cz.nic.tablexia.util.listener;
 
 import com.badlogic.gdx.math.Vector2;
+import com.badlogic.gdx.scenes.scene2d.Action;
 import com.badlogic.gdx.scenes.scene2d.Actor;
 import com.badlogic.gdx.scenes.scene2d.InputEvent;
 import com.badlogic.gdx.scenes.scene2d.InputListener;
@@ -9,9 +10,12 @@ import com.badlogic.gdx.scenes.scene2d.actions.Actions;
 import net.dermetfan.utils.Pair;
 
 import java.util.LinkedHashMap;
-import java.util.TreeMap;
 
+import cz.nic.tablexia.game.games.pursuit.action.RotateAndMovePieceInPosition;
+import cz.nic.tablexia.game.games.pursuit.action.RotatePieceToClosestAngle;
 import cz.nic.tablexia.game.games.pursuit.helper.ArithmeticsHelper;
+import cz.nic.tablexia.game.games.pursuit.model.Point;
+import cz.nic.tablexia.game.games.pursuit.model.PuzzlePiece;
 import cz.nic.tablexia.util.Log;
 
 /**
@@ -23,38 +27,39 @@ public class DragAndRotateActorListener extends InputListener {
     public static final float MOVETO_ANIMATION_DURATION = 0.4f;
     private float grabX, grabY;
     private float initialFingersAngle;
-    private Actor actor;
+    private Actor draggedActor;
+    private Actor parentActor;
     private IOnRotationFinished iOnRotationFinished;
+    private boolean performingAction;
 
-    private LinkedHashMap<Integer, Pair<Float, Float>> activePointers;
+    private LinkedHashMap<Integer, Point> activePointers;
 
     public DragAndRotateActorListener(IOnRotationFinished iOnRotationFinished) {
         this.iOnRotationFinished = iOnRotationFinished;
-        activePointers = new LinkedHashMap<Integer, Pair<Float, Float>>();
+        activePointers = new LinkedHashMap<Integer, Point>();
     }
 
     public void selected(float x, float y) {
     }
-    ;
 
     public void moved(float x, float y, Actor draggedPiece) {
     }
-    ;
 
     public void dropped(float x, float y, Actor draggedPiece) {
     }
-    ;
 
     @Override
     public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
-        activePointers.put(pointer, new Pair(x, y));
-        selected(x, y);
-        if (actor != null) {
+        activePointers.put(pointer, new Point(x, y));
+        if(activePointers.size()==1){
+            selected(x, y);
+        }
+        if (draggedActor != null&&!performingAction) {
             if (activePointers.size() == 1) {
-                actor.setZIndex(DRAGGED_PIECE_ZINDEX);
-                actor.setScale(1.2f);
+                draggedActor.setZIndex(DRAGGED_PIECE_ZINDEX);
+                draggedActor.setScale(1.2f);
                 Vector2 recalculatedCoords = new Vector2(x, y);
-                actor.stageToLocalCoordinates(recalculatedCoords);
+                draggedActor.stageToLocalCoordinates(recalculatedCoords);
                 grabX = recalculatedCoords.x;
                 grabY = recalculatedCoords.y;
 
@@ -68,56 +73,58 @@ public class DragAndRotateActorListener extends InputListener {
     @Override
     public void touchDragged(InputEvent event, float x, float y, int pointer) {
         super.touchDragged(event, x, y, pointer);
-        if (actor != null&&actor.getActions().size==0) {
-            if (activePointers.size() == 1) {
-                //updating current pointer position
-                activePointers.put(pointer, new Pair(x, y));
-                Vector2 recalculatedCoords = new Vector2(x, y);
-                actor.stageToLocalCoordinates(recalculatedCoords);
-//                Log.info(getClass(), "Event x: " + x + ", " + y + "Actor position: " + actor.getX() + ", " + actor.getY() + "width: " + actor.getWidth() + " height: " + actor.getHeight());
-                float bx = actor.getX() + (recalculatedCoords.x - grabX);
-                float by = actor.getY() + (recalculatedCoords.y - grabY);
-                actor.setPosition(bx, by);
-                moved(bx, by, actor);
-            } else if (activePointers.size() > 1) {
-                if (pointer != activePointers.keySet().toArray()[0]) {
-                    activePointers.put(pointer, new Pair(x, y));
+        if (draggedActor != null&& !performingAction) {
+                if (activePointers.size() == 1) {
+                    //updating current pointer position
+                    activePointers.put(pointer, new Point(x, y));
+                    Vector2 recalculatedCoords = new Vector2(x, y);
+                    draggedActor.stageToLocalCoordinates(recalculatedCoords);
+                    float bx = draggedActor.getX() + (recalculatedCoords.x - grabX);
+                    float by = draggedActor.getY() + (recalculatedCoords.y - grabY);
+                    draggedActor.setPosition(bx, by);
+                    moved(bx, by, draggedActor);
+                } else if (activePointers.size() > 1) {
+                    //not updating the first finger coordinates when rotating so the piece does not move
+                    if (pointer != activePointers.keySet().toArray()[0]) {
+                        activePointers.put(pointer, new Point(x, y));
+                    }
+                    Point firstFingerCoordinates = activePointers.get(activePointers.keySet().toArray()[0]);
+                    Point secondFingerCoordinates = activePointers.get(activePointers.keySet().toArray()[1]);
+                    double angle = ArithmeticsHelper.getAngleBetweenTwoPoints(firstFingerCoordinates, secondFingerCoordinates);
+                    draggedActor.setRotation(draggedActor.getRotation() + (float) (angle - initialFingersAngle));
+                    initialFingersAngle = (float) angle;
                 }
-                Pair<Float, Float> firstFingerCoordinates = activePointers.get(activePointers.keySet().toArray()[0]);
-                Pair<Float, Float> secondFingerCoordinates = activePointers.get(activePointers.keySet().toArray()[1]);
-                double angle = ArithmeticsHelper.getAngleBetweenTwoPoints(firstFingerCoordinates, secondFingerCoordinates);
-                actor.setRotation(actor.getRotation() + (float) (angle - initialFingersAngle));
-                initialFingersAngle = (float) angle;
-            }
         }
     }
 
     @Override
     public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
-        if(actor!=null){
+        if(draggedActor!=null&&!performingAction){
             boolean draggingFingerLifted = ((Integer)(activePointers.keySet().toArray()[0]) == pointer);
             boolean rotatingFingerLifted = false;
-            if (activePointers.size()>1&&activePointers.keySet().toArray()[1] != null) {
+            if (activePointers.size()>1) {
                 rotatingFingerLifted = (Integer)activePointers.keySet().toArray()[1] == pointer;
             }
             activePointers.remove(pointer);
             if (activePointers.size() == 0) {
-                dropped(x, y, actor);
-            } else if (activePointers.size() >= 1) {
+                dropped(x, y, draggedActor);
+            } else if (activePointers.size() > 0) {
+
                 //if user raised the dragging finger, animate piece under second finger
-                Pair<Float, Float> currentFirstPointer = activePointers.get(activePointers.keySet().toArray()[0]);
+                Point currentFirstPointer = activePointers.get(activePointers.keySet().toArray()[0]);
                 if (draggingFingerLifted) {
-                    Vector2 recalculatedCoords = new Vector2(currentFirstPointer.getKey(), currentFirstPointer.getValue());
-                    actor.stageToLocalCoordinates(recalculatedCoords);
-                    float bx = actor.getX() + (recalculatedCoords.x-(actor.getWidth()/2));
-                    float by = actor.getY() + (recalculatedCoords.y-(actor.getHeight()/2));
+                    Vector2 recalculatedCoords = new Vector2(currentFirstPointer.x, currentFirstPointer.y);
+                    draggedActor.stageToLocalCoordinates(recalculatedCoords);
+                    float bx = draggedActor.getX() + (recalculatedCoords.x-(draggedActor.getWidth()/2));
+                    float by = draggedActor.getY() + (recalculatedCoords.y-(draggedActor.getHeight()/2));
 
-                    actor.addAction(Actions.parallel(Actions.rotateTo(ArithmeticsHelper.getClosestRightAngle(actor.getRotation()), ROTATION_ANIMATION_DURATION), Actions.moveTo(bx,by, MOVETO_ANIMATION_DURATION)));
+                    parentActor.addAction(new RotateAndMovePieceInPosition((PuzzlePiece) draggedActor, new Point(bx, by), iOnRotationFinished));
                 } else if (rotatingFingerLifted) {
-                    actor.addAction(Actions.rotateTo(ArithmeticsHelper.getClosestRightAngle(actor.getRotation()), ROTATION_ANIMATION_DURATION));
-                    iOnRotationFinished.onRotationFinished();
+                    parentActor.addAction(new RotatePieceToClosestAngle((PuzzlePiece) draggedActor, iOnRotationFinished));
                 }
             }
+        }else{
+            activePointers.remove(pointer);
         }
     }
 
@@ -125,11 +132,18 @@ public class DragAndRotateActorListener extends InputListener {
         void onRotationFinished();
     }
 
-    public void setActor(Actor actor) {
-        this.actor = actor;
+    public void setDraggedActor(Actor actor) {
+        this.draggedActor = actor;
+    }
+
+    public Actor getDraggedActor() {
+        return draggedActor;
     }
 
-    public Actor getActor() {
-        return actor;
+    public void setPerformingAction(boolean performingAction){
+        this.performingAction = performingAction;
+    }
+    public void setParentActor(Actor parentActor){
+        this.parentActor = parentActor;
     }
 }
-- 
GitLab