diff --git a/app/src/main/java/ru/ok/technopolis/basketball/CustomView/FieldView.java b/app/src/main/java/ru/ok/technopolis/basketball/CustomView/FieldView.java
new file mode 100644
index 0000000..0bf8953
--- /dev/null
+++ b/app/src/main/java/ru/ok/technopolis/basketball/CustomView/FieldView.java
@@ -0,0 +1,76 @@
+package ru.ok.technopolis.basketball.CustomView;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+import ru.ok.technopolis.basketball.R;
+
+public class FieldView extends View {
+
+ private Float currentX;
+ private Float currentY;
+ private Paint dotPaint = new Paint();
+ private Path dotPath = new Path();
+ private int pointRadius;
+ private static final int DEFAULT_POINT_COLOR = Color.BLACK;
+ public FieldView(Context context) {
+ super(context);
+ }
+
+ public FieldView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ int pointStrokeWidthFromAttr = Utils.pxFromDP(displayMetrics, R.dimen.default_point_stroke_width);
+ int pointRadiusFromAttr = Utils.pxFromDP(displayMetrics, R.dimen.default_point_radius);
+ int pointColorFromAttr = DEFAULT_POINT_COLOR;
+ if (attrs != null) {
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.FieldView);
+ pointStrokeWidthFromAttr = typedArray.getDimensionPixelOffset(R.styleable.FieldView_pointStrokeWidth, pointStrokeWidthFromAttr);
+ pointRadiusFromAttr = typedArray.getDimensionPixelSize(R.styleable.FieldView_pointRadius, pointRadiusFromAttr);
+ pointColorFromAttr = typedArray.getColor(R.styleable.FieldView_pointColor, pointColorFromAttr);
+ typedArray.recycle();
+ }
+
+ dotPaint.setStyle(Paint.Style.STROKE);
+ dotPaint.setColor(pointColorFromAttr);
+ dotPaint.setStrokeWidth(pointStrokeWidthFromAttr);
+ pointRadius = pointRadiusFromAttr;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (currentX == null || currentY == null) {
+ canvas.drawPath(dotPath, dotPaint);
+ return;
+ }
+ dotPath.addCircle(currentX, currentY, pointRadius, Path.Direction.CW);
+ canvas.drawPath(dotPath, dotPaint);
+ }
+
+ public void drawDot(float x, float y) {
+ currentX = x;
+ currentY = y;
+ invalidate();
+ }
+
+ public void clearField() {
+ dotPath.reset();
+ currentX = null;
+ currentY = null;
+ invalidate();
+ }
+}
diff --git a/app/src/main/java/ru/ok/technopolis/basketball/CustomView/ScoreView.java b/app/src/main/java/ru/ok/technopolis/basketball/CustomView/ScoreView.java
new file mode 100644
index 0000000..a0f348d
--- /dev/null
+++ b/app/src/main/java/ru/ok/technopolis/basketball/CustomView/ScoreView.java
@@ -0,0 +1,77 @@
+package ru.ok.technopolis.basketball.CustomView;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+
+import ru.ok.technopolis.basketball.R;
+
+public class ScoreView extends View {
+
+ private static final int DEFAULT_MARK_COLOR = Color.BLACK;
+ private Path markPath = new Path();
+ private Paint markPaint = new Paint();
+
+ public ScoreView(Context context) {
+ super(context);
+ }
+
+ public ScoreView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ int markStrokeWidthFromAttr = Utils.pxFromDP(displayMetrics, R.dimen.default_point_stroke_width);
+ int markColorFromAttr = DEFAULT_MARK_COLOR;
+ if (attrs != null) {
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScoreView);
+ markStrokeWidthFromAttr = typedArray.getDimensionPixelSize(R.styleable.ScoreView_markStrokeWidth, markStrokeWidthFromAttr);
+ markColorFromAttr = typedArray.getColor(R.styleable.ScoreView_markColor, markColorFromAttr);
+ typedArray.recycle();
+ }
+ markPaint.setStyle(Paint.Style.STROKE);
+ markPaint.setColor(markColorFromAttr);
+ markPaint.setStrokeWidth(markStrokeWidthFromAttr);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawPath(markPath, markPaint);
+ }
+
+ public void setMark(int mark) {
+ resetMark();
+ int leftPadding = getPaddingLeft();
+ int rightPadding = getPaddingRight();
+ int topPadding = getPaddingTop();
+ int bottomPadding = getPaddingBottom();
+ int width = getWidth() / 5 - leftPadding - rightPadding;
+ int xStart = width / 2 + leftPadding;
+ int yStart = getHeight() - bottomPadding;
+ int xEnd;
+ int yEnd;
+ for (int i = 0; i < mark; i++) {
+ markPath.moveTo(xStart, yStart);
+ xEnd = xStart + width / 2;
+ yEnd = yStart - getHeight() + topPadding + bottomPadding;
+ markPath.lineTo(xEnd, yEnd);
+ markPath.moveTo(xStart, yStart);
+ xEnd = xStart - width / 2;
+ yEnd = yStart - getHeight() / 2 + bottomPadding;
+ markPath.lineTo(xEnd, yEnd);
+ xStart += (width + leftPadding + rightPadding);
+ }
+ invalidate();
+ }
+
+ public void resetMark() {
+ markPath.reset();
+ invalidate();
+ }
+}
diff --git a/app/src/main/java/ru/ok/technopolis/basketball/CustomView/Utils.java b/app/src/main/java/ru/ok/technopolis/basketball/CustomView/Utils.java
new file mode 100644
index 0000000..f86231c
--- /dev/null
+++ b/app/src/main/java/ru/ok/technopolis/basketball/CustomView/Utils.java
@@ -0,0 +1,10 @@
+package ru.ok.technopolis.basketball.CustomView;
+
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+
+public final class Utils {
+ public static int pxFromDP(DisplayMetrics displayMetrics, int res){
+ return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, res, displayMetrics) + 0.5f);
+ }
+}
diff --git a/app/src/main/java/ru/ok/technopolis/basketball/MainActivity.java b/app/src/main/java/ru/ok/technopolis/basketball/MainActivity.java
index 8f71141..8e1d42f 100644
--- a/app/src/main/java/ru/ok/technopolis/basketball/MainActivity.java
+++ b/app/src/main/java/ru/ok/technopolis/basketball/MainActivity.java
@@ -1,13 +1,135 @@
package ru.ok.technopolis.basketball;
-import android.support.v7.app.AppCompatActivity;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.content.Context;
import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.animation.LinearInterpolator;
+import android.widget.Toast;
+
+import ru.ok.technopolis.basketball.CustomView.FieldView;
+import ru.ok.technopolis.basketball.CustomView.ScoreView;
-public class MainActivity extends AppCompatActivity {
+public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
+ private View ball;
+ private FieldView fieldView;
+ private ScoreView scoreView;
+ private View hoop;
+ private View player;
+ private VelocityTracker velocityTracker;
+ private Point startPoint;
+ private MotionOfProjectile motionOfProjectile;
+ private float currentX;
+ private float currentY;
+ private Context context;
+ private float G = 9800;
+ private float maxDistance;
+ private ValueAnimator animator;
+
+ @SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ fieldView = findViewById(R.id.field_view_basketball_field);
+ fieldView.setOnTouchListener(this);
+ ball = findViewById(R.id.image_ball);
+ float density = getResources().getDisplayMetrics().density;
+ hoop = findViewById(R.id.image_hoop);
+ player = findViewById(R.id.image_player);
+ scoreView = findViewById(R.id.score_view_score);
+ context = this;
+ G = G / density;
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ velocityTracker = VelocityTracker.obtain();
+ break;
+ case MotionEvent.ACTION_UP:
+ fieldView.clearField();
+ scoreView.resetMark();
+ velocityTracker.computeCurrentVelocity(1000);
+ calculateInitialCondition(event.getX(), event.getY(), velocityTracker.getXVelocity(), velocityTracker.getYVelocity());
+ initialiseAnimation();
+ velocityTracker.recycle();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ velocityTracker.addMovement(event);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ break;
+ }
+ ball.setTranslationX(event.getX() - ball.getLeft() - ball.getWidth() / 2);
+ ball.setTranslationY(event.getY() - ball.getTop() - ball.getHeight() / 2);
+ return true;
+ }
+
+ void calculateInitialCondition(float x0, float y0, float vx0, float vy0) {
+ startPoint = new Point(x0, y0, vx0, vy0);
+ startPoint.changeVerticalAxisTo(fieldView.getHeight());
+ motionOfProjectile = new MotionOfProjectile(startPoint, G);
+ }
+
+ void initialiseAnimation() {
+ if (isScored(startPoint.getX(), fieldView.getHeight() - startPoint.getY())) {
+ Toast.makeText(context, R.string.cheater, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ float timeStart = 0;
+ animator = ValueAnimator.ofFloat(timeStart, motionOfProjectile.getTimeFlight());
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ currentX = motionOfProjectile.getXFromTime((float) animation.getAnimatedValue());
+ currentY = fieldView.getHeight() - motionOfProjectile.getYFromTime((float) animation.getAnimatedValue());
+ ball.setX(currentX - ball.getWidth() / 2);
+ ball.setY(currentY - ball.getHeight() / 2);
+ if (isScored(currentX, currentY)) {
+ Toast.makeText(context, R.string.goll, Toast.LENGTH_SHORT).show();
+ maxDistance = Point.getDistance(player.getWidth(), fieldView.getHeight() - player.getHeight(), currentX, currentY);
+ startPoint.changeVerticalAxisTo(fieldView.getHeight());
+ scoreView.setMark(calculateScore(maxDistance, startPoint.getDistance(currentX, currentY)));
+
+ }
+ fieldView.drawDot(currentX, currentY);
+ if (animation.getAnimatedValue().equals(motionOfProjectile.getTimeFlight())) {
+ Toast.makeText(context, R.string.not_goll, Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ animator.setInterpolator(new LinearInterpolator());
+ animator.setDuration(2000);
+ animator.start();
+ }
+
+ private boolean isScored(float x, float y) {
+ if (x > (hoop.getLeft() + hoop.getWidth() / 2 - hoop.getWidth() / 6) && x < (hoop.getLeft() + hoop.getWidth() / 2 + hoop.getWidth() / 6)) {
+ if (y > (hoop.getTop() + hoop.getHeight() / 3) && y < (hoop.getTop() + hoop.getHeight() / 2 + hoop.getHeight() / 3)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (animator != null){
+ animator.cancel();
+ }
+ }
+
+ private int calculateScore(float maxDist, float dist) {
+ int score = (int) (dist / (maxDist / 4)) + 1;
+ return score > 5 ? 5 : score;
}
}
diff --git a/app/src/main/java/ru/ok/technopolis/basketball/MotionOfProjectile.java b/app/src/main/java/ru/ok/technopolis/basketball/MotionOfProjectile.java
new file mode 100644
index 0000000..1d392f5
--- /dev/null
+++ b/app/src/main/java/ru/ok/technopolis/basketball/MotionOfProjectile.java
@@ -0,0 +1,26 @@
+package ru.ok.technopolis.basketball;
+
+public class MotionOfProjectile {
+
+ private Point point;
+ private float G;
+
+ MotionOfProjectile(Point point, float G) {
+ this.point = point;
+ this.G = G;
+ }
+
+ public float getTimeFlight() {
+ float t1 = (float) (-point.getVy() + Math.sqrt(point.getVy() * point.getVy() + 2 * G * point.getY())) / (-G);
+ float t2 = (float) (-point.getVy() - Math.sqrt(point.getVy() * point.getVy() + 2 * G * point.getY())) / (-G);
+ return t1 > t2 ? t1 : t2;
+ }
+
+ public float getXFromTime(float t) {
+ return point.getX() + point.getVx() * t;
+ }
+
+ public float getYFromTime(float t) {
+ return (point.getY() + point.getVy() * t - G * t * t / 2);
+ }
+}
diff --git a/app/src/main/java/ru/ok/technopolis/basketball/Point.java b/app/src/main/java/ru/ok/technopolis/basketball/Point.java
new file mode 100644
index 0000000..0543150
--- /dev/null
+++ b/app/src/main/java/ru/ok/technopolis/basketball/Point.java
@@ -0,0 +1,53 @@
+package ru.ok.technopolis.basketball;
+
+public class Point {
+
+ private float x;
+ private float y;
+ private float vx;
+ private float vy;
+
+ public Point(float coordinate) {
+ this(coordinate, coordinate);
+ }
+
+ public Point(float x, float y) {
+ this(x, y, 0, 0);
+ }
+
+ public Point(float x, float y, float vx, float vy) {
+ this.x = x;
+ this.y = y;
+ this.vx = vx;
+ this.vy = vy;
+ }
+
+ public float getX() {
+ return x;
+ }
+
+ public float getY() {
+ return y;
+ }
+
+ public float getVx() {
+ return vx;
+ }
+
+ public float getVy() {
+ return vy;
+ }
+
+ public float getDistance(float x, float y) {
+ return (float) Math.sqrt((this.x - x) * (this.x - x) + (this.y - y) * (this.y - y));
+ }
+
+ public static float getDistance(float x1, float y1, float x2, float y2) {
+ return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
+ }
+
+ public void changeVerticalAxisTo(float y0) {
+ y = y0 - y;
+ vy = -vy;
+ }
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 037bef1..34e6033 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,10 +1,49 @@
-
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..f1d94f4
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
new file mode 100644
index 0000000..8f62931
--- /dev/null
+++ b/app/src/main/res/values/dimen.xml
@@ -0,0 +1,5 @@
+
+
+ 5dp
+ 5dp
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fa967e1..bd0712d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,6 @@
basketball_homework
+ Забил гол!
+ Не забил.
+ Играй честно.
diff --git a/build.gradle b/build.gradle
index e11a5b3..02199bb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.3.2'
+ classpath 'com.android.tools.build:gradle:3.4.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index d8eb277..31e6ac7 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Mar 24 00:28:03 MSK 2019
+#Tue May 21 19:39:42 MSK 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip