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