public abstract class Item implements Serializable { private Color color; public Item(Color color) { setColor(color); } public Color getColor() { return color; } private void setColor(Color color) { this.color = color; } @Override public String toString() { return "Item{" + "color=" + color + '}'; } }
public class Block extends Item { public Block() { super(Color.GRAY); } }
public class Ball extends Item { public Ball(Color color) { super(color); } }
public class Hole extends Item { public Hole(Color color) { super(color); } }
public class Level implements Serializable { private Item[][] field; private int ballsCount; public Level(Item[][] field) { this.field = field; } }
private int countBallsOnLevel(Item[][] field) { int ballsCount = 0; for (Item[] aField : field) { for (int j = 0; j < field[0].length; j++) { if (aField[j] != null && aField[j].getClass().equals(Ball.class)) { ballsCount++; } } } return ballsCount; }
this.ballsCount = countBallsOnLevel(field);
private Level level; private int ballsCount; public Field(Level level) { this.level = level; this.ballsCount = level.getBallsCount(); }
public enum Direction { LEFT, RIGHT, UP, DOWN, NOWHERE }
public class Coordinates { private int horizontal; private int vertical; public Coordinates(int horizontal, int vertical) { this.horizontal = horizontal; this.vertical = vertical; } }
private Coordinates moveRight(int xCoord, int yCoord) { try { while (level.getField()[yCoord][xCoord + 1] == null) { level.getField()[yCoord][xCoord + 1] = level.getField()[yCoord][xCoord]; level.getField()[yCoord][xCoord++] = null; } } catch (ArrayIndexOutOfBoundsException ex) { } return new Coordinates(xCoord, yCoord); }
private Coordinates moveItem(Coordinates coordinates, Direction direction) { int horizontal = coordinates.getHorizontal(); int vertical = coordinates.getVertical(); if (direction.equals(Direction.NOWHERE) || level.getField()[vertical][horizontal] == null) { return null; } Class clazz = level.getField()[vertical][horizontal].getClass(); if (!clazz.equals(Ball.class)) { return null; } switch (direction) { case RIGHT: return moveRight(horizontal, vertical); case LEFT: return moveLeft(horizontal, vertical); case UP: return moveUp(horizontal, vertical); case DOWN: return moveDown(horizontal, vertical); } return null; }
private boolean acceptRight(Coordinates coordinates) { try { int horizontal = coordinates.getHorizontal(); int vertical = coordinates.getVertical(); Item upItem = level.getField()[vertical][horizontal + 1]; Item item = level.getField()[vertical][horizontal]; if (upItem == null || !upItem.getClass().equals(Hole.class) || !(upItem.getColor().equals(item.getColor()))) { return false; } level.getField()[vertical][horizontal] = null; } catch (ArrayIndexOutOfBoundsException ex) { } return true; }
private boolean acceptHole(Coordinates coordinates, Direction direction) { boolean isAccepted = false; switch (direction) { case UP: isAccepted = acceptUp(coordinates); break; case DOWN: isAccepted = acceptDown(coordinates); break; case RIGHT: isAccepted = acceptRight(coordinates); break; case LEFT: isAccepted = acceptLeft(coordinates); break; } if (!isAccepted) { return false; } catchBall(); return checkWin(); }
private void catchBall() { ballsCount--; }
private boolean checkWin() { return ballsCount == 0; }
public boolean makeTurn(Coordinates coordinates, Direction direction) { Coordinates newCoordinates = moveItem(coordinates, direction); return newCoordinates != null && acceptHole(newCoordinates, direction); }
public class FieldView extends View { private final double ROUND_RECT_SIZE = 0.15; private final int PADDING_DIVIDER = 4; int paddingSize = 0; private int elementSize; private Field field; private Size fieldSize; private Size maxViewSize; public FieldView(Context context, AttributeSet attrs) { super(context, attrs); } }
public Size countFieldSize() { if (maxViewSize == null) { maxViewSize = new Size(this.getWidth(), this.getHeight()); } int horizontalElementsNum = field.getField()[0].length; int verticalElementsNum = field.getField().length; int maxHorizontalElSize = maxViewSize.getWidth() / horizontalElementsNum; int maxVerticalElSize = maxViewSize.getHeight() / verticalElementsNum; this.elementSize = (maxHorizontalElSize < maxVerticalElSize) ? maxHorizontalElSize : maxVerticalElSize; int newWidth = this.elementSize * horizontalElementsNum; int newHeight = this.elementSize * verticalElementsNum; return new Size(newWidth, newHeight); }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Size countedFieldSize = countFieldSize(); if (fieldSize == null || !fieldSize.equals(countedFieldSize)) { this.fieldSize = countedFieldSize; setFieldSize(this.fieldSize); paddingSize = (int) (Math.sqrt(elementSize) / PADDING_DIVIDER); } }
public void setFieldSize(Size size) { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(size.getWidth(), size.getHeight()); params.gravity = Gravity.CENTER_HORIZONTAL; this.setLayoutParams(params); }
Class clazz = item.getClass(); Color color = item.getColor(); if (clazz.equals(Block.class)) { GradientDrawable bgShape = new GradientDrawable(); bgShape.setColor(ContextCompat.getColor(getContext(), R.color.gray)); bgShape.setCornerRadius((float) (elementSize * ROUND_RECT_SIZE)); return bgShape; }
if (clazz.equals(Ball.class)) { GradientDrawable bgShape = new GradientDrawable(); bgShape.setColor(ContextCompat.getColor(getContext(), R.color.gray)); bgShape.setCornerRadius(elementSize); switch (color) { case GREEN: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.green)); return bgShape; case RED: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.red)); return bgShape; case BLUE: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.blue)); return bgShape; case YELLOW: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.yellow)); return bgShape; case PURPLE: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.purple)); return bgShape; case CYAN: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.cyan)); return bgShape; } }
<color name="red">#D81B60</color>
if (clazz.equals(Hole.class)) { GradientDrawable bgShape = new GradientDrawable(); bgShape.setCornerRadius((float) (elementSize * ROUND_RECT_SIZE)); switch (color) { case GREEN: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.green)); return bgShape; case RED: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.red)); return bgShape; case BLUE: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.blue)); return bgShape; case YELLOW: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.yellow)); return bgShape; case PURPLE: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.purple)); return bgShape; case CYAN: bgShape.setColor(ContextCompat.getColor(getContext(), R.color.cyan)); return bgShape; } }
if (item == null) { GradientDrawable bgShape = new GradientDrawable(); bgShape.setColor(ContextCompat.getColor(getContext(), android.R.color.transparent)); bgShape.setCornerRadius((float) (elementSize * ROUND_RECT_SIZE)); return bgShape; }
@Override protected void onDraw(Canvas canvas) { if (field == null) { return; } for (int i = 0; i < field.getField().length; i++) { for (int j = 0; j < field.getField()[0].length; j++) { Drawable d = selectDrawable(field.getField()[i][j]); d.setBounds(j * elementSize + paddingSize, i * elementSize + paddingSize, (j + 1) * elementSize - paddingSize, (i + 1) * elementSize - paddingSize); d.draw(canvas); } } }
public class Level { private Item[][] field; public Item[][] getField() { return field; } public Level() { field = new Item[6][6]; field[0][0] = new Block(); field[0][1] = new Block(); field[0][2] = new Hole(Color.RED); field[0][3] = new Block(); field[0][4] = new Block(); field[0][5] = new Block(); field[1][0] = new Block(); field[1][1] = new Ball(Color.RED); field[1][2] = new Ball(Color.GREEN); field[1][3] = new Ball(Color.YELLOW); field[1][4] = new Ball(Color.CYAN); field[1][5] = new Block(); field[2][0] = new Block(); field[2][1] = new Hole(Color.GREEN); field[2][2] = new Hole(Color.YELLOW); field[2][3] = new Hole(Color.PURPLE); field[2][4] = new Hole(Color.CYAN); field[2][5] = new Hole(Color.BLUE); field[3][0] = new Block(); field[3][1] = new Ball(Color.PURPLE); field[3][5] = new Block(); field[4][0] = new Block(); field[4][1] = new Block(); field[4][3] = new Ball(Color.BLUE); field[4][5] = new Block(); field[5][1] = new Block(); field[5][2] = new Block(); field[5][3] = new Block(); field[5][4] = new Block(); } }
public Direction getSwipeDirection(float downHorizontal, float upHorizontal, float downVertical, float upVertical) { float xDistance = Math.abs(upHorizontal - downHorizontal); float yDistance = Math.abs(upVertical - downVertical); double swipeLength = getSwipeLength(xDistance, yDistance); if (swipeLength < elementSize / 2) { return Direction.NOWHERE; } if (xDistance >= yDistance) { if (upHorizontal > downHorizontal) { return Direction.RIGHT; } return Direction.LEFT; } if (yDistance > xDistance) { if (upVertical > downVertical) { return Direction.DOWN; } return Direction.UP; } return Direction.DOWN; }
public Coordinates getElementCoordinates(float horizontal, float vertical) { float xElCoordinate = horizontal / elementSize; float yElCoordinate = vertical / elementSize; return new Coordinates((int) xElCoordinate, (int) yElCoordinate); }
private OnTouchListener onFieldTouchListener = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downHorizontal = event.getX(); downVertical = event.getY(); break; case MotionEvent.ACTION_UP: upHorizontal = event.getX(); upVertical = event.getY(); boolean isWin = fieldView.getField().makeTurn( fieldView.getElementCoordinates(downHorizontal, downVertical), fieldView.getSwipeDirection(downHorizontal, upHorizontal, downVertical, upVertical) ); }
fieldView.invalidate(); if (isWin) { animateView(fieldView); try { levelManager.finishLevel(); openLevel(levelManager.getCurrentLevelNumber()); } catch (GameException ex) { onMenuClick(); } } } return true;
public class LevelManager { private static final String LEVELS_FOLDER = "levels"; private static final String LEVEL_FILE_EXTENSION = ".lev"; private static final int EMPTY_CELL = 0; private static final int BLOCK_CELL = 1; private static final int GREEN_BALL_CELL = 2; private static final int RED_BALL_CELL = 3; private static final int BLUE_BALL_CELL = 4; private static final int YELLOW_BALL_CELL = 5; private static final int PURPLE_BALL_CELL = 6; private static final int CYAN_BALL_CELL = 7; private static final int GREEN_HOLE_CELL = 22; private static final int RED_HOLE_CELL = 33; private static final int BLUE_HOLE_CELL = 44; private static final int YELLOW_HOLE_CELL = 55; private static final int PURPLE_HOLE_CELL = 66; private static final int CYAN_HOLE_CELL = 77; private static Context context; private static SharedSettingsManager sharedSettingsManager; private static LevelManager instance; private LevelManager() { } public static LevelManager build(Context currentContext) { context = currentContext; sharedSettingsManager = SharedSettingsManager.build(currentContext); if (instance == null) { instance = new LevelManager(); } return instance; }
private Scanner openLevel(int levelNumber) throws IOException { AssetManager assetManager = context.getAssets(); InputStream inputStream = assetManager.open( LEVELS_FOLDER + "/" + String.valueOf(levelNumber) + LEVEL_FILE_EXTENSION); BufferedReader bufferedReader = new BufferedReader (new InputStreamReader(inputStream)); return new Scanner(bufferedReader); }
private Item convertLegendToItem(int itemLegend) { switch (itemLegend) { case EMPTY_CELL: return null; case BLOCK_CELL: return new Block(); case GREEN_BALL_CELL: return new Ball(Color.GREEN); case RED_BALL_CELL: return new Ball(Color.RED); case BLUE_BALL_CELL: return new Ball(Color.BLUE); case YELLOW_BALL_CELL: return new Ball(Color.YELLOW); case PURPLE_BALL_CELL: return new Ball(Color.PURPLE); case CYAN_BALL_CELL: return new Ball(Color.CYAN); case GREEN_HOLE_CELL: return new Hole(Color.GREEN); case RED_HOLE_CELL: return new Hole(Color.RED); case BLUE_HOLE_CELL: return new Hole(Color.BLUE); case YELLOW_HOLE_CELL: return new Hole(Color.YELLOW); case PURPLE_HOLE_CELL: return new Hole(Color.PURPLE); case CYAN_HOLE_CELL: return new Hole(Color.CYAN); } return null; }
public Level getLevel(int levelNumber) throws IOException { Scanner scanner = openLevel(levelNumber); int levelWidth = scanner.nextInt(); int levelHeight = scanner.nextInt(); Item levelMatrix[][] = new Item[levelHeight][levelWidth]; for (int i = 0; i < levelHeight; i++) { for (int j = 0; j < levelWidth; j++) { levelMatrix[i][j] = convertLegendToItem(scanner.nextInt()); } } Level level = new Level(levelMatrix); sharedSettingsManager.setCurrentLevel(levelNumber); return level; }
public void finishLevel() { sharedSettingsManager.setCurrentLevel( sharedSettingsManager.getCurrentLevel() + 1 ); if (sharedSettingsManager.getCurrentLevel() > sharedSettingsManager.getMaxLevel()) { throw new GameException(GameExceptionCodes.INCORRECT_LEVEL); } }
public static final String LAST_LEVEL = "current_level"; public static final String MAX_LEVEL = "max_level"; public static final String WAS_RAN_BEFORE = "was_ran_before"; private static final String APP_PREFS = "qook_prefs"; public static Context context; public static SharedSettingsManager instance; SharedPreferences sharedPreferences; private SharedSettingsManager() { sharedPreferences = context.getSharedPreferences(APP_PREFS, Context.MODE_PRIVATE); }
public int getMaxLevel() { return sharedPreferences.getInt(MAX_LEVEL, 1); }
public int getCurrentLevel() { return sharedPreferences.getInt(LAST_LEVEL, 1); }
private void setMaxLevel(int maxLevel) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt(MAX_LEVEL, maxLevel); editor.apply(); }
public void setCurrentLevel(int currentLevel) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putInt(LAST_LEVEL, currentLevel); editor.apply(); if (getMaxLevel() < currentLevel) { setMaxLevel(currentLevel); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/game_activity" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background" android:gravity="center_vertical" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".ui.activities.LevelActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/level_counter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="16dp" android:paddingTop="5dp" android:text="01 / 60" android:textSize="34sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:paddingBottom="10dp"> <ImageButton android:id="@+id/back_level_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:src="@drawable/menu_icon" /> <ImageButton android:id="@+id/reset_level_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:src="@drawable/restore_level" /> <ImageButton android:id="@+id/undo_step_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:src="@drawable/undo_step" /> </LinearLayout> </LinearLayout> <org.grakovne.qook.ui.views.FieldView android:id="@+id/field" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:background="@drawable/field_ground" android:foregroundGravity="center" /> </LinearLayout>
<TextView android:id="@+id/title_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:paddingBottom="16dp" android:text="@string/app_name" android:textAllCaps="true" android:textSize="48sp" android:textStyle="bold" /> <GridView android:id="@+id/level_grid" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="9" android:numColumns="5"> </GridView>
public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater vi; vi = LayoutInflater.from(getContext()); @SuppressLint("ViewHolder") View view = vi.inflate(R.layout.level_item, null); Integer currentLevelNumber = getItem(position); if (currentLevelNumber != null) { Button levelButton = (Button) view.findViewById(R.id.level_item_button); if (levelButton != null) { levelButton.setText(String.valueOf(currentLevelNumber)); if (position < maxOpenedLevel) { levelButton.setBackgroundResource(R.drawable.opened_level_item); levelButton.setClickable(true); levelButton.setOnClickListener(clickListener); levelButton.setId(currentLevelNumber); } else { levelButton.setBackgroundResource(R.drawable.closed_level_item); levelButton.setClickable(false); } } } return view; }
public class LevelButton extends Button { @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } }
@Override public void onResume() { super.onResume(); manager = LevelManager.build(getBaseContext()); View.OnClickListener levelClick = new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getBaseContext(), LevelActivity.class); intent.putExtra(DESIRED_LEVEL, v.getId()); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); startActivity(intent); } }; LevelGridAdapter adapter = new LevelGridAdapter(this, R.layout.level_item, getListOfLevelNumbers(), manager.getMaximalLevelNumber(), levelClick); adapter.setNotifyOnChange(false); levelGrid.setAdapter(adapter); levelGrid.setVerticalScrollBarEnabled(false); }
Source: https://habr.com/ru/post/283132/
All Articles